Skip to content

Instantly share code, notes, and snippets.

@emdnaia
Created March 6, 2026 23:32
Show Gist options
  • Select an option

  • Save emdnaia/65115ba1b7c2a5e295e091256d68764f to your computer and use it in GitHub Desktop.

Select an option

Save emdnaia/65115ba1b7c2a5e295e091256d68764f to your computer and use it in GitHub Desktop.
#!/bin/sh
# watch_host.sh — full traffic + C2 monitor for a single host
# Usage: sh watch_host.sh <target_ip> [interface]
TARGET="${1:-1.1.1.1}"
IFACE="${2:-vio0}"
echo "=========================================="
echo " Host Monitor Target:$TARGET Iface:$IFACE"
echo " Started: $(date)"
echo "=========================================="
{
tcpdump -i "$IFACE" -nn -s 65535 -l \
"host $TARGET and (port 53 or port 853 or port 80 or port 443)" 2>/dev/null \
| awk '{print "STD " $0; fflush()}' &
tcpdump -i "$IFACE" -nn -s 65535 -l \
"ip6 and host $TARGET and (port 53 or port 853 or port 80 or port 443)" 2>/dev/null \
| awk '{print "STD " $0; fflush()}' &
tcpdump -i "$IFACE" -nn -s 65535 -l \
"host $TARGET and icmp" 2>/dev/null \
| awk '{print "ICMP " $0; fflush()}' &
tcpdump -i "$IFACE" -nn -s 65535 -l \
"ip6 and host $TARGET and icmp6" 2>/dev/null \
| awk '{print "ICMP " $0; fflush()}' &
tcpdump -i "$IFACE" -nn -s 65535 -l \
"host $TARGET and not (port 53 or port 80 or port 443 or port 853) and not icmp" 2>/dev/null \
| awk '{print "C2 " $0; fflush()}' &
tcpdump -i "$IFACE" -nn -s 65535 -l \
"ip6 and host $TARGET and not (port 53 or port 80 or port 443 or port 853) and not icmp6" 2>/dev/null \
| awk '{print "C2 " $0; fflush()}' &
wait
} | awk -v target="$TARGET" '
BEGIN {
c2ports[22]="SSH"; c2ports[23]="TELNET"; c2ports[25]="SMTP"
c2ports[110]="POP3"; c2ports[143]="IMAP"; c2ports[465]="SMTPS"
c2ports[587]="SMTP-SUB"; c2ports[993]="IMAPS"; c2ports[995]="POP3S"
c2ports[1080]="SOCKS"; c2ports[3389]="RDP"; c2ports[4444]="METERPRETER"
c2ports[5353]="mDNS"; c2ports[6667]="IRC"; c2ports[6697]="IRC-TLS"
c2ports[8080]="HTTP-ALT"; c2ports[8443]="HTTPS-ALT"; c2ports[8888]="HTTP-ALT"
c2ports[9001]="TOR"; c2ports[9030]="TOR"; c2ports[51820]="WIREGUARD"
}
function rdns(ip, cmd, r) {
if(ip in RC) return RC[ip]
cmd = "host " ip " 2>/dev/null | awk \047/pointer/{print $NF}\047 | head -1"
cmd | getline r; close(cmd)
gsub(/\.$/, "", r)
RC[ip] = (r == "") ? "-" : r
return RC[ip]
}
function whois(ip, cmd, c, o) {
if(ip in WC) return WC[ip]
cmd = "whois " ip " 2>/dev/null | awk \047/^(country|Country|COUNTRY)[^a-z]/{print $2;exit}\047"
cmd | getline c; close(cmd)
cmd = "whois " ip " 2>/dev/null | awk \047/^(OrgName|org-name|netname|descr)[^a-z]/{$1=\"\";print;exit}\047"
cmd | getline o; close(cmd)
WC[ip] = "[" (c==""?"??":c) "]" (o==""?" unknown":o)
return WC[ip]
}
function stripport(a, p,n,r,i) {
if(a ~ /:/) {
n=split(a,p,"."); r=""
for(i=1;i<n;i++) r=r (i>1?".":"") p[i]
gsub(/:$/,"",r); return r
}
n=split(a,p,"."); return p[1]"."p[2]"."p[3]"."p[4]
}
function getport(a, p,n,x) {
n=split(a,p,"."); x=p[n]; gsub(/:.*$/,"",x); return x
}
function tunnel(dom, p,n,l) {
n=split(dom,p,"."); l=p[1]
if(length(l)>40) return "***DNS-TUNNEL:long-subdomain"
if(l~/^[0-9a-f]{20,}$/) return "***DNS-TUNNEL:hex"
if(l~/^[A-Za-z0-9+\/]{30,}/) return "***DNS-TUNNEL:base64"
return ""
}
{
# DO NOT modify $0 — use fixed field positions from sed-prefixed lines:
# $1=TAG $2=timestamp $3=src[.port] $4=> $5=dst[.port]: $6+=data
tag = $1
ts = strftime("%H:%M:%S")
# ── ICMP ──────────────────────────────────────────────────────────────────
# ICMP 20:44:31.712982 192.168.7.30 > 184.86.103.69: icmp: echo request (DF)
# $1 $2 $3 $4 $5 $6 $7 $8
if(tag == "ICMP") {
src = $3
dst = $5; gsub(/:$/,"",dst)
dir = (src==target)?"OUT":"IN "
remote = (src==target)?dst:src
# icmp: echo request ($6=icmp: $7=echo $8=request)
# icmp6: echo request ($6=icmp6: $7=echo $8=request)
itype = $7" "$8; gsub(/,$/,"",itype)
v6 = (src~/:/ || dst~/:/) ? " (v6)" : ""
flag=""
for(i=1;i<=NF;i++) if($i=="length"&&$(i+1)+0>64) flag="***ICMP-TUNNEL:payload="$(i+1)
if(!(remote in IS)) {
IS[remote]=1
printf "%s ICMP %s %-25s %-35s %s %s%s %s\n", ts,dir,remote,rdns(remote),whois(remote),itype,v6,flag
} else {
printf "%s ICMP %s %-25s %s%s %s\n", ts,dir,remote,itype,v6,flag
}
next
}
# ── DNS ───────────────────────────────────────────────────────────────────
# STD 20:xx 192.168.7.30.port > x.x.x.x.53: id A? domain. (n)
# $1 $2 $3 $4 $5 $6 $7 $8
if(tag=="STD" && $5~/\.53:$/) {
# cache A replies: answer lines have format: domain. A ip
for(i=1;i<=NF;i++) {
if($i=="A" && $(i+1)~/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) {
for(j=i-1;j>=1;j--) {
if($(j)~/\.[a-z]{2,}\.$/) {
d=$(j); gsub(/\.$/,"",d); gsub(/\([0-9]+\)/,"",d)
DNS[$(i+1)]=d; break
}
}
}
}
# print queries
for(i=1;i<=NF;i++) {
if($i~/^(A|AAAA|TXT|MX|CNAME)\?$/) {
d=$(i+1); gsub(/\.$/,"",d); gsub(/\([0-9]+\)/,"",d)
printf "%s DNS Q %-45s %s\n", ts, d, tunnel(d)
}
}
next
}
# ── HTTP / HTTPS / DoT ────────────────────────────────────────────────────
# STD 20:xx 192.168.7.30.sport > 1.2.3.4.443: ...
# $1 $2 $3 $4 $5
if(tag=="STD") {
if($5~/\.853:/) proto="DoT "
else if($5~/\.80:/) proto="HTTP"
else proto="TLS "
src = stripport($3)
dst = stripport($5)
if(src==target && !(dst in SS)) {
SS[dst]=1
label = (dst in DNS)?DNS[dst]:dst
printf "%s %s OUT %-45s %-35s %s\n", ts,proto,label,rdns(dst),whois(dst)
}
next
}
# ── C2 / anomaly ──────────────────────────────────────────────────────────
# C2 20:xx 192.168.7.30.sport > 1.2.3.4.dport: ...
if(tag=="C2") {
src = stripport($3)
dst = stripport($5)
dport = getport($5)
sport = getport($3)
dir = (src==target)?"OUT":"IN "
remote = (src==target)?dst:src
port = (src==target)?dport:sport
proto = ($0~/UDP/)?"UDP ":"TCP "
flag=""
if(port in c2ports) flag="***C2-PORT:"c2ports[port]
if($0~/UDP/ && port!=123 && port!=5353 && port!=51820) flag=flag" ***UNUSUAL-UDP"
key=remote":"port
if(!(key in CS)) {
CS[key]=1
printf "%s %s %s %-20s:%-6s %-35s %s %s\n", ts,proto,dir,remote,port,rdns(remote),whois(remote),flag
}
next
}
# ── OTHER — anything not matched above ────────────────────────────────────
# catches ARP, multicast, broadcast, unknown protos, malformed lines
if($0~/ARP/) proto="ARP "
else if($0~/IGMP/) proto="IGMP "
else if($0~/OSPF/) proto="OSPF "
else if($0~/GRE/) proto="GRE "
else if($0~/ESP/) proto="ESP "
else if($0~/AH /) proto="AH "
else if($0~/VRRP/) proto="VRRP "
else if($0~/SCTP/) proto="SCTP "
else proto="??? "
key = $3":"$5":"proto
if(!(key in OT)) {
OT[key]=1
printf "%s %s raw: %s\n", ts, proto, $0
}
}
'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment