一、XML基础知识
XML是一种非常流利的标记语言,在解析外部实体的过程中,XML解析器可以根据URL中指定的方案(协议)来查询各种网络协议和服务(DNS,FTP,HTTP,SMB等)。外部实体对于在文档中创建动态引用非常有用,这样对引用资源所做的任何更改都会在文档中自动更新。但是,在处理外部实体时,可以针对应用程序启动许多攻击。这些攻击包括泄露本地系统文件,这些文件可能包含密码和私人用户数据等敏感信息,或利用各种方案的网络访问功能来操纵内部应用程序。通过将这些攻击与其它实现缺陷相结合,这些攻击的范围可以扩展到客户端内存损坏,任意代码执行,甚至服务中断,取决于这些攻击的上下文。
XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的元语言。
XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。
DTD(document type definition,文档类型定义)的作用是定义XML文档的合法构建模块。DTD可以在XML文档内部声明,也可以外部引用。
内部声明DTD
<根元素[声明元素]>
引用外部DTD
<根元素 SYSTEM “文件名”>
或
<根元素 PUBLIC “public_id” “文件名”>
DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量&#xff0c;可以内部声明或外部引用。
内部实体
]>
这里定义元素为ANY说明接受任何元素&#xff0c;但是定义了一个XML的实体&#xff08;实体其实可以看成一个变量&#xff0c;到时候我们可以在XML中通过&&#xff1b;进行引用&#xff09;
例如&#xff1a;
&xxe;
mypass
我们使用&xxe&#xff1b;对上面定义的xxe实体进行了引用&#xff0c;到时候输出的时候&xxe&#xff1b;就会被“test”替换。
外部实体
<实体名称 SYSTEM “URI”>
或
<实体名称 PUBLIC “public_ID” “URI”>
]>
&xxe;mypass
上面将实体分为两个派别&#xff08;内部实体和外部实体&#xff09;&#xff0c;但是实际上从另一个角度看 &#xff0c;实体可以分为另外两个派别&#xff08;通用实体和参数实体&#xff09;。
通用实体
用&实体名&#xff1b;在DTD中定义&#xff0c;在XML文档中引用
]>
Joe &file; ...
参数实体
&#xff08;1&#xff09;使用% 实体名&#xff08;这里空格不能少&#xff09;在DTD中定义&#xff0c;并且只能在DTD中使用%实体名&#xff1b;引用
&#xff08;2&#xff09;只有在DTD文件中&#xff0c;参数实体的声明才能引用其他实体
&#xff08;3&#xff09;和通用实体一样&#xff0c;参数实体也可以外部引用
">
%an-element; %remote-dtd;
参数实体在Blind XXE中起到了至关重要的作用
二、XML外部实体注入&#xff08;XML External Entity&#xff09;
当允许引用外部实体时&#xff0c;通过构造恶意内容&#xff0c;可导致读取任意文件、执行系统命令、探测内网端口、攻击内网网站等危害。
引入外部实体的方式有多种&#xff0c;比如&#xff1a;
恶意引入外部实体方式1&#xff1a;
]>
&xxe;
恶意引入外部实体方式2&#xff1a;
%d;
]>
&xxe;
恶意引入外部实体方式3&#xff1a;
%d;
]>
&xxe;
DTD文件(evil.dtd)内容&#xff1a;
另外&#xff0c;不同程序支持的协议不一样
还支持扩展协议&#xff0c;如php支持的扩展协议&#xff1a;
三、漏洞危害
1&#xff1a;读取任意文件
]>
&xxe;
该CASE是读取C://下的文件&#xff0c;有些XML解析支持列目录&#xff0c;攻击者通过列目录、读文件&#xff0c;获取账号密码后进一步攻击&#xff0c;如读取tomcat-users.xml得到账号密码后登录tomcat的manager部署webshell。
无数据回显的情况
xxe.dtd:
"php://filter/read&#61;convert.base64-encode/resource&#61;file:///c:/xxx.txt">
">
payload:
%remote;%int;%send;
]>
我们从payload中能看到连续待用了三个参数实体%remote&#xff1b;%int&#xff1b;%send&#xff1b;&#xff0c;这就是我们的利用顺序&#xff0c;%remote&#xff1b;先调用&#xff0c;调用后请求远程服务器上的xxe.dtd&#xff0c;有点类似于将xxe.dtd包含进来&#xff0c;然后%int&#xff1b;调用xxe.dtd中的%file&#xff1b;&#xff0c;%file&#xff1b;就会去获取服务器上面的敏感文件&#xff0c;然后将%file&#xff1b;的结果填入到%send&#xff1b;后面&#xff08;因为实体的值中不能有%&#xff0c;所以将其转换成html实体编码%#37;&#xff09;&#xff0c;我们在调用%send&#xff1b;把我们读取到的数据发送到我们远程VPS上&#xff0c;这样就实现了外带数据的效果&#xff0c;完美解决了XXE无回显的问题。
2&#xff1a;查看php源代码
查看php源代码一般用php伪协议php://filter
]>
&xxe;
将得到的base数据解码即可。
3&#xff1a;远程代码执行
这种情况很少发生&#xff0c;主要时由于配置不当导致的。如果我们足够幸运&#xff0c;并且PHP expect模块被加载到了易受攻击的系统或处理XML的内部应用程序上&#xff0c;我们可以执行如下的代码&#xff1a;
]>
&xxe;
系统将执行id命令&#xff0c;并在响应中返回命令执行结果。
4:SSRF
XXE可以和SSRF&#xff08;服务端请求伪造&#xff09;漏洞一起用于探测其他内网主机的信息&#xff0c;基于http协议。
]>
&xxe;
当然也可以用来探测端口信息&#xff0c;根据响应包的信息判断。
四、漏洞发现
XXE漏洞主要是webserver危险的引用外部实体并且未对外部实体进行敏感字符过滤所造成的&#xff0c;所以如果web服务存在XXE漏洞&#xff0c;首先是应该存在xml传输数据。如果http头的Content-Type为application/xml时可以尝试进行XXE注入&#xff0c;或者当Content-Type为application/json时&#xff0c;修改其为Content-Type为application/xml或者text/xml再尝试进行注入。
以下利用主要基于libxml2
版本&#xff0c;其中libxml是PHP的xml支持。
而libxml版本在2.9.1及以后&#xff0c;默认不解析外部实体&#xff0c;很多利用将无法实现。
检测方法&#xff1a;
尝试修改请求体的内容&#xff1a;
如图返回内部实体定义内容。
尝试加载本地文件&#xff1a;
可以看到已经返回/etc/passwd这个文件了。
五、防御XXE
XXE漏洞存在是因为XML解析器解析了用户发送的不可信数据。然而&#xff0c;要去检验DTD&#xff08;document type definition&#xff09;中SYSTEM标识符定义的数据&#xff0c;并不太容易&#xff0c;也不大可能。大部分的XML解析器默认对于XXE攻击是脆弱的。因此&#xff0c;最好的解决办法就是配置XML解析器去使用本地静态的DTD&#xff0c;不允许XML中含有任何自己声明的DTD。通过设置相应的属性值为False&#xff0c;XML外部实体攻击就能够被阻止。因此&#xff0c;可将外部实体、参数实体和内联DTD都设置为false&#xff0c;从而避免基于XXE漏洞的攻击。
1、使用开发语言提供的禁用外部实体的方法
PHP&#xff1a;
libxml_disable_entity_loader(true);
JAVA:
DocumentBuilderFactory dbf &#61; DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
Python:
from lxml import etree
xmlData &#61; etree.parse(xmlSource,etree.XMLParser(resolve_entities&#61;False))
2、过滤用户提供的XML数据
过滤关键字&#xff1a;、、SYSTEM、PUBLIC等。
不允许XML中含有自己定义的DTD
参考&#xff1a;
未知攻焉知防——XXE漏洞攻防 - 博客 - 腾讯安全应急响应中心
pikachu XXE (XML外部实体注入)&#xff08;皮卡丘漏洞平台通关系列&#xff09;_仙女象的博客-CSDN博客_皮卡丘漏洞平台