Chapter 22

Network Artifacts in Memory

Active and recently-closed network connections, DNS cache, ARP tables, and raw socket data are all preserved in RAM. This chapter covers how to extract network forensic evidence from a memory image — evidence that disappears on shutdown but is invaluable for establishing C2 communications and lateral movement.

Scenario

An attacker's beacon maintained an active HTTPS connection to 185.220.101.47:443 before you captured the memory image. The beacon had gone through a Domain Fronting CDN, so proxy logs showed only the CDN's IP — not the real C2. The memory image has the established TCP connection with the real destination IP, the process (svchost.exe PID 1384) that owns the socket, and the decrypted TLS session key cached in the NSS3 structure (for browser-based C2). Without the memory image, the network investigation would have hit a dead end at the CDN. This chapter shows how to extract all of that.

Network Connections with netscan

Bashvol3-network.sh
RAM="/cases/CASE001/RAM.raw"
OUT="/cases/CASE001/memory"

# netscan — finds all TCP_ENDPOINT, TCP_LISTENER, UDP_ENDPOINT structures
vol -f $RAM windows.netscan --output csv > $OUT/netscan.csv

# netstat — Windows 10+ alternative (more reliable for newer OS)
vol -f $RAM windows.netstat --output csv > $OUT/netstat.csv

# netscan output columns:
#   Offset    — physical address of the TCP structure
#   Proto     — TCP, TCPv6, UDP, UDPv6
#   LocalAddr — local IP:port
#   ForeignAddr — remote IP:port (the C2!)
#   State     — ESTABLISHED, LISTEN, CLOSE_WAIT, TIME_WAIT
#   PID       — process ID that owns the socket
#   Owner     — process name
#   Created   — connection creation timestamp
PowerShellanalyze-netscan.ps1
# Analyze netscan output for suspicious connections
$net = Import-Csv "/cases/CASE001/memory/netscan.csv"

# Established connections to external IPs from unusual processes
$net | Where-Object {
    $_.State -eq "ESTABLISHED" -and
    $_.ForeignAddr -notmatch "^(127\.|10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01]))" -and
    $_.Owner -notmatch "^(chrome|firefox|edge|svchost.*trusted)"
} | Select-Object Created, Owner, PID, LocalAddr, ForeignAddr, State |
  Sort-Object Created |
  Format-Table -AutoSize

# Look for beacon timing patterns — connections at regular intervals
# Group by PID and ForeignAddr to see recurring connections
$net | Where-Object { $_.State -eq "ESTABLISHED" } |
    Group-Object PID, ForeignAddr |
    Where-Object Count -gt 2 |
    Select-Object Name, Count |
    Format-Table

# Suspicious listening ports (backdoors, local C2 tunnels)
$net | Where-Object {
    $_.State -eq "LISTEN" -and
    $_.LocalAddr -notmatch ":80$|:443$|:445$|:135$|:139$|:3389$"
} | Select-Object Owner, PID, LocalAddr | Format-Table

DNS Cache in Memory

Windows DNS cache is maintained in the DNS Client service (svchost.exe hosting Dnscache). Volatility can extract it from memory — this reveals domain names the system resolved even if DNS logs aren't available.

Bashdns-from-memory.sh
RAM="/cases/CASE001/RAM.raw"

# Method 1: Use strings to extract DNS cache entries from memory
# DNS entries often have recognizable patterns
strings -el $RAM | grep -iP "^[a-z0-9.-]+\.(com|net|org|io|xyz|ru|cn)\s*$" | \
    sort -u | \
    grep -v "microsoft.com\|windows.com\|windowsupdate.com" > /tmp/dns-strings.txt

# Method 2: Volatility windows.dnsresolver (newer versions have this plugin)
vol -f $RAM windows.dnsresolver --output csv > /tmp/dns-cache.csv 2>/dev/null

# Method 3: Find Dnscache service svchost, dump its memory, grep for DNS entries
# Get PID of svchost hosting Dnscache
vol -f $RAM windows.cmdline | grep -i dnscache

