0x01 前言
寫這篇文章的緣由其實還挺魔幻的,起因是在一次實戰滲透時通過弱口令拿下一個低權限用戶成功進入後台,在後台尋找功能點通過抓包分析,定位到目標系統後台存在SQL注入,通過os shell拿下內網之後閒着無聊就谷歌了下,發現這個系統的開發商是某某公司,同時cnvd也沒有收錄該產品,於是想着能不能撿漏搞個cnvd證書。
礙於信息檢索能力太差,只收集到屈指可數的幾個url,而且這幾個系統都沒有弱口令可以進入後台,因為進不了後台,就猜測後台的功能也都無法使用,漏洞無法復現,於是在知道肯定過不了的情況下還是硬着頭皮只交了幾個url上去(沒記錯通用漏洞需要至少3個以上驗證成功漏洞案例),結果果不其然,三審的時候給我駁回了。
不甘心,案例找不出來,我把代碼審計一遍還不行嗎?於是就通過webshell打包了一份代碼(因為是.net的站,就只打包了bin包下來),於是便有了這篇文章。
0x02 漏洞利用
還是先簡單聊聊sql注入如何拿下內網的吧(以前的一次實戰,沒有截圖,腦補一下,見諒)。
漏洞點抓包。
嘗試直接sqlmap拿下—os-shell,苦於沒有絕對路徑,就嘗試百度看看還有沒有其他漏洞,然而網上資料幾乎沒有,就在要放棄的時候從百度文庫中找到一線希望,找到了該系統的使用說明,從說明書中得知系統的mysql數據庫安裝路徑和web路徑在同一目錄下,於是通過—sql-shell使用。
獲取到mysql的安裝目錄,同時也就獲得了web目錄,最後就可以直接—os-shell了。
拿到os-shell之後先tasklist,沒有殺軟,不需要免殺;ping了下發現服務器出網,基礎操作certutil下載msf馬上線,先用msf上傳一個web shell到網站目錄(感覺拿到web shell後要放心點)。看了下權限,system,不用提權了;看了下systeminfo,08的機器,load kiwi模塊,讀取明文密碼;netstat看下3389端口,沒開啟,用註冊表開啟。msf起socks代理,mstsc遠程連接之。net view看了下沒有域,上傳fscan進行內網資產掃描,同時在桌面看到WinScp軟件,而且其中還保存着好幾台內網服務器,都是root權限,試了試都能連接上。這裡我下了個星號密碼查看器傳上去,想獲取它們的明文密碼,結果失敗了。谷歌了下,發現WinScp配置默認加密保存在註冊表中,可以修改保存方式為ini文件並用工具破解其密碼,於是修改之後dump到本地通過工具get到密碼。
另一邊fscan掃到了兩台服務器的弱密碼,還有幾台有redis未授權漏洞,都可以寫私鑰登錄。
此外,從sql備份文件中又找到另外平台的賬號密碼。
0x03 代碼審計
從webshell的文件管理處定位到漏洞文件Default.ashx,可以看到調用了UserInfo.Default這個類。
在bin包中找到對應dll文件,使用dnSpy反編譯得到源碼,開始審計。
結構如下:
首先全局搜索一下session關鍵字,沒有發現。再在所有外部引用中搜索session關鍵字,還是沒有發現,是個好兆頭,說明系統可能沒有對session進行驗證。
代碼第20行,定義ProcessRequest方法並將http請求體作為該方法的參數傳入,並在第22行定義httpCookie變量存儲當前cookie中鍵名為」WCMS.User」的數據,可以看到在代碼第23行,程序只進行了三種判斷,cookie不為空,cookie中UserID不為空且RoleID也不為空。
只要滿足上述三個條件,程序就會繼續處理請求,否則才返回204代碼報錯。
這裡由於身份校驗不嚴,導致攻擊者可以在沒有後台管理員權限的情況下也能執行相應操作。審計到這裡我興奮起來了,因為之前擔心系統會對session進行判斷就沒有對另外幾個站點進行復現,導致cnvd提交被駁回,然而現在完全不需要擔心了,因為系統根本就沒有對session進行驗證,只需要修改http請求中的host參數就可以實現漏洞的批量利用。
但是審計到這裡還沒有結束,我們繼續對sql注入漏洞的成因進行分析。
在代碼第32行,對action參數進行判斷,我們根據payload中的Read值,跟進到GetData()函數。
從代碼第190行,不難看出該函數並未對參數進行過濾,只進行了是否為空的判斷。
在代碼第197行程序還進行了RoleInfoID的校驗,擔心這裡可能會要求提供服務器中存在的id導致身份鑒權失敗,我們着重分析下這裡。
定義一個text變量接收結果,如果在http form表單中不存在RoleInfoID,就調用Lib.CommonFunction類中的GetRoleID()方法進行獲取,我們跟進後發現程序仍然只判斷了cookie是否存在,只有當cookie不存在時才會返回為空,導致代碼第198行判斷為假進而導致api返回為空。
如果cookie存在,會調用DESDec()函數將cookie中RoleID的值進行DES解密,並將結果保存以待後用。
這裡我根據源碼用c#重寫了下解密過程,並將payload中的RoleID用於解密,結果最後是亂碼(可能是我代碼沒寫對的鍋…)。
然後我用在線的DES工具解密出來又是正確的…(蚌埠住了,我寫的代碼就是屎嗚嗚嗚)。
然後我們再回到GetData()函數,代碼第186行通過Lib.Factory類中的CreateUserInfo()函數創建了DBHelper對象,並在第205行調用了GetItems()函數。
通過分析發現IDBHelper接口由Mysql.DBHelper類實現,跟進到DBHelper類的GetItems()函數進行分析。
代碼第302行,使用for循環遍歷之前text變量中的值,構造sql語句,使用where in語法對查詢結果進行限定。同時,我們注意到,搜索關鍵字keyWords到目前為止仍未進行任何的過濾,而且後續通過分析,發現開發者也未在全局使用預處理和參數化,導致keyWords參數易於受到攻擊。
綜上,雖然RoleID會用於獲取子賬號ID,然而如果數據庫中不存在該RoleID的用戶也沒有關係,因為我們的攻擊方式是基於時間的盲注,即使數據庫查詢返回為空,也不妨礙我們通過時間比較進行攻擊。因此可以下定結論,該漏洞在未經授權就可被利用。
整個流程如下圖所示:
0x04 後話
細心細心細心!