reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to the Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by the Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding any notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. Please do not remove or change
|
||||
the license header comment from a contributed file except when
|
||||
necessary.
|
||||
|
||||
Copyright 2026 mukul975
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,340 @@
|
||||
---
|
||||
name: analyzing-network-traffic-of-malware
|
||||
description: 'Analyzes network traffic generated by malware during sandbox execution
|
||||
or live incident response to identify C2 protocols, data exfiltration channels,
|
||||
payload downloads, and lateral movement patterns using Wireshark, Zeek, and Suricata.
|
||||
Activates for requests involving malware network analysis, C2 traffic decoding,
|
||||
malware PCAP analysis, or network-based malware detection.
|
||||
|
||||
'
|
||||
domain: cybersecurity
|
||||
subdomain: malware-analysis
|
||||
tags:
|
||||
- malware
|
||||
- network-analysis
|
||||
- PCAP
|
||||
- Wireshark
|
||||
- C2-detection
|
||||
version: 1.0.0
|
||||
author: mahipal
|
||||
license: Apache-2.0
|
||||
nist_csf:
|
||||
- DE.AE-02
|
||||
- RS.AN-03
|
||||
- ID.RA-01
|
||||
- DE.CM-01
|
||||
mitre_attack:
|
||||
- T1071.001
|
||||
- T1571
|
||||
- T1573
|
||||
- T1095
|
||||
---
|
||||
|
||||
# Analyzing Network Traffic of Malware
|
||||
|
||||
## When to Use
|
||||
|
||||
- Sandbox execution has captured a PCAP file and the network behavior needs detailed analysis
|
||||
- Identifying the C2 protocol structure for writing network detection signatures
|
||||
- Determining what data the malware exfiltrates and to which external infrastructure
|
||||
- Analyzing DNS tunneling, domain generation algorithms (DGA), or fast-flux behavior
|
||||
- Creating Suricata/Snort signatures based on observed malware network patterns
|
||||
|
||||
**Do not use** for host-based analysis of malware behavior; use Cuckoo sandbox reports or Volatility memory analysis for process-level activity.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Wireshark 4.x installed for interactive PCAP analysis
|
||||
- tshark (Wireshark CLI) for scripted packet extraction
|
||||
- Zeek installed for automated metadata generation from PCAPs
|
||||
- Suricata with ET Open/ET Pro rulesets for signature matching
|
||||
- NetworkMiner for file extraction and credential detection from PCAPs
|
||||
- Python 3.8+ with `scapy` and `dpkt` for programmatic packet analysis
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Initial PCAP Overview
|
||||
|
||||
Get a high-level understanding of the network traffic:
|
||||
|
||||
```bash
|
||||
# Capture statistics
|
||||
capinfos malware.pcap
|
||||
|
||||
# Protocol hierarchy
|
||||
tshark -r malware.pcap -q -z io,phs
|
||||
|
||||
# Endpoint statistics (top talkers)
|
||||
tshark -r malware.pcap -q -z endpoints,ip
|
||||
|
||||
# Conversation statistics
|
||||
tshark -r malware.pcap -q -z conv,tcp
|
||||
|
||||
# DNS query summary
|
||||
tshark -r malware.pcap -q -z dns,tree
|
||||
```
|
||||
|
||||
### Step 2: Analyze DNS Activity
|
||||
|
||||
Examine DNS queries for DGA, tunneling, or C2 domain resolution:
|
||||
|
||||
```bash
|
||||
# Extract all DNS queries
|
||||
tshark -r malware.pcap -T fields -e frame.time -e dns.qry.name -e dns.a \
|
||||
-Y "dns.flags.response == 1" | sort
|
||||
|
||||
# Detect DGA patterns (high entropy domain names)
|
||||
python3 << 'PYEOF'
|
||||
import math
|
||||
from collections import Counter
|
||||
|
||||
def entropy(s):
|
||||
p = [n/len(s) for n in Counter(s).values()]
|
||||
return -sum(pi * math.log2(pi) for pi in p if pi > 0)
|
||||
|
||||
# Parse DNS queries from tshark output
|
||||
import subprocess
|
||||
result = subprocess.run(
|
||||
["tshark", "-r", "malware.pcap", "-T", "fields", "-e", "dns.qry.name",
|
||||
"-Y", "dns.flags.response == 0"],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
|
||||
domains = set(result.stdout.strip().split('\n'))
|
||||
print("Suspicious DNS queries (high entropy):")
|
||||
for domain in domains:
|
||||
if domain:
|
||||
subdomain = domain.split('.')[0]
|
||||
ent = entropy(subdomain)
|
||||
if ent > 3.5 and len(subdomain) > 10:
|
||||
print(f" {domain} (entropy: {ent:.2f})")
|
||||
PYEOF
|
||||
|
||||
# Detect DNS tunneling (large TXT responses)
|
||||
tshark -r malware.pcap -T fields -e dns.qry.name -e dns.txt \
|
||||
-Y "dns.resp.type == 16 and dns.resp.len > 100"
|
||||
```
|
||||
|
||||
### Step 3: Analyze HTTP/HTTPS C2 Communication
|
||||
|
||||
Examine web-based command-and-control traffic:
|
||||
|
||||
```bash
|
||||
# Extract HTTP requests
|
||||
tshark -r malware.pcap -T fields \
|
||||
-e frame.time -e ip.src -e ip.dst -e http.host \
|
||||
-e http.request.method -e http.request.uri -e http.user_agent \
|
||||
-Y "http.request"
|
||||
|
||||
# Extract HTTP response bodies (potential payload downloads)
|
||||
tshark -r malware.pcap -T fields \
|
||||
-e http.host -e http.request.uri -e http.content_type -e tcp.len \
|
||||
-Y "http.response and tcp.len > 1000"
|
||||
|
||||
# Extract POST data (potential exfiltration)
|
||||
tshark -r malware.pcap -T fields \
|
||||
-e http.host -e http.request.uri -e http.file_data \
|
||||
-Y "http.request.method == POST"
|
||||
|
||||
# TLS analysis (SNI, JA3 fingerprints)
|
||||
tshark -r malware.pcap -T fields \
|
||||
-e tls.handshake.extensions_server_name \
|
||||
-e tls.handshake.ja3 \
|
||||
-Y "tls.handshake.type == 1"
|
||||
|
||||
# Extract TLS certificate details
|
||||
tshark -r malware.pcap -T fields \
|
||||
-e x509ce.dNSName -e x509af.serialNumber \
|
||||
-e x509sat.utf8String \
|
||||
-Y "tls.handshake.type == 11"
|
||||
|
||||
# Export HTTP objects (downloaded files)
|
||||
tshark -r malware.pcap --export-objects http,exported_files/
|
||||
```
|
||||
|
||||
### Step 4: Detect Beaconing Patterns
|
||||
|
||||
Identify regular periodic communication indicating C2 beaconing:
|
||||
|
||||
```python
|
||||
# Beacon detection from PCAP
|
||||
from scapy.all import rdpcap, IP, TCP
|
||||
from collections import defaultdict
|
||||
import statistics
|
||||
|
||||
packets = rdpcap("malware.pcap")
|
||||
|
||||
# Group connections by destination IP:port
|
||||
connections = defaultdict(list)
|
||||
for pkt in packets:
|
||||
if IP in pkt and TCP in pkt:
|
||||
if pkt[TCP].flags & 0x02: # SYN flag
|
||||
dst = f"{pkt[IP].dst}:{pkt[TCP].dport}"
|
||||
connections[dst].append(float(pkt.time))
|
||||
|
||||
# Analyze timing intervals for beaconing
|
||||
print("Beacon Analysis:")
|
||||
for dst, times in connections.items():
|
||||
if len(times) >= 5:
|
||||
intervals = [times[i+1] - times[i] for i in range(len(times)-1)]
|
||||
avg = statistics.mean(intervals)
|
||||
stdev = statistics.stdev(intervals) if len(intervals) > 1 else 0
|
||||
jitter = (stdev / avg * 100) if avg > 0 else 0
|
||||
|
||||
if 10 < avg < 3600 and jitter < 30: # Regular interval with < 30% jitter
|
||||
print(f" [!] {dst}: {len(times)} connections")
|
||||
print(f" Interval: {avg:.1f}s ± {stdev:.1f}s (jitter: {jitter:.1f}%)")
|
||||
print(f" Pattern: LIKELY BEACONING")
|
||||
```
|
||||
|
||||
### Step 5: Generate Network Detection Signatures
|
||||
|
||||
Create Suricata/Snort rules from observed traffic patterns:
|
||||
|
||||
```bash
|
||||
# Run Suricata against the PCAP for existing signature matches
|
||||
suricata -r malware.pcap -l suricata_output/ -c /etc/suricata/suricata.yaml
|
||||
|
||||
# Review alerts
|
||||
cat suricata_output/fast.log
|
||||
|
||||
# Create custom Suricata rule from observed patterns
|
||||
cat << 'EOF' > custom_malware.rules
|
||||
# C2 beacon detection based on observed URI pattern
|
||||
alert http $HOME_NET any -> $EXTERNAL_NET any (
|
||||
msg:"MALWARE MalwareX C2 Beacon";
|
||||
flow:established,to_server;
|
||||
http.method; content:"POST";
|
||||
http.uri; content:"/gate.php?id=";
|
||||
http.user_agent; content:"Mozilla/5.0 (compatible; MSIE 10.0)";
|
||||
sid:9000001; rev:1;
|
||||
)
|
||||
|
||||
# DNS query for known C2 domain
|
||||
alert dns $HOME_NET any -> any any (
|
||||
msg:"MALWARE MalwareX C2 DNS Query";
|
||||
dns.query; content:"update.malicious.com";
|
||||
sid:9000002; rev:1;
|
||||
)
|
||||
|
||||
# JA3 hash match for malware TLS client
|
||||
alert tls $HOME_NET any -> $EXTERNAL_NET any (
|
||||
msg:"MALWARE MalwareX JA3 Match";
|
||||
ja3.hash; content:"a0e9f5d64349fb13191bc781f81f42e1";
|
||||
sid:9000003; rev:1;
|
||||
)
|
||||
EOF
|
||||
```
|
||||
|
||||
### Step 6: Extract Files and Artifacts from Traffic
|
||||
|
||||
Recover transferred files and embedded data:
|
||||
|
||||
```bash
|
||||
# Extract files using Zeek
|
||||
zeek -r malware.pcap /opt/zeek/share/zeek/policy/frameworks/files/extract-all-files.zeek
|
||||
ls extract_files/
|
||||
|
||||
# Extract files using NetworkMiner (GUI)
|
||||
# Or use tshark for specific protocol exports
|
||||
tshark -r malware.pcap --export-objects http,http_objects/
|
||||
tshark -r malware.pcap --export-objects smb,smb_objects/
|
||||
tshark -r malware.pcap --export-objects tftp,tftp_objects/
|
||||
|
||||
# Hash all extracted files
|
||||
sha256sum http_objects/* smb_objects/* 2>/dev/null
|
||||
|
||||
# Generate Zeek logs for comprehensive metadata
|
||||
zeek -r malware.pcap
|
||||
# Output: conn.log, dns.log, http.log, ssl.log, files.log, etc.
|
||||
```
|
||||
|
||||
## Key Concepts
|
||||
|
||||
| Term | Definition |
|
||||
|------|------------|
|
||||
| **Beaconing** | Regular periodic connections from malware to C2 server, identifiable by consistent time intervals and packet sizes |
|
||||
| **JA3/JA3S** | TLS fingerprinting method creating a hash from ClientHello/ServerHello parameters to uniquely identify malware TLS implementations |
|
||||
| **DGA (Domain Generation Algorithm)** | Algorithm generating pseudo-random domain names that malware queries to locate C2 servers, evading static domain blocklists |
|
||||
| **DNS Tunneling** | Encoding data in DNS queries and responses to establish a C2 channel or exfiltrate data through DNS infrastructure |
|
||||
| **Fast Flux** | DNS technique rapidly rotating IP addresses for a domain to avoid takedown and distribute C2 across many compromised hosts |
|
||||
| **SNI (Server Name Indication)** | TLS extension revealing the hostname the client is connecting to; visible even in encrypted HTTPS connections |
|
||||
| **Network Signature** | Suricata/Snort rule matching specific patterns in network traffic (headers, payloads, timing) to detect malicious communications |
|
||||
|
||||
## Tools & Systems
|
||||
|
||||
- **Wireshark**: Open-source packet analyzer for deep interactive inspection of network traffic at the protocol level
|
||||
- **Zeek**: Network analysis framework generating structured metadata logs (conn, dns, http, ssl) from live or captured traffic
|
||||
- **Suricata**: High-performance network IDS/IPS for signature-based detection with Lua scripting for custom detection logic
|
||||
- **NetworkMiner**: Network forensic analysis tool for extracting files, images, and credentials from PCAP files
|
||||
- **Scapy**: Python packet manipulation library for programmatic packet analysis, beacon detection, and protocol decoding
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
### Scenario: Decoding a Custom Binary C2 Protocol
|
||||
|
||||
**Context**: Malware communicates with its C2 server using a custom binary protocol over TCP port 8443. Standard HTTP analysis yields no results. The protocol structure needs to be reverse engineered from the PCAP.
|
||||
|
||||
**Approach**:
|
||||
1. Filter the PCAP for TCP port 8443 conversations and follow the TCP stream
|
||||
2. Identify the message framing (length prefix, delimiter, fixed-size headers)
|
||||
3. Compare multiple messages to identify static header fields vs variable data fields
|
||||
4. Cross-reference with reverse engineering findings from Ghidra (if the binary was analyzed)
|
||||
5. Write a Wireshark dissector or Scapy parser for the custom protocol
|
||||
6. Create Suricata rules matching the static header bytes for network detection
|
||||
7. Document the full protocol specification for threat intelligence sharing
|
||||
|
||||
**Pitfalls**:
|
||||
- Analyzing only the first few packets; some C2 protocols change behavior after initial handshake
|
||||
- Not decrypting TLS traffic when the sandbox has MITM capabilities
|
||||
- Confusing legitimate CDN or cloud traffic with C2 (validate destination IPs)
|
||||
- Missing C2 traffic that uses DNS or ICMP instead of TCP/UDP
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
MALWARE NETWORK TRAFFIC ANALYSIS
|
||||
===================================
|
||||
PCAP File: malware_sandbox.pcap
|
||||
Duration: 300 seconds
|
||||
Total Packets: 12,847
|
||||
Total Bytes: 4.2 MB
|
||||
|
||||
DNS ACTIVITY
|
||||
Total Queries: 47
|
||||
DGA Detected: Yes (23 high-entropy queries to .com TLD)
|
||||
Tunneling: No
|
||||
Resolved C2: update.malicious[.]com -> 185.220.101[.]42
|
||||
|
||||
C2 COMMUNICATION
|
||||
Protocol: HTTPS (TLS 1.2)
|
||||
Server: 185.220.101[.]42:443
|
||||
SNI: update.malicious[.]com
|
||||
JA3 Hash: a0e9f5d64349fb13191bc781f81f42e1
|
||||
Beacon Interval: 60.2s ± 6.8s (11.3% jitter)
|
||||
Total Sessions: 237
|
||||
Data Sent: 147 MB
|
||||
Data Received: 2.3 MB
|
||||
Certificate: CN=update.malicious[.]com (self-signed, expired)
|
||||
|
||||
PAYLOAD DOWNLOADS
|
||||
GET /payload.dll from compromised-site[.]com
|
||||
Size: 98,304 bytes
|
||||
SHA-256: abc123def456...
|
||||
Content-Type: application/octet-stream
|
||||
|
||||
EXFILTRATION
|
||||
Method: HTTPS POST to /gate.php
|
||||
Content-Type: application/octet-stream
|
||||
Average Size: 15,432 bytes per request
|
||||
Total Volume: 147 MB over 4 hours
|
||||
|
||||
SURICATA ALERTS
|
||||
[1:2028401] ET MALWARE Generic C2 Beacon Pattern
|
||||
[1:2028500] ET POLICY Self-Signed Certificate
|
||||
|
||||
GENERATED SIGNATURES
|
||||
SID 9000001: MalwareX HTTP beacon pattern
|
||||
SID 9000002: MalwareX DNS C2 domain
|
||||
SID 9000003: MalwareX JA3 TLS fingerprint
|
||||
```
|
||||
@@ -0,0 +1,128 @@
|
||||
# API Reference: Malware Network Traffic Analysis
|
||||
|
||||
## dpkt - Python Packet Parsing
|
||||
|
||||
### PCAP Reading
|
||||
```python
|
||||
import dpkt
|
||||
with open("malware.pcap", "rb") as f:
|
||||
pcap = dpkt.pcap.Reader(f)
|
||||
for ts, buf in pcap:
|
||||
eth = dpkt.ethernet.Ethernet(buf)
|
||||
ip = eth.data
|
||||
tcp = ip.data
|
||||
```
|
||||
|
||||
### HTTP Parsing
|
||||
```python
|
||||
http_req = dpkt.http.Request(tcp.data)
|
||||
http_req.method # GET, POST
|
||||
http_req.uri # Request URI
|
||||
http_req.headers # Header dict
|
||||
http_req.body # POST body
|
||||
|
||||
http_resp = dpkt.http.Response(tcp.data)
|
||||
http_resp.status # Status code
|
||||
http_resp.body # Response body
|
||||
```
|
||||
|
||||
### IP Address Conversion
|
||||
```python
|
||||
dpkt.utils.inet_to_str(ip.src) # bytes -> "1.2.3.4"
|
||||
dpkt.utils.inet_aton("1.2.3.4") # "1.2.3.4" -> bytes
|
||||
```
|
||||
|
||||
## Wireshark Display Filters for Malware
|
||||
|
||||
### C2 Detection
|
||||
```
|
||||
http.request.method == "POST" && http.content_length > 0
|
||||
tls.handshake.type == 1 # TLS Client Hello
|
||||
tcp.flags.syn == 1 && tcp.flags.ack == 0 # New connections
|
||||
dns.qry.type == 16 # TXT records
|
||||
```
|
||||
|
||||
### Payload Analysis
|
||||
```
|
||||
tcp.payload contains "MZ" # PE downloads
|
||||
http.response.code == 200 && http.content_type contains "octet"
|
||||
frame.len > 1400 # Large packets
|
||||
```
|
||||
|
||||
## tshark - Field Extraction
|
||||
|
||||
### HTTP Requests
|
||||
```bash
|
||||
tshark -r malware.pcap -Y "http.request" -T fields \
|
||||
-e http.request.method -e http.host -e http.request.uri \
|
||||
-e http.user_agent -e http.content_length
|
||||
```
|
||||
|
||||
### TLS/JA3 Fingerprinting
|
||||
```bash
|
||||
tshark -r malware.pcap -Y "tls.handshake.type==1" -T fields \
|
||||
-e ip.src -e ip.dst -e tls.handshake.ja3
|
||||
```
|
||||
|
||||
### DNS Queries
|
||||
```bash
|
||||
tshark -r malware.pcap -Y "dns.qr==0" -T fields \
|
||||
-e ip.src -e dns.qry.name -e dns.qry.type
|
||||
```
|
||||
|
||||
### Stream Follow
|
||||
```bash
|
||||
tshark -r malware.pcap -z follow,tcp,ascii,0
|
||||
tshark -r malware.pcap -z follow,http,ascii,0
|
||||
```
|
||||
|
||||
## Suricata Rule Syntax
|
||||
|
||||
### HTTP Rules
|
||||
```
|
||||
alert http $HOME_NET any -> $EXTERNAL_NET any (
|
||||
msg:"MALWARE C2 Beacon";
|
||||
flow:established,to_server;
|
||||
http.method; content:"POST";
|
||||
http.uri; content:"/gate.php";
|
||||
sid:9000001; rev:1;
|
||||
)
|
||||
```
|
||||
|
||||
### DNS Rules
|
||||
```
|
||||
alert dns $HOME_NET any -> any any (
|
||||
msg:"MALWARE DNS Tunneling";
|
||||
dns.query; pcre:"/^[a-z0-9]{20,}\./";
|
||||
threshold:type threshold, track by_src, count 10, seconds 60;
|
||||
sid:9000002; rev:1;
|
||||
)
|
||||
```
|
||||
|
||||
### TLS Rules
|
||||
```
|
||||
alert tls $HOME_NET any -> $EXTERNAL_NET any (
|
||||
msg:"MALWARE JA3 Match";
|
||||
ja3.hash; content:"a0e9f5d64349fb13191bc781f81f42e1";
|
||||
sid:9000003; rev:1;
|
||||
)
|
||||
```
|
||||
|
||||
## RITA - Beacon Analysis
|
||||
|
||||
### Syntax
|
||||
```bash
|
||||
rita import zeek_logs dataset_name
|
||||
rita analyze dataset_name
|
||||
rita show-beacons dataset_name
|
||||
rita show-long-connections dataset_name
|
||||
rita show-dns-fqdn-lengths dataset_name
|
||||
```
|
||||
|
||||
## NetworkMiner
|
||||
|
||||
### CLI Syntax
|
||||
```bash
|
||||
NetworkMiner --inputfile malware.pcap --outputdir /tmp/extracted
|
||||
```
|
||||
Extracts files, sessions, credentials, DNS from PCAP
|
||||
@@ -0,0 +1,243 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Malware network traffic analysis agent for C2 protocol decoding and signature generation."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import math
|
||||
from collections import defaultdict, Counter
|
||||
|
||||
try:
|
||||
import dpkt
|
||||
HAS_DPKT = True
|
||||
except ImportError:
|
||||
HAS_DPKT = False
|
||||
|
||||
try:
|
||||
from scapy.all import rdpcap, IP, TCP, DNS, DNSQR
|
||||
HAS_SCAPY = True
|
||||
except ImportError:
|
||||
HAS_SCAPY = False
|
||||
|
||||
|
||||
def shannon_entropy(data):
|
||||
"""Calculate Shannon entropy of byte data."""
|
||||
if not data:
|
||||
return 0.0
|
||||
counter = Counter(data)
|
||||
length = len(data)
|
||||
return -sum((c / length) * math.log2(c / length) for c in counter.values())
|
||||
|
||||
|
||||
def extract_tcp_streams(pcap_path):
|
||||
"""Extract TCP stream payloads grouped by conversation."""
|
||||
if not HAS_DPKT:
|
||||
return {}
|
||||
streams = defaultdict(list)
|
||||
with open(pcap_path, "rb") as f:
|
||||
pcap = dpkt.pcap.Reader(f)
|
||||
for ts, buf in pcap:
|
||||
try:
|
||||
eth = dpkt.ethernet.Ethernet(buf)
|
||||
if not isinstance(eth.data, dpkt.ip.IP):
|
||||
continue
|
||||
ip = eth.data
|
||||
if not isinstance(ip.data, dpkt.tcp.TCP):
|
||||
continue
|
||||
tcp = ip.data
|
||||
if len(tcp.data) > 0:
|
||||
src = f"{dpkt.utils.inet_to_str(ip.src)}:{tcp.sport}"
|
||||
dst = f"{dpkt.utils.inet_to_str(ip.dst)}:{tcp.dport}"
|
||||
key = tuple(sorted([src, dst]))
|
||||
streams[key].append({
|
||||
"ts": ts,
|
||||
"src": src,
|
||||
"dst": dst,
|
||||
"data": tcp.data,
|
||||
"data_len": len(tcp.data),
|
||||
})
|
||||
except Exception:
|
||||
continue
|
||||
return streams
|
||||
|
||||
|
||||
def analyze_payload_structure(payloads):
|
||||
"""Analyze payload structure to identify protocol framing."""
|
||||
if not payloads:
|
||||
return {}
|
||||
analysis = {
|
||||
"total_payloads": len(payloads),
|
||||
"sizes": [len(p) for p in payloads],
|
||||
"avg_size": sum(len(p) for p in payloads) / len(payloads),
|
||||
"entropy_values": [],
|
||||
}
|
||||
for p in payloads[:20]:
|
||||
ent = shannon_entropy(p)
|
||||
analysis["entropy_values"].append(round(ent, 4))
|
||||
avg_ent = sum(analysis["entropy_values"]) / len(analysis["entropy_values"])
|
||||
analysis["avg_entropy"] = round(avg_ent, 4)
|
||||
analysis["likely_encrypted"] = avg_ent > 7.5
|
||||
|
||||
# Check for common header patterns
|
||||
first_bytes = [p[:4] for p in payloads if len(p) >= 4]
|
||||
if first_bytes:
|
||||
byte_counter = Counter([b.hex() for b in first_bytes])
|
||||
most_common = byte_counter.most_common(3)
|
||||
analysis["common_headers"] = [
|
||||
{"hex": h, "count": c} for h, c in most_common
|
||||
]
|
||||
return analysis
|
||||
|
||||
|
||||
def detect_dns_tunneling(pcap_path, entropy_threshold=3.5):
|
||||
"""Detect DNS tunneling in malware traffic."""
|
||||
if not HAS_SCAPY:
|
||||
return []
|
||||
packets = rdpcap(pcap_path)
|
||||
suspicious = []
|
||||
for pkt in packets:
|
||||
if DNS in pkt and pkt[DNS].qr == 0 and DNSQR in pkt:
|
||||
qname = pkt[DNSQR].qname.decode("utf-8", errors="replace").rstrip(".")
|
||||
parts = qname.split(".")
|
||||
if len(parts) > 2:
|
||||
subdomain = ".".join(parts[:-2])
|
||||
ent = shannon_entropy(subdomain.encode())
|
||||
if ent > entropy_threshold or len(subdomain) > 50:
|
||||
suspicious.append({
|
||||
"query": qname,
|
||||
"subdomain_length": len(subdomain),
|
||||
"entropy": round(ent, 4),
|
||||
"src": pkt[IP].src if IP in pkt else "?",
|
||||
"qtype": pkt[DNSQR].qtype,
|
||||
})
|
||||
return suspicious
|
||||
|
||||
|
||||
def detect_dga_domains(pcap_path, min_length=12, entropy_threshold=3.5):
|
||||
"""Detect DGA (Domain Generation Algorithm) domains."""
|
||||
if not HAS_SCAPY:
|
||||
return []
|
||||
packets = rdpcap(pcap_path)
|
||||
dga_suspects = []
|
||||
for pkt in packets:
|
||||
if DNS in pkt and pkt[DNS].qr == 0 and DNSQR in pkt:
|
||||
qname = pkt[DNSQR].qname.decode("utf-8", errors="replace").rstrip(".")
|
||||
parts = qname.split(".")
|
||||
if len(parts) >= 2:
|
||||
sld = parts[-2]
|
||||
if len(sld) >= min_length:
|
||||
ent = shannon_entropy(sld.encode())
|
||||
if ent > entropy_threshold:
|
||||
dga_suspects.append({
|
||||
"domain": qname,
|
||||
"sld": sld,
|
||||
"length": len(sld),
|
||||
"entropy": round(ent, 4),
|
||||
})
|
||||
return dga_suspects
|
||||
|
||||
|
||||
def extract_http_c2(pcap_path):
|
||||
"""Extract HTTP-based C2 communication patterns."""
|
||||
if not HAS_DPKT:
|
||||
return []
|
||||
requests = []
|
||||
with open(pcap_path, "rb") as f:
|
||||
pcap = dpkt.pcap.Reader(f)
|
||||
for ts, buf in pcap:
|
||||
try:
|
||||
eth = dpkt.ethernet.Ethernet(buf)
|
||||
if not isinstance(eth.data, dpkt.ip.IP):
|
||||
continue
|
||||
ip = eth.data
|
||||
if not isinstance(ip.data, dpkt.tcp.TCP):
|
||||
continue
|
||||
tcp = ip.data
|
||||
if len(tcp.data) > 0:
|
||||
try:
|
||||
http = dpkt.http.Request(tcp.data)
|
||||
requests.append({
|
||||
"timestamp": ts,
|
||||
"src": dpkt.utils.inet_to_str(ip.src),
|
||||
"dst": dpkt.utils.inet_to_str(ip.dst),
|
||||
"method": http.method,
|
||||
"uri": http.uri,
|
||||
"host": http.headers.get("host", ""),
|
||||
"user_agent": http.headers.get("user-agent", ""),
|
||||
"content_type": http.headers.get("content-type", ""),
|
||||
"body_size": len(http.body) if http.body else 0,
|
||||
"body_entropy": round(shannon_entropy(http.body), 4) if http.body else 0,
|
||||
})
|
||||
except (dpkt.dpkt.NeedData, dpkt.dpkt.UnpackError):
|
||||
pass
|
||||
except Exception:
|
||||
continue
|
||||
return requests
|
||||
|
||||
|
||||
def generate_suricata_signatures(http_requests, dns_tunneling):
|
||||
"""Generate Suricata IDS signatures from observed malware network patterns."""
|
||||
rules = []
|
||||
sid = 9100000
|
||||
seen_uris = set()
|
||||
for req in http_requests:
|
||||
if req["uri"] not in seen_uris:
|
||||
seen_uris.add(req["uri"])
|
||||
rules.append(
|
||||
f'alert http $HOME_NET any -> $EXTERNAL_NET any ('
|
||||
f'msg:"MALWARE Suspected C2 HTTP {req["method"]} {req["uri"][:30]}"; '
|
||||
f'flow:established,to_server; '
|
||||
f'http.method; content:"{req["method"]}"; '
|
||||
f'http.uri; content:"{req["uri"]}"; '
|
||||
f'sid:{sid}; rev:1;)'
|
||||
)
|
||||
sid += 1
|
||||
if dns_tunneling:
|
||||
domains = set()
|
||||
for t in dns_tunneling:
|
||||
parts = t["query"].split(".")
|
||||
if len(parts) >= 2:
|
||||
domains.add(".".join(parts[-2:]))
|
||||
for domain in list(domains)[:5]:
|
||||
rules.append(
|
||||
f'alert dns $HOME_NET any -> any any ('
|
||||
f'msg:"MALWARE DNS Tunneling to {domain}"; '
|
||||
f'dns.query; content:"{domain}"; nocase; '
|
||||
f'sid:{sid}; rev:1;)'
|
||||
)
|
||||
sid += 1
|
||||
return rules
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=" * 60)
|
||||
print("Malware Network Traffic Analysis Agent")
|
||||
print("C2 protocol decoding, DNS tunneling, DGA detection")
|
||||
print("=" * 60)
|
||||
|
||||
pcap = sys.argv[1] if len(sys.argv) > 1 else None
|
||||
|
||||
if pcap and os.path.exists(pcap):
|
||||
print(f"\n[*] Analyzing: {pcap}")
|
||||
|
||||
print("\n--- HTTP C2 Communication ---")
|
||||
http_reqs = extract_http_c2(pcap)
|
||||
for r in http_reqs[:10]:
|
||||
print(f" {r['method']} {r['host']}{r['uri']} "
|
||||
f"(body={r['body_size']}B, entropy={r['body_entropy']})")
|
||||
|
||||
print("\n--- DNS Tunneling Detection ---")
|
||||
tunneling = detect_dns_tunneling(pcap)
|
||||
for t in tunneling[:10]:
|
||||
print(f" [!] {t['query']} (len={t['subdomain_length']}, ent={t['entropy']})")
|
||||
|
||||
print("\n--- DGA Domain Detection ---")
|
||||
dga = detect_dga_domains(pcap)
|
||||
for d in dga[:10]:
|
||||
print(f" [!] {d['domain']} (sld_len={d['length']}, ent={d['entropy']})")
|
||||
|
||||
print("\n--- Generated Suricata Rules ---")
|
||||
rules = generate_suricata_signatures(http_reqs, tunneling)
|
||||
for r in rules[:5]:
|
||||
print(f" {r}")
|
||||
else:
|
||||
print(f"\n[DEMO] Usage: python agent.py <malware_traffic.pcap>")
|
||||
Reference in New Issue
Block a user