├── .gitignore
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
└── main
├── java
└── com
│ └── leadroyal
│ └── xxe
│ ├── Main.java
│ ├── ResourceUtils.java
│ ├── model
│ └── Person.java
│ └── sample
│ ├── DocumentBuilderFactorySample.java
│ ├── SAXBuilderSample.java
│ ├── SAXParserFactorySample.java
│ ├── SAXReaderSample.java
│ ├── SAXTransformerFactorySample.java
│ ├── SchemaFactorySample.java
│ ├── TransformerFactorySample.java
│ ├── UnmarshallerSample.java
│ ├── ValidatorSample.java
│ ├── XMLInputFactorySample.java
│ └── XMLReaderSample.java
└── resources
├── poc1.xml
├── poc2.xml
└── poc3.xsl
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle/
2 | .idea/
3 | build/
4 | lib/
5 | target/
6 | out/
7 | *.iml
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # java-xxe-defense-demo
2 |
3 | 2018年8月,在微信支付SDK的XXE影响下,写了百分百可以防御住的demo,并且经过了配置,有些配置是冗余的。
4 |
5 | 2019年7月,重新测试了每个设置对XXE的影响,之前为了保险建议全部都添加,现在筛选出了起作用的和不起作用的设置。
6 |
7 | 测试方式是使用两种poc,看是否可以读取到文件,一种是使用通用实体(external-general-entity),将文件内容打到xml的内容里,一种是使用参数实体(external-parameter-entity),将文件内容外带。
8 |
9 | 配合攻击demo食用更佳:[https://github.com/LeadroyaL/java_xxe_2019](https://github.com/LeadroyaL/java_xxe_2019)
10 |
11 | ### 有效的防御方式的列表
12 |
13 | | FEATURE | String |
14 | | --- | --- |
15 | | A | http://javax.xml.XMLConstants/feature/secure-processing |
16 | | B | http://apache.org/xml/features/disallow-doctype-decl |
17 | | C | http://xml.org/sax/features/external-parameter-entities |
18 | | D | http://xml.org/sax/features/external-general-entities |
19 | | E | http://javax.xml.XMLConstants/property/accessExternalDTD |
20 | | F | http://javax.xml.XMLConstants/property/accessExternalStylesheet |
21 | | G | http://javax.xml.XMLConstants/property/accessExternalSchema |
22 | | H | javax.xml.stream.supportDTD |
23 | | I | javax.xml.stream.isSupportingExternalEntities |
24 |
25 |
26 | | 组件 | FEATURE | 作用 |
27 | |------|--------|-----|
28 | | DocumentBuilderFactory | A | 禁用DTD |
29 | | DocumentBuilderFactory | B | 禁用DTD |
30 | | DocumentBuilderFactory | C | 可挡blind-xxe |
31 | | DocumentBuilderFactory | D | 可挡回显xxe |
32 | | SAXBuilder | A | 禁用DTD |
33 | | SAXBuilder | C | 可挡blind-xxe |
34 | | SAXParserFactory | B | 禁用DTD |
35 | | SAXParserFactory | C | 可挡blind-xxe |
36 | | SAXParserFactory | D | 不确定,因为默认无回显 |
37 | | SAXReader | B | 禁用DTD |
38 | | SAXReader | C | 可挡blind-xxe |
39 | | SAXReader | D | 可挡回显xxe |
40 | | SAXTransformerFactory | E | 禁用DTD |
41 | | SAXTransformerFactory | F | 不确定,引入额外stylesheet没有攻击成功 |
42 | | SchemaFactory | E | 禁用DTD |
43 | | SchemaFactory | G | 不确定,引入额外schema没有攻击成功 |
44 | | TransformerFactory | E | 禁用DTD |
45 | | TransformerFactory | F | 不确定,引入额外stylesheet没有攻击成功 |
46 | | Unmarshaller | - | 默认禁用DTD |
47 | | Validator | E | 禁用DTD |
48 | | Validator | G | 不确定,引入额外schema没有攻击成功 |
49 | | XMLInputFactory | H | 禁用DTD |
50 | | XMLInputFactory | I | 禁用DTD |
51 | | XMLReaderFactory | B | 禁用DTD |
52 | | XMLReaderFactory | C | 可挡blind-xxe |
53 | | XMLReaderFactory | D | 不确定,因为默认无回显 |
54 |
55 | ### 输出全部支持的feature和properties:
56 |
57 | `com.sun.org.apache.xerces.internal.impl.Constants.Main(String[] args)`
58 |
59 |
60 | ### 推荐的最小化配置(出锅了别怪我)
61 |
62 | 一般来说,禁用了DTD就万事大吉了,禁用了通用实体就不会被回显,禁用了参数实体就不会被oob。
63 |
64 | ### DocumentBuilderFactory_v1
65 |
66 | ```java
67 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
68 | String FEATURE = null;
69 | FEATURE = XMLConstants.FEATURE_SECURE_PROCESSING;
70 | dbf.setFeature(FEATURE, true);
71 | DocumentBuilder builder = dbf.newDocumentBuilder();
72 | ```
73 |
74 | ### DocumentBuilderFactory_v2
75 |
76 | ```java
77 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
78 | String FEATURE = null;
79 | FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
80 | dbf.setFeature(FEATURE, true);
81 | DocumentBuilder builder = dbf.newDocumentBuilder();
82 | ```
83 |
84 | ### DocumentBuilderFactory_v3
85 |
86 | ```java
87 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
88 | String FEATURE = null;
89 | FEATURE = "http://xml.org/sax/features/external-parameter-entities";
90 | dbf.setFeature(FEATURE, false);
91 | FEATURE = "http://xml.org/sax/features/external-general-entities";
92 | dbf.setFeature(FEATURE, false);
93 | DocumentBuilder builder = dbf.newDocumentBuilder();
94 | ```
95 |
96 | ### SAXBuilder
97 |
98 | ```java
99 | SAXBuilder builder = new SAXBuilder();
100 | builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
101 | Document doc = builder.build(ResourceUtils.getPoc1());
102 | ```
103 |
104 | ### SAXParserFactory
105 |
106 | ```java
107 | SAXParserFactory spf = SAXParserFactory.newInstance();
108 | spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
109 | SAXParser parser = spf.newSAXParser();
110 | parser.parse(ResourceUtils.getPoc1(), (HandlerBase) null);
111 | ```
112 |
113 | ### SAXReader_v1
114 |
115 | ```java
116 | SAXReader saxReader = new SAXReader();
117 | saxReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
118 | org.dom4j.Document doc = saxReader.read(ResourceUtils.getPoc1());
119 | ```
120 |
121 | ### SAXReader_v2
122 |
123 | ```java
124 | SAXReader saxReader = new SAXReader();
125 | saxReader.setFeature("http://xml.org/sax/features/external-general-entities", false);
126 | saxReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
127 | org.dom4j.Document doc = saxReader.read(ResourceUtils.getPoc1());
128 | ```
129 |
130 | ### SAXTransformerFactory
131 |
132 | ```java
133 | SAXTransformerFactory sf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
134 | sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
135 | StreamSource source = new StreamSource(ResourceUtils.getPoc3());
136 | sf.newXMLFilter(source);
137 | ```
138 |
139 | ### SchemaFactory
140 |
141 | ```java
142 | SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
143 | factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
144 | StreamSource source = new StreamSource(ResourceUtils.getPoc1());
145 | Schema schema = factory.newSchema(source);
146 | ```
147 |
148 | ### TransformerFactory
149 |
150 | ```java
151 | TransformerFactory tf = TransformerFactory.newInstance();
152 | tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
153 | StreamSource source = new StreamSource(ResourceUtils.getPoc1());
154 | tf.newTransformer().transform(source, new DOMResult());
155 | ```
156 |
157 | ### Unmarshaller
158 |
159 | ```java
160 | Class tClass = Person.class;
161 | JAXBContext context = JAXBContext.newInstance(tClass);
162 | Unmarshaller um = context.createUnmarshaller();
163 | Object o = um.unmarshal(ResourceUtils.getPoc2());
164 | tClass.cast(o);
165 | ```
166 |
167 | ### Validator
168 |
169 | ```java
170 | SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
171 | Schema schema = factory.newSchema();
172 | Validator validator = schema.newValidator();
173 | validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
174 | StreamSource source = new StreamSource(ResourceUtils.getPoc1());
175 | validator.validate(source);
176 | ```
177 |
178 | ### XMLInputFactory_v1
179 |
180 | ```java
181 | XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
182 | xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
183 | XMLStreamReader reader = xmlInputFactory.createXMLStreamReader(ResourceUtils.getPoc1());
184 | ```
185 |
186 | ### XMLInputFactory_v2
187 |
188 | ```java
189 | XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
190 | xmlInputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
191 | XMLStreamReader reader = xmlInputFactory.createXMLStreamReader(ResourceUtils.getPoc1());
192 | ```
193 |
194 | ### XMLReader
195 |
196 | ```java
197 | XMLReader reader = XMLReaderFactory.createXMLReader();
198 | reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
199 | reader.parse(new InputSource(ResourceUtils.getPoc1()));
200 | ```
201 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | }
4 |
5 | group 'com.leadroyal'
6 | version '1.0.0'
7 |
8 | sourceCompatibility = 1.8
9 |
10 | repositories {
11 | mavenLocal()
12 | mavenCentral()
13 | }
14 |
15 | dependencies {
16 | // for jdom1
17 | compile group: 'jdom', name: 'jdom', version: '1.1'
18 | // for jdom2
19 | // compile group: 'org.jdom', name: 'jdom', version: '2.0.0'
20 | compile group: 'dom4j', name: 'dom4j', version: '1.6.1'
21 | testCompile group: 'junit', name: 'junit', version: '4.12'
22 | }
23 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LeadroyaL/java-xxe-defense-demo/e928f1775f5c992a54c6ba448ffd21af4c113398/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'java-xxe-defense-demo'
2 |
3 |
--------------------------------------------------------------------------------
/src/main/java/com/leadroyal/xxe/Main.java:
--------------------------------------------------------------------------------
1 | package com.leadroyal.xxe;
2 |
3 |
4 | import com.leadroyal.xxe.sample.*;
5 |
6 | public class Main {
7 | public static void main(String args[]) {
8 | DocumentBuilderFactorySample.test();
9 | SAXBuilderSample.test();
10 | SAXBuilderSample.test2();
11 | SAXParserFactorySample.test();
12 | SAXReaderSample.test();
13 | SAXTransformerFactorySample.test();
14 | SchemaFactorySample.test();
15 | TransformerFactorySample.test();
16 | ValidatorSample.test();
17 | XMLInputFactorySample.test();
18 | XMLReaderSample.test();
19 | UnmarshallerSample.test();
20 | UnmarshallerSample.test2();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/leadroyal/xxe/ResourceUtils.java:
--------------------------------------------------------------------------------
1 | package com.leadroyal.xxe;
2 |
3 | import java.io.InputStream;
4 |
5 | public class ResourceUtils {
6 | public static InputStream getPoc1() {
7 | return ResourceUtils.class.getClassLoader().getResourceAsStream("poc1.xml");
8 | }
9 |
10 | public static InputStream getPoc2() {
11 | return ResourceUtils.class.getClassLoader().getResourceAsStream("poc2.xml");
12 | }
13 |
14 | public static InputStream getPoc3() {
15 | return ResourceUtils.class.getClassLoader().getResourceAsStream("poc3.xsl");
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/leadroyal/xxe/model/Person.java:
--------------------------------------------------------------------------------
1 | package com.leadroyal.xxe.model;
2 |
3 | import javax.xml.bind.annotation.XmlElement;
4 | import javax.xml.bind.annotation.XmlRootElement;
5 |
6 | @XmlRootElement
7 | public class Person {
8 | @XmlElement(name = "age")
9 | public int age;
10 | @XmlElement(name = "person")
11 | public String name;
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/leadroyal/xxe/sample/DocumentBuilderFactorySample.java:
--------------------------------------------------------------------------------
1 | package com.leadroyal.xxe.sample;
2 |
3 | import com.leadroyal.xxe.ResourceUtils;
4 | import org.xml.sax.SAXException;
5 |
6 | import javax.xml.XMLConstants;
7 | import javax.xml.parsers.DocumentBuilder;
8 | import javax.xml.parsers.DocumentBuilderFactory;
9 | import javax.xml.parsers.ParserConfigurationException;
10 | import java.io.IOException;
11 |
12 | public class DocumentBuilderFactorySample {
13 | public void safe() throws ParserConfigurationException, IOException, SAXException {
14 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
15 | String FEATURE = null;
16 | // 2019年7月17日20:24:45
17 | // 测试环境8u172
18 | FEATURE = XMLConstants.FEATURE_SECURE_PROCESSING; // 开启可挡回显xxe和blind-xxe
19 | dbf.setFeature(FEATURE, true);
20 | FEATURE = "http://apache.org/xml/features/disallow-doctype-decl"; // 开启可挡回显xxe和blind-xxe
21 | dbf.setFeature(FEATURE, true);
22 | FEATURE = "http://xml.org/sax/features/external-parameter-entities"; // 开启可挡blind-xxe
23 | dbf.setFeature(FEATURE, false);
24 | FEATURE = "http://xml.org/sax/features/external-general-entities"; // 开启可挡回显xxe
25 | dbf.setFeature(FEATURE, false);
26 | FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; // 无效
27 | dbf.setFeature(FEATURE, false);
28 | dbf.setXIncludeAware(false); // 无效
29 | dbf.setExpandEntityReferences(false); // 无效
30 | DocumentBuilder builder = dbf.newDocumentBuilder();
31 | builder.parse(ResourceUtils.getPoc1());
32 | }
33 |
34 | public void unsafe() throws ParserConfigurationException, IOException, SAXException {
35 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
36 | DocumentBuilder builder = dbf.newDocumentBuilder();
37 | String FEATURE = null;
38 | FEATURE = XMLConstants.FEATURE_SECURE_PROCESSING;
39 | dbf.setFeature(FEATURE, true);
40 | FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
41 | dbf.setFeature(FEATURE, true);
42 | FEATURE = "http://xml.org/sax/features/external-parameter-entities";
43 | dbf.setFeature(FEATURE, false);
44 | FEATURE = "http://xml.org/sax/features/external-general-entities";
45 | dbf.setFeature(FEATURE, false);
46 | FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
47 | dbf.setFeature(FEATURE, false);
48 | dbf.setXIncludeAware(false);
49 | dbf.setExpandEntityReferences(false);
50 | builder.parse(ResourceUtils.getPoc1());
51 | }
52 |
53 | public static void test(){
54 | try {
55 | new DocumentBuilderFactorySample().safe();
56 | } catch (ParserConfigurationException e) {
57 | e.printStackTrace();
58 | } catch (IOException e) {
59 | e.printStackTrace();
60 | } catch (SAXException e) {
61 | e.printStackTrace();
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/leadroyal/xxe/sample/SAXBuilderSample.java:
--------------------------------------------------------------------------------
1 | package com.leadroyal.xxe.sample;
2 |
3 | import com.leadroyal.xxe.ResourceUtils;
4 | import org.jdom.Document;
5 | import org.jdom.JDOMException;
6 | import org.jdom.input.SAXBuilder;
7 |
8 | import java.io.IOException;
9 |
10 | public class SAXBuilderSample {
11 | public void safe() throws JDOMException, IOException {
12 | SAXBuilder builder = new SAXBuilder();
13 | // 2019年7月17日20:24:45
14 | // 测试环境8u172
15 | // 2019年7月18日11:52:21, jdom2与jdom1表现一致
16 | builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // 开启可挡回显xxe和blind-xxe
17 | builder.setFeature("http://xml.org/sax/features/external-general-entities", false); // 无效
18 | builder.setFeature("http://xml.org/sax/features/external-parameter-entities", false); // 开启可挡blind-xxe
19 | Document doc = builder.build(ResourceUtils.getPoc1());
20 | }
21 |
22 | public void unsafe2() throws JDOMException, IOException {
23 | SAXBuilder builder = new SAXBuilder(true); // 对blind-xxe无效,好像可以挡回显xxe,
24 | Document doc = builder.build(ResourceUtils.getPoc1());
25 | }
26 |
27 | public static void test() {
28 | try {
29 | new SAXBuilderSample().safe();
30 | } catch (JDOMException e) {
31 | e.printStackTrace();
32 | } catch (IOException e) {
33 | e.printStackTrace();
34 | }
35 | }
36 |
37 | public static void test2() {
38 | try {
39 | new SAXBuilderSample().unsafe2();
40 | } catch (JDOMException e) {
41 | e.printStackTrace();
42 | } catch (IOException e) {
43 | e.printStackTrace();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/leadroyal/xxe/sample/SAXParserFactorySample.java:
--------------------------------------------------------------------------------
1 | package com.leadroyal.xxe.sample;
2 |
3 | import com.leadroyal.xxe.ResourceUtils;
4 | import org.xml.sax.HandlerBase;
5 | import org.xml.sax.SAXException;
6 |
7 | import javax.xml.parsers.ParserConfigurationException;
8 | import javax.xml.parsers.SAXParser;
9 | import javax.xml.parsers.SAXParserFactory;
10 | import java.io.IOException;
11 |
12 | public class SAXParserFactorySample {
13 | public void safe() throws IOException, SAXException, ParserConfigurationException {
14 | SAXParserFactory spf = SAXParserFactory.newInstance();
15 | // 2019年7月17日20:24:45
16 | // 测试环境8u172
17 | spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // 开启可挡回显xxe和blind-xxe
18 | spf.setFeature("http://xml.org/sax/features/external-general-entities", false); // 可能挡回显xxe,未测试,因为在这个case里,Handler完全是自己写
19 | spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); // 开启可挡blind-xxe
20 | spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); // 无效
21 | SAXParser parser = spf.newSAXParser();
22 | parser.parse(ResourceUtils.getPoc1(), (HandlerBase) null);
23 | }
24 |
25 | public static void test() {
26 | try {
27 | new SAXParserFactorySample().safe();
28 | } catch (IOException e) {
29 | e.printStackTrace();
30 | } catch (SAXException e) {
31 | e.printStackTrace();
32 | } catch (ParserConfigurationException e) {
33 | e.printStackTrace();
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/leadroyal/xxe/sample/SAXReaderSample.java:
--------------------------------------------------------------------------------
1 | package com.leadroyal.xxe.sample;
2 |
3 | import com.leadroyal.xxe.ResourceUtils;
4 | import org.dom4j.DocumentException;
5 | import org.dom4j.io.SAXReader;
6 | import org.xml.sax.SAXException;
7 |
8 | public class SAXReaderSample {
9 |
10 | public void safe() throws SAXException, DocumentException {
11 | // 2019年7月18日00:42:28
12 | // 测试环境8u191
13 | SAXReader saxReader = new SAXReader();
14 | saxReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // 开启可挡回显xxe和blind-xxe
15 | saxReader.setFeature("http://xml.org/sax/features/external-general-entities", false); // 开启可挡回显xxe
16 | saxReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); // 开启可挡blind-xxe
17 | org.dom4j.Document doc = saxReader.read(ResourceUtils.getPoc1());
18 |
19 | }
20 |
21 | public static void test() {
22 | try {
23 | new SAXReaderSample().safe();
24 | } catch (SAXException e) {
25 | e.printStackTrace();
26 | } catch (DocumentException e) {
27 | e.printStackTrace();
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/leadroyal/xxe/sample/SAXTransformerFactorySample.java:
--------------------------------------------------------------------------------
1 | package com.leadroyal.xxe.sample;
2 |
3 | import com.leadroyal.xxe.ResourceUtils;
4 |
5 | import javax.xml.XMLConstants;
6 | import javax.xml.transform.TransformerConfigurationException;
7 | import javax.xml.transform.sax.SAXTransformerFactory;
8 | import javax.xml.transform.stream.StreamSource;
9 |
10 | public class SAXTransformerFactorySample {
11 | public void safe() throws TransformerConfigurationException {
12 | // 2019年7月18日00:42:28
13 | // 测试环境8u191
14 | SAXTransformerFactory sf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
15 | sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // 开启可挡回显xxe和blind-xxe
16 | sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); // 疑似无影响
17 | StreamSource source = new StreamSource(ResourceUtils.getPoc3());
18 | sf.newXMLFilter(source);
19 | }
20 |
21 | public static void test() {
22 | try {
23 | new SAXTransformerFactorySample().safe();
24 | } catch (TransformerConfigurationException e) {
25 | e.printStackTrace();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/leadroyal/xxe/sample/SchemaFactorySample.java:
--------------------------------------------------------------------------------
1 | package com.leadroyal.xxe.sample;
2 |
3 | import com.leadroyal.xxe.ResourceUtils;
4 | import org.xml.sax.SAXException;
5 |
6 | import javax.xml.XMLConstants;
7 | import javax.xml.transform.stream.StreamSource;
8 | import javax.xml.validation.Schema;
9 | import javax.xml.validation.SchemaFactory;
10 |
11 | public class SchemaFactorySample {
12 | public void safe() throws SAXException {
13 | // 2019年7月18日00:42:28
14 | // 测试环境8u191
15 | SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
16 | factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // 开启可挡回显xxe和blind-xxe
17 | factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // 疑似无影响
18 | StreamSource source = new StreamSource(ResourceUtils.getPoc1());
19 | Schema schema = factory.newSchema(source);
20 | }
21 |
22 | public static void test() {
23 | try {
24 | new SchemaFactorySample().safe();
25 | } catch (SAXException e) {
26 | e.printStackTrace();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/leadroyal/xxe/sample/TransformerFactorySample.java:
--------------------------------------------------------------------------------
1 | package com.leadroyal.xxe.sample;
2 |
3 | import com.leadroyal.xxe.ResourceUtils;
4 |
5 | import javax.xml.XMLConstants;
6 | import javax.xml.transform.TransformerException;
7 | import javax.xml.transform.TransformerFactory;
8 | import javax.xml.transform.dom.DOMResult;
9 | import javax.xml.transform.stream.StreamSource;
10 |
11 | public class TransformerFactorySample {
12 | public void safe() throws TransformerException {
13 | // 2019年7月18日00:42:28
14 | // 测试环境8u191
15 | TransformerFactory tf = TransformerFactory.newInstance();
16 | tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // 开启可挡回显xxe和blind-xxe
17 | tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); // 疑似无影响
18 | StreamSource source = new StreamSource(ResourceUtils.getPoc1());
19 | tf.newTransformer().transform(source, new DOMResult());
20 | }
21 |
22 | public static void test() {
23 | try {
24 | new TransformerFactorySample().safe();
25 | } catch (TransformerException e) {
26 | e.printStackTrace();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/leadroyal/xxe/sample/UnmarshallerSample.java:
--------------------------------------------------------------------------------
1 | package com.leadroyal.xxe.sample;
2 |
3 | import com.leadroyal.xxe.ResourceUtils;
4 | import com.leadroyal.xxe.model.Person;
5 | import org.xml.sax.*;
6 |
7 | import javax.xml.XMLConstants;
8 | import javax.xml.bind.JAXBContext;
9 | import javax.xml.bind.JAXBException;
10 | import javax.xml.bind.Unmarshaller;
11 | import javax.xml.parsers.ParserConfigurationException;
12 | import javax.xml.parsers.SAXParserFactory;
13 | import javax.xml.transform.Source;
14 | import javax.xml.transform.sax.SAXSource;
15 |
16 | public class UnmarshallerSample {
17 | public void safe() throws JAXBException {
18 | // 2019年7月18日11:28:27
19 | // 测试环境8u172
20 | // 默认禁用dtd,可以挡回显xxe和blind-xxe
21 | Class tClass = Person.class;
22 | JAXBContext context = JAXBContext.newInstance(tClass);
23 | Unmarshaller um = context.createUnmarshaller();
24 | Object o = um.unmarshal(ResourceUtils.getPoc2());
25 | tClass.cast(o);
26 | }
27 |
28 | public void safe2() throws SAXException, ParserConfigurationException, JAXBException {
29 | // 2019年7月18日11:28:27
30 | // 测试环境8u172
31 | JAXBContext context = JAXBContext.newInstance(Person.class);
32 | Unmarshaller unmarshaller = context.createUnmarshaller();
33 | SAXParserFactory sax = SAXParserFactory.newInstance();
34 | sax.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); // 开启可以挡回显xxe和blind-xxe
35 | sax.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // 开启可以挡回显xxe和blind-xxe
36 | sax.setFeature("http://xml.org/sax/features/external-general-entities", false); // 未测试,因为没有回显成功
37 | sax.setFeature("http://xml.org/sax/features/external-parameter-entities", false); // 开启可以挡blind-xxe
38 | sax.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); // 无效
39 | sax.setNamespaceAware(false); // 无效
40 | XMLReader xmlReader = sax.newSAXParser().getXMLReader();
41 | xmlReader.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); // 无效
42 | xmlReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // 开启可以挡回显xxe和blind-xxe
43 | xmlReader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); // 无效
44 | xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false); // 未测试,因为没有回显成功
45 | xmlReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); // 开启可以挡blind-xxe
46 | Source source = new SAXSource(xmlReader, new InputSource(ResourceUtils.getPoc2()));
47 | Object obj = unmarshaller.unmarshal(source);
48 | System.out.println(((Person) obj).age);
49 | System.out.println(((Person) obj).name);
50 | }
51 |
52 | public static void test() {
53 | try {
54 | new UnmarshallerSample().safe();
55 | } catch (JAXBException e) {
56 | e.printStackTrace();
57 | }
58 | }
59 |
60 | public static void test2() {
61 | try {
62 | new UnmarshallerSample().safe2();
63 | } catch (JAXBException e) {
64 | e.printStackTrace();
65 | } catch (SAXException e) {
66 | e.printStackTrace();
67 | } catch (ParserConfigurationException e) {
68 | e.printStackTrace();
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/leadroyal/xxe/sample/ValidatorSample.java:
--------------------------------------------------------------------------------
1 | package com.leadroyal.xxe.sample;
2 |
3 | import com.leadroyal.xxe.ResourceUtils;
4 | import org.xml.sax.SAXException;
5 |
6 | import javax.xml.XMLConstants;
7 | import javax.xml.transform.stream.StreamSource;
8 | import javax.xml.validation.Schema;
9 | import javax.xml.validation.SchemaFactory;
10 | import javax.xml.validation.Validator;
11 | import java.io.IOException;
12 |
13 | public class ValidatorSample {
14 | public void safe() throws SAXException, IOException {
15 | // 2019年7月18日00:42:28
16 | // 测试环境8u191
17 | SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
18 | Schema schema = factory.newSchema();
19 | Validator validator = schema.newValidator();
20 | validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // 开启可挡回显xxe和blind-xxe
21 | validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // 疑似无影响
22 | StreamSource source = new StreamSource(ResourceUtils.getPoc1());
23 | validator.validate(source);
24 | }
25 |
26 | public static void test() {
27 | try {
28 | new ValidatorSample().safe();
29 | } catch (SAXException e) {
30 | e.printStackTrace();
31 | } catch (IOException e) {
32 | e.printStackTrace();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/leadroyal/xxe/sample/XMLInputFactorySample.java:
--------------------------------------------------------------------------------
1 | package com.leadroyal.xxe.sample;
2 |
3 | import com.leadroyal.xxe.ResourceUtils;
4 |
5 | import javax.xml.stream.XMLInputFactory;
6 | import javax.xml.stream.XMLStreamConstants;
7 | import javax.xml.stream.XMLStreamException;
8 | import javax.xml.stream.XMLStreamReader;
9 |
10 | public class XMLInputFactorySample {
11 | public void safe() throws XMLStreamException {
12 | // 2019年7月18日11:28:27
13 | // 测试环境8u172
14 | XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
15 | xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false); // 开启可挡回显xxe和blind-xxe
16 | xmlInputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); // 开启可挡回显xxe和blind-xxe
17 | XMLStreamReader reader = xmlInputFactory.createXMLStreamReader(ResourceUtils.getPoc1());
18 | while (reader.hasNext()) {
19 | int type = reader.next();
20 | if (type == XMLStreamConstants.START_ELEMENT) {
21 | System.out.print(reader.getAttributeValue(0) + ":");
22 | System.out.println(reader.getElementText());
23 | }
24 | }
25 | }
26 |
27 | public static void test() {
28 | try {
29 | new XMLInputFactorySample().safe();
30 | } catch (XMLStreamException e) {
31 | e.printStackTrace();
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/leadroyal/xxe/sample/XMLReaderSample.java:
--------------------------------------------------------------------------------
1 | package com.leadroyal.xxe.sample;
2 |
3 | import com.leadroyal.xxe.ResourceUtils;
4 | import org.xml.sax.InputSource;
5 | import org.xml.sax.SAXException;
6 | import org.xml.sax.XMLReader;
7 | import org.xml.sax.helpers.XMLReaderFactory;
8 |
9 | import java.io.IOException;
10 |
11 | public class XMLReaderSample {
12 | public void safe() throws SAXException, IOException {
13 | // 2019年7月18日11:28:27
14 | // 测试环境8u172
15 | XMLReader reader = XMLReaderFactory.createXMLReader();
16 | reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // 开启可挡回显xxe和blind-xxe
17 | reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); // 未测试,因为默认没有回显
18 | reader.setFeature("http://xml.org/sax/features/external-general-entities", false); // 未测试,因为默认没有回显
19 | reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); // 开启可挡blind-xxe
20 | reader.parse(new InputSource(ResourceUtils.getPoc1()));
21 | }
22 |
23 | public static void test() {
24 | try {
25 | new XMLReaderSample().safe();
26 | } catch (SAXException e) {
27 | e.printStackTrace();
28 | } catch (IOException e) {
29 | e.printStackTrace();
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/resources/poc1.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | ]>
5 |
6 | &xxe;
7 |
--------------------------------------------------------------------------------
/src/main/resources/poc2.xml:
--------------------------------------------------------------------------------
1 |
2 | ]>
4 |
5 | 10
6 | &poc;
7 |
--------------------------------------------------------------------------------
/src/main/resources/poc3.xsl:
--------------------------------------------------------------------------------
1 |
2 |
4 | ]>
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Mainkind |
15 | Monkey |
16 | Pig |
17 | celestial |
18 | Horse |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------