简单介绍一下背景知识:
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中定义元素,我们还可以在DTD中定义实体(对应XML标签中的内容),除了标签以外,还有一些内容是固定的。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ #文档类型(DTD)
<!ELEMENT foo ANY > #元素
<!ENTITY xxe "test" >]> #实体
这里 定义元素为 ANY ,说明接收任何元素,但是定义了一个XML的实体,那么我们就可以写成这样(实体可以看成一个变量,到时候我们可以在xml中 用 &来引用):
<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>
我们使用 &xxe 对 上面定义的 xxe 实体进行了引用,到时候输出的时候 &xxe 就会被 "test" 替换。
重点:
一:
实体分为两种,内部实体和外部实体。上面举例的是内部实体,但是实体实际上是可以从外部引进内容的:
<?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 起到一样的作用。
其实有system file 等关键字,可以简单认定为是外部实体。
二:
我们上面已经将实体分成了两个派别(内部实体和外部外部),但是实际上从另一个角度看,实体也可以分成两个派别(通用实体和参数实体)。
1.通用实体:
用&实体名 ; 引用的实体,他在DTD中定义。在XML文档中引用。如:
<?xml versio