Created
March 6, 2026 23:32
-
-
Save emdnaia/65115ba1b7c2a5e295e091256d68764f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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