挖洞經驗 | Uber服務端響應中的API呼叫缺陷導致的賬戶劫持
今天分享的writeup是香港白帽Ron Chan (@ngalongc)發現的一個關於Uber網站的漏洞,他通過分析Uber的微服務架構和其中的API呼叫機制,利用其中的服務端響應缺陷,能以SSRF和目錄遍歷(PAth Traversal)方式獲取到服務端為使用者分配的token資訊,從而實現對使用者的賬戶劫持。雖然整個漏洞利用構造鏈亮點不多,但“Old but GOLD”,薑還是老的辣,漏洞還是老的好。
Uber微服務架構
微服務英文名稱Microservice,Microservice架構模式就是將整個Web應用組織為一系列小的Web服務。這些小的Web服務可以獨立地編譯及部署,並通過各自暴露的API介面相互通訊。它們彼此相互協作,作為一個整體為使用者提供功能,也可以獨立地進行修改和擴容。
Uber的Web應用服務體系是基於 很多微服務架構 部署的,由於微服務中會涉及到大量的REST模式,因此,在與各種Uber應用的互動過程中,Uber服務端難免會呼叫到一些REST API介面。就比如說,你要檢視某位司機的狀態資訊,Uber後端會涉及到類似如下的REST API介面呼叫:
https://localhost:1234/partner/PARTNER_UUID/trips?from=2018-01-01&to=2019-01-01
從請求響應中發現端倪
設計理論上來說,顯然,這種呼叫都是在Web應用後端(Backend)來執行實現的,因為在呼叫過程中,其內部的微服務架構沒有針對IDOR攻擊的安全檢查許可權。所以,矛盾點來了,如果這類API呼叫都是以預定的path/variables/host方式進行的,而且,這些呼叫是使用者無法控制的,那麼,Web應用後端(Backend)設定的身份驗證措施又有何用呢?
使用者確實不能控制這類API呼叫嗎?我覺得這裡要打個問號。2018年初,我在Uber網站partners.uber.com下發現了一個有意思的路徑(Endpoint),它用來查詢讀取Uber司機的服務狀態,其前端請求連結如下:
https://partners.uber.com/p3/money/statements/view/current
該查詢連結涉及的請求看不出什麼問題,但服務端對其的響應訊息中卻存在一些有意思的引數,如下:
{ "request": { "uri": { "protocol": "http:", "slashes": true, "auth": null, "host": "127.0.0.1:123", "port": "123", "hostname": "127.0.0.1", "hash": null, "search": "?earnings_structure_type=&locale=en&user_id=xxxxx", "query": "earnings_structure_type=&locale=en&user_id=xxxxx", "pathname": "/v1/partners/xxxxx/statements/current", "path": "/v1/partners/xxxxxx/statements/current?earnings_structure_type=&locale=en&user_id=xxxxx", "href": "http://127.0.0.1:123/v1/partners/xxxxx/statements/current?earnings_structure_type=&locale=en&user_id=xxxxxx" }, "token":"ACCESS_TOKEN_OF_USER", ....
從上述響應訊息可看出,涉及該查詢連結的後端API GET請求呼叫如下所示:
這是一個典型的後端REST API呼叫。
仔細觀察上述響應訊息,可見其中的API呼叫對current的請求來自於原始前端請求連結: https://partners.uber.com/p3/money/statements/view/current ,而且還會把 current 新增到 “pathname”引數的結尾,形成 “ /v1/partners/xxxxx/statements/current ” 。另外,呼叫中還包含其它查詢相關引數,如涉及收入結構型別的earnings_structure_type,以及查詢區域locale=en等。
上述響應訊息的有意思之處在於,第一,其中包含了應用使用者的訪問token鍵值對 – “token”:”ACCESS_TOKEN_OF_USER” ,這裡還曾出現過一個Uber第三方應用的token撤銷漏洞;第二,在查詢請求request中缺乏驗證呼叫者身份的 X-Auth-Token 頭,但是,在服務端響應訊息中竟然還返回了使用者的訪問token!
構造漏洞利用
這樣來看,在請求中,如果我們能以某種方式,通過把我當前賬戶相關的使用者ID數值(user_id或my_user_uuid) 更改為其他使用者對應的使用者ID數值(victim_id或victim_uuid),就可能實現對請求呼叫的操縱。之後,服務端通過這個其他使用者的使用者ID數值,會響應回來與其對應的賬戶token,那麼,有了這個token,我們就能實現對該使用者的賬號劫持了。
基於以上思路,需要找到一個具備以下條件的前端請求路徑(Endpoint):
能從其GET請求中傳遞任意相關引數;
能從其GET請求中傳遞經過編碼轉義的字元,防止一些不必要的字元解析和引數傳遞錯誤,如 %23 或 # 會截斷URL中的引數截斷;
服務端對GET請求能完整響應並可讀。
漏洞實現
最終,經過查詢分析,我發現了滿足以上測試條件的一個前端請求路徑(Endpoint):
https://partners.uber.com/p3/money/statements/view/4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa
Uber服務端對這個請求路徑的響應包含了如下的API GET請求呼叫:
"href": "http://127.0.0.1:123/v1/statements/4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa?earnings_structure_type=&locale=en&statement_uuid=4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa&user_id=your_user_id"
我覺得其中的uuid – 4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa,是用來在API GET請求呼叫中傳遞給path和query引數的,所以,我對原始的前端請求路徑(Endpoint)做了如下修改:
“/” 經url編碼後為%2f,哪想到,上述查詢連結的請求發起後,服務端響應的訊息竟然和修改之前是一樣的!那麼,也就間接說明可用 “../”來對目錄路徑進行轉義編碼,還能用它來進行目錄遍歷。接下來,我們可以用 .. / 這種目錄遍歷方式,構造直達服務端根目錄的前端請求連結,然後,到達根目錄後,可以構造請求,獲得服務端包含使用者token和API呼叫的響應,另外,還可以用 # 來截斷一些不必要的請求欄位。其實,這就是一種間接的服務端請求偽造(SSRF)結合目錄遍歷(PAth Traversal)的漏洞利用。
預想一下,我們希望在服務端響應中能返回的API GET請求呼叫如下:
這樣,我們可以對它進行控制修改的樣式就為:
因此,基於要在服務端響應中獲得以上預想的API GET請求呼叫,我構造瞭如下的前端請求連結:
最終,我們執行以上前端請求連結後,在服務端響應中,獲得了預想的如下API GET請求呼叫:
因為服務端響應回來的訊息包含了當前請求使用者的token,所以,我們只要在上述構造的前端請求連結中,修改VICTIM_UUID為其他使用者的的UUID,就能在服務端響應中獲得該使用者的token資訊,從而間接實現了對該賬戶的賬號劫持了。
以上即為 Ron Chan 對於這個漏洞的分享,整個過程就 是SSRF + Path Tranversal = Account Takeover。基於Uber漏洞賞金政策和漏洞的嚴重性來看,該漏洞的獎勵賞金應該不會低於$4,000美金。
*參考來源: Ron Chan ,clouds編譯,轉載請註明來自FreeBuf.COM