Skip to content

Commit 621c300

Browse files
committed
Add XXE
1 parent c3c41b4 commit 621c300

File tree

8 files changed

+98
-82
lines changed

8 files changed

+98
-82
lines changed

docker-compose.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
version : '2'
1+
version : '3'
22
services:
33
jsc:
44
image: joychou/jsc:latest
5+
command: ["java", "-Xdebug", "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=0.0.0.0:8000", "-jar", "jsc.jar"]
56
ports:
67
- "8080:8080"
8+
- "8000:8000"
79
links:
810
- j_mysql
911

java-sec-code.iml

+13-7
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@
3838
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:1.5.1.RELEASE" level="project" />
3939
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.1.9" level="project" />
4040
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.1.9" level="project" />
41-
<orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.22" level="project" />
4241
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.22" level="project" />
4342
<orderEntry type="library" name="Maven: org.slf4j:log4j-over-slf4j:1.7.22" level="project" />
4443
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:1.5.1.RELEASE" level="project" />
45-
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:8.5.11" level="project" />
46-
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:8.5.11" level="project" />
47-
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:8.5.11" level="project" />
44+
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:8.5.85" level="project" />
45+
<orderEntry type="library" name="Maven: org.apache.tomcat:tomcat-annotations-api:8.5.85" level="project" />
46+
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:8.5.85" level="project" />
47+
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:8.5.85" level="project" />
4848
<orderEntry type="library" name="Maven: org.hibernate:hibernate-validator:5.3.4.Final" level="project" />
4949
<orderEntry type="library" name="Maven: javax.validation:validation-api:1.1.0.Final" level="project" />
5050
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.3.0.Final" level="project" />
@@ -127,7 +127,7 @@
127127
<orderEntry type="library" scope="RUNTIME" name="Maven: com.google.inject.extensions:guice-multibindings:4.0" level="project" />
128128
<orderEntry type="library" scope="RUNTIME" name="Maven: com.google.inject.extensions:guice-grapher:4.0" level="project" />
129129
<orderEntry type="library" scope="RUNTIME" name="Maven: com.google.inject.extensions:guice-assistedinject:4.0" level="project" />
130-
<orderEntry type="library" scope="RUNTIME" name="Maven: org.ow2.asm:asm:5.0.4" level="project" />
130+
<orderEntry type="library" name="Maven: org.ow2.asm:asm:5.0.4" level="project" />
131131
<orderEntry type="library" scope="RUNTIME" name="Maven: org.codehaus.woodstox:woodstox-core-asl:4.4.1" level="project" />
132132
<orderEntry type="library" scope="RUNTIME" name="Maven: javax.xml.stream:stax-api:1.0-2" level="project" />
133133
<orderEntry type="library" scope="RUNTIME" name="Maven: org.codehaus.woodstox:stax2-api:3.1.4" level="project" />
@@ -170,8 +170,8 @@
170170
<orderEntry type="library" name="Maven: commons-httpclient:commons-httpclient:3.1" level="project" />
171171
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.2" level="project" />
172172
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:1.5.1.RELEASE" level="project" />
173-
<orderEntry type="library" name="Maven: org.apache.tomcat:tomcat-jdbc:8.5.11" level="project" />
174-
<orderEntry type="library" name="Maven: org.apache.tomcat:tomcat-juli:8.5.11" level="project" />
173+
<orderEntry type="library" name="Maven: org.apache.tomcat:tomcat-jdbc:8.5.85" level="project" />
174+
<orderEntry type="library" name="Maven: org.apache.tomcat:tomcat-juli:8.5.85" level="project" />
175175
<orderEntry type="library" name="Maven: org.springframework:spring-jdbc:4.3.6.RELEASE" level="project" />
176176
<orderEntry type="library" name="Maven: org.springframework:spring-tx:4.3.6.RELEASE" level="project" />
177177
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:1.3.2" level="project" />
@@ -222,5 +222,11 @@
222222
<orderEntry type="library" name="Maven: com.auth0:java-jwt:4.0.0" level="project" />
223223
<orderEntry type="library" name="Maven: cn.hutool:hutool-all:5.8.10" level="project" />
224224
<orderEntry type="library" name="Maven: org.javassist:javassist:3.27.0-GA" level="project" />
225+
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:1.13.11.RELEASE" level="project" />
226+
<orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.22" level="project" />
227+
<orderEntry type="library" name="Maven: com.jayway.jsonpath:json-path:2.2.0" level="project" />
228+
<orderEntry type="library" name="Maven: net.minidev:json-smart:2.2.1" level="project" />
229+
<orderEntry type="library" name="Maven: net.minidev:accessors-smart:1.1" level="project" />
230+
<orderEntry type="library" name="Maven: org.xmlbeam:xmlprojector:1.4.13" level="project" />
225231
</component>
226232
</module>

