Skip to content

Commit 0e35d16

Browse files
authored
Merge pull request kevoreilly#2938 from enzok/fix-01
Fix on-demand subfile updates and handle related oversized Mongo writes
2 parents a0d9ef3 + 48a575b commit 0e35d16

3 files changed

Lines changed: 68 additions & 25 deletions

File tree

web/analysis/views.py

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@
2626
from django.views.decorators.http import require_POST, require_safe
2727
from rest_framework.decorators import api_view
2828

29+
MONGO_DOCUMENT_TOO_LARGE_ERRORS = ()
30+
try:
31+
from pymongo.errors import DocumentTooLarge
32+
33+
MONGO_DOCUMENT_TOO_LARGE_ERRORS = (DocumentTooLarge,)
34+
except ImportError:
35+
pass
36+
2937
sys.path.append(settings.CUCKOO_PATH)
3038

3139
from lib.cuckoo.common.pcap_utils import PcapToNg
@@ -2521,6 +2529,11 @@ def on_demand(request, service: str, task_id: str, category: str, sha256):
25212529
).get("on_demand"):
25222530
return render(request, "error.html", {"error": "Not supported/enabled service on demand"})
25232531

2532+
# Restrict category to known report sections writable by this endpoint.
2533+
allowed_categories = {"static", "CAPE", "procdump", "procmemory", "dropped"}
2534+
if category not in allowed_categories:
2535+
return render(request, "error.html", {"error": f"Unsupported category: {category}"}, status=400)
2536+
25242537
# Self Extracted support folder
25252538
path = os.path.join(CUCKOO_ROOT, "storage", "analyses", task_id, "selfextracted", sha256)
25262539

@@ -2534,7 +2547,9 @@ def on_demand(request, service: str, task_id: str, category: str, sha256):
25342547
else:
25352548
path = os.path.join(ANALYSIS_BASE_PATH, "analyses", task_id, category, sha256)
25362549
else:
2537-
category = "target.file"
2550+
# selfextracted storage is shared by multiple categories; keep non-static category intact
2551+
if category == "static":
2552+
category = "target.file"
25382553
extractedfile = True
25392554

25402555
if path and (not _path_safe(path) or not path_exists(path)):
@@ -2587,37 +2602,65 @@ def on_demand(request, service: str, task_id: str, category: str, sha256):
25872602
details = Floss(path, package, on_demand=True).run()
25882603
if not details:
25892604
details = {"msg": "No results"}
2605+
2606+
def _set_service_by_sha256(node, target_sha256, service_name, service_details):
2607+
if isinstance(node, dict):
2608+
if node.get("sha256") == target_sha256:
2609+
node[service_name] = service_details
2610+
return True
2611+
for value in node.values():
2612+
if isinstance(value, (dict, list)) and _set_service_by_sha256(value, target_sha256, service_name, service_details):
2613+
return True
2614+
return False
2615+
if isinstance(node, list):
2616+
for item in node:
2617+
if _set_service_by_sha256(item, target_sha256, service_name, service_details):
2618+
return True
2619+
return False
2620+
25902621
if details:
25912622
buf = mongo_find_one("analysis", {"info.id": int(task_id)}, {"_id": 1, category: 1})
25922623

25932624
servicedata = {}
25942625
if category == "CAPE":
2595-
for block in buf[category].get("payloads", []) or []:
2596-
if block.get("sha256") == sha256:
2597-
block[service] = details
2598-
break
2626+
_set_service_by_sha256(buf[category].get("payloads", []) or [], sha256, service, details)
25992627
servicedata = buf[category]
26002628
elif category in ("procdump", "procmemory", "dropped"):
2601-
for block in buf[category] or []:
2602-
if block.get("sha256") == sha256:
2603-
block[service] = details
2604-
break
2629+
_set_service_by_sha256(buf[category] or [], sha256, service, details)
26052630
servicedata = buf[category]
2606-
elif "target" in category:
2631+
elif category == "target.file":
26072632
servicedata = buf.get("target", {}).get("file", {})
26082633
if servicedata:
26092634
if service == "xlsdeobf":
26102635
servicedata.setdefault("office", {}).setdefault("XLMMacroDeobfuscator", details)
26112636
elif extractedfile:
2612-
for block in servicedata.get("extracted_files", []):
2613-
if block.get("sha256") == sha256:
2614-
block[service] = details
2615-
break
2637+
_set_service_by_sha256(servicedata, sha256, service, details)
26162638
else:
26172639
servicedata.setdefault(service, details)
26182640

