前言
在 OWASP Top 10 2017 - SQL Injection 有介紹如何透過 SQL Injection 引發錯誤來將資料表的內容透過錯誤顯示出來。
因為是在登入頁面,所以 SQL 查詢條件會是 Where Email = ‘使用者Email’ And Password = ‘使用者密碼’ ,而這範例的前題是,使用者Email必需要存在資料表之中,否則會取不到資料。
為什麼會這樣子呢?
研究
原本資料表中有 rm@gss.com.tw 這筆資料,系統執行結果如下,
它的 sql 如下,
1 | SELECT * FROM Users |
而 SQL 的執行計畫如下,

從上面的執行計畫來看,上方是 Where Email = ‘rm@gss.com.tw‘ 後,取得該筆的資料,並將 Password 放到變數 Expr1004 (Compute Scalar) 而下方則是 SELECT Top 1 A2.Email … 並將 Top 1 的 Email 放到變數 Expr1003(Compute Scalar) 之中,在 Nested Loops 時,會將該筆資料及變數 Expr1004, Expr1003 送到 Filter 比較 Expr1004 = CONVERT(INT, ‘[‘ + Expr1003 + ‘]’) 。
所以,如果將 Email 改成不存在資料表中的話, Where Email = ‘abc@rm.com‘ 資料不存在的話,自然就不會有任何資料會進行 Filter ,也就不會發生錯誤,而將 Top 1 的資料顯示出來了哦! 如下的執行計畫(線上方的數值為輸出的筆數)


而昨天在分享時,有新註冊一個使用者為 ok@rm.com ,密碼設定為 gss ,結果使用上述的方式要讓系統發生錯誤將資料顯示出來時,卻發生以下的錯誤,
Conversion failed when converting the varchar value ‘gss’ to data type int.
居然是將使用者的密碼轉成 int 而發生錯誤,怎麼會這樣子呢?
同樣可以從 SQL Plan 中發現這個問題,如下,

從上面的 SQL Plan 可以發現,因為我們要將 Email 轉成 INT ,所以它會將 Password 隱含轉換成 INT 再來做比較,
所以當使用者的 Password 無法轉成 INT 時,自然就會先發生轉換的錯誤。
所以,透過這個方式取得資料除了使用者的 Email 要存在之外, Password 也要可以轉成 INT 哦!