錢櫃 KTV 架構問題導致任意點歌、訊息發送、SQL Injection 等多個漏洞 - HITCON ZeroDay

Vulnerability Detail Report

Vulnerability Overview

  • ZDID: ZD-2016-00074
  •  發信 Vendor: 錢櫃企業股份有限公司
  • Title: 錢櫃 KTV 架構問題導致任意點歌、訊息發送、SQL Injection 等多個漏洞
  • Introduction: 錢櫃 KTV 架構問題導致任意點歌、訊息發送、SQL Injection 等多個漏洞

處理狀態

目前狀態

公開
Last Update : 2017/02/02
  • 新提交
  • 已審核
  • 已通報
  • 已修補
  • 未複測
  • 公開

處理歷程

  • 2016/05/17 16:18:47 : 新提交 (由 Orange 更新此狀態)
  • 2016/05/17 16:20:03 : 新提交 (由 Orange 更新此狀態)
  • 2016/05/17 16:45:49 : 審核完成 (由 HITCON ZeroDay 服務團隊 更新此狀態)
  • 2016/05/30 17:52:54 : 通報未回應 (由 HITCON ZeroDay 服務團隊 更新此狀態)
  • 2016/05/30 17:53:06 : 通報已回應 (由 HITCON ZeroDay 服務團隊 更新此狀態)
  • 2016/05/30 17:53:26 : 修補中 (由 HITCON ZeroDay 服務團隊 更新此狀態)
  • 2016/09/19 23:33:19 : 已修補 (由 HITCON ZeroDay 服務團隊 更新此狀態)
  • 2017/02/02 03:00:02 : 公開 (由 HITCON ZeroDay 平台自動更新)

詳細資料

  • ZDID:ZD-2016-00074
  • 通報者:orange (Orange)
  • 風險:高
  • 類型:邏輯漏洞 (Logic Flaws)

參考資料

攻擊者可經由該漏洞繞過網站邏輯行為進行惡意攻擊。

漏洞說明: OWASP - Testing for business logic
https://www.owasp.org/index.php/Testing_for_business_logic

漏洞說明: CWE-840: Business Logic Errors
https://cwe.mitre.org/data/definitions/840.html
(本欄位資訊由系統根據漏洞類別自動產生,做為漏洞參考資料。)

相關網址

http://mobileappv2.cashboxparty.com/
http://mobileappv2.cashboxparty.com/WebService/SongService.asmx/LoginKeysSelect
http://mobileappv2.cashboxparty.com/WebService/Song.asmx/UseMyPartyMessageV2

敘述

很久很久以前,CrBoy 及 Orange 心血來潮唱歌時,發現

錢櫃有 App 可以用!
錢櫃有 App 可以用!
錢櫃有 App 可以用!

因此來始看一下錢櫃 App 有什麼好玩的!

錢櫃 App 可使用包廂內點歌系統右上角的四位數驗證碼來登入 App,並透過手機進行點歌、插歌,發送訊息到 KTV 包廂螢幕上等動作!

透過設置手機 Proxy 後擷取送驗證碼的請求發現得到錢櫃 App 使用 HTTP 連線至
>> http://mobileappv2.cashboxparty.com/WebService/SongService.asmx/LoginKeysSelect
>> POST={storeID : '',billNo: '',loginKey: 'ABCD'}

看到傳送內容時原思路為暴力破解 loginKey 嘗試爆出其他包廂的驗證碼,但四位數驗證碼範圍從 A-Z 0-9 共約 36^4 次方,似乎不太可能暴力破解出便先暫時放棄往其他的路嘗試。

將網址後端去掉,直接訪問
>> http://mobileappv2.cashboxparty.com/WebService/SongService.asmx

發現使用 ASP.NET 內建 WebService 實作,可以列出所有 WebService 方法,因此得到了更多的 undocumented API 可使用
(如圖 2.png)

在首頁原始碼中也發現了
>> http://mobileappv2.cashboxparty.com/WebService/PromoEventService.asmx
>> http://mobileappv2.cashboxparty.com/WebService/CommonWebService.asmx
>> http://mobileappv2.cashboxparty.com/WebService/MemberService.asmx
>> http://mobileappv2.cashboxparty.com/WebService/SongService.asmx
>> http://mobileappv2.cashboxparty.com/WebService/SettingsWebService.asmx
>> http://mobileappv2.cashboxparty.com/WebService/StoreInfo.asmx

