Posts CVE-2020-9054 - zyxel CGI Vulnerability
Post
Cancel

CVE-2020-9054 - zyxel CGI Vulnerability

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有兩種方法

  1. 照著此blog 一步一步解開
  2. 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 了

逆向分析

這部分我稍微列一下步驟

  1. 程式流程分析
  2. 找到廠商修補處
  3. 檢查可疑 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 密碼

程式狀態碼

This post is licensed under CC BY 4.0 by the author.