一直认为预处理语句结合PHP
中PDO
是可以用来有效防止SQL
注入的,直到在writeup
中看到有用预处理语句来绕过限制完成注入的,脑洞大开!
0x01 预处理语句
MySQL
语法常用三个语句:
PREPARE stmt_name FROM preparable_stmt; //预备语句
EXECUTE stmt_name [USING @var_name [, @var_name] ...]; //执行语句
{DEALLOCATE | DROP} PREPARE stmt_name; //删除语句
学习测试一,不使用变量
mysql> prepare testpre from 'select * from studytest.test';
Query OK, 0 rows affected (0.00 sec)
Statement prepared
mysql> execute testpre;
+------+-------+
| id | name |
+------+-------+
| 1 | baynk |
| 2 | cisco |
+------+-------+
2 rows in set (0.00 sec)
mysql> drop prepare testpre;
Query OK, 0 rows affected (0.00 sec)
学习测试二,使用变量
mysql> set @a=1;
Query OK, 0 rows affected (0.00 sec)
mysql> prepare pretest2 from "select * from studytest.test where id=?";
Query OK, 0 rows affected (0.00 sec)
Statement prepared
mysql> execute pretest2 using @a;
+------+-------+
| id | name |
+------+-------+
| 1 | baynk |
+------+-------+
1 row in set (0.00 sec)
mysql> drop prepare pretest2;
Query OK, 0 rows affected (0.00 sec)
0x02 CTF测试复现
由于在当时的ctf
环境中,将select
过滤了,所以都是使用预处理语句来拼接select
,有用concat()
,有用char()
,估计hex()
也可以绕过。
但是!本地复现却不成功。
mysql> PREPARE hacker from concat(char(115,101,108,101,99,116), ' version()');EXECUTE hacker;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'concat(char(115,101,108,101,99,116), ' version()')' at line 1
ERROR 1243 (HY000): Unknown prepared statement handler (hacker) given to EXECUTE
同样的语句,无法执行。另外还测试过了把表名让?
进行占位,也是失败的,猜测应该是版本的问题
查了下资料,不一定正确。
-
Mariadb 5.5 对应 mysql 5.5
-
5.5以下的版本都是上述对应关系
-
Mariadb 10.0 对应 mysql 5.6
-
Mariadb 10.1 对应 mysql 5.7
而CTF
的玩意是10.3
的Mariadb
,大概是相当于MySQL
的8
版本了吧,我的MySQL
只有5.5
,估计是版本差距过大的原因。
不过本地虽然复现失败,但是还是学到了不少知识,这波强行不亏。