assemblyline-v4-service 4.6.1.dev248__py3-none-any.whl → 4.7.0.dev25__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- assemblyline_v4_service/VERSION +1 -1
- assemblyline_v4_service/common/api.py +0 -47
- assemblyline_v4_service/common/base.py +2 -6
- assemblyline_v4_service/common/ontology_helper.py +2 -0
- assemblyline_v4_service/common/request.py +4 -5
- assemblyline_v4_service/common/result.py +241 -219
- assemblyline_v4_service/common/task.py +6 -6
- assemblyline_v4_service/dev/updater.py +7 -2
- assemblyline_v4_service/healthz.py +18 -19
- {assemblyline_v4_service-4.6.1.dev248.dist-info → assemblyline_v4_service-4.7.0.dev25.dist-info}/METADATA +1 -1
- {assemblyline_v4_service-4.6.1.dev248.dist-info → assemblyline_v4_service-4.7.0.dev25.dist-info}/RECORD +15 -16
- test/test_common/test_api.py +0 -24
- assemblyline_v4_service/run_privileged_service.py +0 -337
- {assemblyline_v4_service-4.6.1.dev248.dist-info → assemblyline_v4_service-4.7.0.dev25.dist-info}/WHEEL +0 -0
- {assemblyline_v4_service-4.6.1.dev248.dist-info → assemblyline_v4_service-4.7.0.dev25.dist-info}/licenses/LICENCE.md +0 -0
- {assemblyline_v4_service-4.6.1.dev248.dist-info → assemblyline_v4_service-4.7.0.dev25.dist-info}/top_level.txt +0 -0
|
@@ -417,22 +417,22 @@ class SandboxMachineMetadata:
|
|
|
417
417
|
|
|
418
418
|
def __init__(
|
|
419
419
|
self,
|
|
420
|
-
# The IP of the machine
|
|
420
|
+
# The IP address of the analysis machine.
|
|
421
421
|
ip: Optional[str] = None,
|
|
422
422
|
|
|
423
|
-
# The hypervisor
|
|
423
|
+
# The hypervisor used by the analysis machine (e.g., VMware, KVM).
|
|
424
424
|
hypervisor: Optional[str] = None,
|
|
425
425
|
|
|
426
|
-
# The
|
|
426
|
+
# The hostname of the machine used for analysis.
|
|
427
427
|
hostname: Optional[str] = None,
|
|
428
428
|
|
|
429
|
-
# The platform
|
|
429
|
+
# The platform or operating system name (e.g., Windows, Linux, macOS).
|
|
430
430
|
platform: Optional[str] = None,
|
|
431
431
|
|
|
432
|
-
# The version of the operating system
|
|
432
|
+
# The version of the operating system.
|
|
433
433
|
version: Optional[str] = None,
|
|
434
434
|
|
|
435
|
-
# The architecture of the
|
|
435
|
+
# The architecture of the operating system (e.g., x86, x64, ARM).
|
|
436
436
|
architecture: Optional[str] = None,
|
|
437
437
|
):
|
|
438
438
|
self.ip = ip
|
|
@@ -453,96 +453,153 @@ class SandboxMachineMetadata:
|
|
|
453
453
|
"architecture": self.architecture,
|
|
454
454
|
}
|
|
455
455
|
|
|
456
|
+
LookupType = Literal[
|
|
457
|
+
"A", "AAAA", "AFSDB", "APL", "CAA", "CDNSKEY", "CDS", "CERT", "CNAME", "CSYNC",
|
|
458
|
+
"DHCID", "DLV", "DNAME", "DNSKEY", "DS", "EUI48", "EUI64", "HINFO", "HIP",
|
|
459
|
+
"HTTPS", "IPSECKEY", "KEY", "KX", "LOC", "MX", "NAPTR", "NS", "NSEC", "NSEC3",
|
|
460
|
+
"NSEC3PARAM", "OPENPGPKEY", "PTR", "RRSIG", "RP", "SIG", "SMIMEA", "SOA",
|
|
461
|
+
"SRV", "SSHFP", "SVCB", "TA", "TKEY", "TLSA", "TSIG", "TXT", "URI", "ZONEMD"
|
|
462
|
+
]
|
|
463
|
+
|
|
464
|
+
RequestMethod = Literal[
|
|
465
|
+
"GET", "POST", "PUT", "DELETE", "HEAD", "CONNECT", "OPTIONS", "TRACE", "PATCH",
|
|
466
|
+
"BCOPY", "BDELETE", "BMOVE", "BPROPFIND", "BPROPPATCH", "COPY", "LOCK",
|
|
467
|
+
"MKCOL", "MOVE", "NOTIFY", "POLL", "PROPFIND", "PROPPATCH", "SEARCH",
|
|
468
|
+
"SUBSCRIBE", "UNLOCK", "UNSUBSCRIBE", "X-MS-ENUMATTS"
|
|
469
|
+
]
|
|
470
|
+
|
|
471
|
+
ConnectionType = Literal["http", "dns", "tls", "smtp"]
|
|
472
|
+
ConnectionDirection = Literal["outbound", "inbound", "unknown"]
|
|
473
|
+
SignatureType = Literal["CUCKOO", "YARA", "SIGMA", "SURICATA"]
|
|
474
|
+
|
|
475
|
+
class SandboxMachineMetadata:
|
|
476
|
+
"""Information about the sandbox machine used during analysis."""
|
|
477
|
+
|
|
478
|
+
def __init__(
|
|
479
|
+
self,
|
|
480
|
+
# The IP address of the machine used for analysis.
|
|
481
|
+
ip: Optional[str] = None,
|
|
482
|
+
|
|
483
|
+
# The hypervisor type of the machine used for analysis.
|
|
484
|
+
hypervisor: Optional[str] = None,
|
|
485
|
+
|
|
486
|
+
# The hostname of the machine used for analysis.
|
|
487
|
+
hostname: Optional[str] = None,
|
|
488
|
+
|
|
489
|
+
# The operating system platform of the machine (e.g., "Windows", "Linux").
|
|
490
|
+
platform: Optional[str] = None,
|
|
491
|
+
|
|
492
|
+
# The version of the operating system.
|
|
493
|
+
version: Optional[str] = None,
|
|
494
|
+
|
|
495
|
+
# The system architecture of the machine (e.g., "x64", "arm64").
|
|
496
|
+
architecture: Optional[str] = None,
|
|
497
|
+
):
|
|
498
|
+
self.ip = ip
|
|
499
|
+
self.hypervisor = hypervisor
|
|
500
|
+
self.hostname = hostname
|
|
501
|
+
self.platform = platform
|
|
502
|
+
self.version = version
|
|
503
|
+
self.architecture = architecture
|
|
504
|
+
|
|
505
|
+
def as_primitives(self) -> Dict[str, Any]:
|
|
506
|
+
return {
|
|
507
|
+
"ip": self.ip,
|
|
508
|
+
"hypervisor": self.hypervisor,
|
|
509
|
+
"hostname": self.hostname,
|
|
510
|
+
"platform": self.platform,
|
|
511
|
+
"version": self.version,
|
|
512
|
+
"architecture": self.architecture,
|
|
513
|
+
}
|
|
514
|
+
|
|
456
515
|
|
|
457
516
|
class SandboxAnalysisMetadata:
|
|
458
|
-
"""Metadata
|
|
517
|
+
"""Metadata describing the context and configuration of a sandbox analysis."""
|
|
459
518
|
|
|
460
519
|
def __init__(
|
|
461
520
|
self,
|
|
462
|
-
# The
|
|
463
|
-
task_id: Optional[
|
|
521
|
+
# The unique identifier of the analysis task.
|
|
522
|
+
task_id: Optional[int] = None,
|
|
464
523
|
|
|
465
|
-
# The
|
|
524
|
+
# The timestamp when the analysis started (ISO 8601 format).
|
|
466
525
|
start_time: str = "",
|
|
467
526
|
|
|
468
|
-
# The
|
|
527
|
+
# The timestamp when the analysis ended (ISO 8601 format).
|
|
469
528
|
end_time: Optional[str] = None,
|
|
470
529
|
|
|
471
|
-
# The routing used
|
|
530
|
+
# The network routing used during analysis (e.g., "Spoofed", "Internet", "Tor", "VPN").
|
|
472
531
|
routing: Optional[str] = None,
|
|
473
532
|
|
|
474
|
-
# The resolution used for the
|
|
533
|
+
# The screen resolution or window size used for the sandbox environment.
|
|
475
534
|
window_size: Optional[str] = None,
|
|
535
|
+
|
|
536
|
+
# Metadata describing the machine on which the analysis ran.
|
|
537
|
+
machine_metadata: Optional[SandboxMachineMetadata] = None,
|
|
476
538
|
):
|
|
477
539
|
self.task_id = task_id
|
|
478
540
|
self.start_time = start_time
|
|
479
541
|
self.end_time = end_time
|
|
480
542
|
self.routing = routing
|
|
481
543
|
self.window_size = window_size
|
|
544
|
+
self.machine_metadata = machine_metadata
|
|
482
545
|
|
|
483
|
-
def as_primitives(self) -> Dict:
|
|
484
|
-
"""Return a JSON-serializable representation."""
|
|
546
|
+
def as_primitives(self) -> Dict[str, Any]:
|
|
485
547
|
return {
|
|
486
548
|
"task_id": self.task_id,
|
|
487
549
|
"start_time": self.start_time,
|
|
488
550
|
"end_time": self.end_time,
|
|
489
551
|
"routing": self.routing,
|
|
490
552
|
"window_size": self.window_size,
|
|
553
|
+
"machine_metadata": (
|
|
554
|
+
self.machine_metadata.as_primitives() if self.machine_metadata else None
|
|
555
|
+
),
|
|
491
556
|
}
|
|
492
557
|
|
|
493
558
|
|
|
494
559
|
class SandboxProcessItem:
|
|
495
|
-
"""
|
|
560
|
+
"""Information about a process observed during sandbox execution."""
|
|
496
561
|
|
|
497
562
|
def __init__(
|
|
498
563
|
self,
|
|
499
|
-
|
|
500
|
-
# The image of the process. Default: "<unknown_image>".
|
|
564
|
+
# The executable image name of the process. Default: "<unknown_image>".
|
|
501
565
|
image: str,
|
|
502
566
|
|
|
503
|
-
# The
|
|
567
|
+
# The timestamp when the process started (ISO 8601 format).
|
|
504
568
|
start_time: str,
|
|
505
569
|
|
|
506
|
-
# The process ID
|
|
570
|
+
# The parent process ID (PPID).
|
|
507
571
|
ppid: Optional[int] = None,
|
|
508
572
|
|
|
509
|
-
# The process ID.
|
|
573
|
+
# The process ID (PID).
|
|
510
574
|
pid: Optional[int] = None,
|
|
511
575
|
|
|
512
|
-
# The command line
|
|
576
|
+
# The full command line used to start the process.
|
|
513
577
|
command_line: Optional[str] = None,
|
|
514
578
|
|
|
515
|
-
# The
|
|
579
|
+
# The timestamp when the process terminated (ISO 8601 format).
|
|
516
580
|
end_time: Optional[str] = None,
|
|
517
581
|
|
|
518
|
-
# The integrity level of the process.
|
|
582
|
+
# The integrity level of the process (e.g., "High", "Medium", "Low").
|
|
519
583
|
integrity_level: Optional[str] = None,
|
|
520
584
|
|
|
521
|
-
# The hash of the file
|
|
585
|
+
# The hash of the executable file for the process (e.g., SHA256).
|
|
522
586
|
image_hash: Optional[str] = None,
|
|
523
587
|
|
|
524
|
-
# The original name
|
|
588
|
+
# The original file name as embedded in the binary metadata.
|
|
525
589
|
original_file_name: Optional[str] = None,
|
|
526
590
|
|
|
527
|
-
#
|
|
591
|
+
# Indicates whether this process was safelisted (whitelisted).
|
|
528
592
|
safelisted: Optional[bool] = False,
|
|
529
593
|
|
|
530
|
-
#
|
|
531
|
-
file_count: int = 0,
|
|
594
|
+
# The number of file I/O events associated with this process.
|
|
595
|
+
file_count: Optional[int] = 0,
|
|
532
596
|
|
|
533
|
-
#
|
|
534
|
-
registry_count: int = 0,
|
|
597
|
+
# The number of registry modification events associated with this process.
|
|
598
|
+
registry_count: Optional[int] = 0,
|
|
535
599
|
):
|
|
536
|
-
# ----------------------------
|
|
537
|
-
# Core process information
|
|
538
|
-
# ----------------------------
|
|
539
600
|
self.image = image or "<unknown_image>"
|
|
540
601
|
self.start_time = start_time
|
|
541
|
-
|
|
542
|
-
# Parent process information
|
|
543
602
|
self.ppid = ppid
|
|
544
|
-
|
|
545
|
-
# Current process information
|
|
546
603
|
self.pid = pid
|
|
547
604
|
self.command_line = command_line
|
|
548
605
|
self.end_time = end_time
|
|
@@ -550,15 +607,10 @@ class SandboxProcessItem:
|
|
|
550
607
|
self.image_hash = image_hash
|
|
551
608
|
self.original_file_name = original_file_name
|
|
552
609
|
self.safelisted = safelisted
|
|
553
|
-
|
|
554
|
-
# ----------------------------
|
|
555
|
-
# Relationships & statistics
|
|
556
|
-
# ----------------------------
|
|
557
610
|
self.file_count = file_count
|
|
558
611
|
self.registry_count = registry_count
|
|
559
612
|
|
|
560
|
-
def as_primitives(self) -> Dict:
|
|
561
|
-
"""Return a JSON-serializable dictionary representation of this process."""
|
|
613
|
+
def as_primitives(self) -> Dict[str, Any]:
|
|
562
614
|
return {
|
|
563
615
|
"image": self.image,
|
|
564
616
|
"start_time": self.start_time,
|
|
@@ -575,100 +627,82 @@ class SandboxProcessItem:
|
|
|
575
627
|
}
|
|
576
628
|
|
|
577
629
|
|
|
578
|
-
LookupType = Literal[
|
|
579
|
-
"A", "AAAA", "AFSDB", "APL", "CAA", "CDNSKEY", "CDS", "CERT", "CNAME", "CSYNC",
|
|
580
|
-
"DHCID", "DLV", "DNAME", "DNSKEY", "DS", "EUI48", "EUI64", "HINFO", "HIP",
|
|
581
|
-
"HTTPS", "IPSECKEY", "KEY", "KX", "LOC", "MX", "NAPTR", "NS", "NSEC", "NSEC3",
|
|
582
|
-
"NSEC3PARAM", "OPENPGPKEY", "PTR", "RRSIG", "RP", "SIG", "SMIMEA", "SOA",
|
|
583
|
-
"SRV", "SSHFP", "SVCB", "TA", "TKEY", "TLSA", "TSIG", "TXT", "URI", "ZONEMD"
|
|
584
|
-
]
|
|
585
|
-
|
|
586
|
-
RequestMethod = Literal[
|
|
587
|
-
"GET", "POST", "PUT", "DELETE", "HEAD", "CONNECT", "OPTIONS", "TRACE", "PATCH",
|
|
588
|
-
"BCOPY", "BDELETE", "BMOVE", "BPROPFIND", "BPROPPATCH", "COPY", "LOCK",
|
|
589
|
-
"MKCOL", "MOVE", "NOTIFY", "POLL", "PROPFIND", "PROPPATCH", "SEARCH",
|
|
590
|
-
"SUBSCRIBE", "UNLOCK", "UNSUBSCRIBE", "X-MS-ENUMATTS"
|
|
591
|
-
]
|
|
592
|
-
|
|
593
|
-
ConnectionType = Literal["http", "dns", "tls", "smtp"]
|
|
594
|
-
|
|
595
|
-
ConnectionDirection = Literal["outbound", "inbound", "unknown"]
|
|
596
630
|
|
|
597
631
|
|
|
598
632
|
class SandboxNetworkDNS:
|
|
599
|
-
"""Details
|
|
633
|
+
"""Details of a DNS query observed during sandbox execution."""
|
|
600
634
|
|
|
601
635
|
def __init__(
|
|
602
636
|
self,
|
|
637
|
+
# The domain name requested (queried).
|
|
603
638
|
domain: str,
|
|
639
|
+
|
|
640
|
+
# The DNS lookup type (e.g., "A", "AAAA", "MX").
|
|
604
641
|
lookup_type: LookupType,
|
|
642
|
+
|
|
643
|
+
# A list of IP addresses returned in the DNS response.
|
|
605
644
|
resolved_ips: Optional[List[str]] = None,
|
|
645
|
+
|
|
646
|
+
# A list of domain names returned in the DNS response (for CNAMEs, etc.).
|
|
606
647
|
resolved_domains: Optional[List[str]] = None,
|
|
607
648
|
):
|
|
608
|
-
# The domain requested.
|
|
609
649
|
self.domain = domain
|
|
610
|
-
|
|
611
|
-
# A list of IPs that were resolved.
|
|
650
|
+
self.lookup_type = lookup_type
|
|
612
651
|
self.resolved_ips = resolved_ips or []
|
|
613
|
-
|
|
614
|
-
# A list of domains that were resolved.
|
|
615
652
|
self.resolved_domains = resolved_domains or []
|
|
616
653
|
|
|
617
|
-
|
|
618
|
-
self.lookup_type = lookup_type
|
|
619
|
-
|
|
620
|
-
def as_primitives(self) -> Dict:
|
|
654
|
+
def as_primitives(self) -> Dict[str, Any]:
|
|
621
655
|
return {
|
|
622
656
|
"domain": self.domain,
|
|
657
|
+
"lookup_type": self.lookup_type,
|
|
623
658
|
"resolved_ips": self.resolved_ips,
|
|
624
659
|
"resolved_domains": self.resolved_domains,
|
|
625
|
-
"lookup_type": self.lookup_type,
|
|
626
660
|
}
|
|
627
661
|
|
|
628
662
|
|
|
629
663
|
class SandboxNetworkHTTP:
|
|
630
|
-
"""Details
|
|
664
|
+
"""Details of an HTTP request/response observed during sandbox execution."""
|
|
631
665
|
|
|
632
666
|
def __init__(
|
|
633
667
|
self,
|
|
668
|
+
# The URI requested by the process.
|
|
634
669
|
request_uri: str,
|
|
635
|
-
|
|
670
|
+
|
|
671
|
+
# Headers included in the HTTP request.
|
|
672
|
+
request_headers: Optional[Dict[str, Any]] = None,
|
|
673
|
+
|
|
674
|
+
# The HTTP request method (e.g., "GET", "POST").
|
|
636
675
|
request_method: Optional[RequestMethod] = None,
|
|
637
|
-
|
|
676
|
+
|
|
677
|
+
# Headers included in the HTTP response.
|
|
678
|
+
response_headers: Optional[Dict[str, Any]] = None,
|
|
679
|
+
|
|
680
|
+
# The raw body content of the HTTP request.
|
|
638
681
|
request_body: Optional[str] = None,
|
|
682
|
+
|
|
683
|
+
# The HTTP status code of the response (e.g., 200, 404).
|
|
639
684
|
response_status_code: Optional[int] = None,
|
|
685
|
+
|
|
686
|
+
# The raw body content of the HTTP response.
|
|
640
687
|
response_body: Optional[str] = None,
|
|
641
|
-
|
|
688
|
+
|
|
689
|
+
# Metadata about any file contained in the HTTP response body.
|
|
690
|
+
response_content_fileinfo: Optional[Dict[str, Any]] = None,
|
|
691
|
+
|
|
692
|
+
# The MIME type of the HTTP response content.
|
|
642
693
|
response_content_mimetype: Optional[str] = None,
|
|
643
694
|
):
|
|
644
|
-
# The URI requested.
|
|
645
695
|
self.request_uri = request_uri
|
|
646
|
-
|
|
647
|
-
# Headers included in the request.
|
|
648
696
|
self.request_headers = request_headers or {}
|
|
649
|
-
|
|
650
|
-
# The method of the request.
|
|
651
697
|
self.request_method = request_method
|
|
652
|
-
|
|
653
|
-
# Headers included in the response.
|
|
654
698
|
self.response_headers = response_headers or {}
|
|
655
|
-
|
|
656
|
-
# The body of the request.
|
|
657
699
|
self.request_body = request_body
|
|
658
|
-
|
|
659
|
-
# The status code of the response.
|
|
660
700
|
self.response_status_code = response_status_code
|
|
661
|
-
|
|
662
|
-
# The body of the response.
|
|
663
701
|
self.response_body = response_body
|
|
664
|
-
|
|
665
|
-
# File information of the response content.
|
|
666
702
|
self.response_content_fileinfo = response_content_fileinfo
|
|
667
|
-
|
|
668
|
-
# MIME type returned by the server.
|
|
669
703
|
self.response_content_mimetype = response_content_mimetype
|
|
670
704
|
|
|
671
|
-
def as_primitives(self) -> Dict:
|
|
705
|
+
def as_primitives(self) -> Dict[str, Any]:
|
|
672
706
|
return {
|
|
673
707
|
"request_uri": self.request_uri,
|
|
674
708
|
"request_headers": self.request_headers,
|
|
@@ -683,24 +717,24 @@ class SandboxNetworkHTTP:
|
|
|
683
717
|
|
|
684
718
|
|
|
685
719
|
class SandboxNetworkSMTP:
|
|
686
|
-
"""Details
|
|
720
|
+
"""Details of an SMTP email transaction observed during sandbox execution."""
|
|
687
721
|
|
|
688
722
|
def __init__(
|
|
689
723
|
self,
|
|
724
|
+
# The sender email address in the SMTP transaction.
|
|
690
725
|
mail_from: str,
|
|
726
|
+
|
|
727
|
+
# A list of recipient email addresses in the SMTP transaction.
|
|
691
728
|
mail_to: List[str],
|
|
692
|
-
|
|
729
|
+
|
|
730
|
+
# Information about any attachments transmitted via SMTP.
|
|
731
|
+
attachments: Optional[List[Dict[str, Any]]] = None,
|
|
693
732
|
):
|
|
694
|
-
# Sender of the email.
|
|
695
733
|
self.mail_from = mail_from
|
|
696
|
-
|
|
697
|
-
# Recipients of the email.
|
|
698
734
|
self.mail_to = mail_to
|
|
699
|
-
|
|
700
|
-
# File information about the attachments.
|
|
701
735
|
self.attachments = attachments or []
|
|
702
736
|
|
|
703
|
-
def as_primitives(self) -> Dict:
|
|
737
|
+
def as_primitives(self) -> Dict[str, Any]:
|
|
704
738
|
return {
|
|
705
739
|
"mail_from": self.mail_from,
|
|
706
740
|
"mail_to": self.mail_to,
|
|
@@ -709,51 +743,51 @@ class SandboxNetworkSMTP:
|
|
|
709
743
|
|
|
710
744
|
|
|
711
745
|
class SandboxNetflowItem:
|
|
712
|
-
"""Details
|
|
746
|
+
"""Details of a network flow (connection) observed during sandbox execution."""
|
|
713
747
|
|
|
714
748
|
def __init__(
|
|
715
749
|
self,
|
|
716
|
-
|
|
717
|
-
# The destination IP of the connection.
|
|
750
|
+
# The destination IP address of the network connection.
|
|
718
751
|
destination_ip: Optional[str] = None,
|
|
719
752
|
|
|
720
|
-
# The destination port of the connection.
|
|
753
|
+
# The destination port number of the connection.
|
|
721
754
|
destination_port: Optional[int] = None,
|
|
722
755
|
|
|
723
|
-
# The transport layer protocol (e.g., tcp, udp).
|
|
756
|
+
# The transport layer protocol used (e.g., "tcp", "udp").
|
|
724
757
|
transport_layer_protocol: Optional[Literal["tcp", "udp"]] = None,
|
|
725
758
|
|
|
726
|
-
# The direction of the network connection.
|
|
727
|
-
direction: Optional[ConnectionDirection] = None,
|
|
759
|
+
# The direction of the network connection (e.g., "inbound", "outbound").
|
|
760
|
+
direction: Optional["ConnectionDirection"] = None,
|
|
728
761
|
|
|
729
|
-
#
|
|
730
|
-
|
|
762
|
+
# The process ID that initiated or owned the network connection.
|
|
763
|
+
process: Optional[int] = None,
|
|
731
764
|
|
|
732
|
-
# The source IP of the connection.
|
|
765
|
+
# The source IP address of the connection.
|
|
733
766
|
source_ip: Optional[str] = None,
|
|
734
767
|
|
|
735
|
-
# The source port of the connection.
|
|
768
|
+
# The source port number of the connection.
|
|
736
769
|
source_port: Optional[int] = None,
|
|
737
770
|
|
|
738
|
-
|
|
771
|
+
# The timestamp when the network event was observed (ISO 8601 format).
|
|
772
|
+
time_observed: Optional[str] = None,
|
|
739
773
|
|
|
740
|
-
# HTTP
|
|
741
|
-
http_details: Optional[SandboxNetworkHTTP] = None,
|
|
774
|
+
# Detailed HTTP request/response data, if the flow is HTTP-related.
|
|
775
|
+
http_details: Optional["SandboxNetworkHTTP"] = None,
|
|
742
776
|
|
|
743
|
-
# DNS
|
|
744
|
-
dns_details: Optional[SandboxNetworkDNS] = None,
|
|
777
|
+
# Detailed DNS query/response data, if the flow is DNS-related.
|
|
778
|
+
dns_details: Optional["SandboxNetworkDNS"] = None,
|
|
745
779
|
|
|
746
|
-
# SMTP
|
|
780
|
+
# Detailed SMTP email data, if the flow is SMTP-related.
|
|
747
781
|
smtp_details: Optional[SandboxNetworkSMTP] = None,
|
|
748
782
|
|
|
749
|
-
#
|
|
750
|
-
connection_type: Optional[ConnectionType] = None,
|
|
783
|
+
# The type or category of the connection (e.g., "download", "upload").
|
|
784
|
+
connection_type: Optional["ConnectionType"] = None,
|
|
751
785
|
):
|
|
752
786
|
self.destination_ip = destination_ip
|
|
753
787
|
self.destination_port = destination_port
|
|
754
788
|
self.transport_layer_protocol = transport_layer_protocol
|
|
755
789
|
self.direction = direction
|
|
756
|
-
self.
|
|
790
|
+
self.process = process
|
|
757
791
|
self.source_ip = source_ip
|
|
758
792
|
self.source_port = source_port
|
|
759
793
|
self.time_observed = time_observed
|
|
@@ -762,14 +796,13 @@ class SandboxNetflowItem:
|
|
|
762
796
|
self.smtp_details = smtp_details
|
|
763
797
|
self.connection_type = connection_type
|
|
764
798
|
|
|
765
|
-
def as_primitives(self) -> Dict:
|
|
766
|
-
"""Return a JSON-serializable representation."""
|
|
799
|
+
def as_primitives(self) -> Dict[str, Any]:
|
|
767
800
|
data: Dict[str, Any] = {
|
|
768
801
|
"destination_ip": self.destination_ip,
|
|
769
802
|
"destination_port": self.destination_port,
|
|
770
803
|
"transport_layer_protocol": self.transport_layer_protocol,
|
|
771
804
|
"direction": self.direction,
|
|
772
|
-
"
|
|
805
|
+
"process": self.process,
|
|
773
806
|
"source_ip": self.source_ip,
|
|
774
807
|
"source_port": self.source_port,
|
|
775
808
|
"time_observed": self.time_observed,
|
|
@@ -778,10 +811,8 @@ class SandboxNetflowItem:
|
|
|
778
811
|
|
|
779
812
|
if self.http_details is not None:
|
|
780
813
|
data["http_details"] = self.http_details.as_primitives()
|
|
781
|
-
|
|
782
814
|
if self.dns_details is not None:
|
|
783
815
|
data["dns_details"] = self.dns_details.as_primitives()
|
|
784
|
-
|
|
785
816
|
if self.smtp_details is not None:
|
|
786
817
|
data["smtp_details"] = self.smtp_details.as_primitives()
|
|
787
818
|
|
|
@@ -789,12 +820,17 @@ class SandboxNetflowItem:
|
|
|
789
820
|
|
|
790
821
|
|
|
791
822
|
class SandboxAttackItem:
|
|
792
|
-
"""
|
|
823
|
+
"""Describes an ATT&CK technique or tactic detected during sandbox execution."""
|
|
793
824
|
|
|
794
825
|
def __init__(
|
|
795
826
|
self,
|
|
827
|
+
# The MITRE ATT&CK technique ID (e.g., "T1059.001").
|
|
796
828
|
attack_id: str,
|
|
797
|
-
|
|
829
|
+
|
|
830
|
+
# The name or pattern describing the attack behavior.
|
|
831
|
+
pattern: str,
|
|
832
|
+
|
|
833
|
+
# The list of categories or tactics associated with this attack.
|
|
798
834
|
categories: List[str] = [],
|
|
799
835
|
):
|
|
800
836
|
self.attack_id = attack_id
|
|
@@ -810,50 +846,45 @@ class SandboxAttackItem:
|
|
|
810
846
|
|
|
811
847
|
|
|
812
848
|
class SandboxSignatureItem:
|
|
813
|
-
"""
|
|
849
|
+
"""Represents a detection signature triggered during analysis."""
|
|
814
850
|
|
|
815
851
|
def __init__(
|
|
816
852
|
self,
|
|
817
|
-
|
|
818
|
-
# The name of the signature.
|
|
853
|
+
# The name of the detection signature.
|
|
819
854
|
name: str,
|
|
820
855
|
|
|
821
|
-
#
|
|
856
|
+
# The source type of the signature (e.g., "CUCKOO", "YARA", "SIGMA", "SURICATA").
|
|
822
857
|
type: Literal["CUCKOO", "YARA", "SIGMA", "SURICATA"],
|
|
823
858
|
|
|
824
|
-
#
|
|
859
|
+
# The classification of the signature (e.g., "malicious", "benign").
|
|
825
860
|
classification: str,
|
|
826
861
|
|
|
827
|
-
#
|
|
828
|
-
attacks: Optional[List[SandboxAttackItem]] =
|
|
829
|
-
|
|
830
|
-
# List of actors of the signature.
|
|
831
|
-
actors: Optional[List[str]] = [],
|
|
862
|
+
# The list of ATT&CK patterns or related attack metadata linked to this signature.
|
|
863
|
+
attacks: Optional[List[SandboxAttackItem]] = None,
|
|
832
864
|
|
|
833
|
-
#
|
|
834
|
-
|
|
865
|
+
# The list of threat actors associated with this signature.
|
|
866
|
+
actors: Optional[List[str]] = None,
|
|
835
867
|
|
|
836
|
-
#
|
|
837
|
-
|
|
868
|
+
# The list of malware families linked to this signature.
|
|
869
|
+
malware_families: Optional[List[str]] = None,
|
|
838
870
|
|
|
839
|
-
#
|
|
840
|
-
|
|
871
|
+
# A human-readable description of what the signature represents.
|
|
872
|
+
description: Optional[str] = None,
|
|
841
873
|
|
|
842
|
-
#
|
|
843
|
-
|
|
874
|
+
# The list of process IDs (PIDs) that triggered the signature.
|
|
875
|
+
pid: Optional[List[int]] = None,
|
|
844
876
|
|
|
845
|
-
#
|
|
846
|
-
score: int = None,
|
|
877
|
+
# The score or weight associated with the heuristic signature.
|
|
878
|
+
score: Optional[int] = None,
|
|
847
879
|
):
|
|
848
880
|
self.name = name
|
|
849
881
|
self.type = type
|
|
850
882
|
self.classification = classification
|
|
851
|
-
self.attacks = attacks
|
|
852
|
-
self.actors = actors
|
|
853
|
-
self.malware_families = malware_families
|
|
854
|
-
self.
|
|
855
|
-
self.
|
|
856
|
-
self.pids = pids
|
|
883
|
+
self.attacks = attacks or []
|
|
884
|
+
self.actors = actors or []
|
|
885
|
+
self.malware_families = malware_families or []
|
|
886
|
+
self.description = description
|
|
887
|
+
self.pid = pid or []
|
|
857
888
|
self.score = score
|
|
858
889
|
|
|
859
890
|
def as_primitives(self) -> Dict[str, Any]:
|
|
@@ -861,12 +892,11 @@ class SandboxSignatureItem:
|
|
|
861
892
|
"name": self.name,
|
|
862
893
|
"type": self.type,
|
|
863
894
|
"classification": self.classification,
|
|
864
|
-
"attacks": [a.as_primitives() for a in self.attacks] if self.attacks else
|
|
895
|
+
"attacks": [a.as_primitives() for a in self.attacks] if self.attacks else [],
|
|
865
896
|
"actors": self.actors,
|
|
866
897
|
"malware_families": self.malware_families,
|
|
867
|
-
"
|
|
868
|
-
"
|
|
869
|
-
"pids": self.pids,
|
|
898
|
+
"description": self.description,
|
|
899
|
+
"pid": self.pid,
|
|
870
900
|
"score": self.score,
|
|
871
901
|
}
|
|
872
902
|
|
|
@@ -874,32 +904,33 @@ class SandboxSignatureItem:
|
|
|
874
904
|
|
|
875
905
|
|
|
876
906
|
class SandboxSectionBody(SectionBody):
|
|
877
|
-
"""
|
|
878
|
-
Represents the structured body of a sandbox analysis section.
|
|
879
|
-
Collects all sandbox-relevant entities: sandbox metadata, processes, network flows, and signatures.
|
|
880
|
-
"""
|
|
907
|
+
"""The main sandbox analysis body containing all observed data and metadata."""
|
|
881
908
|
|
|
882
909
|
def __init__(self) -> None:
|
|
883
910
|
super().__init__(BODY_FORMAT.SANDBOX, body={
|
|
884
|
-
"
|
|
885
|
-
"sandbox_version": None,
|
|
886
|
-
"machine_metadata": None,
|
|
887
|
-
"analysis_metadata": None,
|
|
911
|
+
"analysis_information": None,
|
|
888
912
|
"processes": [],
|
|
889
|
-
"
|
|
913
|
+
"network_connections": [],
|
|
890
914
|
"signatures": [],
|
|
891
915
|
})
|
|
892
916
|
|
|
893
|
-
def
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
917
|
+
def set_analysis_information(
|
|
918
|
+
self,
|
|
919
|
+
# The name of the sandbox used to perform the analysis.
|
|
920
|
+
sandbox_name: str,
|
|
921
|
+
|
|
922
|
+
# The version of the sandbox software.
|
|
923
|
+
sandbox_version: str,
|
|
924
|
+
|
|
925
|
+
# Metadata about when and how the analysis was executed.
|
|
926
|
+
analysis_metadata: SandboxAnalysisMetadata,
|
|
927
|
+
) -> None:
|
|
928
|
+
"""Set the general analysis information for the sandbox execution."""
|
|
929
|
+
self._data["analysis_information"] = {
|
|
930
|
+
"sandbox_name": sandbox_name,
|
|
931
|
+
"sandbox_version": sandbox_version,
|
|
932
|
+
"analysis_metadata": analysis_metadata.as_primitives(),
|
|
933
|
+
}
|
|
903
934
|
|
|
904
935
|
def add_process(self, process: SandboxProcessItem) -> None:
|
|
905
936
|
"""Add a single process to the sandbox result."""
|
|
@@ -908,42 +939,38 @@ class SandboxSectionBody(SectionBody):
|
|
|
908
939
|
self._data["processes"].append(process.as_primitives())
|
|
909
940
|
|
|
910
941
|
def add_processes(self, processes: List[SandboxProcessItem]) -> None:
|
|
911
|
-
"""Add multiple processes
|
|
942
|
+
"""Add multiple processes to the sandbox result."""
|
|
912
943
|
for proc in processes:
|
|
913
944
|
self.add_process(proc)
|
|
914
945
|
|
|
915
|
-
def
|
|
916
|
-
"""Add a network
|
|
917
|
-
if not isinstance(
|
|
946
|
+
def add_network_connection(self, connection: SandboxNetflowItem) -> None:
|
|
947
|
+
"""Add a single network connection to the sandbox result."""
|
|
948
|
+
if not isinstance(connection, SandboxNetflowItem):
|
|
918
949
|
raise TypeError("Expected SandboxNetflowItem")
|
|
919
|
-
self._data["
|
|
950
|
+
self._data["network_connections"].append(connection.as_primitives())
|
|
920
951
|
|
|
921
|
-
def
|
|
922
|
-
"""Add multiple network
|
|
923
|
-
for
|
|
924
|
-
self.
|
|
952
|
+
def add_network_connections(self, connections: List[SandboxNetflowItem]) -> None:
|
|
953
|
+
"""Add multiple network connections to the sandbox result."""
|
|
954
|
+
for conn in connections:
|
|
955
|
+
self.add_network_connection(conn)
|
|
925
956
|
|
|
926
957
|
def add_signature(self, signature: SandboxSignatureItem) -> None:
|
|
927
|
-
"""Add a detection signature to the sandbox result."""
|
|
958
|
+
"""Add a single detection signature to the sandbox result."""
|
|
928
959
|
if not isinstance(signature, SandboxSignatureItem):
|
|
929
960
|
raise TypeError("Expected SandboxSignatureItem")
|
|
930
961
|
self._data["signatures"].append(signature.as_primitives())
|
|
931
962
|
|
|
932
963
|
def add_signatures(self, signatures: List[SandboxSignatureItem]) -> None:
|
|
933
|
-
"""Add multiple detection signatures
|
|
964
|
+
"""Add multiple detection signatures to the sandbox result."""
|
|
934
965
|
for sig in signatures:
|
|
935
966
|
self.add_signature(sig)
|
|
936
967
|
|
|
937
|
-
|
|
938
968
|
def as_primitives(self) -> Dict[str, Any]:
|
|
939
969
|
"""Return a fully JSON-serializable structure."""
|
|
940
970
|
return {
|
|
941
|
-
"
|
|
942
|
-
"sandbox_version": self._data["sandbox_version"],
|
|
943
|
-
"machine_metadata": self._data["machine_metadata"],
|
|
944
|
-
"analysis_metadata": self._data["analysis_metadata"],
|
|
971
|
+
"analysis_information": self._data["analysis_information"],
|
|
945
972
|
"processes": self._data["processes"],
|
|
946
|
-
"
|
|
973
|
+
"network_connections": self._data["network_connections"],
|
|
947
974
|
"signatures": self._data["signatures"],
|
|
948
975
|
}
|
|
949
976
|
|
|
@@ -1343,48 +1370,43 @@ class ResultSandboxSection(TypeSpecificResultSection):
|
|
|
1343
1370
|
self.section_body: SandboxSectionBody
|
|
1344
1371
|
super().__init__(title_text, SandboxSectionBody(), **kwargs)
|
|
1345
1372
|
|
|
1346
|
-
def
|
|
1373
|
+
def set_analysis_information(
|
|
1347
1374
|
self,
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
machine_metadata: Optional[SandboxMachineMetadata],
|
|
1375
|
+
sandbox_name: Optional[str],
|
|
1376
|
+
sandbox_version: Optional[str],
|
|
1351
1377
|
analysis_metadata: Optional[SandboxAnalysisMetadata],
|
|
1352
1378
|
) -> None:
|
|
1353
|
-
"""Set the
|
|
1354
|
-
self.section_body.
|
|
1379
|
+
"""Set the general analysis information for the sandbox execution."""
|
|
1380
|
+
self.section_body.set_analysis_information(
|
|
1381
|
+
sandbox_name,
|
|
1382
|
+
sandbox_version,
|
|
1383
|
+
analysis_metadata,
|
|
1384
|
+
)
|
|
1355
1385
|
|
|
1356
1386
|
def add_process(self, process: SandboxProcessItem) -> None:
|
|
1357
1387
|
"""Add a single process to the sandbox result."""
|
|
1358
1388
|
self.section_body.add_process(process)
|
|
1359
1389
|
|
|
1360
1390
|
def add_processes(self, processes: List[SandboxProcessItem]) -> None:
|
|
1361
|
-
"""Add multiple processes
|
|
1391
|
+
"""Add multiple processes to the sandbox result."""
|
|
1362
1392
|
self.section_body.add_processes(processes)
|
|
1363
1393
|
|
|
1364
|
-
def
|
|
1365
|
-
"""Add a single network
|
|
1366
|
-
self.section_body.
|
|
1394
|
+
def add_network_connection(self, connection: SandboxNetflowItem) -> None:
|
|
1395
|
+
"""Add a single network connection to the sandbox result."""
|
|
1396
|
+
self.section_body.add_network_connection(connection)
|
|
1367
1397
|
|
|
1368
|
-
def
|
|
1369
|
-
"""Add multiple network
|
|
1370
|
-
self.section_body.
|
|
1398
|
+
def add_network_connections(self, connections: List[SandboxNetflowItem]) -> None:
|
|
1399
|
+
"""Add multiple network connections to the sandbox result."""
|
|
1400
|
+
self.section_body.add_network_connections(connections)
|
|
1371
1401
|
|
|
1372
1402
|
def add_signature(self, signature: SandboxSignatureItem) -> None:
|
|
1373
|
-
"""Add a detection signature to the sandbox result."""
|
|
1403
|
+
"""Add a single detection signature to the sandbox result."""
|
|
1374
1404
|
self.section_body.add_signature(signature)
|
|
1375
1405
|
|
|
1376
1406
|
def add_signatures(self, signatures: List[SandboxSignatureItem]) -> None:
|
|
1377
|
-
"""Add multiple detection signatures
|
|
1407
|
+
"""Add multiple detection signatures to the sandbox result."""
|
|
1378
1408
|
self.section_body.add_signatures(signatures)
|
|
1379
1409
|
|
|
1380
|
-
def add_heuristic(self, heuristic: SandboxHeuristicItem) -> None:
|
|
1381
|
-
"""Add a heuristic to the sandbox result."""
|
|
1382
|
-
self.section_body.add_heuristic(heuristic)
|
|
1383
|
-
|
|
1384
|
-
def add_heuristics(self, heuristics: List[SandboxHeuristicItem]) -> None:
|
|
1385
|
-
"""Add multiple heuristics at once."""
|
|
1386
|
-
self.section_body.add_heuristics(heuristics)
|
|
1387
|
-
|
|
1388
1410
|
|
|
1389
1411
|
class ResultTableSection(TypeSpecificResultSection):
|
|
1390
1412
|
def __init__(self, title_text: Union[str, List], **kwargs):
|