手工SQL注入尋找技巧

手工SQL注入尋找技巧

根據bugbountyforum.com的AMA版面,最常見的問題之一就是:如何測試服務器端漏洞,例如SQL注入?直到最近我還在努力解決這個問題(特別是關於SQL注入)。我發現,SQL注入經常被發現並被sqlmap利用的,之後我發現這個服務器對單引號的反應很奇怪。然而在過去的兩個月,我被迫深入到手工SQL注入發現,因為我的目標有一個很強的防火牆可以使sqlmap失效。在這兩個月裡我能夠找到超過10個SQL注入,從這些中我學到了很多。這個博客也會專注於分享我的過程和知識以及展示現實中的例子。我將會把這個博客分成兩個部分:發現和利用,因為這兩部分都需要很好的報告。最後,這個博客假設用的是MySQL,因為它擁有半數以上的市場份額。

發現

找到有效SQL注入的第一部分是發現漏洞。而其中最重要的部分是知道在你的輸入會在哪一SQL語境中結束。這裡有一些基本的例子:

· SELECT user_input FROM tournament ORDER BY region;

· INSERT INTO tbl_name (col1,col2) VALUES (15,user_input);

· DELETE FROM somelog WHERE texts ='user_input'

現在我們可以看到我們的user_input在不同語境中結束:在()之間,在’之間或者沒有任何分隔符。這些命令的共同之處是,一旦’作為輸入進行注入,它們就會失效。如果使用了不存在的系統變量,前兩個即使沒有分隔符也會給出一個錯誤。像:@@versionz'(取代@@version)。

一旦你能夠讓這個服務返回錯誤(主要是HTTP 500),你需要確認是SQL命令引起這個錯誤而不是一些類似數據解析器的東西。要做到這一點,你可以使用一系列技巧:

| 如果一個’導致錯誤,試著查看\’能否成功(因為反斜槓在MySQL中取消了單引號)

l 你也可以嘗試註釋掉’就會返回成功消息,就像:%23’或者--’。這是因為你告訴MYSQL忽略註釋之後的所有東西,包括額外的’。

l 如果’是不允許,你可以在有效和無效的系統變量之間比較,類似@@versionzvs @@version',或在無效函數和有效函數之間的比較:SLEP(5) vsSLEEP(5)。

l 有些時候你的輸入會在()之間結束,以確保你可以測試input)%23,也會查看你是否可以突破這些,例如利用UnionSQL注入( input)order by 5%23)。

l 如果正常的輸入只是一個整數,你可以嘗試減去一些量,然後查看減法是否有效( id=460-5 )。

l 試著看偶數的引號是否會返回成功(例如460''或460-'')並且奇數的引號會導致錯誤(460' 或460-''')。

例子

想要把這些弄清楚,你需要下面這個URL:

https://www.example.com/php/sales_dash_poc_handle.php?action=month-breakdown&type_of_report=billing&city=all&month=8&year=2017&poc=35141008

這個基本的URL返回一個狀態碼200。輸入poc=35141008'以及poc=35141008'%23返回錯誤500,但是poc=35141008''返回狀態200。這就提示,這個參數可能沒有使用任何分隔符,因此我嘗試了poc=35141008%23',它會返回狀態碼200。現在我們知道了我們可以在35141008和%23之間注入。在這之後我嘗試了一個簡單的35141008OR 2 LIKE 2%23,它起作用了,但是35141008 OR 2 LIKE 1%23返回錯誤500,在這裡證明布爾類型的SQL注入是可行的。然而,這並不總是如此簡單,而且這個例子並沒有顯示出太大的影響,這是下一章節的內容,證明數據檢索。

利用

在你找到SQL注入之後,你總是要嘗試證明輸出或者輸出中的敏感數據有差異。不幸的是這並不總是直截了當的,特別是防火牆和黑名單會妨礙你。這部分是幫助你繞過那些問題。

防火牆

