技術分析 – 如何遙控ATM吐錢

首先,你要懂ATM,幸運的是國際品牌的ATM控制有標準,WOSA(Windows Open System Atchitecture),只要ATM有裝WOSA的驅動程式,我們就可以透過這個標準介面來控制ATM,這樣就解決了第一個問題ATM控制。如果你找的到ATM廠商的內部人,就算沒有WOSA,每個廠牌也還是會有自己控制ATM的API,你也可以使用這些API來直接控制ATM,跟WOSA的差異就是,你只能控制某廠牌甚至只有某型號的ATM,幸運的是銀行通常都整批購買,所以就算只能控制某銀行的某廠牌某型號,你能控制的機器應該都在百台以上。

第二個問題,怎麼把你的程式放進ATM呢?超級夜貓子應該常常會發現,怎麼在深夜,到處都是ATM在暫停營業,他們在幹嘛呢?換版。也就是說,如果你能夠在換板之前把你的程式塞到換版包裡,你的程式在隔天凌晨就上線了。

一定有人想問,不能就透過windows update,網路芳鄰或是瀏覽器劫持的方式來安裝嗎?理論上,ATM機器是獨立網路,只能與指定的機器透過指定的通訊協定來通訊。通常為了安全,這通訊協定有兩,第一類交易訊息(加密應該都升級到TLS 1.1以上了),第二類檔案傳輸(FTPS應該也升級到TLS1.1了,但是透過MS SMS的話,就麻煩了,SMS可以遠端安裝、遠端執行,只要拿到SMS Server的控制權,能做的事情就多了),交易訊息沒辦法換檔案,但是檔案傳輸就可以上下其手了,如果是用SMS作軟體派送,沒有把Port關好(例如UDP 270x),那麼,拿到SMS Server控ATM就是你的了。

當然,現在還會有影像監控的路、設備監控的路、廣告伺服器(越後面的越好用來攻擊)的路等等新的通訊可以讓ATM連接,都是可以攻擊的門。

第三個問題,怎麼外部遙控,能解決第二個問題的人,代表他已經在資料中心佔有領地(殭屍),但是理論上能跟ATM連接的系統,他的對外網路存取是正面表列的,跟ATM一樣只能透過指定的通訊協定跟指定的系統通訊,在不處理防火牆的情況下,黑客就要不斷的進行各種嗅探,尋找漏洞來建立據點,直到找到能通往Internet的門,有了門之後。像是著名的TeamViewer,SSH tunnel都是可以在嗅探內網漏洞,建立可以對外被遙控殭屍網路後,可以用來由外向內直接控制的方法,至於定時喚醒,ShadowSocket、Tor這許許多多的匿蹤技術就先不討論。

以上三個問題處理完畢,你就可以遙控ATM來吐錢了。

 

因此,通銀行在

  1. ATM網路建立防火牆,只做正面表列(前兩年還有些銀行直接在ATM設備裡面就裝了一台小防火牆),其餘一律封殺。
  2. ATM系統群對外建立防火牆,還是只做正面表列,只連線到交易主機,其餘一律封殺。
  3. 銀行對外也會有DMZ的戰區,戰區往內只有指定的正面表列能進來。

在這,幫國內僅有的幾家漏洞偵測公司宣傳一下,銀行大人們,花點錢們來攻擊看看吧,保證你有意外的收穫,花小錢省大錢。

但是,銀行人員的上網?電子郵件?如何管理?這會是最大的漏洞。

以現在技術的演進,實體分離(內網完全不能連Internet,要上Internet的就不能連內網)會是最安全的。

這樣對操作人員的麻煩,是目前我想的到的最安全。不然,只要能上網,就有可能被種木馬。

 

—實務演練—

我要作的話,我會去當保全,那些負責ATM維護跟補鈔的保全,在以行員模式打開ATM的時候,塞一個模擬光碟片的USB隨身碟進去,就搞定了。
想要領錢,就直接在ATM鍵盤打密碼,可以一次領光,可以不用一次領光,慢慢領。
不想碰PIN PAD的話,塞個USB藍芽接收器,就可以現場遙控了,不過這太麻煩也無聊了。

這樣搞,以後保全補鈔也要兩個人互相全程錄影了。

另一種方式,安排人進銀行作聯管科的大夜班OP,木馬種進去之後,走到ATM前面,告訴內線,他就可以在中心遙控ATM吐錢。

以上就是建立在實體分離是確實執行的前提下可以做的。
實體分離怎麼解?人在電腦前,接電話,搞定。

突然發現中國廠商自己做的Linux ATM瞬間變成相對安全的東東,哈。

對了,有些ATM為了保護網路通訊安裝的奇奇怪怪(沒品牌、沒維護的意思)硬體防火牆反而也是個很好的突破口

鍵盤柯南 – 一銀ATM盜領事件

每台ATM有四個鈔箱,每個鈔箱裝滿就是一百萬,但是通常銀行只會裝三個鈔箱,所以掃蕩了二十幾台,領到七千萬左右的數字,合理。

再來,詭異的是一銀第一時間就說跟無卡取款無關,那我懷疑就是有關了。如果我是Wincor的工程師,最近最大單的修改作業就是自行跟跨行無卡取款,跨行流程理論上還不能上線,但是自行無卡取款,以一銀的地位,不能落後太多,應該有請Wincor配合趕工。這批程式上線前,不知道有沒有第三者看過source code,我猜沒有。一銀有是標準的test case而已,test case跟源碼弱點掃描做完就放行了,金管會應該很快就會要求多一到人眼的程序了。

怎麼做到人一去就吐錢呢?最簡單的作業就是配合iBeacon,如果無卡取款是配合iBeacon作業,那可以很容易的做到,人走到ATM前面才吐錢。問題是,在這情況下,iBeacon本身,理論上不會有資料線連在電腦,感測達成了,中心端程式沒有修改的話,也不會吐錢。所以,中心端的程式應該也被改了,改ATM交易電文嗎?機率不。能的地方,Wincor有提供,Wincor本身有獨立的設備監控系統,這設備監控系統可以控制ATM,這是一個很好的下手地方,使用設備監控系統來遙控ATM進入維護模式,進行鈔箱測試,讓ATM把所有鈔券都吐出來,一台機器要吐完三百萬,需要很長一段時間,再快應該也要20分鐘。三點重開機,兩個人,每人分15台去跑,就快要五小時,剛好以上行人到達前做完,但還有交通時間,二十幾台,是極限了。

Wincor如果本身有配合一銀在最近加裝模組(例如:Apple Pay/Android Pay/PayPass/PayWave的非接觸感應模組),那會更方便,連ATM監控程式都不用動,只要在ATM交易程式修改,配合特殊卡號的卡片,感測到就啟動(但是有六公分的限制)。

 

後記:這次作案的手法與之前在歐洲跟日本發生的最大不同是,歐洲的木馬是靠鍵盤輸入啟動,日本只是跨國盜領,而台灣目前公布的照片,沒有碰觸鍵盤,但是好像有打電話,如果打電話是告知ATM編號,那就表示木馬主控系統在中心端,能從Internet連進銀行中心端,那事情就更大條了。

 

為什麼我只懷疑是本土作案呢?因為ATM廠商在台灣,他的應用程式有走國際標準的只有一家銀行,總共幾十台ATM而已,剩下數萬台ATM,都是台灣分公司依照銀行的需求去找程師出來程式,非原廠有留下WOSA驅動程式,不然國際木馬都無效。而且,為了廣告跟使用者介面的互動性,現在很多新ATM都在交易線路之外,還有資料更新線路、設備監控線路,而這些新線路走的都是新通訊協定,是現代黑客跟惡意程式撰寫人所熟悉的,走這種路來偷,相對傳統交易路線,方便太多了。

 

又後記:一直人錢呢?猜錢在台灣,不會離開,但是已經走地下匯兌出境了,雖然台灣的海關不太會查白人(如果真的是),但是還有後面別國的海關,都計畫這麼久了,不需要拼這30%的手續費。至於地下匯兌之後會變成什麼?bitcoin也是可以啦,但是不用搞的這麼麻煩。

也來寫機器人 – 後半

原本寫的機器人,是在做Line跟Facebook的機器人平台串接測試,所以後台的功能一模一樣,算是重複且浪費,尤其是後來一直增加功能,要在兩邊不斷的copy/paste,很傻。

因此,我把前後台切開,原本寫的功能只留下Line跟Facebook平台串接功能,後端的文字服務就獨立的寫在

https://github.com/orsonwang/text_Service

裡面的程式就很單純的,扮演nats的服務接收端,等待前面的服務要求,找出對應的回應來回覆給前端。

使用RegExp來做文字服務只有一個大原則,『從大從長優照的指令,關鍵字越長的要擺在前面,字數越多的要擺在前面,最後再擺上短句,這樣就不會出錯了。

裡面應用了golang的空switch多重case的語法,也就是在以前要寫長長的if-else if敘述的部分,用case處理,乾淨點也好整理調整。

以下是範例

   case matchString("(美元|美金|USD)+.*匯率+.*", strAfterCut):
        strResult = "美金匯率\n" +
            "現金 " + exRates["美金"].inCashRate + "\n" +
            "現金賣出 " + exRates["美金"].outCashRate + "\n" +
            "即期買入 " + exRates["美金"].inRate + "\n" +
            "即期賣出 " + exRates["美金"].outRate
        break
    case matchString("匯率+.*(美元|美金|USD)+.*", strAfterCut):
        strResult = "美金匯率\n" +
            "現金買入 " + exRates["美金"].inCashRate + "\n" +
            "現金賣出 " + exRates["美金"].outCashRate + "\n" +
            "即期買入 " + exRates["美金"].inRate + "\n" +
            "即期賣出 " + exRates["美金"].outRate
        break
    case matchString("(美元|美金|USD)+.*", strAfterCut):
        strResult = "美金匯率\n" +
            "現金買入 " + exRates["美金"].inCashRate + "\n" +
            "現金賣出 " + exRates["美金"].outCashRate + "\n" +
            "即期買入 " + exRates["美金"].inRate + "\n" +
            "即期賣出 " + exRates["美金"].outRate
        break

先處理「幣別」-匯率,然後處理倒裝的匯率-「幣別」,最後沒東西了,送給使用者「幣別」的預設處理,這樣就完成了在一個句子裡查詢單一匯率的功能。

當然,如果你想要對應來亂的一個句子放兩個幣別,甚至於穿插其他鍵,那就需使用/撰寫具有NLU(Natural Language Understanding)能力的文字處理引擎,如果你有寫好了,請告訴我,我想用。