commit 8261b4bc3504e111b998861b394494779921494b Author: kenny Date: Fri Nov 21 21:33:29 2025 +0200 First commit diff --git a/bpftrace_20251121_212318.log b/bpftrace_20251121_212318.log new file mode 100644 index 0000000..e69de29 diff --git a/bpftrace_20251121_212423.log b/bpftrace_20251121_212423.log new file mode 100644 index 0000000..e69de29 diff --git a/bpftrace_20251121_212538.log b/bpftrace_20251121_212538.log new file mode 100644 index 0000000..e69de29 diff --git a/bpftrace_20251121_212615.log b/bpftrace_20251121_212615.log new file mode 100644 index 0000000..e69de29 diff --git a/dns-debunk.sh b/dns-debunk.sh new file mode 100755 index 0000000..6a30744 --- /dev/null +++ b/dns-debunk.sh @@ -0,0 +1,171 @@ +#!/usr/bin/env bash +# dns_bpf_correlate.sh +# Usage: sudo ./dns_bpf_correlate.sh +# +# Requires: bpftrace, tcpdump, date (GNU) +# Purpose: correlate DNS packets (tcpdump) with the process that issued them using bpftrace syscall tracing. +set -u + +DOMAIN=$1 +WINDOW_MS=2000 # how many ms back to search for matching bpftrace events +BASE_TS="$(date +%Y%m%d_%H%M%S)" +DNSLOG="${DOMAIN}_${BASE_TS}_dns.log" +BPFLOG="bpftrace_${BASE_TS}.log" +INCIDENT_DIR="incidents_${BASE_TS}" +mkdir -p "$INCIDENT_DIR" + +RED="\e[31m"; GREEN="\e[32m"; YELLOW="\e[33m"; BLUE="\e[34m"; RESET="\e[0m" + +TCPDUMP_PID="" +BPF_PID="" + +now_ms() { date +%s%3N; } # epoch milliseconds (GNU date) + +cleanup() { + echo -e "${BLUE}[*] Stopping background processes...${RESET}" + [[ -n "$TCPDUMP_PID" ]] && sudo kill "$TCPDUMP_PID" 2>/dev/null || true + [[ -n "$BPF_PID" ]] && sudo kill "$BPF_PID" 2>/dev/null || true + sleep 0.1 + echo -e "${BLUE}[*] Done.${RESET}" + exit 0 +} +trap cleanup SIGINT SIGTERM + +echo -e "${BLUE}[*] Domain: ${YELLOW}$DOMAIN${RESET}" +echo -e "${BLUE}[*] DNS log: ${YELLOW}$DNSLOG${RESET}" +echo -e "${BLUE}[*] bpftrace log: ${YELLOW}$BPFLOG${RESET}" +echo -e "${BLUE}[*] Incidents directory: ${YELLOW}$INCIDENT_DIR${RESET}" +echo -e "${BLUE}[*] Window for correlation: ${YELLOW}${WINDOW_MS} ms${RESET}" +echo "" + +# Start tcpdump -> DNSLOG (writes raw tcpdump lines) +sudo tcpdump -n -i any port 53 -s0 -ttt -l 2>/dev/null >> "$DNSLOG" & +TCPDUMP_PID=$! +echo -e "${GREEN}[*] tcpdump started (PID $TCPDUMP_PID)${RESET}" + +# Start bpftrace inline printing epoch seconds + ms and PID/COMM/FD +# We print: . PID= COMM= FD= +# Use time (seconds since epoch) and nsecs to produce ms fraction. +sudo bpftrace -e ' +tracepoint:syscalls:sys_enter_sendto +{ + $s = time; // seconds since epoch + $ms = (nsecs/1000000) % 1000; + printf("%d.%03d PID=%d COMM=%s FD=%d\n", $s, $ms, pid, comm, args->fd); +} +' > "$BPFLOG" 2>/dev/null & +BPF_PID=$! +sleep 0.2 + +# Quick liveness check for bpftrace log (it may stay empty until events occur, but we ensure process exists) +if ! kill -0 "$BPF_PID" 2>/dev/null; then + echo -e "${YELLOW}[!] bpftrace failed to start (process exited). Check bpftrace availability and permissions.${RESET}" + echo -e "${YELLOW} Try: sudo bpftrace -e 'tracepoint:syscalls:sys_enter_sendto { printf(\"hi\\n\"); }'${RESET}" + cleanup +fi + +# Wait a short moment and check file is being appended to (if no events yet file may be empty - warn instead of failing) +sleep 1 +if [[ ! -s "$BPFLOG" ]]; then + echo -e "${YELLOW}[!] Note: bpftrace log is currently empty (no sendto events observed yet). This is normal until a process performs sendto().${RESET}" +fi + +echo -e "${GREEN}[*] bpftrace started (PID $BPF_PID) -- logging to $BPFLOG${RESET}" +echo "" + +# Helper: gather proc info for PID +proc_info_for_pid() { + local pid="$1" + if [[ -r "/proc/$pid/cmdline" ]]; then + local exe + exe=$(sudo readlink -f "/proc/$pid/exe" 2>/dev/null || true) + local cmd + cmd=$(sudo tr '\0' ' ' < "/proc/$pid/cmdline" 2>/dev/null || true) + echo "pid=$pid exe=${exe:-N/A} cmdline='${cmd:-N/A}'" + else + echo "pid=$pid (no /proc info)" + fi +} + +# Tail dns log and correlate with bpftrace by timestamp +tail -Fn0 "$DNSLOG" | while IFS= read -r dnsline; do + # case-insensitive match for domain + if echo "$dnsline" | grep -qi -- "$DOMAIN"; then + detect_ms=$(now_ms) + echo -e "${RED}[!] Suspicious DNS request detected @ ${YELLOW}${detect_ms}${RESET}" + echo -e "${YELLOW}$dnsline${RESET}" + echo "" + + INCIDENT_TS="$(date +%Y%m%d_%H%M%S_%3N)" + INCIDENT_FILE="${INCIDENT_DIR}/incident_${INCIDENT_TS}.txt" + { + echo "=== INCIDENT ${INCIDENT_TS} ===" + echo "dns_line: $dnsline" + echo "detected_at_ms: $detect_ms" + } > "$INCIDENT_FILE" + + # extract src token (token after IP token) + src_tok=$(echo "$dnsline" | awk '{for(i=1;i<=NF;i++) if($i=="IP" || $i=="IP6"){print $(i+1); exit}}' || true) + if [[ -n "$src_tok" ]]; then + srcPort="${src_tok##*.}" + srcIP="${src_tok%.*}" + echo -e "${GREEN}[+] Extracted source: IP=${YELLOW}${srcIP}${RESET} PORT=${YELLOW}${srcPort}${RESET}" + echo "extracted_src_ip: $srcIP" >> "$INCIDENT_FILE" + echo "extracted_src_port: $srcPort" >> "$INCIDENT_FILE" + else + echo -e "${YELLOW}[!] Could not extract source IP/port from tcpdump line${RESET}" + echo "extracted_src_ip: N/A" >> "$INCIDENT_FILE" + echo "extracted_src_port: N/A" >> "$INCIDENT_FILE" + fi + + # Search BPFLOG for events within WINDOW_MS before detection + # BPF lines start like: 1600000000.123 PID=123 COMM=foo FD=... + low_ms=$((detect_ms - WINDOW_MS)) + high_ms=$((detect_ms)) + awk -v low="$low_ms" -v high="$high_ms" ' + BEGIN{FS=" "; OFS=" "} + { + # parse first token as seconds.ms + if ($1 ~ /^[0-9]+\.[0-9]{3}$/) { + split($1, a, ".") + t_s = a[1]; t_ms = a[2] + t = t_s * 1000 + t_ms + if (t >= low && t <= high) print $0 + } + }' "$BPFLOG" | tee -a "$INCIDENT_FILE" > /tmp/_bpf_matches.$$ || true + + if [[ -s /tmp/_bpf_matches.$$ ]]; then + echo -e "${GREEN}[+] bpftrace events found within ${WINDOW_MS} ms:${RESET}" + sed 's/^/ /' /tmp/_bpf_matches.$$ + echo "" >> "$INCIDENT_FILE" + echo "bpftrace_matches:" >> "$INCIDENT_FILE" + cat /tmp/_bpf_matches.$$ >> "$INCIDENT_FILE" + + # extract PIDs + pids=$(sed -n 's/.*PID=\([0-9]\+\).*/\1/p' /tmp/_bpf_matches.$$ | sort -u) + if [[ -n "$pids" ]]; then + echo -e "${GREEN}[+] Candidate PIDs: ${YELLOW}$pids${RESET}" + echo "" >> "$INCIDENT_FILE" + echo "candidate_pids:" >> "$INCIDENT_FILE" + for pid in $pids; do + info=$(proc_info_for_pid "$pid") + echo " - $info" + echo " - $info" >> "$INCIDENT_FILE" + done + fi + else + echo -e "${YELLOW}[!] No bpftrace events found in window (this can happen if syscall happened >${WINDOW_MS}ms before tcpdump line or bpftrace didn't capture).${RESET}" + echo "bpftrace_matches: NONE in ${WINDOW_MS}ms window" >> "$INCIDENT_FILE" + fi + + # append an ss snapshot for context + echo "" >> "$INCIDENT_FILE" + echo "ss_snapshot:" >> "$INCIDENT_FILE" + sudo ss -tulpn 2>/dev/null >> "$INCIDENT_FILE" || true + + echo -e "${GREEN}[+] Incident saved to ${YELLOW}${INCIDENT_FILE}${RESET}" + echo -e "${BLUE}------------------------------------------------------${RESET}" + echo "" + rm -f /tmp/_bpf_matches.$$ + fi +done diff --git a/ipify_20251121_212318_dns.log b/ipify_20251121_212318_dns.log new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ipify_20251121_212318_dns.log @@ -0,0 +1 @@ + diff --git a/ipify_20251121_212423_dns.log b/ipify_20251121_212423_dns.log new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ipify_20251121_212423_dns.log @@ -0,0 +1 @@ + diff --git a/ipify_20251121_212538_dns.log b/ipify_20251121_212538_dns.log new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ipify_20251121_212538_dns.log @@ -0,0 +1 @@ + diff --git a/ipify_20251121_212615_dns.log b/ipify_20251121_212615_dns.log new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ipify_20251121_212615_dns.log @@ -0,0 +1 @@ + diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..5e4a8d4 --- /dev/null +++ b/shell.nix @@ -0,0 +1,9 @@ +with (import {}); +mkShell { + buildInputs = with pkgs; [ + bpftrace + tcpdump + conntrack-tools +]; + shellHook = ""; +}