TL;DR
由於這個漏洞已經被 Mirai 成功利用,因此就來了解一下,我會分別介紹如何 Extract zyxel firmware 跟 reverse 有問題的 cgi
Report
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-9054
Malware 利用
https://thehackernews.com/2020/03/zyxel-mukashi-mirai-iot-botnet.html?fbclid=IwAR2-QybQQGXCr6eFs7m9gshmqSdT4qfOOYw5K_5thLZFo8cFxM8Z-7V0YTI
POC 發現處
https://kb.cert.org/artifacts/cve-2020-9054.html
extract firmware
解開firmware有兩種方法
- 照著此blog 一步一步解開
- binwalk 無腦暴力拆
下面是我驗證了一下方法1 blog 的正確性
0x00 parse header
zyxel 的 firmware 有個特性,前30byte 後是一連串[key][data length][data] 的格式 已我手上的 NAS520 V5.21(AASZ.3)C0
解析除來如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
id= 0000 len= 4 data= 1.00
id= 0100 len= 13 data= V5.21(AATB.4)
id= 0200 len= 5 data= 51173
id= 0101 len= 4 data= B103
id= 0002 len= 32 data= c6984d9bf878745b9abecc7c50347748
id= 0102 len= 32 data= 49b827a07910c04502e0275364de5128
id= 0202 len= 4 data= A04E
id= 0302 len= 4 data= 0000
id= 0402 len= 32 data= 0c5dab12667961fb111f46bdc0e4a496
id= 0010 len= 4 data= 0x10e
id= 0110 len= 4 data= 0x7162ed
id= 0410 len= 4 data= 0x7162ee
id= 0510 len= 4 data= 0x3945e33
id= 00a0 len= 4 data= 0x3945e34
id= 01a0 len= 4 data= 0x394629e
id= 02a0 len= 4 data= 0x394629f
id= 03a0 len= 4 data= 0x3946654
可以看到一些明文表示解析的格式是正確的 每個值都是有意義的
0x01 拆內容
利用 id: 0010 ~ 03a0 所提供的 address 可以拆成四段區塊,拆開後用 file 和 md5 驗證,發現id: 0002 和 0402 正確的記錄著我們拆出來的 md5,而另外兩個就先不管,主要的資訊都會放在270.bin 這個 uImage 裡面
1
2
3
4
5
6
7
8
9
270.bin: u-boot legacy uImage, Linux-3.2.54, Linux/ARM, OS Kernel Image
60055092.bin: POSIX shell script, ASCII text executable
60056223.bin: POSIX shell script, ASCII text executable
7430894.bin: gzip compressed data
c6984d9bf878745b9abecc7c50347748 270.bin
df27a44b76a9fe182834c785f1713054 60055092.bin
66450075a442dadba541ab9dab57f7fd 60056223.bin
49b827a07910c04502e0275364de5128 7430894.bin
提醒: 上面 header 的address全部都要位移30才是真正的位置(估計是一開始沒有算進前面的header)
我有寫一個小工具來解前面的部份,如果想要自動化可以參考此連結
0x02 拆 uzImage
使用 https://gist.github.com/adamvr/1079762
0x03 拆 zImage
接著用 binwalk 就可以挖出 rootfs 了
逆向分析
這部分我稍微列一下步驟
- 程式流程分析
- 找到廠商修補處
- 檢查可疑 Function
0x10 程式流程分析
開頭先判斷是否已經有 auth token,如果有就跳到別的地方,但我覺得驗證方式頗怪,之後再來探討
由於網路上已有 POC username=admin';echo aaa
利用單引號加分號來關閉,看起來很 sql injection,所以我們就順著看有哪邊可能會照成問題
抓取 username, paaswd, reauth time, lease time
順便檢查了HTML 確定這幾個參數都是會傳進來的
接著檢查有用到 username 的 function,估計漏洞就會在其中一個 function 中
1
2
3
4
5
6
seup_pam_tunnel(&username, &passwd, addr, &rand_num, &reauthtime, &lease_time)
uam_find_first_match(&v10, "Web", &username, ip_value)
final_response(v12, 1, &rand_num, &username, &passwd, 0)
0x12 可疑 function 檢查
uam_find_first_match(&v10, “Web”, &username, ip_value)
對於username 沒有過多的處理
setup_pam_tunnel(&username, &passwd, addr, &rand_num, &reauthtime, &lease_time)
這個function是用來設定使用者的資訊,並保存起來 而他的 struct結構 和 用到的 function call 我直接列網址給大家自行參考。
找到廠商修補處
在這個 function 中,新款的多了對 Username 和 password 檢查的機制,在username 的部分禁止 分號和冒號的使用,明顯是為了預防這次的 CVE
NAS540_V5.21(AATB.4)C0 (修補後)
NSA325 v2_V4.81(AALS.1)C0 (未修補)
我想接下來 PAM 的應用就是問題最大的地方,但是 PAM 整體的架構讓我不太好trace所以只好到這裡就罷手了
final_response(v12, 1, &rand_num, &username, &passwd, 0)
這部分是最後將 response 整理好回傳的function,看了一遍也沒有特別的
0x12 漏洞成因討論
檢查過一輪後這隻binary沒看到特別處理 username 的地方,最多就用strcmp去比較字串,因此推測是輸入進 pam 後,select 方式有錯誤導致,所以可能要再往後挖才找的到。
附錄
初始 admin 密碼
程式狀態碼