SQL 注入原理
阿新 • • 發佈:2020-12-22
SQL 注入原理
sql 注入的原因是應用程式對使用者輸入的資料沒有進行合法判斷,並且直接將資料傳給資料庫進行查詢。
流程如下:
- 【 P 】:「使用者輸入」資料 P
- 【 Q = X + P 】:「應用程式」將 P 與其他資料拼接
- 【 Q --> R 】:「資料庫 」將 Q 作為 SQL語句執行,返回結果 R
- 【 R 】:「應用程式」接收資料 R,將 R 返回給使用者
基於查詢注入
如果應用程式會直接返回查詢的結果,那麼我們將可以使用基於查詢的注入方法。
聯合查詢法:
- 【 P 】:「使用者輸入」資料 P =
-1' union select @@version --
- 【 Q = X + P 】:「應用程式」拼接資料 Q =
SELECT sc FROM score WHERE id='-1' union select @@datadir -- '
[2] - 【 Q --> R 】:「資料庫 」將 Q 作為 SQL 語句執行,返回結果 R =
/var/sql/233.db
- 【 R 】:「應用程式」接收資料 R,將 R 返回給使用者
基於報錯注入
應用程式不返回查詢結果,反而返回 sql 資料庫的報錯資訊。其流程如下:
- 【 P 】:「使用者輸入」:P =
' and updatexml(1,concat(1,database()),1)#
- 【 Q = X + P 】:「應用程式」:Q =
SELECT sc FROM score WHERE id='' and updatexml(1,concat(1,database()),1)#'
[3] - 【 Q --> R 】:「資料庫 」:Q --> R = updatexml 執行錯誤的資訊,其中帶有
concat(1,database())
的執行結果。 - 【 R 】:「應用程式」:將 R 返回給使用者
基於布林注入
應用程式不會返回查詢結果,而是會返回一個狀態。比如:
- 0 , 1
- 真, 假
- 高,中,低(當然三種狀態)
其中前兩個只有兩種狀態的資訊被稱為布林值。流程如下:
- 【 P 】:「使用者輸入」:P =
1' and length((select @@version)) > 0 #
[4] - 【 Q = X + P 】:「應用程式」:Q =
SELECT sc FROM score WHERE id='1' and length((select @@version)) > 0 #'
- 【 Q --> R 】:「資料庫 」:Q --> R =「真」 或 「假」
- 【 R 】:「應用程式」:將 R 返回給使用者
基於時間注入
應用程式僅返回一種狀態,意為當前查詢結束。但是沒有返回任何資料或者其他狀態。流程如下:
- 【 C 】:「計時程式」使用者開始計時 C
- 【 P 】:「使用者輸入」P =
1' and length((select @@version))>0 and sleep(5) #
- 【 Q = X + P 】:「應用程式」Q =
SELECT sc FROM score WHERE id='1' and length(version()) and sleep(5) > 0 #'
- 【 Q --> R 】:「資料庫 」Q --> R =「sleep(5),並返回資料」 或 「不執行,返回資料」
- 【 R 】:「應用程式」將 R 返回給使用者
- 【 C 】:「計時程式」結束計時 C
可以看出,時間注入與布林注入本質相同。只是前者返回的是 「無延遲,查詢結束」與「延遲 5 秒,查詢結束」這兩種特殊的狀態。
二次注入
之前的注入都是一次輸入,一次輸出式的。而二次注入,則是兩次輸入,兩次輸出。
用一個 web 應用程式舉例,假設它的業務邏輯為:
- 【 P 】:「使用者輸入」資料 P
- 【 P --> P' 】:「應用程式」將 P 中的特殊字元進行轉義,得到 P'
- 【 Q = X + P' 】:「應用程式」將 P' 與其他資料拼接
- 【 Q --> R 】:「資料庫 」Q 執行後,P' 將轉換[5]為 P 並儲存。同時返回一個結果資訊 R
- 【 R 】:「應用程式」將 R 返回給使用者
- 第二次查詢
- 【 R 】:「使用者輸入」資料 R
- 【 R --> R' 】:「應用程式」將 R 中特殊字元轉義,得到 R'
- 【 Q2 = X2 + R' 】:「應用程式」將 R' 與其他資料拼接
- 【 Q2 --> P 】:「資料庫 」Q2 執行後,返回結果資訊 P[6]
- 【 Q3 = X3 + P 】:「應用程式」將 P 與其他資料拼接(注意:資料 P 特殊字元沒有被轉義!)
- 【 Q3 --> R2 】:「資料庫 」Q3 執行後,返回 R2
- 【 R2 】:「應用程式」將 R2 返回給使用者
從業務看出,第二查詢的過程中,應用程式在拼接資料 P 時沒有對 P 進行轉義。這意味著我們可以在第一次查詢時,將注入語句 P 儲存進資料庫,在第二次查詢執行含有 P 的語句。來成功注入。
兩個減號之後是有一個空格的。如果這資料通過 url 傳輸的話。需要將空格等價替換成
+
再傳輸。 ↩︎可以觀察到資料 P 在 Q 末尾的 WHERE 中,這不是必然,而是常見情況。特殊狀態下,P 可能在 SELECT、GROUP BY 等之中。 ↩︎
updatexml 函式需要三個引數,因此
concat(1,database())
前後的 1 只是佔位置的引數。 ↩︎如果這裡
select @@version
不加括號,將會被length
認為是變數名。引發語法錯誤。 ↩︎資料庫在儲存資料時,會自動去掉資料中的轉義符號。 ↩︎
這裡的結果 P 就是第一次訪問時儲存的資料 P。 ↩︎