Analyzing a Mirai Botnet PCAP with Claude Code

In a previous post I walked through analyzing a DoublePulsar/EternalBlue capture with Claude Code. This time the target is sample.pcap — a capture of an IoT device downloading what turns out to be a Mirai-variant botnet binary. The same single-prompt workflow, but with a very different payload at the end.

The Prompt

Analyse the sample.pcap file, extract any IOCs, if there are any files being transmitted please examine them. Report source and destination IP addresses and protocols, file types and content.

Analysis Methodology

Claude worked through the capture in layers — start wide, then drill down.

Step 1 — Protocol Hierarchy

tshark -r sample.pcap -q -z io,phs

The -z io,phs flag prints a protocol hierarchy tree with frame and byte counts at each layer. Quick way to see what's in a capture without looking at individual frames. Result: pure TCP/HTTP — no DNS, no TLS, no lateral movement protocols.

===================================================================
Protocol Hierarchy Statistics

eth                                      frames:147 bytes:161716
  ip                                     frames:147 bytes:161716
    tcp                                  frames:147 bytes:161716
      http                               frames:6 bytes:7266
        media                            frames:1 bytes:950
          tcp.segments                   frames:1 bytes:950
===================================================================

Step 2 — IP Conversations

tshark -r sample.pcap -q -z conv,ip

Shows all IP-layer conversations: who talked to whom, how many frames each direction, total bytes, and session duration. This capture has exactly one conversation — a single internal host talking to one external IP.

================================================================================
IPv4 Conversations
                                               |       <-      | |       ->      |
                                               | Frames  Bytes | | Frames  Bytes |
10.30.10.10          <-> 117.248.67.201            73 156 kB         74 5,146 bytes
================================================================================

The traffic asymmetry stands out immediately: 156 KB inbound vs 5 KB outbound. Something large was downloaded.

Step 3 — HTTP Request/Response Details

tshark -r sample.pcap -Y http -T fields \
  -e frame.number -e ip.src -e ip.dst \
  -e http.request.method -e http.request.uri \
  -e http.response.code -e http.content_type \
  -e http.content_length

The -Y http display filter isolates HTTP frames. -T fields with -e flags extracts specific columns — cleaner than reading full packet decode. Shows the request URI, HTTP method, response code, content type, and content length for each HTTP transaction.

4    10.30.10.10  117.248.67.201  GET  /i                              
107  117.248.67.201  10.30.10.10       200  application/zip  135784
113  10.30.10.10  117.248.67.201  GET  /i                              
115  117.248.67.201  10.30.10.10       200                            
129  10.30.10.10  117.248.67.201  GET  /i

Step 4 — Host and User-Agent Extraction

tshark -r sample.pcap -Y http -T fields \
  -e http.host -e http.user_agent -e http.request.full_uri \
  | sort -u

Pulls the HTTP Host header, User-Agent, and full URI from every HTTP frame. The sort -u deduplicates — useful when the same request repeats. Two different download tools appear: the victim machine used both wget and curl to fetch the same file, a common dropper pattern that tries multiple methods for reliability.

117.248.67.201:51451    curl/7.85.0    hxxp://117.248.67.201:51451/i
117.248.67.201:51451    Wget/1.21.3    hxxp://117.248.67.201:51451/i

Step 5 — Export HTTP Objects

tshark -r sample.pcap -q --export-objects http,/tmp/pcap_exports
ls -la /tmp/pcap_exports/

--export-objects http,<dir> reassembles and saves every HTTP-transported file to disk — the same function as Wireshark's File → Export Objects → HTTP. Two files came out: i (135,784 bytes, the main payload) and object120 (2,840 bytes, a smaller blob from the third stream).

Step 6 — File Type Identification

file /tmp/pcap_exports/i /tmp/pcap_exports/object120

The file command reads magic bytes — the first bytes of a file that identify its format. Despite the server sending Content-Type: application/zip, the actual magic bytes reveal an ELF binary. The mislabeled content type is deliberate evasion.

/tmp/pcap_exports/i:         ELF 32-bit MSB executable, MIPS, MIPS-I version 1 (SYSV), statically linked, no section header
/tmp/pcap_exports/object120: data

Step 7 — ELF Header Analysis

readelf -h /tmp/pcap_exports/i

Reads the ELF header metadata: architecture, endianness, entry point, and section/program header counts. MIPS big-endian with no section headers (stripped) — typical of statically compiled IoT malware targeting routers and embedded devices.

  Machine:    MIPS R3000
  Entry point address: 0x4206a8
  Flags:      0x1007, noreorder, pic, cpic, o32, mips1
  Number of section headers: 0

Step 8 — String Extraction

strings /tmp/pcap_exports/i | grep -iE \
  "bot|cnc|c2|prot_exec|socket|udp|tcp|proc|upx|arm"

strings extracts printable character sequences from a binary. Combined with grep for known malware keywords, this gives quick classification without executing anything. Even through UPX packing, enough metadata leaks to identify the sample.

