2626from django .views .decorators .http import require_POST , require_safe
2727from 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+
2937sys .path .append (settings .CUCKOO_PATH )
3038
3139from 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 )
0 commit comments