打败XXE的攻略
XXE漏洞学习小记
靶场用的是xxe_labs和bwapp
XXE漏洞原理特征详解
漏洞原理
XML外部实体注入
攻击者输入的是
1 | User1</USER><USER role="admin">User2 |
它的 “破坏逻辑” 是:
</USER>
:闭合原本的 <USER>
标签,让原始 <USER role="guest">用户输入</USER>
变成 <USER role="guest">User1</USER>
(截断原始逻辑)。
<USER role="admin">User2
:注入新的 <USER>
标签,还带 role="admin"
高权限,强行新增一个管理员身份的用户。
利用用户可控输入破坏原本合法的 XML 格式,插入额外内容实现越权等攻击
XXE漏洞原理
漏洞成因:解析时未对XML外部实体加以限制,导致攻击者将恶意代码注入到XML中,导致服务器加载恶意的外部实体引发文件读取,SSRF,命令执行等危害操作。
特征:在HTTP的Request报文出现一下请求报文,即表明此时是采用XML进行数据传输,就可以测试是否存在XML漏洞。
Content-type:text/xml application/xml
XXE
即XML外部实体注入
注入:是指XML
数据在传输过程中被修改,导致服务器执行了修改后的恶意代码,从而达到攻击目的。
外部实体:则是指攻击者通过利用外部实体声明部分来对XML
数据进行修改、插入恶意代码。
所以XXE
就是指XML
数据在传输过程中利用外部实体声明部分的“SYSTEM”
关键词导致XML
解析器可以从本地文件或者远程URI
中读取受保护的数据。
分析:
XML 与外部实体:
XML(eXtensible Markup Language,可扩展标记语言 )是一种用于存储和传输数据的标记语言。在 XML 中,外部实体是一种可以引入外部资源(比如文件、网络资源等)的机制。举个简单的例子,正常情况下,在 XML 中可以通过<!ENTITY>
声明来引入外部实体,比如想要在 XML 文档中引用一个本地文件,就可以这样写:
1 |
|
这里<!ENTITY file SYSTEM "file:///etc/passwd">
就声明了一个名为file
的外部实体,它指向了本地的/etc/passwd
文件,然后在<root>
标签里通过&file;
来引用这个实体。
当 XML 解析器在解析 XML 文档时,如果没有对外部实体的引入做限制,攻击者就有机可乘。攻击者可以精心构造恶意的 XML 文档,将恶意代码注入到 XML 中。例如,攻击者把上述代码发送给存在 XXE 漏洞的服务器,服务器的 XML 解析器在解析时,就会按照攻击者的意图去读取本地的/etc/passwd
文件(在 Linux 系统中,这个文件包含了系统用户的重要信息 ),这就是文件读取攻击。
此外,攻击者还可以通过设置外部实体指向其他网络资源,比如内部的数据库服务器、内网的 Web 服务等,引发 SSRF(Server-Side Request Forgery,服务器端请求伪造)攻击,让服务器代替攻击者去访问内网资源,从而获取敏感数据或执行一些非法操作。更严重的情况下,在一些配置不当的环境中,攻击者可以实现命令执行,控制服务器。
漏洞特征
- Content-type 与数据传输方式:在 HTTP 协议中,
Content-type
(内容类型) 头字段用于告诉服务器或客户端发送的数据是什么格式。当Content-type
的值为text/xml
或application/xml
时,就表明这次 HTTP 请求中传输的数据是 XML 格式的。 - 测试漏洞存在的依据:因为 XXE 漏洞是针对 XML 数据解析产生的,所以当发现 HTTP 请求报文里
Content-type
是上述提到的与 XML 相关的值时,就意味着有可能存在 XXE 漏洞。这时就可以通过构造一些包含外部实体声明的测试用 XML 数据,发送给服务器,看服务器的 XML 解析器是否会按照我们预想的(也就是存在漏洞的情况下)去处理外部实体,从而判断是否真的存在 XXE 漏洞。
html和xml的小区别
首先他们两个都是标记语言 只不过是在设计目标 语法规则 应用场景下有一些区别
1. 设计目标
HTML:聚焦网页内容呈现,为浏览器提供渲染网页的 “蓝图” 。它预定义了 <p>
(段落 )、<h1>
(标题 )、<img>
(图片 )等标签,直接关联网页视觉与交互展现,核心是让用户 “看到” 结构化的网页内容。
XML:专注数据存储与传输,作为通用的 “数据容器” 。无预定义标签,用户可自定义 <订单>
、<用户信息>
等标签描述数据关系,核心是让系统 “读懂” 结构化数据,实现跨系统的数据交换。
DTD实体是什么
XML 文档有自己的一个格式规范,这个格式规范是由一个叫做 DTD的东西控制的
长这样
1 | <?xml version="1.0"?>//这一行是文档定义 用来指定xml的版本 |
定义了根元素是message 然后其他的就是子元素 这个DTD就规定了xml要如下
1 | <message> |
然后进阶一点的 就是说可以不用每次都改我输入的内容(元素) 使用的相当于就是一个变量
1 | <?xml version="1.0" encoding="ISO-8859-1"?> |
这里就是定义的foo元素为any 可以接受任意元素
<!ENTITY xxe "test" >
:
这个是实体定义 把xxe定义为一个实体(类似于变量)他的值是test
实体的作用是 预存一段内容,后续在 XML 里用 &实体名;
引用,解析时会替换成对应的值。
1 | <creds> |
这就是xml的内容
用 &
开头、;
结尾的语法引用实体 xxe
。
解析 XML 时,解析器会识别 &xxe;
,自动替换成实体定义的值(即 "test"
)。
所以最终解析后的 XML 内容等价于:
1 | <creds> |
DTD 就像是 XML 文档的蓝图或规则手册,规定了 XML 文档中元素的层级关系、出现顺序以及元素内容的类型等。
上面的例子都是内部实体 其实实体分为两种内部和外部
实体实际上可以从外部的dtd文件引用 比如下面
1 | <?xml version="1.0" encoding="ISO-8859-1"?> |
在 XML 中,一些字符拥有特殊的意义,如果把这些字符放在XML元素中就会产生错误,所以必须用实体引用来代替
文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。
(1)内部的 DOCTYPE 声明<!DOCTYPE 根元素 [元素声明]>
(2)外部文档声明<!DOCTYPE 根元素 SYSTEM ”文件名”>
实体
(1)内部实体声明<!ENTITY 实体名称 ”实体的值”>
(2)外部实体声明<!ENTITY 实体名称 SYSTEM ”URI”>
(3)参数实体声明<!ENTITY %实体名称 ”实体的值”>
或者<!ENTITY %实体名称 SYSTEM ”URI”>
三种实体声明方式使用区别:
参数实体用%实体名称申明,引用时也用%
实体名称;
其余实体直接用实体名称申明,引用时用&
实体名称。
参数实体只能在DTD
中申明,DTD
中引用;
其余实体只能在DTD
中申明,可在xml
文档中引用。
XXE分类
按照构造外部实体声明的方法不同可分为
直接通过DTD
外部实体声明
通过DTD
文档引入外部DTD
文档中的外部实体声明
通过DTD
外部实体声明引入外部DTD
文档中的外部实体声明
按照XXE
回显信息不同可分为`正常回显XXE``
报错XXE
``Blind XXE`。
xxe_labs
php_xxe
可以看到这里 数据是以xml格式发送的
常见数据传递格式
表单数据(application/x-www-form-urlencoded
)
JSON(application/json
)
过程大概就是 前端通过post请求把xml格式的账号密码发送到dologin.php
然后dologin.php作为后端处理脚本 会对接受的xml数据进行一个解析 比如说提取输入的username passwd标签中的内容 继续后面的验证
所以我们要做的就是 在body(请求体)中加入xml内容进行测试
body是啥
举个栗子 当你在网页上提交登录表单时,请求的结构大致如下
1 | POST /doLogin.php HTTP/1.1 // 请求行(方法+路径+协议) |
这里的username=admin&password=123456
就是放在 body 中的登录数据,服务器会从 body 中解析这些内容并处理登录逻辑
有回显的xx漏洞
1 | file:/// #file协议读取文件 |
1 | <?xml version="1.0" ?> |
1 |
|
file:///e://test.txt
读取本地文件
使用PHP伪协议读取文件如下图
php://filter/read=convert.base64-encode/resource=d:/1.txt
探测内网存活主机与端口如下图
无回显数据外带
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ANY [ <!ENTITY % shit SYSTEM "http://127.0.0.1:80/1.txt"> %shit; ]>
这种写法和上面那种写法的不同
差不太多我感觉
这个是改了靶场的文件 然后使他没有回显了