來自i春秋作者:萬年死宅

目錄

root@1~# Training: MySQL II的簡單分析 root@2~# MySQL高級注射技巧load_file()來讀文件 root@3~# MySQL高級注射技巧into otfile來getshell

root@1~# Training: MySQL II的簡單分析

OK,昨天的Training:MySQL I給大家的啟發很大吧。總之,對我啟發很大,因為,我就是從這道題開始才真正的算是開始了解MySQL注射的(之前就是背注射語句,然后套。。。) 好了,我們不廢話,直接來看這道題: 小宅的傳送門 OK,大家可以先嘗試解一下,然后在回來繼續看這份教程,首先,我們還是先來看高亮的代碼: 小宅的傳送門 我們定位到HTML的Form表單(68~83行):

我們注意表單的method為POST,要傳送的參數是username和password,于是定位到接收參數的地方(10~13行):

我們看到接收了POST參數username和password就調用了auth2_onLogin()函數,我們跟蹤到該函數的定義處(36~66行):

我們來看函數的流程,可以發現于昨天的No.6paper極其相似,但是,有一處不同,就是認證不同了,我們來觀察一下。首先是用于我們可控的SQL語句不同了(42行): 本次的SQL語句成了這樣,接著,我們來看44~47行,這是和上道題一樣的判斷,只是SQL語句變了,但是還是一個道理:

if (false === ($result = $db->queryFirst($query)))

可以看到,還是調用result,然后以這個整體(也就是這次查詢的返回值)與false進行比較。當為false時自然就是說查詢語句失敗,例如,傳入“xxx”,SQL語句則是:

SELECT * FROM users WHERE username='xxx';

若查詢失敗,則證明不存在xxx這條記錄,若查詢成功則證明存在xxx這條記錄。這次的查詢語句還有不同的是select的是*,所以,我們來看下users表的表結構(2~8行):

可以看到這個users表里有三個字段,分別是:“userid,username,password”。因為我們select的是*所以$result里就同時存在這三個與username同行的userid和password。 接著,我們來看重頭戲,新的認證檢測步驟(50~56行):

我們來看這個新增的步驟:

if ($result['password'] !== $password)

這個if語句的條件是查詢結果里的與我們賦值的username同行的password是否與我們傳入的password相同,如果不相同則執行if里的內容。 看起來簡直天衣無縫,這樣的驗證從邏輯上來講幾乎沒有問題了,所以,我們的突破口,絕不會在PHP代碼上。 于是,我們就發現這次的SQL語句也是存在注射漏洞的,因為我們來看這個代碼片段:

從圖中可以看到,從SQL語句的生成到查詢之間并未進行任何過濾,所以存在SQL注射。所以問題就出在我們可控的SQL語句上,我就提示到這里,大家先自己動動腦筋,想想怎么繞過認證。

我們得清楚,首先,我們不知道正確的username和password,而且不是以SQL的返回值來認證的,那怎么辦?

這個,其實解決方案,我在No.5paper里講過,就不知道大家有沒印象了。

好了,大家想完之后呢,就來看正確的解題思路吧。 首先,既然我們不知道正確的用戶名和密碼,那我們就構造啊,什么意思呢?

大家記不記得UNION的神奇功效,假設我們如下SQL語句:

SELECT A FROM B WHERE C='$aaa'

假設在B表里有C等于111,但是我們不知道,那么如果我們構造如下$aaa的值會發生什么?

xxx' UNION SELECT 1#

這樣一拼接就成了:

SELECT A FROM B WHERE C='xxx' UNION SELECT 1#'

所以A就成了1,對吧,嘿嘿,其實就是這么簡單,只是由于我們對SQL的理解還不夠深,才導致我們一時半會沒想出解法。 于是我們在還去看題里的SQL語句:

SELECT * FROM users WHERE username='$username';

所以我們構造:

xxx' UNION SELECT 1,'test','123456'#

就拼接成了:

SELECT * FROM users WHERE username='xxx' UNION SELECT 1,'test','123456'#';

由于xxx這個username本就不存在,所以查詢結果自然的變成了UNION的,于是userid變為1,username變為test,而password變為123456。

所以,我們username填"xxx' UNION SELECT 1,'test','123456'#",password填123456就OK了嗎?我們試試就知道了,如下圖:

我們點Login聽天由命吧,哈哈:

密碼錯誤!知道為什么嗎?恩?嘿嘿,大家細想一個細節,在PHP程序中處理我們傳入password的細節(在40行,哈哈):

知道問題出在哪里了嗎?哈哈,對的,我們UNION的password一定要是輸入的password的MD5值,當然,也可以是我們輸入的password是UNION的password的MD5值。 我們來試試看(123456的MD5值是:e10adc3949ba59abbe56e057f20f883e)。把username填成:"xxx' UNION SELECT 1,'test','e10adc3949ba59abbe56e057f20f883e'#",把password填成123456,我們來看: 結果是: 成功!Bypass了新的認證方式!但是,這道題并沒解出來,我們來看原題的題意:

要以admin的身份登錄,而不是test,所以,我們得稍稍的改一下payload:

xxx' UNION SELECT 1,'admin','e10adc3949ba59abbe56e057f20f883e'#

我們再來看: 來,和我一起歡呼!yeah!(O了,別**了,我們還有事呢。)

root@2~# MySQL高級注射技巧load_file()來讀文件

...

有關該文章更多內容可到 http://bbs.ichunqiu.com/thread-10359-1-1.html?from=paper 查看


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/27/