# Then look at the process's heap memory for resolved entries
# Manual: extract VAD memory pages from the Dnscache svchost PID
vol -f $RAM windows.vadump --pid  --output-dir /tmp/dnscache-vad/
strings /tmp/dnscache-vad/*.dmp | grep -iP "\.(com|net|org|io)" | sort -u

ARP Cache and Routing from Memory

The ARP cache maps IP addresses to MAC addresses — captured in live response, it reveals which hosts on the network the compromised system had recently communicated with.

Basharp-from-memory.sh
# ARP cache from live response (captured BEFORE memory image)
# Should be captured as part of live response phase (Chapter 2)
cat /cases/CASE001/live-response/arp-live.txt

# Alternative: extract from memory image using raw string search
# ARP entries are stored in the TCP/IP driver's MIB structure
# Less reliable than live response — prefer live capture

# strings approach for IP address extraction:
strings -el $RAM | grep -P "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$" | \
    grep -v "0\.0\.0\.0\|255\.255\|127\.0" | \
    sort -u > /tmp/ip-addresses-in-memory.txt

# Cross-reference against known corporate IP ranges
# IPs outside corporate ranges in the ARP cache = lateral movement targets
# or attacker infrastructure

Reconstructing C2 Communication from Memory

Evidence typeWhat it revealsExtraction method
Established TCP connection (netscan)Real C2 IP even if proxied through CDN at network layerwindows.netscan / windows.netstat
DNS cache entriesC2 domain names resolved by the implantwindows.dnsresolver, strings against memory, live response dns cache
HTTP request buffersCleartext HTTP C2 requests — URL, headers, body — in process heap if not encryptedstrings against process dump, looking for HTTP/1.1, User-Agent, GET/POST
TLS session keys (NSS3)Browser-based C2 session keys — decrypt HTTPS traffic from PCAPExtract NSS3 keylog from Firefox/Chrome process memory using specialized tools
Decrypted beacon configC2 hostname, port, sleep interval, jitter, User-Agent, malleable profilemalfind dump + 1768.py / CobaltStrikeParser against beacon memory
Why network artifacts in memory are uniquely valuable in encrypted-C2 investigations

Modern C2 frameworks use HTTPS with domain fronting, certificate pinning, and malleable profiles that make network-level detection extremely difficult — the traffic looks like normal CDN HTTPS. At the network level (proxy logs, NDR appliances), you see connections to legitimate CDN IPs like Cloudflare or Azure CDN. The memory image breaks through this obfuscation: the TCP connection in memory shows the actual destination IP because the beacon resolved it before the CDN request was made. The decrypted C2 config in the beacon's memory region shows the actual C2 hostname and communication parameters. This is evidence that network-layer tools cannot provide — it's the reason why memory forensics is not optional for sophisticated C2 investigations.

Q & A

Q: The memory image was taken 20 minutes after the alert — the beacon already closed its connection to check back in later. Will netscan still show the connection?

Probably not in ESTABLISHED state — TCP connections in TIME_WAIT or CLOSE_WAIT may persist for a few minutes after closing, but after that the socket structures are freed. However: (1) The next check-in may have happened during the 20-minute window and netscan may catch it in ESTABLISHED or TIME_WAIT. (2) Even if the active connection is gone, the DNS cache entry for the C2 domain often persists longer in memory. (3) The TCP connection history in the beacon's C2 communication structure may still be in the beacon's memory region with the previous connection IP. (4) Windows can retain recently-closed connection metadata in the TCP/IP driver for minutes to hours in some states. (5) netscan often finds CLOSE_WAIT and FIN_WAIT states that represent recently-closed connections. Report what netscan finds but also note what the next check-in interval likely is from any extracted beacon config — if the beacon has a 60-second sleep with 10% jitter, it will connect again within 66 seconds of the memory image, and you should see it in netscan if you take a second image.