Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
寫在前面的話
SQL注入可以稱得上是最臭名昭著的安全漏洞了,而SQL注入漏洞也已經給整個網絡世界造成了巨大的破壞。針對SQL漏洞,研究人員也已經開發出了多種不同的利用技術來實施攻擊,包括非法訪問存儲在遠程數據庫中的數據、從服務器讀/寫數據、以及通過MSSQL的SA賬號完成任意命令執行等等。
在這篇文章中,我們準備利用一個存在于文件下載函數中的SQL注入漏洞,我們將利用存在漏洞的SQL語句并從遠程服務器中下載我們所需要的文件。假設現在有一個由用戶提供的參數,我們可以將這個參數添加到SQL查詢語句之中,當SQL語句處理完這個參數之后,查詢語句將會返回我們目標文件的地址。現在,如果我們將這條SQL查詢語句返回的文件地址提供給文件下載函數的話,我們就可以下載服務器中的本地文件了。在這種情況下,如果Web應用沒有對用戶的輸入進行檢測的話,攻擊者就可以在知道文件地址的情況下通過構造SQL語句來下載任意文件了,不過這個文件必須要有可讀權限才行。
所以在這篇文章中,我將會給大家講解這個SQL注入漏洞。實際上,這個漏洞是PHP文件下載函數中的一個本地文件泄露漏洞,我們所使用的Web應用后端為MySQL數據庫。
實驗環境
為了演示漏洞的利用過程,我們需要在設備上完成以下配置:
1.Web服務器(我用的是Apache);
2.PHP環境
3.MySQL數據庫
4.包含漏洞的Web應用樣本,你可以從我的GitHub上下載【下載地址】。
下載樣本代碼,然后用以下信息創建一個MySQL用戶:
=dsqli
=
And name = dsqli
為了創建數據庫,用戶必須要有數據庫的讀權限,請大家按照下面的步驟進行操作。
首先以root賬號登錄MySQL的終端控制臺,然后用下面的語句創建一個新的數據庫:
Create dsqli;
然后創建新用戶“dsqli”,密碼為“”,并賦予數據庫dsqli的讀/寫權限:
grant all on dsqli.* to dsqli@ BY '';
當你設置好了數據庫和用戶賬號之后,直接將據庫文件dsqli.sql導入到dsqli數據庫中。導入成功之后,數據庫中將會出現一個表:
i) (列名為id、、)
漏洞分析
我們給出的漏洞利用技術只有當SQL查詢語句的返回值會傳遞給目標Web應用的文件下載函數時才能奏效,我們的樣本代碼中存在SQL注入漏洞,而SQl查詢語句返回的數據會被傳遞給PHP的文件下載函數()。
我們可以從上面這段代碼中看到,如果我們可以想辦法修改查詢語句,然后讓SQL查詢語句將服務器本地文件或Web應用源碼文件的地址保存在$row[‘’]變量之中,那么()函數將會幫我們把這個文件下載下來。實際上,我們只需要在SQL查詢中使用UNION就可以輕松實現注入,在注入的過程中,我們需要提供目標文件完整的本地路徑,然后再以十六進制格式下載該文件。
漏洞利用
1. 通過SQL注入獲取服務器本地文件
首先,我們要確定目標Web應用是否存在基于整型的SQL注入漏洞或基于字符串的SQL注入漏洞。確定之后,我們還要確定SQL語句所查詢的表中有多少列。
在我們給出的樣本中,Web應用存在基于整型的SQL注入漏洞。
確定表中有多少列:
首先我們要知道,如果查詢語句正確執行并給出了輸出結果,我們將會看到彈出的文件下載窗口。那么為了確定表中列的數量,我們需要注入order by子句并不斷增加order by的值,直到Web應用停止彈出下載窗口為止。
樣本Web應用的index.php中存在SQL注入漏洞,index.php頁面中的文件下載請求參數如下:
image=1&=
現在,我們可以嘗試用order by字句枚舉出列數量。
Page Index.php
Post
image=1 order by 1--&=
現在,向語句中注入參數‘order by 5–’
Page index.php
Post
image=1 order by 5--&=
當我們將order by字句的值從1增加到5之后,Web應用就不會再彈出下載窗口了,所以select語句所使用的列值肯定是小于5的。接下來我們試一下‘order by 4’:
Page index.php
Post
image=1 order by 4--&=
從上圖中可以看到,我們剛才的語句導致頁面出現了錯誤,接下來嘗試一下‘order by 3’:
Page index.php
Post
image=1 order by 3--&=
這一次Web頁面終于彈出了文件下載窗口,所以這個表的列數量為3。現在我們可以嘗試用UNION語句完成注入了。注入后的請求如下:
Page index.php
Post
image=1 union select 1,2,3--&=
這條注入請求同樣會讓頁面彈出文件下載窗口。
確定用于文件下載的列:
現在既然我們已經確定了表中的列數量,接下來我們就要找到那個允許我們定義文件路徑的列。我們需要將文件路徑的十六進制依次填入語句的列編號之中,直到我們找到了目標列為止。
接下來,我們可以嘗試下載/etc/passwd文件。首先我們需要將字符串‘/etc/passwd’轉換為十六進制格式(我使用的是Firefox的hex bar插件),然后在字符串前面加上一個‘0x’。我們現在還不能確定Web應用到底是用數據庫表中的哪一列來獲取文件路徑的,所以我們先用‘/etc/passwd’的十六進制值替換union select語句中的‘1’,具體如下圖所示:
修改之前的查詢語句如下:
Page index.php
Post
image=1 union select 1,2,3--&=
修改之后的查詢語句如下:
Page index.php
Post
image=1 union select 1,2,3--&=
我們需要將包含漏洞的參數值修改為一個無效值,這樣一來,當原本的查詢語句跟我們注入的查詢子句一起執行時,原本的查詢語句將不會返回任何內容,而我們注入的查詢語句將會返回我們想要的結果。如果我們沒有進行這樣的修改,那么頁面執行的仍然是原本合法的文件下載請求。修改之后的查詢語句如下(修改了image的值):
Page index.php
Post
image=1337 union select 1,2,3--&=
好的,如果我們注入的是能夠將文件地址返回給文件下載函數的列,那么Web應用將會幫我們下載/etc/passwd文件。
不幸的是,Web應用彈出了錯誤信息,這意味著我們選錯了一個列。接下來用第二列試一下。修改后的請求如下:
Page index.php
Post
image=1337 union select 1,,3-- &=
還是沒有成功,那么第三列應該沒問題了吧?修改后的請求如下:
Page index.php
Post
image=1337 union select 1,2,-- &=
果不其然,這一次終于成功了,我們成功將Web應用的passwd文件下載了下來。當然了,如果我們能夠直到Web應用的文件結構或路徑,我們甚至還可以下載Web應用的源代碼。對于PHP項目來說,我們可以通過修改參數類型來獲取Web應用的本地目錄結構。在我們的實驗環境中,原始的請求如下:
image=1&=
將‘image’參數修改為數組類型之后,請求如下:
image[]=1&=
現在,我們就知道了服務器的本地目錄結構了,我們只需要將文件路徑的十六進制值填入查詢語句的列編號之中就可以下載任意文件了。如果你對SQL注入漏洞感興趣的話,可以親自動手搭建環境并進行測試,相信你肯定會在這個過程中收獲不少的東西。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。