Mysql 儲存過程注入
Mysql 儲存過程注入
mysql有著儲存過程這個功能, 這次作者剛好遇到注入點在呼叫儲存過程的sql注入.
基本知識
mysql可以通過以下語句建立一個儲存過程
CREATE PROCEDURE sp_name(IN param1 INT,OUT param2 INT) BEGIN # code END
sp_name是名字, 為IN的引數是入參,為OUT的引數為返回值
呼叫儲存過程的語句
CALL sp_name(1);
注入分析
從語法我們可以分析出我們的輸入可能出現在兩處,和作為引數進入儲存過程
CALL <儲存過程名注入點>(<儲存過程引數注入點>);
首先如果對引數過濾不嚴,無需進入儲存過程就可以直接注入.用以下語句為例
CALL test([可控點])
由於是直接執行,所以我們可直接注入語句例如(select 1)
.由於語法問題,這個括號是必須的,這語句就變成了
CALL test((select 1))
這種注入和普通注入差別不大,已有技巧基本可以套用.
如果引數不可控,但是方法名可控也可以進行注入.但是首先要得知一個存在的儲存過程名,然後通過註釋後續語句來進行自己語句
CALL [可控]()
示例poc
test((select updatexml(1,concat(0x7e,(select @@version),0x7e),1))) --
可以看到和引數注入差距不大,只是用於引數不可控,或被安全處理的情況.
最後一種可能,在儲存過程中出現.雖然儲存過程被認為非常安全,但是實際上如果編寫不慎 例如進行動態sql拼接 還是會出現注入的.. 例如
# 來自網上的一個例子 _field和_table是引數 SET @strSql = CONCAT('SELECT ',_field,' FROM ',_table); PREPARE stmt FROM @strSql; EXECUTE stmt;
最後附上我遇上的一個漏洞程式碼
<?php if (isset($_POST['mode'])) { @$m = new mysqli('localhost', 'root', '123456', 'UseStudio_Develop'); /*省略錯誤處理*/ $ary = explode('&', $_POST['mode']); if (count($ary) == 1) { $sql = 'CALL ' . $m->real_escape_string($ary[0]) . '()'; } else { $sql = 'CALL ' . $m->real_escape_string($ary[0]) . "('"; for ($i = 1; $i < count($ary); $i++) { $sql.= $m->real_escape_string($ary[$i]); if ($i < count($ary) - 1) { $sql.= "','"; } } $sql.= "')"; } //執行查詢,獲取結果集 $res = $m->query($sql); // 省略返回的程式碼 }