嗨! 好久不見,這是我在今年年初的研究,講述如何尋找一款知名行動裝置管理產品的漏洞,並繞過層層保護取得遠端程式碼執行的故事! 其中的漏洞經回報後在六月由官方釋出修補程式並緊急通知他們的客戶,而我們也在修補程式釋出 15 天後發現 Facebook 並未及時更新,因此透過漏洞取得伺服器權限並回報給 Facebook!
此份研究同時發表於 HITCON 2020,你可以從這裡取得這次演講的投影片!
身為一個專業的紅隊,我們一直在尋找著更快速可以從外部進入企業內網的最佳途徑! 如同我們去年在 Black Hat USA 發表的研究,SSL VPN 理所當然會放在外部網路,成為保護著網路安全、使員工進入內部網路的基礎設施,而當你所信任、並且用來保護你安全的設備不再安全了,你該怎麼辦?
由此為發想,我們開始尋找著有沒有新的企業網路脆弱點可當成我們紅隊攻擊滲透企業的初始進入點,在調查的過程中我們對 MDM/UEM 開始產生了興趣,而這篇文章就是從此發展出來的研究成果!
什麼是 MDM/UEM ?
Mobile Device Management,簡稱 MDM,約是在 2012 年間,個人手機、平板裝置開始興起時,為了使企業更好的管理員工的 BYOD 裝置,應運而生的資產盤點系統,企業可以透過 MDM 產品,管理員工的行動裝置,確保裝置只在信任的環境、政策下運行,也可以從中心的端點伺服器,針對所控制的手機,部署應用程式、安裝憑證甚至遠端操控以管理企業資產,更可以在裝置遺失時,透過 MDM 遠端上鎖,或是抹除整台裝置資料達到企業隱私不外漏的目的!
UEM (Unified Endpoint Management) 則為近幾年來更新的一個術語,其核心皆為行動裝置的管理,只是 UEM 一詞包含更廣的裝置定義! 我們以下皆用 MDM 一詞來代指同類產品。
我們的目標
MDM 作為一個中心化的端點控制系統,可以控制、並管理旗下所有員工個人裝置! 對日益壯大的企業來說,絕對是一個最佳的資產盤點產品,相對的,對駭客來說也是! 而為了管理來自世界各地的員工裝置連線,MDM 又勢必得曝露在外網。 一個可以「管理員工裝置」又「放置在外網」的設備,這對我們的紅隊演練來說無疑是最棒的滲透管道!
另外,從這幾年的安全趨勢也不難發現 MDM 逐漸成為駭客、APT 組織的首選目標! 誘使受害者同意惡意的 MDM 成為你裝置的 C&C 伺服器,或是乾脆入侵企業放置在外網的 MDM 設備,在批次地派送行動裝置木馬感染所有企業員工手機、電腦,以達到進一步的攻擊! 這些都已成真,詳細的報告可參閱 Cisco Talos 團隊所發表的 Malicious MDM: Let’s Hide This App 以及 CheckPoint CPR 團隊所發表的 First seen in the wild - Malware uses Corporate MDM as attack vector!
從前面的幾個案例我們得知 MDM 對於企業安全來說,是一個很好的切入點,因此我們開始研究相關的攻擊面! 而市面上 MDM 廠商有非常多,各個大廠如 Microsoft、IBM 甚至 Apple 都有推出自己的 MDM 產品,我們要挑選哪個開始成為我們的研究對象呢?
因此我們透過公開情報列舉了市面上常見的 MDM 產品,並配合各家特徵對全世界進行了一次掃描,發現最多企業使用的 MDM 為 VMware AirWatch 與 MobileIron 這兩套產品! 至於要挑哪一家研究呢? 我們選擇了後者,除了考量到大部分的客戶都是使用 MobileIron 外,另外一個吸引我的點則是 Facebook 也是他們的客戶! 從我們在 2016 年發表的 How I Hacked Facebook, and Found Someone’s Backdoor Script 研究中,就已發現 Facebook 使用 MobileIron 作為他們的 MDM 解決方案!
根據 MobileIron 官方網站描述,至少有 20000+ 的企業使用 MobileIron 當成他們的 MDM 解決方案,而根據我們實際對全世界的掃描,也至少有 15% 以上的財富世界 500 大企業使用 MobileIron 且曝露在外網(實際上一定更多),因此,尋找 MobileIron 的漏洞也就變成我們的首要目標!
如何開始研究
從過往出現過的漏洞可以得知 MobileIron 並沒有受到太多安全人員研究,其中原因除了 MDM 這個攻擊向量尚未廣為人知外,另一個可能是因為關於 MobileIron 的相關韌體太難取得,研究一款設備最大的問題是如何從純粹的黑箱,到可以分析的灰箱、甚至白箱! 由於無法從官網下載韌體,我們花費了好幾天嘗試著各種關鍵字在網路上尋找可利用的公開資訊,最後才在 Goolge Search 索引到的其中一個公開網站根目錄上發現疑似是開發商測試用的 RPM 包。
下載回的韌體為 2018 年初的版本,離現在也有很長一段時間,也許核心程式碼也大改過,不過總比什麼都沒有好,因此我們就從這份檔案開始研究起。
備註: 經通知 MobileIron 官方後,此開發商網站已關閉。
如何尋找漏洞
整個 MobileIron 使用 Java 作為主要開發語言,對外開放的連接埠為 443, 8443, 9997,各個連接埠對應功能如下:
- 443 為使用者裝置註冊介面
- 8443 為設備管理介面
- 9997 為一個 MobileIron 私有的裝置同步協定 (MI Protocol)
三個連接埠皆透過 TLS 保護連線的安全性及完整性,網頁部分則是透過 Apache 的 Reverse Proxy 架構將連線導至後方,由 Tomcat 部署的網頁應用處理,網頁應用則由 Spring MVC 開發。
由於使用的技術架構相對新,傳統類型的漏洞如 SQL Injection 也較難從單一的點來發現,因此理解程式邏輯並配合架構層面的攻擊就變成我們這次尋找漏洞的主要目標!
這次的漏洞也很簡單,主要是 Web Service 使用了 Hessian 格式處理資料進而產生了反序列化的弱點! 雖然漏洞一句話就可以解釋完了,但懂的人才知道反序列化並不代表你可以做任何事,接下來的利用才是精彩的地方!
現在已知 MobileIron 在處理 Web Service 的地方存在 Hessian 反序列化漏洞! 但漏洞存在,並不代表我們碰得到漏洞,可以觸發 Hessian 反序列化的路徑分別在:
- 一般使用者介面 -
https://mobileiron/mifs/services/
- 管理介面 -
https://mobileiron:8443/mifs/services/
管理介面基本上沒有任何阻擋,可以輕鬆的碰到 Web Service,而一般使用者介面的 Web Service 則無法存取,這對我們來說是一個致命性的打擊,由於大部分企業的網路架構並不會將管理介面的連接埠開放在外部網路,因此只能攻擊管理介面對於的利用程度並不大,因此我們必須尋找其他的方式去觸發這個漏洞!
仔細觀察 MobileIron 的阻擋方式,發現它是透過在 Apache 上使用 Rewrite Rules 去阻擋對一般使用者介面 Web Service 的存取:
RewriteRule ^/mifs/services/(.*)$ https://%{SERVER_NAME}:8443/mifs/services/$1 [R=307,L]
RewriteRule ^/mifs/services [F]
嗯,很棒! 使用 Reverse Proxy 架構而且是在前面那層做阻擋,你是否想到什麼呢?
沒錯! 就是我們在 2015 年發現,並且在 Black Hat USA 2018 上所發表的針對 Reverse Proxy 架構的新攻擊面 Breaking Parser Logic! 這個優秀的技巧最近也被很好的利用在 CVE-2020-5902,F5 BIG-IP TMUI 的遠端程式碼執行上!
透過 Apache 與 Tomcat 對路徑理解的不一致,我們可以透過以下方式繞過 Rewrite Rule 再一次攻擊 Web Service!
https://mobileiron/mifs/.;/services/someService
碰! 因此現在不管是 8443 的管理介面還是 443 的一般使用者介面,我們都可以碰到有 Hessian 反序列化存在的 Web Service 了!
如何利用漏洞
現在讓我們回到 Hessian 反序列化的利用上! 針對 Hessian 反序列化,Moritz Bechler 已經在他的 Java Unmarshaller Security 中做了一個很詳細的研究報告! 從他所開源的 marshalsec 原始碼中,我們也學習到 Hessian 在反序列化過程中除了透過 HashMap 觸發 equals()
以及 hashcode()
等觸發點外,也可透過 XString
串出 toString()
,而目前關於 Hessian 反序列化已存在的利用鏈有四條:
- Apache XBean
- Caucho Resin
- Spring AOP
- ROME EqualsBean/ToStringBean
而根據我們的目標環境,可以觸發的只有 Spring AOP 這條利用鏈!
Name | Effect | |
---|---|---|
x | Apache XBean | JNDI 注入 |
x | Caucho Resin | JNDI 注入 |
√ | Spring AOP | JNDI 注入 |
x | ROME EqualsBean | RCE |
無論如何,我們現在有了 JNDI 注入後,接下來只要透過 Alvaro Muñoz 與 Oleksandr Mirosh 在 Black Hat USA 2016 上所發表的 A Journey From JNDI/LDAP to Remote Code Execution Dream Land 就可以取得遠端程式碼執行了… 甘安內?
自從 Alvaro Muñoz 與 Oleksandr Mirosh 在 Black Hat 發表了這個新的攻擊向量後,不知道幫助了多少大大小小的駭客,甚至會有人認為「遇到反序列化就用 JNDI 送就對了!」,但自從 2018 年十月,Java 終於把關於 JNDI 注入的最後一塊拼圖給修復,這個修復被記載在 CVE-2018-3149 中,自此之後,所有 Java 高於 8u181, 7u191, 6u201 的版本皆無法透過 JNDI/LDAP 的方式執行程式碼,因此若要在最新版本的 MobileIron 上實現攻擊,我們勢必得面對這個問題!
關於 CVE-2018-3149,是透過將 com.sun.jndi.ldap.object.trustURLCodebase
的預設值改為 False
的方式以達到禁止攻擊者下載遠端 Bytecode 取得執行程式碼。
但幸運的是,我們依然可以透過 JNDI 的 Naming Reference 到本機既有的 Class Factory 上! 透過類似 Return-Oriented Programming 的概念,尋找本機 ClassPath 中可利用的類別去做更進一步的利用,詳細的手法可參考由 Michael Stepankin 在 2019 年年初所發表的 Exploiting JNDI Injections in Java,裡面詳細敘述了如何透過 Tomcat 的 BeanFactory
去載入 ELProcessor
達成任意程式碼執行!
這條路看似通暢,但實際上卻差那麼一點,由於 ELProcessor
在 Tomcat 8 後才被引入,因此上面的繞過方式只能在 Tomcat 版本大於 8 後的某個版本才能成功,而我們的目標則是 Tomcat 7.x,因此得為 BeanFactory
尋找一個新的利用鏈! 而經過搜尋,發現在 Welkin 的文章中所提到:
除了 javax.el.ELProcessor,当然也还有很多其他的类符合条件可以作为 beanClass 注入到 BeanFactory 中实现利用。举个例子,如果目标机器 classpath 中有 groovy 的库,则可以结合之前 Orange 师傅发过的 Jenkins 的漏洞实现利用
目標的 ClassPath 上剛好有 Groovy 存在! 於是我們又讓 Meta Programming 偉大了一次 :D
然而事實上,目標伺服器上 Groovy 版本為 1.5.6,是一個距今十年前老舊到不支援 Meta Programming 的版本,所以我們最後還是基於 Groovy 的程式碼,重新尋找了一個在 GroovyShell
上的利用鏈! 詳細的利用鏈可參考我送給 JNDI-Injection-Bypass 的這個 Pull Request!
攻擊 Facebook
現在我們已經有了一個基於 JNDI
+ BeanFactory
+ GroovyShell
的完美遠端程式碼執行漏洞,接下來就開始攻擊 Facebook 吧! 從前文提到,我們在 2016 年時就已知 Facebook 使用 MobileIron 當作他們的 MDM 解決方案,雖然現在再檢查一次發現首頁直接變成 403 Forbidden 了,不過幸運的是 Web Service 層並無阻擋!
s
萬事俱備,只欠東風! 正當要攻擊 Facebook 的前幾天,我們突然想到,從上次進入 Facebook 伺服器的經驗,由於安全上的考量,Facebook 似乎會禁止所有對外部非法的連線,這點對我們 JNDI 注入攻擊有著至關重要的影響! 首先,JNDI 注入的核心就是透過受害者連線至攻擊者控制的惡意伺服器,並接收回傳的惡意 Naming Reference 後所導致的一系列利用,但現在連最開始的連線到攻擊者的惡意伺服器都無法,更別談後續的利用。
自此,我們關於 JNDI 注入的路已全被封殺,只能回到 Hessian 反序列化重新思考! 而現有的利用鏈皆無法達到遠端程式碼執行,所以我們勢必得拋棄 JNDI 注入,尋找一個新的利用鏈!
為了尋找新的利用鏈,必須先深入理解已存在利用鏈的原理及成因,在重讀 Java Unmarshaller Security 的論文後,我對其中一句話感到了好奇:
Cannot restore Groovy’s MethodClosure as readResolve() is called which throws an exception.
哦,為什麼作者要特地補上這句話呢? 我開始有個猜想:
作者評估過把 Groovy 當成利用鏈的可行性,雖然被限制住了,但一定覺得有機會才會寫進論文中!
從這個猜想出發,雖然 Groovy 的利用鏈被 readResolve()
限制住了,但剛好我們目標版本的 Groovy 很舊,說不定尚未把這個限制加入程式庫!
我們比較了一下 Groovy-1.5.6 與最新版本位於 groovy/runtime/MethodClosure.java
中的 readSolve()
實現:
$ diff 1_5_6/MethodClosure.java 3_0_4/MethodClosure.java
> private Object readResolve() {
> if (ALLOW_RESOLVE) {
> return this;
> }
> throw new UnsupportedOperationException();
> }
可以看到的確在舊版是沒有 ALLOW_RESOLVE
限制的,而後來經過考古後也發現,這個限制其實 Groovy 自己為了因應 2015 年所出現 Java 反序列化漏洞的減緩措施,因此也被分配了 CVE-2015-3253 這個漏洞編號! 由於 Groovy 只是一個只在內部使用、不會對外的小配角,因此在沒有特別需求下開發者也不會特地去更新它,因此成為了我們攻擊鏈的一環! 這也再一次驗證了「任何看似舉無輕重的小元件,都有可能成為你被攻擊的主因」!
最後,當然! 我們成功的取得在 Facebook 伺服器上的 Shell,以下是影片:
漏洞通報與修復
我們約在三月時完成整個漏洞研究,並在 4/3 日將研究成果寫成報告,透過 [email protected]
回報給 MobileIron! 官方收到後著手開始修復,在 6/15 釋出修補程式並記錄了三個 CVE 編號,詳細的修復方式請參閱 MobileIron 官方網站!
- CVE-2020-15505 - Remote Code Execution
- CVE-2020-15506 - Authentication Bypass
- CVE-2020-15507 - Arbitrary File Reading
當官方釋出修補程式後,我們也開始監控世界上所有有使用 MobileIron 企業的修復狀況,這裡只單純檢查靜態檔案的 Last-Modified
Header,結果僅供參考不完全代表實際情況(Unknown 代表未開 443/8443 無法利用):
與此同時,我們也持續監控著 Facebook,並在 15 天確認都未修補後於 7/2 日成功進入 Facebook 伺服器後回報 Facebook Bug Bounty Program!
結語
到此,我們已經成功示範了如何尋找一個 MDM 伺服器的漏洞! 從繞過 Java 語言層級的保護、網路限制,到寫出攻擊程式並成功的利用在 Bug Bounty Program 上! 因為文長,還有許多來不及分享的故事,這裡僅條列一下供有興趣繼續研究的人參考!
- 如何從 MDM 伺服器,控制回員工的手機裝置
- 如何分析 MobileIron 的私有 MI Protocol
- CVE-2020-15506 本質上其實是一個很有趣的認證繞過漏洞
希望這篇文章能夠喚起大眾對於 MDM 攻擊面的注意,以及企業安全的重要性! 感謝收看 :D