From 473fa8c0d05e7d420f695c9964a6b6414e664d44 Mon Sep 17 00:00:00 2001 From: boban Date: Sun, 5 Jul 2026 10:34:05 +0200 Subject: [PATCH] feat(honeypot): trap fake-login submits + capture the attempted credentials MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously a POST to a fake login hit a Laravel 419 (CSRF) or 405, unmasking the framework, and the phpMyAdmin/generic forms even posted to real paths (/index.php, /login). Now: the decoy paths are CSRF-exempt (bootstrap/app.php) and drop BlockBannedIp (an already-banned prober stays inside the deception, always fed a fake — never a revealing 403 — while the ban still blocks them from the REAL login). Every fake form posts back to its own decoy, so a submit re-serves the fake page (looks like a failed login) and trap() records the guessed username + password as threat intel (meta.tried_user / tried_pass). DetectHoneytoken stays on the group, so a submitted canary is still caught. --- app/Http/Controllers/HoneypotController.php | 30 ++++++++--- bootstrap/app.php | 12 ++++- routes/web.php | 39 ++++++++------ tests/Feature/HoneypotSubmitTest.php | 59 +++++++++++++++++++++ 4 files changed, 115 insertions(+), 25 deletions(-) create mode 100644 tests/Feature/HoneypotSubmitTest.php diff --git a/app/Http/Controllers/HoneypotController.php b/app/Http/Controllers/HoneypotController.php index e5528db..488e418 100644 --- a/app/Http/Controllers/HoneypotController.php +++ b/app/Http/Controllers/HoneypotController.php @@ -33,17 +33,33 @@ class HoneypotController extends Controller $ip = (string) $request->ip(); + $meta = [ + 'ua' => Str::limit((string) $request->userAgent(), 190), + 'method' => $request->method(), + 'query' => Str::limit((string) $request->getQueryString(), 190), + ]; + + // Capture the credentials a prober typed into the fake login — their guesses, which are + // threat intel (a legitimate user never reaches a decoy). The field names span the + // impersonated apps: WordPress (log/pwd), phpMyAdmin (pma_username/pma_password), and the + // generic form (username/password). This is the attacker's OWN submission, so logging + + // banning stays keyed to their IP — no reflected-victim risk. + $user = $request->input('log') ?? $request->input('pma_username') ?? $request->input('username'); + $pass = $request->input('pwd') ?? $request->input('pma_password') ?? $request->input('password'); + if (is_string($user) && $user !== '') { + $meta['tried_user'] = Str::limit($user, 120); + } + if (is_string($pass) && $pass !== '') { + $meta['tried_pass'] = Str::limit($pass, 120); + } + AuditEvent::create([ 'user_id' => null, 'actor' => 'system', 'action' => 'security.honeypot_hit', 'target' => Str::limit($request->path(), 190), 'ip' => $ip, - 'meta' => [ - 'ua' => Str::limit((string) $request->userAgent(), 190), - 'method' => $request->method(), - 'query' => Str::limit((string) $request->getQueryString(), 190), - ], + 'meta' => $meta, ]); app(BruteforceGuard::class)->banNow($ip, 'honeypot'); @@ -209,7 +225,7 @@ form.login legend{background:#e5e5e5;border:1px solid #a0a0a0;border-radius:4px;

Welcome to phpMyAdmin

-