26192641
if servicedata:
2620-
mongo_update_one("analysis", {"_id": ObjectId(buf["_id"])}, {"$set": {category: servicedata}})
2642+
try:
2643+
mongo_update_one("analysis", {"_id": ObjectId(buf["_id"])}, {"$set": {category: servicedata}})
2644+
except MONGO_DOCUMENT_TOO_LARGE_ERRORS:
2645+
return render(
2646+
request,
2647+
"error.html",
2648+
{
2649+
"error": (
2650+
f"Generated {service} data is too large to store for this file. "
2651+
"Please narrow extraction scope or use offline extraction."
2652+
)
2653+
},
2654+
status=413,
2655+
)
2656+
except Exception as e:
2657+
print(f"on_demand update failed for task_id={task_id} service={service} category={category} sha256={sha256}: {e}")
2658+
return render(
2659+
request,
2660+
"error.html",
2661+
{"error": f"Failed to store generated {service} data."},
2662+
status=500,
2663+
)
26212664
del details
26222665

26232666
return redirect("report", task_id=task_id)

web/templates/analysis/generic/_file_info.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -273,31 +273,31 @@ <h5 class="mb-0 text-white"><i class="fas fa-file-alt me-2 text-info"></i> File
273273

274274
{% if config.flare_capa %}
275275
{% if not file.flare_capa and on_demand.flare_capa %}
276-
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "flare_capa" id tab_name file.sha256 %}">Gen CAPA</a>
276+
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "flare_capa" id tab_name file.sha256 %}">Extract: CAPA</a>
277277
{% elif file.flare_capa %}
278278
<a class="btn btn-sm btn-outline-warning me-2 mb-2" data-bs-toggle="collapse" href="#flare_capa_{{file.sha256}}">View CAPA</a>
279279
{% endif %}
280280
{% endif %}
281281

282282
{% if config.strings %}
283283
{% if "strings" not in file %}
284-
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "strings" id tab_name file.sha256 %}">Gen Strings</a>
284+
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "strings" id tab_name file.sha256 %}">Extract: Strings</a>
285285
{% elif file.strings %}
286286
<a class="btn btn-sm btn-outline-light me-2 mb-2" data-bs-toggle="collapse" href="#strings_{{file.sha256}}">Strings</a>
287287
{% endif %}
288288
{% endif %}
289289

290290
{% if config.floss %}
291291
{% if not file.floss %}
292-
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "floss" id tab_name file.sha256 %}">Gen Floss</a>
292+
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "floss" id tab_name file.sha256 %}">Extract: Floss</a>
293293
{% else %}
294294
<a class="btn btn-sm btn-outline-light me-2 mb-2" data-bs-toggle="collapse" href="#floss_{{file.sha256}}">Floss</a>
295295
{% endif %}
296296
{% endif %}
297297

298298
{% if config.bingraph %}
299299
{% if not graphs.bingraph.content|getkey:file.sha256 and on_demand.bingraph %}
300-
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "bingraph" id tab_name file.sha256 %}">Gen BinGraph</a>
300+
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "bingraph" id tab_name file.sha256 %}">Extract: BinGraph</a>
301301
{% else %}
302302
<a class="btn btn-sm btn-outline-light me-2 mb-2" href="{% url "file_nl" "bingraph" id file.sha256 %}">BinGraph</a>
303303
{% endif %}

