張小白的滲透之路(二)——SQL隱碼攻擊漏洞原理詳解

Litbai_zhang發表於2018-09-22

SQL隱碼攻擊漏洞簡介

亂七八糟的就不多說了,自己百度去

SQL隱碼攻擊原理

想要更好的學習SQL隱碼攻擊,那麼我們就必須要深入的瞭解每種資料庫的SQL語法及特性。下面通過一個經典的萬能密碼的例子帶大家來撥開一下SQL隱碼攻擊漏洞的神祕面紗。本次環境為:DVWA的第一關(DVWA是一個滲透環境,可以用來當作學習滲透的靶機)。實驗環境是PHP+MYSQL

如下圖是一個正常登入的表單
表單
輸入正確的密碼後,php程式會查詢資料庫,如果存在此使用者並且密碼是正確的,那麼登入肯定是成功的。使用者不存在或者密碼不正確,則會提示賬號或者密碼錯誤

登陸成功
登入成功
登入失敗
登陸失敗
我們接下來使用一個比較特殊的使用者“ admin’ or ‘1’='1 ”來登入,密碼可以隨意填寫或者不填,在點選登入按鈕之後發現是可以登入的。
結果如下
登陸成功
那麼問題到底出現在哪裡呢?
我們通過檢視原始碼可以發現,登入處最終呼叫result來實現登入。
原始碼審計
上述SQL語句意思非常清楚:在獲取到使用者輸入的username和password之後,和資料庫進行比對。若返回結果==1,那麼登陸成功。若返回其他值,那麼登陸失敗。
看起來這段程式碼是沒有什麼錯誤,現在我們提交賬戶admin,密碼為password,再對應執行語句原始碼,發現執行的SQL語句為

SELECT * FROM 'users' WHERE user = 'admin' AND password = 'password' 

在資料庫中,存在admin使用者,並且密碼為password,所以此時返回結果為1,所以通過驗證,使用者可以成功登入。

接下來繼續輸入特殊使用者admin’ or ‘1’='1 ,並對照執行語句,發現:

SELECT * FROM 'users' WHERE user = 'admin' or '1'='1' AND password = ''

終於找到問題的根源了
從開發人員的角度理解,SQL語句的本義是:
username=‘賬戶’ and password=‘密碼’
現在卻變為
username=‘賬戶’ or ‘1’=‘1’ and password=‘密碼’
因為在SQL語句中and的優先順序比or高,所以先執行’1’=‘1’ and password='密碼’判斷為假,然後因為username=‘admin’ or false為真,所以result=1即result=true順利通過驗證。
由此可見,SQL隱碼攻擊漏洞的形成原因就是:使用者輸入的資料被SQL直譯器執行。

注入漏洞分類

在測試注入漏洞之前,我們首先要搞清楚注入有哪些分類,這樣再去測試注入的時候就將會起到事半功倍的效果。
常見的SQL隱碼攻擊型別一般分為兩大類:數字型和字元型。也有人分的更多,但不管注入的型別如何,攻擊者的目標只有一個,就是繞過程式限制,使使用者輸入的資料帶入資料庫執行,利用資料庫的特殊性獲取更多的資訊或者更大的許可權。
數字型注入
當輸入的引數為整型的時候,比如ID,年齡,頁碼等,如果存在注入漏洞,則可以認為是數字型注入,數字型注入是最為簡單的一種。假設有URL為http://www.xxser.com/test.php?id=8,那麼我們可以對SQL語句進行猜測。
測試步驟:

  • http://www.xxser.com/test.php?id=8'
    SQL語句為:select * from table where id=8',這樣的語句肯定會出錯,導致指令碼程式無法從資料庫中正常獲取資料,從而使原來的頁面出現異常。
  • http://www.xxser.com/test.php?id=8 and 1=1
    SQ語句為:select * from table where id =8 and 1=1,語句執行正常,返回的資料與原始請求無任何差異
  • http://www.xxser.com/test.php?id=8 and 1=2
    SQL語句為:select * from table where id=8 and 1=2語句執行正常,但是無法查詢出資料,因為1=2始終為假,返回資料與原始請求有差異。
    如果以上三個步驟都滿足,則程式就可能存在SQL隱碼攻擊漏洞。
    這種數字型的注入最多出現在ASP、PHP等弱型別的語言當中,因為弱型別的語言會自動推匯出變數型別。打個比方,引數id=8,php會自動推導變數id的資料型別為int型別,那麼id=8 and 1=1 則會推導為String型別,這就是弱型別語言的特性。而對於java、C#這些強型別的語言,如果試圖把一個string轉換為int型別,則會丟擲異常,無法繼續執行。所以,強型別二點語言很少存在數字型注入漏洞,強型別語言在這方面會比弱型別語言有優勢。
    字元型注入
    當我們輸入的引數是string型別時,稱為字元型。數字型和字元型注入最大的區別在於:數字型別不需要單引號合併,而字串型別一般需要使用單引號來閉合。
  • 數字型例句如下:
select * from table where id = 8
  • 字元型例句如下:
select * from table where username = 'admin'

字元型注入最關鍵的就是如何閉合SQL語句以及註釋多餘語句或者對SQL語句的執行進行邏輯上的更改。
當攻擊者進行SQL隱碼攻擊時,如果輸入 admin and 1=1 ,則無法進行注入。因為 admin and 1=1 會被資料庫當作查詢的字串,SQL語句變為

select * from table where username = 'admin and 1=1'

這時候如果我們想要注入,那麼就必須要注意字串的閉合問題,輸入admin’ and 1=1 - - 就可以繼續注入,SQL語句如下

select * from table where username ='admin' and 1=1 - -'

只要是字元型的注入,都必須要閉合單引號以及註釋多餘的程式碼。

值得一提的SQL隱碼攻擊

通過翻閱大量的參考資料,張小白比較同意的一種觀點是:SQL隱碼攻擊只分為數字型和字元型。
但是很多人可能要問了,那不是還有Cookie注入、POST注入、盲注、延時等注入嗎?沒錯,但是大家可以仔細分析一下就會發現,這些型別的注入其實都是以上兩大類二點不同展現形式或者不同的展現位置罷了。

那麼怎麼去理解上面這段話呢?
我們都知道,對資料庫進行資料查詢的時候,輸入的資料一般只有兩種;一個是數字型別,比如where id = 1、where age >20,另外一種是字串型別,比如where name = ‘root’ 、where datetime > ‘2018-09-22’.
也許不同的資料庫的比較方式不一樣,但是代入資料庫查詢時一定是字串(嚴格的說,數字也是字串,在資料庫當中進行資料查詢時,where id ='1’也是合法的,只不過在查詢條件為數字時一般不會加單引號)。所以,無論是POST注入還是其他型別的注入,都可以歸納為數字型或者字元型注入。

那麼Cookie注入,POST注入等是怎麼一回事呢?其實這類注入主要通過注入的位置來分辨,比如有以下請求

POST /user/login.php HTTP/1.1
Host:www.secbug.org
Proxy-Connection:keep-alive
Content-Length:53
Cache-Control:max-age=0
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.17 (KHTML, like Gecko)
Chrom/24.0.1312.57 Safari/537.17 SE 2.X MetaSr 1.0
Content-type:application/x-www-form-urlencoded
Cookie:_jkb_10667=1

username=admin&password=123456

我想看了張小白的滲透之路(一)——HTTP詳解的小夥伴一定能夠很輕鬆的搞清楚上面這塊程式碼想要表達什麼意思。
我們可以看到此時呢為POST請求,但是POST資料中的username欄位存在漏洞,一般就直接說POST注入,卻不再考慮username是什麼型別的注入
如果此時的HTTP請求如下:

GET /user/login.php?username=admin&password=123456 HTTP/1.1
Host:www.secbug.org
Proxy-Connection:keep-alive
Content-Length:53
Cache-Control:max-age=0
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.17 (KHTML, like Gecko)
Chrom/24.0.1312.57 Safari/537.17 SE 2.X MetaSr 1.0
Content-type:application/x-www-form-urlencoded
Cookie:_jkb_10667=1

那麼是不是應該又叫做GET注入呢?
下面呢是張小白整理的一些注入叫法,大家可以參考一下

  • POST注入:注入欄位在POST資料中;
  • Cookie注入:注入欄位在Cookie資料中;
  • 延時注入:使用資料庫延時特性注入;
  • 搜尋注入:注入處為搜尋的地點;
  • base64注入:注入字串需要經過base64加密;

對於SQL隱碼攻擊更加深入的瞭解,大家可以嘗試在張小白的滲透之路(三)尋找到屬於自己的答案

相關文章