assemblyline-v4-service 4.6.1.dev248__py3-none-any.whl → 4.7.0.dev31__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 +257 -220
- 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.dev31.dist-info}/METADATA +1 -1
- {assemblyline_v4_service-4.6.1.dev248.dist-info → assemblyline_v4_service-4.7.0.dev31.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.dev31.dist-info}/WHEEL +0 -0
- {assemblyline_v4_service-4.6.1.dev248.dist-info → assemblyline_v4_service-4.7.0.dev31.dist-info}/licenses/LICENCE.md +0 -0
- {assemblyline_v4_service-4.6.1.dev248.dist-info → assemblyline_v4_service-4.7.0.dev31.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,157 @@ 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
|
-
#
|
|
570
|
+
# Name of the sources who identified this information
|
|
571
|
+
sources: Optional[List[str]],
|
|
572
|
+
|
|
573
|
+
# The parent process ID (PPID).
|
|
507
574
|
ppid: Optional[int] = None,
|
|
508
575
|
|
|
509
|
-
# The process ID.
|
|
576
|
+
# The process ID (PID).
|
|
510
577
|
pid: Optional[int] = None,
|
|
511
578
|
|
|
512
|
-
# The command line
|
|
579
|
+
# The full command line used to start the process.
|
|
513
580
|
command_line: Optional[str] = None,
|
|
514
581
|
|
|
515
|
-
# The
|
|
582
|
+
# The timestamp when the process terminated (ISO 8601 format).
|
|
516
583
|
end_time: Optional[str] = None,
|
|
517
584
|
|
|
518
|
-
# The integrity level of the process.
|
|
585
|
+
# The integrity level of the process (e.g., "High", "Medium", "Low").
|
|
519
586
|
integrity_level: Optional[str] = None,
|
|
520
587
|
|
|
521
|
-
# The hash of the file
|
|
588
|
+
# The hash of the executable file for the process (e.g., SHA256).
|
|
522
589
|
image_hash: Optional[str] = None,
|
|
523
590
|
|
|
524
|
-
# The original name
|
|
591
|
+
# The original file name as embedded in the binary metadata.
|
|
525
592
|
original_file_name: Optional[str] = None,
|
|
526
593
|
|
|
527
|
-
#
|
|
594
|
+
# Indicates whether this process was safelisted (whitelisted).
|
|
528
595
|
safelisted: Optional[bool] = False,
|
|
529
596
|
|
|
530
|
-
#
|
|
531
|
-
file_count: int = 0,
|
|
597
|
+
# The number of file I/O events associated with this process.
|
|
598
|
+
file_count: Optional[int] = 0,
|
|
532
599
|
|
|
533
|
-
#
|
|
534
|
-
registry_count: int = 0,
|
|
600
|
+
# The number of registry modification events associated with this process.
|
|
601
|
+
registry_count: Optional[int] = 0,
|
|
535
602
|
):
|
|
536
|
-
# ----------------------------
|
|
537
|
-
# Core process information
|
|
538
|
-
# ----------------------------
|
|
539
603
|
self.image = image or "<unknown_image>"
|
|
540
604
|
self.start_time = start_time
|
|
541
|
-
|
|
542
|
-
# Parent process information
|
|
605
|
+
self.sources = sources or []
|
|
543
606
|
self.ppid = ppid
|
|
544
|
-
|
|
545
|
-
# Current process information
|
|
546
607
|
self.pid = pid
|
|
547
608
|
self.command_line = command_line
|
|
548
609
|
self.end_time = end_time
|
|
@@ -550,18 +611,14 @@ class SandboxProcessItem:
|
|
|
550
611
|
self.image_hash = image_hash
|
|
551
612
|
self.original_file_name = original_file_name
|
|
552
613
|
self.safelisted = safelisted
|
|
553
|
-
|
|
554
|
-
# ----------------------------
|
|
555
|
-
# Relationships & statistics
|
|
556
|
-
# ----------------------------
|
|
557
614
|
self.file_count = file_count
|
|
558
615
|
self.registry_count = registry_count
|
|
559
616
|
|
|
560
|
-
def as_primitives(self) -> Dict:
|
|
561
|
-
"""Return a JSON-serializable dictionary representation of this process."""
|
|
617
|
+
def as_primitives(self) -> Dict[str, Any]:
|
|
562
618
|
return {
|
|
563
619
|
"image": self.image,
|
|
564
620
|
"start_time": self.start_time,
|
|
621
|
+
"sources": self.sources,
|
|
565
622
|
"ppid": self.ppid,
|
|
566
623
|
"pid": self.pid,
|
|
567
624
|
"command_line": self.command_line,
|
|
@@ -575,100 +632,82 @@ class SandboxProcessItem:
|
|
|
575
632
|
}
|
|
576
633
|
|
|
577
634
|
|
|
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
635
|
|
|
597
636
|
|
|
598
637
|
class SandboxNetworkDNS:
|
|
599
|
-
"""Details
|
|
638
|
+
"""Details of a DNS query observed during sandbox execution."""
|
|
600
639
|
|
|
601
640
|
def __init__(
|
|
602
641
|
self,
|
|
642
|
+
# The domain name requested (queried).
|
|
603
643
|
domain: str,
|
|
644
|
+
|
|
645
|
+
# The DNS lookup type (e.g., "A", "AAAA", "MX").
|
|
604
646
|
lookup_type: LookupType,
|
|
647
|
+
|
|
648
|
+
# A list of IP addresses returned in the DNS response.
|
|
605
649
|
resolved_ips: Optional[List[str]] = None,
|
|
650
|
+
|
|
651
|
+
# A list of domain names returned in the DNS response (for CNAMEs, etc.).
|
|
606
652
|
resolved_domains: Optional[List[str]] = None,
|
|
607
653
|
):
|
|
608
|
-
# The domain requested.
|
|
609
654
|
self.domain = domain
|
|
610
|
-
|
|
611
|
-
# A list of IPs that were resolved.
|
|
655
|
+
self.lookup_type = lookup_type
|
|
612
656
|
self.resolved_ips = resolved_ips or []
|
|
613
|
-
|
|
614
|
-
# A list of domains that were resolved.
|
|
615
657
|
self.resolved_domains = resolved_domains or []
|
|
616
658
|
|
|
617
|
-
|
|
618
|
-
self.lookup_type = lookup_type
|
|
619
|
-
|
|
620
|
-
def as_primitives(self) -> Dict:
|
|
659
|
+
def as_primitives(self) -> Dict[str, Any]:
|
|
621
660
|
return {
|
|
622
661
|
"domain": self.domain,
|
|
662
|
+
"lookup_type": self.lookup_type,
|
|
623
663
|
"resolved_ips": self.resolved_ips,
|
|
624
664
|
"resolved_domains": self.resolved_domains,
|
|
625
|
-
"lookup_type": self.lookup_type,
|
|
626
665
|
}
|
|
627
666
|
|
|
628
667
|
|
|
629
668
|
class SandboxNetworkHTTP:
|
|
630
|
-
"""Details
|
|
669
|
+
"""Details of an HTTP request/response observed during sandbox execution."""
|
|
631
670
|
|
|
632
671
|
def __init__(
|
|
633
672
|
self,
|
|
673
|
+
# The URI requested by the process.
|
|
634
674
|
request_uri: str,
|
|
635
|
-
|
|
675
|
+
|
|
676
|
+
# Headers included in the HTTP request.
|
|
677
|
+
request_headers: Optional[Dict[str, Any]] = None,
|
|
678
|
+
|
|
679
|
+
# The HTTP request method (e.g., "GET", "POST").
|
|
636
680
|
request_method: Optional[RequestMethod] = None,
|
|
637
|
-
|
|
681
|
+
|
|
682
|
+
# Headers included in the HTTP response.
|
|
683
|
+
response_headers: Optional[Dict[str, Any]] = None,
|
|
684
|
+
|
|
685
|
+
# The raw body content of the HTTP request.
|
|
638
686
|
request_body: Optional[str] = None,
|
|
687
|
+
|
|
688
|
+
# The HTTP status code of the response (e.g., 200, 404).
|
|
639
689
|
response_status_code: Optional[int] = None,
|
|
690
|
+
|
|
691
|
+
# The raw body content of the HTTP response.
|
|
640
692
|
response_body: Optional[str] = None,
|
|
641
|
-
|
|
693
|
+
|
|
694
|
+
# Metadata about any file contained in the HTTP response body.
|
|
695
|
+
response_content_fileinfo: Optional[Dict[str, Any]] = None,
|
|
696
|
+
|
|
697
|
+
# The MIME type of the HTTP response content.
|
|
642
698
|
response_content_mimetype: Optional[str] = None,
|
|
643
699
|
):
|
|
644
|
-
# The URI requested.
|
|
645
700
|
self.request_uri = request_uri
|
|
646
|
-
|
|
647
|
-
# Headers included in the request.
|
|
648
701
|
self.request_headers = request_headers or {}
|
|
649
|
-
|
|
650
|
-
# The method of the request.
|
|
651
702
|
self.request_method = request_method
|
|
652
|
-
|
|
653
|
-
# Headers included in the response.
|
|
654
703
|
self.response_headers = response_headers or {}
|
|
655
|
-
|
|
656
|
-
# The body of the request.
|
|
657
704
|
self.request_body = request_body
|
|
658
|
-
|
|
659
|
-
# The status code of the response.
|
|
660
705
|
self.response_status_code = response_status_code
|
|
661
|
-
|
|
662
|
-
# The body of the response.
|
|
663
706
|
self.response_body = response_body
|
|
664
|
-
|
|
665
|
-
# File information of the response content.
|
|
666
707
|
self.response_content_fileinfo = response_content_fileinfo
|
|
667
|
-
|
|
668
|
-
# MIME type returned by the server.
|
|
669
708
|
self.response_content_mimetype = response_content_mimetype
|
|
670
709
|
|
|
671
|
-
def as_primitives(self) -> Dict:
|
|
710
|
+
def as_primitives(self) -> Dict[str, Any]:
|
|
672
711
|
return {
|
|
673
712
|
"request_uri": self.request_uri,
|
|
674
713
|
"request_headers": self.request_headers,
|
|
@@ -683,24 +722,24 @@ class SandboxNetworkHTTP:
|
|
|
683
722
|
|
|
684
723
|
|
|
685
724
|
class SandboxNetworkSMTP:
|
|
686
|
-
"""Details
|
|
725
|
+
"""Details of an SMTP email transaction observed during sandbox execution."""
|
|
687
726
|
|
|
688
727
|
def __init__(
|
|
689
728
|
self,
|
|
729
|
+
# The sender email address in the SMTP transaction.
|
|
690
730
|
mail_from: str,
|
|
731
|
+
|
|
732
|
+
# A list of recipient email addresses in the SMTP transaction.
|
|
691
733
|
mail_to: List[str],
|
|
692
|
-
|
|
734
|
+
|
|
735
|
+
# Information about any attachments transmitted via SMTP.
|
|
736
|
+
attachments: Optional[List[Dict[str, Any]]] = None,
|
|
693
737
|
):
|
|
694
|
-
# Sender of the email.
|
|
695
738
|
self.mail_from = mail_from
|
|
696
|
-
|
|
697
|
-
# Recipients of the email.
|
|
698
739
|
self.mail_to = mail_to
|
|
699
|
-
|
|
700
|
-
# File information about the attachments.
|
|
701
740
|
self.attachments = attachments or []
|
|
702
741
|
|
|
703
|
-
def as_primitives(self) -> Dict:
|
|
742
|
+
def as_primitives(self) -> Dict[str, Any]:
|
|
704
743
|
return {
|
|
705
744
|
"mail_from": self.mail_from,
|
|
706
745
|
"mail_to": self.mail_to,
|
|
@@ -709,51 +748,55 @@ class SandboxNetworkSMTP:
|
|
|
709
748
|
|
|
710
749
|
|
|
711
750
|
class SandboxNetflowItem:
|
|
712
|
-
"""Details
|
|
751
|
+
"""Details of a network flow (connection) observed during sandbox execution."""
|
|
713
752
|
|
|
714
753
|
def __init__(
|
|
715
754
|
self,
|
|
716
|
-
|
|
717
|
-
# The destination IP of the connection.
|
|
755
|
+
# The destination IP address of the network connection.
|
|
718
756
|
destination_ip: Optional[str] = None,
|
|
719
757
|
|
|
720
|
-
# The destination port of the connection.
|
|
758
|
+
# The destination port number of the connection.
|
|
721
759
|
destination_port: Optional[int] = None,
|
|
722
760
|
|
|
723
|
-
# The transport layer protocol (e.g., tcp, udp).
|
|
761
|
+
# The transport layer protocol used (e.g., "tcp", "udp").
|
|
724
762
|
transport_layer_protocol: Optional[Literal["tcp", "udp"]] = None,
|
|
725
763
|
|
|
726
|
-
# The direction of the network connection.
|
|
727
|
-
direction: Optional[ConnectionDirection] = None,
|
|
764
|
+
# The direction of the network connection (e.g., "inbound", "outbound").
|
|
765
|
+
direction: Optional["ConnectionDirection"] = None,
|
|
728
766
|
|
|
729
|
-
#
|
|
730
|
-
|
|
767
|
+
# The process ID that initiated or owned the network connection.
|
|
768
|
+
process: Optional[int] = None,
|
|
769
|
+
|
|
770
|
+
# Name of the sources who identified this information
|
|
771
|
+
sources: Optional[List[str]] = [],
|
|
731
772
|
|
|
732
|
-
# The source IP of the connection.
|
|
773
|
+
# The source IP address of the connection.
|
|
733
774
|
source_ip: Optional[str] = None,
|
|
734
775
|
|
|
735
|
-
# The source port of the connection.
|
|
776
|
+
# The source port number of the connection.
|
|
736
777
|
source_port: Optional[int] = None,
|
|
737
778
|
|
|
738
|
-
|
|
779
|
+
# The timestamp when the network event was observed (ISO 8601 format).
|
|
780
|
+
time_observed: Optional[str] = None,
|
|
739
781
|
|
|
740
|
-
# HTTP
|
|
741
|
-
http_details: Optional[SandboxNetworkHTTP] = None,
|
|
782
|
+
# Detailed HTTP request/response data, if the flow is HTTP-related.
|
|
783
|
+
http_details: Optional["SandboxNetworkHTTP"] = None,
|
|
742
784
|
|
|
743
|
-
# DNS
|
|
744
|
-
dns_details: Optional[SandboxNetworkDNS] = None,
|
|
785
|
+
# Detailed DNS query/response data, if the flow is DNS-related.
|
|
786
|
+
dns_details: Optional["SandboxNetworkDNS"] = None,
|
|
745
787
|
|
|
746
|
-
# SMTP
|
|
788
|
+
# Detailed SMTP email data, if the flow is SMTP-related.
|
|
747
789
|
smtp_details: Optional[SandboxNetworkSMTP] = None,
|
|
748
790
|
|
|
749
|
-
#
|
|
750
|
-
connection_type: Optional[ConnectionType] = None,
|
|
791
|
+
# The type or category of the connection (e.g., "download", "upload").
|
|
792
|
+
connection_type: Optional["ConnectionType"] = None,
|
|
751
793
|
):
|
|
752
794
|
self.destination_ip = destination_ip
|
|
753
795
|
self.destination_port = destination_port
|
|
754
796
|
self.transport_layer_protocol = transport_layer_protocol
|
|
755
797
|
self.direction = direction
|
|
756
|
-
self.
|
|
798
|
+
self.process = process
|
|
799
|
+
self.sources = sources or []
|
|
757
800
|
self.source_ip = source_ip
|
|
758
801
|
self.source_port = source_port
|
|
759
802
|
self.time_observed = time_observed
|
|
@@ -762,14 +805,14 @@ class SandboxNetflowItem:
|
|
|
762
805
|
self.smtp_details = smtp_details
|
|
763
806
|
self.connection_type = connection_type
|
|
764
807
|
|
|
765
|
-
def as_primitives(self) -> Dict:
|
|
766
|
-
"""Return a JSON-serializable representation."""
|
|
808
|
+
def as_primitives(self) -> Dict[str, Any]:
|
|
767
809
|
data: Dict[str, Any] = {
|
|
768
810
|
"destination_ip": self.destination_ip,
|
|
769
811
|
"destination_port": self.destination_port,
|
|
770
812
|
"transport_layer_protocol": self.transport_layer_protocol,
|
|
771
813
|
"direction": self.direction,
|
|
772
|
-
"
|
|
814
|
+
"process": self.process,
|
|
815
|
+
"sources": self.sources,
|
|
773
816
|
"source_ip": self.source_ip,
|
|
774
817
|
"source_port": self.source_port,
|
|
775
818
|
"time_observed": self.time_observed,
|
|
@@ -778,10 +821,8 @@ class SandboxNetflowItem:
|
|
|
778
821
|
|
|
779
822
|
if self.http_details is not None:
|
|
780
823
|
data["http_details"] = self.http_details.as_primitives()
|
|
781
|
-
|
|
782
824
|
if self.dns_details is not None:
|
|
783
825
|
data["dns_details"] = self.dns_details.as_primitives()
|
|
784
|
-
|
|
785
826
|
if self.smtp_details is not None:
|
|
786
827
|
data["smtp_details"] = self.smtp_details.as_primitives()
|
|
787
828
|
|
|
@@ -789,12 +830,17 @@ class SandboxNetflowItem:
|
|
|
789
830
|
|
|
790
831
|
|
|
791
832
|
class SandboxAttackItem:
|
|
792
|
-
"""
|
|
833
|
+
"""Describes an ATT&CK technique or tactic detected during sandbox execution."""
|
|
793
834
|
|
|
794
835
|
def __init__(
|
|
795
836
|
self,
|
|
837
|
+
# The MITRE ATT&CK technique ID (e.g., "T1059.001").
|
|
796
838
|
attack_id: str,
|
|
797
|
-
|
|
839
|
+
|
|
840
|
+
# The name or pattern describing the attack behavior.
|
|
841
|
+
pattern: str,
|
|
842
|
+
|
|
843
|
+
# The list of categories or tactics associated with this attack.
|
|
798
844
|
categories: List[str] = [],
|
|
799
845
|
):
|
|
800
846
|
self.attack_id = attack_id
|
|
@@ -810,63 +856,62 @@ class SandboxAttackItem:
|
|
|
810
856
|
|
|
811
857
|
|
|
812
858
|
class SandboxSignatureItem:
|
|
813
|
-
"""
|
|
859
|
+
"""Represents a detection signature triggered during analysis."""
|
|
814
860
|
|
|
815
861
|
def __init__(
|
|
816
862
|
self,
|
|
817
|
-
|
|
818
|
-
# The name of the signature.
|
|
863
|
+
# The name of the detection signature.
|
|
819
864
|
name: str,
|
|
820
865
|
|
|
821
|
-
#
|
|
822
|
-
type: Literal["
|
|
866
|
+
# The source type of the signature (e.g., "CAPE", "CUCKOO").
|
|
867
|
+
type: Literal["CAPE", "CUCKOO"],
|
|
823
868
|
|
|
824
|
-
#
|
|
825
|
-
|
|
869
|
+
# Name of the sources who identified this information
|
|
870
|
+
sources: Optional[List[str]],
|
|
826
871
|
|
|
827
|
-
#
|
|
828
|
-
|
|
872
|
+
# The classification of the signature (e.g., "malicious", "benign").
|
|
873
|
+
classification: str,
|
|
829
874
|
|
|
830
|
-
#
|
|
831
|
-
|
|
875
|
+
# The list of ATT&CK patterns or related attack metadata linked to this signature.
|
|
876
|
+
attacks: Optional[List[SandboxAttackItem]] = None,
|
|
832
877
|
|
|
833
|
-
#
|
|
834
|
-
|
|
878
|
+
# The list of threat actors associated with this signature.
|
|
879
|
+
actors: Optional[List[str]] = None,
|
|
835
880
|
|
|
836
|
-
#
|
|
837
|
-
|
|
881
|
+
# The list of malware families linked to this signature.
|
|
882
|
+
malware_families: Optional[List[str]] = None,
|
|
838
883
|
|
|
839
|
-
#
|
|
840
|
-
|
|
884
|
+
# A human-readable description of what the signature represents.
|
|
885
|
+
description: Optional[str] = None,
|
|
841
886
|
|
|
842
|
-
#
|
|
843
|
-
|
|
887
|
+
# The list of process IDs (PIDs) that triggered the signature.
|
|
888
|
+
pid: Optional[List[int]] = None,
|
|
844
889
|
|
|
845
|
-
#
|
|
846
|
-
score: int = None,
|
|
890
|
+
# The score or weight associated with the heuristic signature.
|
|
891
|
+
score: Optional[int] = None,
|
|
847
892
|
):
|
|
848
893
|
self.name = name
|
|
849
894
|
self.type = type
|
|
895
|
+
self.sources = sources or []
|
|
850
896
|
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
|
|
897
|
+
self.attacks = attacks or []
|
|
898
|
+
self.actors = actors or []
|
|
899
|
+
self.malware_families = malware_families or []
|
|
900
|
+
self.description = description
|
|
901
|
+
self.pid = pid or []
|
|
857
902
|
self.score = score
|
|
858
903
|
|
|
859
904
|
def as_primitives(self) -> Dict[str, Any]:
|
|
860
905
|
return {
|
|
861
906
|
"name": self.name,
|
|
862
907
|
"type": self.type,
|
|
908
|
+
"sources": self.sources,
|
|
863
909
|
"classification": self.classification,
|
|
864
|
-
"attacks": [a.as_primitives() for a in self.attacks] if self.attacks else
|
|
910
|
+
"attacks": [a.as_primitives() for a in self.attacks] if self.attacks else [],
|
|
865
911
|
"actors": self.actors,
|
|
866
912
|
"malware_families": self.malware_families,
|
|
867
|
-
"
|
|
868
|
-
"
|
|
869
|
-
"pids": self.pids,
|
|
913
|
+
"description": self.description,
|
|
914
|
+
"pid": self.pid,
|
|
870
915
|
"score": self.score,
|
|
871
916
|
}
|
|
872
917
|
|
|
@@ -874,32 +919,33 @@ class SandboxSignatureItem:
|
|
|
874
919
|
|
|
875
920
|
|
|
876
921
|
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
|
-
"""
|
|
922
|
+
"""The main sandbox analysis body containing all observed data and metadata."""
|
|
881
923
|
|
|
882
924
|
def __init__(self) -> None:
|
|
883
925
|
super().__init__(BODY_FORMAT.SANDBOX, body={
|
|
884
|
-
"
|
|
885
|
-
"sandbox_version": None,
|
|
886
|
-
"machine_metadata": None,
|
|
887
|
-
"analysis_metadata": None,
|
|
926
|
+
"analysis_information": None,
|
|
888
927
|
"processes": [],
|
|
889
|
-
"
|
|
928
|
+
"network_connections": [],
|
|
890
929
|
"signatures": [],
|
|
891
930
|
})
|
|
892
931
|
|
|
893
|
-
def
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
932
|
+
def set_analysis_information(
|
|
933
|
+
self,
|
|
934
|
+
# The name of the sandbox used to perform the analysis.
|
|
935
|
+
sandbox_name: str,
|
|
936
|
+
|
|
937
|
+
# The version of the sandbox software.
|
|
938
|
+
sandbox_version: str,
|
|
939
|
+
|
|
940
|
+
# Metadata about when and how the analysis was executed.
|
|
941
|
+
analysis_metadata: SandboxAnalysisMetadata,
|
|
942
|
+
) -> None:
|
|
943
|
+
"""Set the general analysis information for the sandbox execution."""
|
|
944
|
+
self._data["analysis_information"] = {
|
|
945
|
+
"sandbox_name": sandbox_name,
|
|
946
|
+
"sandbox_version": sandbox_version,
|
|
947
|
+
"analysis_metadata": analysis_metadata.as_primitives(),
|
|
948
|
+
}
|
|
903
949
|
|
|
904
950
|
def add_process(self, process: SandboxProcessItem) -> None:
|
|
905
951
|
"""Add a single process to the sandbox result."""
|
|
@@ -908,42 +954,38 @@ class SandboxSectionBody(SectionBody):
|
|
|
908
954
|
self._data["processes"].append(process.as_primitives())
|
|
909
955
|
|
|
910
956
|
def add_processes(self, processes: List[SandboxProcessItem]) -> None:
|
|
911
|
-
"""Add multiple processes
|
|
957
|
+
"""Add multiple processes to the sandbox result."""
|
|
912
958
|
for proc in processes:
|
|
913
959
|
self.add_process(proc)
|
|
914
960
|
|
|
915
|
-
def
|
|
916
|
-
"""Add a network
|
|
917
|
-
if not isinstance(
|
|
961
|
+
def add_network_connection(self, connection: SandboxNetflowItem) -> None:
|
|
962
|
+
"""Add a single network connection to the sandbox result."""
|
|
963
|
+
if not isinstance(connection, SandboxNetflowItem):
|
|
918
964
|
raise TypeError("Expected SandboxNetflowItem")
|
|
919
|
-
self._data["
|
|
965
|
+
self._data["network_connections"].append(connection.as_primitives())
|
|
920
966
|
|
|
921
|
-
def
|
|
922
|
-
"""Add multiple network
|
|
923
|
-
for
|
|
924
|
-
self.
|
|
967
|
+
def add_network_connections(self, connections: List[SandboxNetflowItem]) -> None:
|
|
968
|
+
"""Add multiple network connections to the sandbox result."""
|
|
969
|
+
for conn in connections:
|
|
970
|
+
self.add_network_connection(conn)
|
|
925
971
|
|
|
926
972
|
def add_signature(self, signature: SandboxSignatureItem) -> None:
|
|
927
|
-
"""Add a detection signature to the sandbox result."""
|
|
973
|
+
"""Add a single detection signature to the sandbox result."""
|
|
928
974
|
if not isinstance(signature, SandboxSignatureItem):
|
|
929
975
|
raise TypeError("Expected SandboxSignatureItem")
|
|
930
976
|
self._data["signatures"].append(signature.as_primitives())
|
|
931
977
|
|
|
932
978
|
def add_signatures(self, signatures: List[SandboxSignatureItem]) -> None:
|
|
933
|
-
"""Add multiple detection signatures
|
|
979
|
+
"""Add multiple detection signatures to the sandbox result."""
|
|
934
980
|
for sig in signatures:
|
|
935
981
|
self.add_signature(sig)
|
|
936
982
|
|
|
937
|
-
|
|
938
983
|
def as_primitives(self) -> Dict[str, Any]:
|
|
939
984
|
"""Return a fully JSON-serializable structure."""
|
|
940
985
|
return {
|
|
941
|
-
"
|
|
942
|
-
"sandbox_version": self._data["sandbox_version"],
|
|
943
|
-
"machine_metadata": self._data["machine_metadata"],
|
|
944
|
-
"analysis_metadata": self._data["analysis_metadata"],
|
|
986
|
+
"analysis_information": self._data["analysis_information"],
|
|
945
987
|
"processes": self._data["processes"],
|
|
946
|
-
"
|
|
988
|
+
"network_connections": self._data["network_connections"],
|
|
947
989
|
"signatures": self._data["signatures"],
|
|
948
990
|
}
|
|
949
991
|
|
|
@@ -1343,48 +1385,43 @@ class ResultSandboxSection(TypeSpecificResultSection):
|
|
|
1343
1385
|
self.section_body: SandboxSectionBody
|
|
1344
1386
|
super().__init__(title_text, SandboxSectionBody(), **kwargs)
|
|
1345
1387
|
|
|
1346
|
-
def
|
|
1388
|
+
def set_analysis_information(
|
|
1347
1389
|
self,
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
machine_metadata: Optional[SandboxMachineMetadata],
|
|
1390
|
+
sandbox_name: Optional[str],
|
|
1391
|
+
sandbox_version: Optional[str],
|
|
1351
1392
|
analysis_metadata: Optional[SandboxAnalysisMetadata],
|
|
1352
1393
|
) -> None:
|
|
1353
|
-
"""Set the
|
|
1354
|
-
self.section_body.
|
|
1394
|
+
"""Set the general analysis information for the sandbox execution."""
|
|
1395
|
+
self.section_body.set_analysis_information(
|
|
1396
|
+
sandbox_name,
|
|
1397
|
+
sandbox_version,
|
|
1398
|
+
analysis_metadata,
|
|
1399
|
+
)
|
|
1355
1400
|
|
|
1356
1401
|
def add_process(self, process: SandboxProcessItem) -> None:
|
|
1357
1402
|
"""Add a single process to the sandbox result."""
|
|
1358
1403
|
self.section_body.add_process(process)
|
|
1359
1404
|
|
|
1360
1405
|
def add_processes(self, processes: List[SandboxProcessItem]) -> None:
|
|
1361
|
-
"""Add multiple processes
|
|
1406
|
+
"""Add multiple processes to the sandbox result."""
|
|
1362
1407
|
self.section_body.add_processes(processes)
|
|
1363
1408
|
|
|
1364
|
-
def
|
|
1365
|
-
"""Add a single network
|
|
1366
|
-
self.section_body.
|
|
1409
|
+
def add_network_connection(self, connection: SandboxNetflowItem) -> None:
|
|
1410
|
+
"""Add a single network connection to the sandbox result."""
|
|
1411
|
+
self.section_body.add_network_connection(connection)
|
|
1367
1412
|
|
|
1368
|
-
def
|
|
1369
|
-
"""Add multiple network
|
|
1370
|
-
self.section_body.
|
|
1413
|
+
def add_network_connections(self, connections: List[SandboxNetflowItem]) -> None:
|
|
1414
|
+
"""Add multiple network connections to the sandbox result."""
|
|
1415
|
+
self.section_body.add_network_connections(connections)
|
|
1371
1416
|
|
|
1372
1417
|
def add_signature(self, signature: SandboxSignatureItem) -> None:
|
|
1373
|
-
"""Add a detection signature to the sandbox result."""
|
|
1418
|
+
"""Add a single detection signature to the sandbox result."""
|
|
1374
1419
|
self.section_body.add_signature(signature)
|
|
1375
1420
|
|
|
1376
1421
|
def add_signatures(self, signatures: List[SandboxSignatureItem]) -> None:
|
|
1377
|
-
"""Add multiple detection signatures
|
|
1422
|
+
"""Add multiple detection signatures to the sandbox result."""
|
|
1378
1423
|
self.section_body.add_signatures(signatures)
|
|
1379
1424
|
|
|
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
1425
|
|
|
1389
1426
|
class ResultTableSection(TypeSpecificResultSection):
|
|
1390
1427
|
def __init__(self, title_text: Union[str, List], **kwargs):
|