當你處理防火牆時,你要做的第一件事是看你是否可以在一個設置中找到錯誤配置。對於大多數防火牆和CDN,你可以通過訪問真實IP並用真實域名作為主機值訪問不受保護的網站(防火牆在IP前面)。這裡第一步應該是找到網站的原始IP,使用追蹤某個網站所使用的IP服務通常不會太難(http://viewdns.info/iphistory/)。通常用在防護牆ip前的那一個是他們仍在使用的那一個(基本上就是後面所說的cloudflare 或 akamai)。在尋找真實IP時Shodan 也非常有用。

在你找到真實IP地址之後,嘗試訪問帶有真實主機HTTP頭信息的網站。在cURL中這部分會這樣工作的(添加頭文件也適用於sqlmap):

$ curl –header ‘Host: www.example.com‘ ‘https://54.165.170.2/‘ -v -k

很不幸我的目標被禁止了。所以我必須具有創造力。在這我發現通過給主機域名後面添加一個點(http://www.example.com.)不會受限制而且仍然允許我瀏覽這個直接IP。在你的/etc/hosts文件中添加:

54.165.170.2 http:www.example.com

就會允許你在瀏覽器中瀏覽http://www.example.com,並且在這之間沒有任何防火牆。從這開始,所有的限制都應該消失,而且SQL注入的利用應該相當容易

繞過黑名單

有時, 您無法繞過防火牆, 這將要求您繞過已就位的 (可能) 黑名單。這裡我最大的提示是, 谷歌是你的朋友。找到具有強大功能的利基功能, 要求您以某種方式提取數據。但是這裡有一些常見的提示:

1. 在查詢中使用註釋作為空格以破壞防火牆中的正則表達式或詞組。例如:2/dhab bc/OR/dahdshka/2/sd/LIKE/da/"2"/**/%23就是:2 OR 2=2%23。

2. 如上例所示,用 LIKE 代替 =,用 2 代替 1,用 ” 代替 ’ 。很多人都很懶,防火牆也是如此,走小路會讓許多防火牆措手不及。

3. 正如我上面說的用Google找niche函數。例如,我發現MID()和SUBSTRING()的工作方式一樣,然而,後一個是被禁止的,第一個不是。變量也是一樣的CURRENT_USER()是被禁止的,而CURRENT_USER不是。

把它們放在一起

從SQL注入發現,這很可能是我最喜歡的。因為利用真的非常難。所以我將詳細地描述它,並且希望你們可以從中學到一些東西。

我偶然發現這個URL:

https://www.example.com/php/analyticsExcel.php?action=res_unique_analytics&resid=2100935&start_date=2016-07-11 00:00:00&end_date=2017-08-11 23:59:59&action=res_unique_analytics&entity_type=restaurant

這裡我有2100935的合法訪問權,而且請求2100935將會導致未經驗證的錯誤。奇怪的是,在2100935後面添加一個引號,就會導致錯誤500,添加兩個引號就會使URL再次起作用。在這裡,為了讓利用更容易,我用www.example.com.繞過。在那裡,我試圖在輸入中找到一個地方在輸入中注入我自己的SQL命令,然而我沒有設法在字符串中插入註釋,因此我斷定這個查詢是非常複雜的。考慮到這一點我決定把側重點煩躁一個更簡單的OR語句上,這個語句幾乎可以在任何地方注入。在這我注意到' OR 1='1會返回狀態碼200,' OR 1='2,' AND1='1,' AND 1='2也都是一樣的。而且最終似乎沒有哪個sleep()命令有效果。

非常奇怪的是,我可以確定我注入的語法是正確的,但是沒有任何技巧可以提取數據。在這我嘗試' OR@@version=5,它會導致狀態碼200,以及' OR@@versionz=5,它會導致錯誤500。這至少證實我正在使用MySQL並表明注入確實在這裡。這裡指向MySQL的IF函數。我的想法是如果我可以根據if語句是真是假來返回一個無效函數,我就可以證明數據提取。由於MySQL似乎在驗證IF語句之前驗證了命令,但是進展並沒有如想象般順利。但是IF語句最終成為解決方案的一部分。在一個具有正整數的IF語句中輸入一個有效的SLEEP命令將會導致服務器超時,而從IF語句中返回一個簡單的整數時,將會迅速返回一個狀態碼200。從這裡我利用了下面的POC:

TRUE: if @@version starts with a 5:

2100935' OR IF(MID(@@version,1,1)='5',sleep(1),1)='2

Response:

HTTP/1.1 500 Internal Server Error

False: if @@version starts with a 4:

2100935' OR IF(MID(@@version,1,1)='4',sleep(1),1)='2

Response:

HTTP/1.1 200 OK

手工SQL注入尋找技巧

總結

如果注入一個單引號會在響應中導致不同的輸出,請嘗試使用這篇博客中列出的其他的技術,以查看你是否在處理SQL注入。在確定了你正在使用的SQL上下文之後,利用一個POC,它可以顯示敏感信息(基於error或union),或者根據問題是真是假(基於布爾和時間)來顯示輸出中的差異。


分享到:


相關文章: