Chapter 9

Protocol Dissectors

Wireshark's protocol dissectors decode each layer of a packet into named fields. Understanding what each dissector extracts — and what it cannot see — determines how deeply you can investigate each protocol. This chapter covers the forensically critical dissectors: HTTP, DNS, SMB, TLS, FTP, SMTP, and Kerberos.

Scenario

During an investigation you encounter: an HTTP session where the response body contains base64-encoded data, a DNS exchange with unusually long TXT records, an SMB session where a named pipe is used to execute a command, a Kerberos exchange requesting service tickets for multiple SPNs in rapid succession. Each of these is visible and analyzable through the right dissector — if you know where to look and what fields mean.

HTTP Dissector

  HTTP Packet Fields in Wireshark Details Pane
  ═══════════════════════════════════════════════════════════════════

  ▼ Hypertext Transfer Protocol
    ▼ GET /updates.rss HTTP/1.1\r\n
        Request Method: GET
        Request URI: /updates.rss
        Request Version: HTTP/1.1
    ▼ Host: updates.microsoft.com\r\n
        Host: updates.microsoft.com
    ▼ User-Agent: Mozilla/5.0...\r\n
        User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
    ▼ Cookie: __cfduid=BQDXJHAX...\r\n
        Cookie: __cfduid=BQDXJHAX...
    [Full request URI: http://updates.microsoft.com/updates.rss]
    [HTTP request sequence number: 1]
    [Response in frame: 47]

  Key display filters for HTTP:
    http.request.method == "POST"        → POST requests (data upload)
    http.request.uri contains ".exe"     → executable downloads
    http.user_agent contains "curl"      → curl user agent
    http.cookie                          → any packet with Cookie header
    http.response.code == 200            → successful responses
    http.content_length > 1000000        → large response bodies
    http.transfer_encoding == "chunked"  → chunked responses (reassembled)

  Chunked transfer encoding:
    Wireshark reassembles chunked HTTP bodies automatically.
    Look for "[Reassembled HTTP]" in Details pane for chunked responses.
    Follow HTTP Stream shows the fully reassembled body.

  HTTP/1.1 keep-alive sessions:
    Multiple request-response cycles in one TCP stream.
    Each HTTP exchange has a unique sequence number.
    Filter: http.request_number == 3 (third request in the session)

DNS Dissector

  DNS Packet Fields
  ═══════════════════════════════════════════════════════════════════

  ▼ Domain Name System (query)
      Transaction ID: 0x3f2a
      Flags: 0x0100 Standard query
        .... 0... = Response: Message is a query
        .... ...0 = Truncated: Not truncated
        .... ..1. = Recursion desired: Do query recursively
      Questions: 1
      ▼ Queries
        ▼ randomxkcd234abf.evil.com: type A, class IN
            Name: randomxkcd234abf.evil.com  ← this is the forensic indicator
            Type: A (1)
            Class: IN (1)

  ▼ Domain Name System (response)
      ▼ Flags: 0x8183 Standard query response, No such name
          .... 1... = Response: Message is a response
          .... .... ..0. = Recursion available: No  ← NXDOMAIN
        RCODE: No such name (3)                     ← DGA candidate

  Key display filters for DNS:
    dns.qry.name                         → any packet with DNS query
    dns.qry.name contains "evil.com"     → specific domain
    dns.flags.rcode == 3                 → NXDOMAIN responses (DGA beacon)
    dns.qry.type == 16                   → TXT record queries (tunneling)
    dns.qry.type == 28                   → AAAA queries (IPv6 or covert use)
    dns.resp.ttl < 60                    → very low TTL (fast-flux C2)
    dns.qry.name matches "[a-z0-9]{20,}" → long random-looking domain names

  DGA pattern in PCAP:
    → Hundreds of NXDOMAIN responses in a short window
    → Each query is a different high-entropy subdomain
    → All queries share the same base domain (the DGA's seed domain)
    → Pattern: randomhash1.seed.com → NXDOMAIN, randomhash2.seed.com → NXDOMAIN
    → Then: randomhashN.seed.com → A record (active C2 domain found)

SMB Dissector — Lateral Movement Artifacts

  SMB2 Protocol Fields (lateral movement session)
  ═══════════════════════════════════════════════════════════════════

  ▼ SMB2 (Server Message Block Protocol version 2)
    ▼ SMB2 Header
        Command: NEGOTIATE (0)
        Message ID: 0
        Process Id: 0xfffe
        Tree Id: 0
        Session Id: 0x0000000000000000
    ▼ Negotiate Protocol Request
        Dialect: SMB 3.1.1 (0x0311)
        Capabilities: DFS, Leasing, LargeMTU, MultiChannel, Encryption

  Authentication chain (NTLM):
  ▼ NTLMSSP_NEGOTIATE → NTLMSSP_CHALLENGE → NTLMSSP_AUTH
      ▼ NTLM Secure Service Provider
          NTLMSSP identifier: NTLMSSP
          NTLM Message Type: NTLMSSP_AUTH (0x00000003)
          ▼ NT-Response
              NTProofStr: ab23cd45ef67...  ← NTLMv2 hash (first 16 bytes)
              NTLMv2 Client Challenge: ...
          Domain name: CORP
          User name: jsmith                ← attacker's credentials
          Host name: WS01

  Named pipe lateral movement — look for:
    smb2.filename contains "svcctl"    → Service Control Manager named pipe
    smb2.filename contains "atsvc"     → Task Scheduler
    smb2.filename contains "samr"      → SAM database access
    smb2.ioctl.function == 0x0011c017  → Named pipe transact

  Share access:
    smb2.tree.share_type == 0x01  → disk share (file access)
    smb2.filename contains "ADMIN$"  → admin share (lateral movement)
    smb2.filename contains "IPC$"    → IPC share (named pipe connection)
Why SMB named pipes are the key lateral movement indicator

When an attacker uses PsExec, Impacket's smbexec, or WMI-based lateral movement, the visible network artifact is almost always an SMB session to IPC$ followed by a named pipe connection. PsExec connects to \\target\ADMIN$ to upload the service binary, then connects to the svcctl named pipe via IPC$ to start the service remotely. In Wireshark, this appears as: SMB2 TREE_CONNECT to \\target\IPC$, followed by SMB2 CREATE for \svcctl. The pipe name is the indicator — svcctl means Service Control Manager, atsvc means Task Scheduler, samr means SAM database. Each of these named pipes represents a specific lateral movement technique.

TLS Dissector — Handshake Analysis

  TLS 1.2 Handshake Fields
  ═══════════════════════════════════════════════════════════════════

  ▼ TLSv1.2 Record Layer: Handshake Protocol: Client Hello
    Content Type: Handshake (22)
    Version: TLS 1.0 (0x0301)  ← Record layer says 1.0 for compatibility
    ▼ Handshake Protocol: Client Hello
        Handshake Type: Client Hello (1)
        Version: TLS 1.2 (0x0303)  ← Actual TLS version
        Random: a3b4c5d6...
        Session ID Length: 0
        ▼ Cipher Suites (13 suites)
            TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
            TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
            ... etc
        ▼ Extensions
            ▼ Extension: server_name (SNI)
                Server Name: updates.microsoft.com  ← forensic key indicator
            ▼ Extension: supported_groups
                Supported Groups: x25519, secp256r1, secp384r1
            ▼ Extension: signature_algorithms
                TLS_SIGNATURE_SHA256_RSA, ...
            ▼ Extension: application_layer_protocol_negotiation (ALPN)
                ALPN Protocol: h2  ← HTTP/2 requested

  JA3 computation (see Ch32):
    JA3 string = Version + CipherSuites + Extensions + Groups + PointFormats
    JA3 hash = MD5(JA3 string)
    Visible in Wireshark with the JA3 plugin

  Key filters:
    tls.handshake.type == 1            → ClientHello
    tls.handshake.extensions_server_name  → SNI present
    tls.handshake.ciphersuite == 0xc02f   → specific cipher suite

Kerberos Dissector — Attack Detection

  Kerberos TGS-REQ (service ticket request)
  ═══════════════════════════════════════════════════════════════════

  ▼ Kerberos
    ▼ as-req / tgs-req
        pvno: 5
        msg-type: krb-tgs-req (12)
        ▼ padata: sequence of PA-DATA
            ▼ PA-DATA PA-TGS-REQ
        ▼ req-body
            kdc-options: ...
            ▼ sname: SEQUENCE
                name-type: kRB5-NT-SRV-INST (2)
                sname-string: MSSQLSvc/db01.corp.local:1433  ← SPN being requested
            ▼ etype: SEQUENCE
                etype: eTYPE-ARCFOUR-HMAC (23)  ← RC4 = KERBEROASTING INDICATOR

  Kerberoasting detection in pcap:
    → Multiple TGS-REQ in rapid succession (5-50 in under 10 seconds)
    → Each requests a different SPN (different service accounts)
    → All use etype=23 (RC4) for the ticket encryption
    → All from the same source IP

  Display filter for Kerberoasting:
    kerberos.msg_type == 12 and kerberos.etype == 23

  AS-REP Roasting (no pre-auth):
    kerberos.msg_type == 10  (AS-REQ)
    Look for AS-REQ with no PA-ENC-TIMESTAMP (pre-auth data missing)
    The absence of PA-DATA padata-type 2 = DONT_REQUIRE_PREAUTH set

Q & A

Q: Wireshark isn't decoding my traffic as the right protocol. How do I force the correct dissector?

Wireshark assigns dissectors based on port numbers by default — port 80 = HTTP, port 443 = TLS, etc. If an application runs on a non-standard port, the packets show as raw TCP with no application-layer decoding. To force a specific dissector: (1) Right-click any packet in the session → "Decode As" → select the protocol from the dropdown (e.g., HTTP for a C2 server running on port 8888). This applies to all packets on that port for the current session. (2) Permanent decode-as rule: Analyze menu → "Decode As" → + → set port range and protocol. This persists in your Wireshark profile. (3) For TLS on non-443 ports, you need the Decode As + TLS session keys configured. Note: forced decoding means Wireshark applies the dissector even if the protocol doesn't match — malformed output means the traffic wasn't actually that protocol.