一直認爲預處理語句結合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
,估計是版本差距過大的原因。
不過本地雖然復現失敗,但是還是學到了不少知識,這波強行不虧。