*UPX!
botv2
(socket y
[cnc]
C2
(!PROT_EXEC|PROT_WRITE failed.
/proc/self/exe
.ARM.
UDP3
TCP!

Step 9 — UPX Unpack Attempt

upx -d /tmp/pcap_exports/i -o /tmp/pcap_exports/i_unpacked

Attempts to decompress the UPX-packed binary for deeper analysis. The unpacker failed with CantUnpackException: p_info corrupted — the UPX header has been deliberately corrupted. This is a standard anti-analysis technique: the binary still runs (the OS loader doesn't check UPX metadata) but automated unpacking tools fail.

Step 10 — Cryptographic Hashing

sha256sum /tmp/pcap_exports/i
md5sum /tmp/pcap_exports/i

Generates file hashes for threat intelligence lookups (VirusTotal, MalwareBazaar, etc.). The SHA256 is the primary identifier; MD5 is included for legacy database compatibility.

SHA256: 4293c1d8574dc87c58360d6bac3daa182f64f7785c9d41da5e0741d2b1817fc7
MD5:    59ce0baba11893f90527fc951ac69912

Step 11 — TCP Stream Reassembly

tshark -r sample.pcap -q -z follow,tcp,ascii,0

Reassembles a full TCP stream and prints both sides in ASCII, with byte counts between direction switches. Used to inspect the raw HTTP exchange for stream 0 (the wget download) and confirm the three separate TCP connections (streams 0, 1, 2) each retrieved the same payload.

Results

Hosts

HostIPRole
Victim10.30.10.10Internal host — downloaded the malware
C2 / Distribution117.248.67.201External — serving the ELF payload, nginx on port 51451

Download Sequence

The victim made three GET requests to http://117.248.67.201:51451/i over 15 seconds, alternating between Wget/1.21.3 and curl/7.85.0. This wget-then-curl pattern is a dropper shell script idiom for maximum compatibility across embedded Linux environments where one tool might be missing.

Payload Analysis

The file i is a Mirai-family MIPS botnet binary:

  • Architecture: ELF 32-bit MIPS R3000, big-endian, statically linked — targets routers, DVRs, and IP cameras running embedded Linux
  • Packer: UPX 3.95 with corrupted p_info header (anti-analysis)
  • Strings: botv2, [cnc], C2 — bot version and C2 framework markers consistent with Mirai/Satori/Masuta lineage
  • Error string: (!PROT_EXEC|PROT_WRITE failed.) — verbatim from Mirai's source, present in hundreds of variants
  • Multi-arch: .ARM. string suggests the dropper serves architecture-specific binaries; this is the MIPS build
  • Self-replication: /proc/self/exe reference for process persistence
  • MIME spoofing: Server returns Content-Type: application/zip for an ELF binary

The 2,840-byte object120 blob (high entropy, no recognizable magic bytes) is consistent with an encrypted C2 beacon sent after payload retrieval — the bot checking in.

IOCs

Network:

TypeValueNotes
IP10.30.10.10Victim / infected host
IP117.248.67.201C2 / malware distribution
Port51451/TCPNon-standard C2 port
URLhttp://117.248.67.201:51451/iMalware download endpoint
User-AgentWget/1.21.3Download tool 1
User-Agentcurl/7.85.0Download tool 2

File:

TypeValue
SHA2564293c1d8574dc87c58360d6bac3daa182f64f7785c9d41da5e0741d2b1817fc7
MD559ce0baba11893f90527fc951ac69912
Filenamei (served as application/zip, actual type ELF MIPS)
Size135,784 bytes

Behavioral:

IOCDescription
ELF served as application/zipMIME-type evasion
UPX with corrupted p_infoAnti-unpack / anti-analysis
3 download attempts via wget + curl in 15sDropper retry loop
botv2 + [cnc] + C2 stringsMirai-family bot framework
PROT_EXEC|PROT_WRITE error stringMirai lineage marker
Encrypted 2,840-byte blob post-downloadC2 check-in beacon
Non-standard port 51451Firewall/port-filter evasion

MITRE ATT&CK Mapping

  • T1105 — Ingress Tool Transfer (ELF binary downloaded via HTTP)
  • T1027 — Obfuscated Files or Information (UPX packing + MIME spoofing)
  • T1571 — Non-Standard Port (C2 on 51451/TCP)
  • T1071.001 — Application Layer Protocol: Web Protocols (HTTP-based delivery)
  • T1059 — Command and Scripting Interpreter (dropper script using wget/curl)

Assessment

This capture shows the initial compromise phase of a Mirai-variant infection: a device on the internal network running a dropper script that fetches the MIPS botnet binary from an external distribution server. The three download attempts in 15 seconds, alternating between wget and curl, are characteristic of Mirai dropper shell scripts designed to run on whatever tools the target embedded Linux has available.

The corrupted UPX header is deliberate — it defeats upx -d and most automated sandbox unpackers while leaving the binary fully functional at runtime. The MIME spoofing (application/zip for an ELF) targets network-layer content inspection that checks headers rather than magic bytes.

The 2,840-byte high-entropy blob in the third TCP stream is most likely an encrypted C2 registration beacon: the bot announcing itself to the operator after successful payload retrieval.

Takeaways

A few things stand out about using Claude Code for this analysis:

  • tshark object export (--export-objects http) is the fastest path from "suspicious PCAP" to "file on disk for analysis" — Claude reached for it automatically
  • MIME type vs magic bytes discrepancy was caught immediately by running file on the exported object — a step that's easy to skip when the HTTP headers look normal
  • String extraction through UPX packing still yielded the key classification strings (botv2, [cnc], the PROT_EXEC error) even without successful unpacking
  • The full workflow — protocol hierarchy → conversations → HTTP dissection → object export → binary analysis → hashing — ran end-to-end from a single prompt

Comments

Popular posts from this blog

Metasploitable 3 - OpenVAS Vulnerability Scan

Metasploitable 3 - Hashdump post Authentication

Metasploitable 3 - Exploiting Tomcat