web/templates/analysis/generic/_subfile_info.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -270,31 +270,31 @@ <h5 class="mb-0 text-white"><i class="fas fa-file-invoice me-2 text-info"></i> S
270270

271271
{% if config.flare_capa %}
272272
{% if not sub_file.flare_capa and on_demand.flare_capa %}
273-
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "flare_capa" id tab_name sub_file.sha256 %}">Gen CAPA</a>
273+
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "flare_capa" id tab_name sub_file.sha256 %}">Extract: CAPA</a>
274274
{% elif sub_file.flare_capa %}
275275
<a class="btn btn-sm btn-outline-warning me-2 mb-2" data-bs-toggle="collapse" href="#flare_capa_{{sub_file.sha256}}">View CAPA</a>
276276
{% endif %}
277277
{% endif %}
278278

279279
{% if config.strings %}
280280
{% if "strings" not in sub_file %}
281-
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "strings" id "static" sub_file.sha256 %}">Gen Strings</a>
281+
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "strings" id tab_name sub_file.sha256 %}">Extract: Strings</a>
282282
{% elif sub_file.strings %}
283283
<a class="btn btn-sm btn-outline-light me-2 mb-2" data-bs-toggle="collapse" href="#strings_{{sub_file.sha256}}">Strings</a>
284284
{% endif %}
285285
{% endif %}
286286

287287
{% if config.floss %}
288288
{% if not sub_file.floss %}
289-
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "floss" id "static" sub_file.sha256 %}">Gen Floss</a>
289+
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "floss" id tab_name sub_file.sha256 %}">Extract: Floss</a>
290290
{% else %}
291291
<a class="btn btn-sm btn-outline-light me-2 mb-2" data-bs-toggle="collapse" href="#floss_{{sub_file.sha256}}">Floss</a>
292292
{% endif %}
293293
{% endif %}
294294

295295
{% if config.bingraph %}
296296
{% if not graphs.bingraph.content|getkey:sub_file.sha256 and on_demand.bingraph %}
297-
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "bingraph" id tab_name sub_file.sha256 %}">Gen BinGraph</a>
297+
<a class="btn btn-sm btn-secondary me-2 mb-2" href="{% url "on_demand" "bingraph" id tab_name sub_file.sha256 %}">Extract: BinGraph</a>
298298
{% elif graphs.bingraph.content|getkey:sub_file.sha256 %}
299299
<a class="btn btn-sm btn-outline-light me-2 mb-2" href="{% url "file_nl" "bingraph" id sub_file.sha256 %}">BinGraph</a>
300300
{% endif %}
@@ -350,7 +350,7 @@ <h5 class="mb-0 text-white"><i class="fas fa-file-invoice me-2 text-info"></i> S
350350
<div class="card bg-dark text-white">
351351
<div class="card-header"><h6 class="mb-0">Strings</h6></div>
352352
<div class="card-body" style="max-height: 400px; overflow-y: auto;">
353-
{{sub_file.strings|safe}}
353+
<pre class="mb-0 small">{% for string in sub_file.strings %}{{string}}<br>{% endfor %}</pre>
354354
</div>
355355
</div>
356356
</div>
@@ -361,7 +361,7 @@ <h5 class="mb-0 text-white"><i class="fas fa-file-invoice me-2 text-info"></i> S
361361
<div class="card bg-dark text-white">
362362
<div class="card-header"><h6 class="mb-0">.NET Strings</h6></div>
363363
<div class="card-body" style="max-height: 400px; overflow-y: auto;">
364-
{% for string in sub_file.dotnet_strings %}<div>{{string|safe}}</div>{% endfor %}
364+
<pre class="mb-0 small">{% for string in sub_file.dotnet_strings %}{{string}}<br>{% endfor %}</pre>
365365
</div>
366366
</div>
367367
</div>

0 commit comments

Comments
 (0)