此外網站使用的 IIS 未修補至最新,存在 IIS tilde 目錄列舉漏洞,詳細技術細節可參閱
>> https://soroush.secproject.com/downloadable/microsoft_iis_tilde_character_vulnerability_feature.pdf
(洩漏結果如圖 3.png)

因此又得到了
>> http://mobileappv2.cashboxparty.com/WebService/Booking.asmx
>> http://mobileappv2.cashboxparty.com/WebService/Store.asmx
>> http://mobileappv2.cashboxparty.com/WebService/AppRegisterWebService.asmx

透過以上 WebService 位置,從這些公開(或未公開)的 API 中來搜尋有何可使用!

首先從最一開始的 LoginKeysSelect 開始,LoginKeysSelect 共會吃三個參數,如
>> {storeID : '',billNo: '',loginKey: 'ABCD'}

在手機 App 與包廂機台進行綁定時只需提供 loginKey,驗證碼正確網站則回傳
>> {"StoreID":"0103","BillNo":"1605170010","LoginKey":"FA46","CreateDateTime":"2016/5/17 上午 12:55:48","ShowCreateDateTime":"2016-05-17 00:55:48","RoomNo":"603"}

其中 StoreID 猜測為錢櫃分店 ID,ID 與分店名稱對應可從 StoreInfo.asmx/SelectStoreInfo 中取得,RoomNo 代表位於哪間包廂,CreateDateTime 為開立包廂時間,billNo 猜測為帳單編號

從錢櫃架構設計中發現可以只提供 loginKey 反查 billNo,"猜測"也許也能單獨傳送其他參數反查 loginKey,經測試後發現無法只提供 storeID,反查 loginKey,但可以只提供 billNo 反查 loginKey,便開始將重心放置到 billNo 的規律破解上。

經過一陣思考後發現
>> 1605170010

前六碼代表當天日期,如 160517 代表 2016/05/17,而後四碼則為流水號,從 0001 到 9999,流水號每天凌晨十二點重置,而每天錢櫃客人包廂數量並不會將流水號佔滿,經測試一天帳單量約 300 ~ 400 組,因此如在 2016/05/18 當天,只需從 1605180001 嘗試至 1605180400 即可取得所有帳單驗證碼、分店、房間號碼、開立包廂時間。

有了所有帳單驗證碼後,即可透過錢櫃 App 內建功能對任意包廂插歌、點歌,並發送任意訊息!

在測試發送訊息時(只測試自己包廂),發現字數上限為 20 字,當超過時會被截斷。
另外,當訊息中存在 "_" 字元時,螢幕顯示的訊息永遠不會消失...
(解決方法只有請店員重開包廂機台。這應該不是資安問題而是程式有 BUG XD)

最後,在測試中額外找到兩個弱點

第一個弱點在 SongService.asmx/LoginKeysSelect,其中參數 storeID 存在 LINQ 的 SQL Injection。

第二個弱點在 Song.asmx/UseMyPartyMessageV2,在發送訊息的參數 partyMessage 上存在 MySQL 的 SQL Injection,同樣的網站存在兩種資料庫猜測為網頁端透過 WebService 將訊息傳送至控制錢櫃包廂的後端伺服器為 MySQL,錢櫃各包廂機台再去查詢是否有新訊息,因此網頁使用 SQL Server 而包廂機台伺服器使用 MySQL 較為合理。

弱點是在 Insert 中的 SQL Injection,因此如在手機傳送訊息填寫
>> \'+123+\'

則會在 KTV 包廂螢幕顯示 123

如要取得當前資料庫名稱長度,在訊息中輸入
>> \'+length(database())+\'

則會在 KTV 包廂螢幕顯示 4
(如圖 4.png)

如要取得當前資料庫內容,因 MySQL 無法使用 "+" 進行字串的串接,因此無法直接將所要的內容顯示在 KTV 包廂螢幕,不過可利用 ascii() 將字串轉成數字來幫助我們達成目的,如在訊息輸入
>> \' + (ascii(mid(database(),1,1))<<24)+(ascii(mid(database(),2,1))<<16)+(ascii(mid(database(),3,1))<<8)+(ascii(mid(database(),4,1))) + \'

則會在 KTV 包廂螢幕顯示 1128354632,再轉成 ASCII 為
>> CASH
(如圖 5.png)

代表當前資料庫名稱為 CASH

修補建議:
過濾或正確的使用 LINQ 及 Prepared Statement
使用隨機的 billNo 及 loginKey

工程師辛苦了...XD

擷圖

留言討論

聯絡組織

 發送私人訊息
您也可以透過私人訊息的方式與組織聯繫,討論有關於這個漏洞的相關資訊。
;