pom.xml

+18
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<properties>
1313
<maven.compiler.source>1.8</maven.compiler.source> <!-- mvn clean package-->
1414
<maven.compiler.target>1.8</maven.compiler.target>
15+
<tomcat.version>8.5.85</tomcat.version>
1516
</properties>
1617

1718

@@ -312,6 +313,23 @@
312313
<version>3.27.0-GA</version>
313314
</dependency>
314315

316+
<dependency>
317+
<groupId>org.springframework.data</groupId>
318+
<artifactId>spring-data-commons</artifactId>
319+
<version>1.13.11.RELEASE</version>
320+
</dependency>
321+
322+
<dependency>
323+
<groupId>com.jayway.jsonpath</groupId>
324+
<artifactId>json-path</artifactId>
325+
</dependency>
326+
327+
<dependency>
328+
<groupId>org.xmlbeam</groupId>
329+
<artifactId>xmlprojector</artifactId>
330+
<version>1.4.13</version>
331+
</dependency>
332+
315333
</dependencies>
316334

317335
<dependencyManagement>

src/main/java/org/joychou/controller/URLWhiteList.java

+10-9
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import org.slf4j.LoggerFactory;
77
import org.springframework.web.bind.annotation.*;
88

9-
import java.net.MalformedURLException;
9+
import javax.servlet.http.HttpServletResponse;
10+
import java.io.IOException;
1011
import java.net.URL;
1112
import java.util.ArrayList;
1213
import java.util.regex.Matcher;
@@ -86,20 +87,21 @@ public String regex(@RequestParam("url") String url) {
8687

8788

8889
/**
89-
* The bypass of using <code>java.net.URL</code> to getHost.
90+
* The bypass of using {@link java.net.URL} to getHost.
9091
* <p>
91-
* Bypass poc1: curl -v 'http://localhost:8080/url/vuln/url_bypass?url=http://evel.com%[email protected]/a.html'
92-
* Bypass poc2: curl -v 'http://localhost:8080/url/vuln/url_bypass?url=http://evil.com%5cwww.joychou.org/a.html'
92+
* <a href="http://localhost:8080/url/vuln/url_bypass?url=http://evil.com%[email protected]/a.html">bypass 1</a>
93+
* <a href="http://localhost:8080/url/vuln/url_bypass?url=http://evil.com%5cwww.joychou.org/a.html">bypass 2</a>
94+
*
9395
* <p>
94-
* More details: https://github.com/JoyChou93/java-sec-code/wiki/URL-whtielist-Bypass
96+
* <a href="https://github.com/JoyChou93/java-sec-code/wiki/URL-whtielist-Bypass">More details</a>
9597
*/
9698
@GetMapping("/vuln/url_bypass")
97-
public String url_bypass(String url) throws MalformedURLException {
99+
public void url_bypass(String url, HttpServletResponse res) throws IOException {
98100

99101
logger.info("url: " + url);
100102

101103
if (!SecurityUtil.isHttp(url)) {
102-
return "Url is not http or https";
104+
return;
103105
}
104106

105107
URL u = new URL(url);
@@ -109,11 +111,10 @@ public String url_bypass(String url) throws MalformedURLException {
109111
// endsWith .
110112
for (String domain : domainwhitelist) {
111113
if (host.endsWith("." + domain)) {
112-
return "Good url.";
114+
res.sendRedirect(url);
113115
}
114116
}
115117

116-
return "Bad url.";
117118
}
118119

119120

src/main/java/org/joychou/controller/XXE.java

+36-46
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import org.dom4j.io.SAXReader;
55
import org.slf4j.Logger;
66
import org.slf4j.LoggerFactory;
7+
import org.springframework.data.web.ProjectedPayload;
8+
import org.springframework.http.HttpEntity;
9+
import org.springframework.http.ResponseEntity;
710
import org.springframework.web.bind.annotation.*;
811

912
import javax.servlet.http.HttpServletRequest;
@@ -27,6 +30,7 @@
2730
import org.apache.commons.digester3.Digester;
2831
import org.jdom2.input.SAXBuilder;
2932
import org.joychou.util.WebUtils;
33+
import org.xmlbeam.annotation.XBRead;
3034

3135
/**
3236
* Java xxe vuln and security code.
@@ -38,8 +42,8 @@
3842
@RequestMapping("/xxe")
3943
public class XXE {
4044

41-
private static Logger logger = LoggerFactory.getLogger(XXE.class);
42-
private static String EXCEPT = "xxe except";
45+
private static final Logger logger = LoggerFactory.getLogger(XXE.class);
46+
private static final String EXCEPT = "xxe except";
4347

4448
@PostMapping("/xmlReader/vuln")
4549
public String xmlReaderVuln(HttpServletRequest request) {
@@ -226,16 +230,15 @@ public String DigesterSec(HttpServletRequest request) {
226230
}
227231

228232

229-
// 有回显
230-
@RequestMapping(value = "/DocumentBuilder/vuln01", method = RequestMethod.POST)
233+
/**
234+
* Use request.getInputStream to support UTF16 encoding.
235+
*/
236+
@RequestMapping(value = "/DocumentBuilder/vuln", method = RequestMethod.POST)
231237
public String DocumentBuilderVuln01(HttpServletRequest request) {
232238
try {
233-
String body = WebUtils.getRequestBody(request);
234-
logger.info(body);
235239
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
236240
DocumentBuilder db = dbf.newDocumentBuilder();
237-
StringReader sr = new StringReader(body);
238-
InputSource is = new InputSource(sr);
241+
InputSource is = new InputSource(request.getInputStream());
239242
Document document = db.parse(is); // parse xml
240243

241244
// 遍历xml节点name和value
@@ -249,7 +252,6 @@ public String DocumentBuilderVuln01(HttpServletRequest request) {
249252
buf.append(String.format("%s: %s\n", node.getNodeName(), node.getTextContent()));
250253
}
251254
}
252-
sr.close();
253255
return buf.toString();
254256
} catch (Exception e) {
255257
e.printStackTrace();
@@ -258,43 +260,6 @@ public String DocumentBuilderVuln01(HttpServletRequest request) {
258260
}
259261
}
260262

261-
262-
// 有回显
263-
@RequestMapping(value = "/DocumentBuilder/vuln02", method = RequestMethod.POST)
264-
public String DocumentBuilderVuln02(HttpServletRequest request) {
265-
try {
266-
String body = WebUtils.getRequestBody(request);
267-
logger.info(body);
268-
269-
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
270-
DocumentBuilder db = dbf.newDocumentBuilder();
271-
StringReader sr = new StringReader(body);
272-
InputSource is = new InputSource(sr);
273-
Document document = db.parse(is); // parse xml
274-
275-
// 遍历xml节点name和value
276-
StringBuilder result = new StringBuilder();
277-
NodeList rootNodeList = document.getChildNodes();
278-
for (int i = 0; i < rootNodeList.getLength(); i++) {
279-
Node rootNode = rootNodeList.item(i);
280-
NodeList child = rootNode.getChildNodes();
281-
for (int j = 0; j < child.getLength(); j++) {
282-
Node node = child.item(j);
283-
// 正常解析XML,需要判断是否是ELEMENT_NODE类型。否则会出现多余的的节点。
284-
if (child.item(j).getNodeType() == Node.ELEMENT_NODE) {
285-
result.append(String.format("%s: %s\n", node.getNodeName(), node.getFirstChild()));
286-
}
287-
}
288-
}
289-
sr.close();
290-
return result.toString();
291-
} catch (Exception e) {
292-
logger.error(e.toString());
293-
return EXCEPT;
294-
}
295-
}
296-
297-
298263
@RequestMapping(value = "/DocumentBuilder/Sec", method = RequestMethod.POST)
299264
public String DocumentBuilderSec(HttpServletRequest request) {
300265
try {
@@ -447,6 +412,31 @@ private static void response(NodeList rootNodeList){
447412
}
448413
}
449414

415+
/**
416+
* Receiving POST requests supporting both JSON and XML.
417+
* CVE-2018-1259
418+
*/
419+
@PostMapping(value = "/xmlbeam/vuln")
420+
HttpEntity<String> post(@RequestBody UserPayload user) {
421+
try {
422+
logger.info(user.toString());
423+
return ResponseEntity.ok(String.format("hello, %s!", user.getUserName()));
424+
}catch (Exception e){
425+
e.printStackTrace();
426+
return ResponseEntity.ok("error");
427+
}
428+
}
429+
430+
/**
431+
* The projection interface using XPath and JSON Path expression to selectively pick elements from the payload.
432+
*/
433+
@ProjectedPayload
434+
public interface UserPayload {
435+
@XBRead("//userName")
436+
String getUserName();
437+
}
438+
439+
450440
public static void main(String[] args) {
451441
}
452442

src/main/java/org/joychou/security/ssrf/SSRFChecker.java

+17-14
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,6 @@ public static boolean isInternalIp(String strIP) {
157157
* <p>Normal:</p>
158158
* <ul>
159159
* <li>69299689 to 10.23.78.233</li>
160-
* <li>69299689 to 10.23.78.233 </li>
161160
* <li>012.0x17.78.233 to 10.23.78.233 </li>
162161
* <li>012.027.0116.0351 to 10.23.78.233</li>
163162
* <li>127.0.0.1.xip.io to 127.0.0.1</li>
@@ -166,8 +165,10 @@ public static boolean isInternalIp(String strIP) {
166165
167166
* <p>Bypass: </p>
168167
* <ul>
169-
* <li>01205647351 to 71.220.183.247, actually 10.23.78.233</li>
170-
* <li>012.23.78.233 to 12.23.78.233, actually 10.23.78.233</li>
168+
* <li>01205647351 {@link InetAddress#getHostAddress()} result is 71.220.183.247, actually 10.23.78.233</li>
169+
* <li>012.23.78.233 {@link InetAddress#getHostAddress()} result is 12.23.78.233, actually 10.23.78.233</li>
170+
* <li>012.23.233 {@link InetAddress#getHostAddress()} result is 12.23.0.233, actually 10.23.0.233</li>
171+
* <li>012.233 {@link InetAddress#getHostAddress()} result is 12.0.0.233, actually 10.0.0.233</li>
171172
* </ul>
172173
* @return decimal ip
173174
*/
@@ -177,13 +178,14 @@ public static String host2ip(String host) {
177178
return "";
178179
}
179180

180-
// convert octal to decimal
181+
// convert octal to decimal
181182
if(isOctalIP(host)) {
182183
host = decimalIp;
183184
}
184185

185186
try {
186-
InetAddress IpAddress = InetAddress.getByName(host); // send dns request
187+
// send dns request
188+
InetAddress IpAddress = InetAddress.getByName(host);
187189
return IpAddress.getHostAddress();
188190
} catch (Exception e) {
189191
return "";
@@ -203,30 +205,31 @@ public static boolean isOctalIP(String host) {
203205
// Octal ip only has number and dot character.
204206
if (isNumberOrDot(host)) {
205207

206-
if (ipParts.length != 1 && ipParts.length != 4) {
207-
return false;
208+
// not support ipv6
209+
if (ipParts.length > 4) {
210+
throw new SSRFException("Illegal ipv4: " + host);
208211
}
209212

210-
// 000000001205647351
213+
// 01205647351
211214
if( ipParts.length == 1 && host.startsWith("0") ) {
212215
decimalIp = Integer.valueOf(host, 8).toString();
213216
return true;
214217
}
215218

216-
// 0000012.23.78.233
219+
// 012.23.78.233
217220
for(String ip : ipParts) {
218221
if (!isNumber(ip)){
219-
throw new SSRFException("Illegal host: " + host + ".");
222+
throw new SSRFException("Illegal ipv4: " + host);
220223
}
221224
if (ip.startsWith("0")) {
222225
if (Integer.valueOf(ip, 8) >= 256){
223-
throw new SSRFException("Illegal host: " + host + ".\t" + ip + " is above 255.");
226+
throw new SSRFException("Illegal ipv4: " + host);
224227
}
225228
newDecimalIP.append(Integer.valueOf(ip, 8)).append(".");
226229
is_octal = true;
227230
}else{
228231
if (Integer.valueOf(ip, 10) >= 256) {
229-
throw new SSRFException("Illegal host: " + host + ".\t" + ip + " is above 255.");
232+
throw new SSRFException("Illegal ipv4: " + host);
230233
}
231234
newDecimalIP.append(ip).append(".");
232235
}
@@ -246,7 +249,7 @@ private static boolean isNumber(String str) {
246249
}
247250
for (int i = 0; i < str.length(); i++) {
248251
char ch = str.charAt(i);
249-
if (ch < 48 || ch > 57) {
252+
if (ch < '0' || ch > '9') {
250253
return false;
251254
}
252255
}
@@ -261,7 +264,7 @@ private static boolean isNumber(String str) {
261264
private static boolean isNumberOrDot(String s) {
262265
for (int i = 0; i < s.length(); i++) {
263266
char ch = s.charAt(i);
264-
if ((ch < 48 || ch > 57) && ch != 46){
267+
if ((ch < '0' || ch > '9') && ch != '.'){
265268
return false;
266269
}
267270
}

src/main/java/org/joychou/util/HttpUtils.java

-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ public static String URLConnection(String url) {
9494
URL u = new URL(url);
9595
URLConnection urlConnection = u.openConnection();
9696
BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); //send request
97-
// BufferedReader in = new BufferedReader(new InputStreamReader(u.openConnection().getInputStream()));
9897
String inputLine;
9998
StringBuilder html = new StringBuilder();
10099

0 commit comments

Comments
 (0)