Syscan360會議胸牌破解揭秘
背景
有幸參加今年11月份的上海Syscan360安全會議,會議期間有一個亮點就是360的獨角獸團隊設計了一款電子badge(胸牌)供參加人員進行破解嘗試,類似於美國Defcon上面的那種解密puzzle的比賽,在參會現場的人都可以參加這種破解,總共9道題,規則是現場會給每道題謎面,在這塊胸牌上面輸入正確的謎底才能進入下一題,解題需要開腦洞,有好些人參與破解,而且有好些人都解出來了,今天筆者從這塊胸牌的硬體和軟體層面去揭密這個胸牌的一些有意思的功能和如何在不需要知道謎面的情況下,快速解密答案,算是硬體破解方面拋磚引玉。
初識篇
我這邊看到有兩塊板,一塊黑色一塊紅色,其中黑色如下
硬體配置如下:
MCU: 德州儀器TI CC1310 型號(CC1310F64RGZ)VQFN (48) 7.00 mm × 7.00 mm
ARM
Cortex-M3處理器,時鐘速度高達48Mhz
64KB片上可編程flash,20KB靜態內存SRAM,30個GPIO口
RF Core支持收發1Ghz以下的無線信號
外置存儲器: Winbond 25Q32bvsig
32Mbits存儲空間
一個LCD液晶屏
四個led燈,若干電阻和電容,6個按鍵和開關,所有的這些構成一個小型的嵌入式系統
使用方法:
6個按鍵,分別負責切換不同的可列印的ASCII碼,刪除,進入和返回等功能
只有所有的關卡通過後才能出現控制閃燈和產生紅外信號去關閉遙控電視的功能,這是後話,後面細講。
硬體篇
要想了解裡面的原理和功能,必須得拿到裡面的代碼邏輯。通過查閱MCU CC1310晶元的數據手冊,我們發現它支持jtag模擬調試,我們只需要外掛支持ARM的模擬器,就可以進行整個內存空間的訪問和片上動態調試,這一點對於我們逆向來講非常有幫助,CC1310晶元布局如下。
DIO_16 26 Digital I/O GPIO, JTAG_TDO, high-drive capability
DIO_17 27 Digital I/O GPIO, JTAG_TDI, high-drive capability
我們知道要進行jtag調試需要至少4根信號線分別是TMS,TCK,TDI,TDO,(RST可選)最後是GND(接地), 具體JTAG的定義和各個信號線的定義大家可以網上搜索,我就不贅述了,找到這幾個信號線接到相應的模擬器上就可以進行調試了。
從該MCU的電子手冊我們得知這四個信號線的Pin腳位置如下。TMS 24nTCK 25nTDO 26nTDI 27n
然後我們可以通過萬電錶量出這幾個引腳引出來的位置,剛好這板子已經把這幾個信號腳引出來了,也省去我們不少麻煩。
好了,焊好線後,需要我們的模擬器出場了,筆者使用的ft2232h mini module,當然大家也可以選用別的模擬器,像jlink之類的,簡單說一下這個mini module,它是一個多硬體協議(MPSSE)集一身的小模塊,比如SPI/JTAG/I2C等,共用GPIO口,非常方便,接下來就是連線了,連接圖如下。
右邊是mini module CN-2介面Pin腳,左邊是CC1310的引腳,GND隨便找一個板子接地的地方接上就好了。
下面就是ft2232h mini module好了,接下來就是激動人心的時刻了。
軟體篇
硬體連接準備就緒後,我們開始驅動模擬器來進行片上調試。
調試工具準備如下:
OpenOCD (開源的硬體調試軟體)
Arm-none-eabi-gdb (arm版的gdb)
在使用openocd之前需要準備好cc1310的調試配置文件cc1310.cfg,在這裡可以找到。
一切準備妥當,接下來就可以開始見證奇蹟的時刻了。
在這裡我們執行halt命令,cpu就斷下來了,效果如下
這個時侯我的gdb就可以遠程attach上去進行動態調試與內存空間訪問了。
運行arm-none-eabi-gdb,gdb裡面執行target remote localhost:3333
進行遠程調試連接,可以內存空間訪問與動態調試。
好了,我們可以內存空間訪問了,先把固件,flash,和內存數據dump出來,靜態分析一下吧。如下是cc13xx晶元的內存空間地址映射表,它可以讓我們知道dump哪些有用的數據
0地址開始到0x10000是我們CC1310F64型號的flash的地址空間
BootROM是從0x10000000到0x10020000
SRAM地址從0x20000000到0x20005000
好了,我們就dump這三塊位置。
在gdb裡面運行如下命令
dump binary memory cc1310_flash.bin 0 0x10000ndump binary memory cc1310_brom.bin 0x10000000 0x10020000ndump binary memory cc1310_sram.bin 0x20000000 0x20005000n
好了,合併這三個文件用IDA進行反彙編,不同的段進行地址重定位,可以做到地址精確引用,如下。
好了,接下來就是逆向篇了,如何找到答案和分析其代碼邏輯等等。
逆向篇
我們通過IDA裡面的一些字元串獲得一些線索。
然後我們很快找到每一道題的答案了
解釋一下這裡面的一些邏輯。
這裡面每一道題的提示和答案,還有用戶自定義ID存儲在flash 0xe000開始的區域裡面,總共長度0xe2個位元組,運行時會把這塊區域數據讀到SRAM裡面,在SRAM裡面進行操作,然後把SRAM結果寫回到0xe000這塊區域里,以保證下次設備重啟數據和進度不會丟失,其結構如下。
0xe000 ---0xe010 存儲用戶設置的ID0xe014 --- 0xe015 存儲用戶過了多少關了(直接改成9就通關了:),修改SRAM裡面相應的存儲的數據,然後通過ID設置來觸發寫回到0xe014,這樣就生效了)
如下是不同關卡的提示和答案
比較每一個關卡的用戶輸入答案,並進行更新
0x20001060存儲著flash地址0xe000裡面的數據
偏移0x14就是用戶當前所在關卡數,如果答案比較相等,這個關卡數加1並寫回到flash裡面,並在屏幕上顯示『right!』。
總共9道題的答案分別是:
UR1NMYW0RLD!42
ORDREDUTEMPLEFQJPVDPOK
VYTX
LOYAL
GNILCS
FIBONACHI
WORLD
通關最後的結果如下
如果你只想知道答案,看到這裡就可以了,接下來會講講裡面的一些其它功能。
探密TVB Gone功能篇
當所有的關卡都通過後,會多出來兩項列表,分別是
Led Light
TVB Gone
進入Led Light前置的兩個led燈可以顯示3種顏色,這裡是通過設置12號GPIO和19號GPIO口,對應在晶元上的引腳是18和29。
這裡我們重點關注這個TVB Gone功能,這個一個可以通過紅外信號遠程關閉很多不同品牌的電視的小應用,具體介紹參考TV-B-Gone - Wikipedia
我們知道我們家裡面使用的電視的遙控器,一般都是發射的紅外信號,來控制電視的開關,調台等操作,這個TVB Gone的功能就是通過發射不同品牌和不同頻率的控制信息來達到關閉遙控電視的目的。紅外控制信號通過一定頻率的PWM(脈衝寬度調製)調製方式輸出給led燈,led燈產生的紅外信號影響遙控電視。
研究發現這個板子裡面存儲了80組紅外控制信號源數據,通過特定的數據結構來存儲,例如如下。
如下是存儲每一組數據的地方指針列表
我們挑選其中一組來看
解釋一下每個欄位的含義
0x9600表示這種數據的發射頻率38400Hz
0x1a 表示有多少對數據需要發送出去0x02 表示每發送一對信號裡面承載著2個bit數據
0x9e38 表示存儲時間對的指針地址0x97b4 表示要發送的數據的指針地址
地址0x97b4在存儲的數據如下
{0xe2, 0x20, 0x80,0x78,0x88,0x20,x10}n
上面有講這些數據需要發送26次,每次是2個bit,總共就是52個bit
上面是7個位元組,總共是56個bit,還有4個bit怎麼辦,後面再說。
這個時候我們需要說說存儲時間對的指針了
地址0x9e38存儲的時間對
{60,60,n60,2700,n120,60,n240,60}n
這個時間對分別是time on和time off
解釋這兩個概念時先計算一下PWM調製的周期時間
1/38400=26μs(微秒)n
該MCU的系統時鐘是46Mhz,這裡使用了一個16位的通用定時器GPT TimerB
我們通過代碼得知該PWM調製的占空比(duty cycle)是33.3%,什麼是占空比,就是在一個PWM周期裡面高電平佔總電平的比例,如下圖
這個PWM的周期是26μs,高電平是8.84μs,所以占空比就是8.84/26=33.3%,也就是1/3,我們從代碼裡面也能看到。
這個PWM輸出使用的是4號GPIO口,地址0x40022090是設置各個GPIO口置bit1的地方,這裡賦值0x10剛好是置4號GPIO口bit1,也就是高電平,地址0x4001002c設置定時器時間,也就是這個高電平持續多長時間,後面0x400220a0是設置各個GPIO口清除bit1,也就是置bit0,這個是0x10,表示置4號GPIO口bit0,也就是進入低電平,設置定時器長度在地址0x4001002c,時長是高電平的2倍,這就是一個周期time on的狀態,通過計算我們能夠得出一個周期高電平的時長。
系統時鐘周期1/46000000(46000000/38400/3.0)*( 1/46000000)=8.67μsn
好了,繼續回來上面的時間對Time on和time off
{60,60,n60,2700,n120,60,n240,60}n
把每個數字乘以10,時間單位是微秒,這個10怎麼來的,代碼裡面看到的,不知道原因(搞硬體的同學幫忙解釋下)
{600,600,n600,27000,n1200,600,n2400,600}n
每對數字前的數字表示Time on,就是在這個數字的時間內,PWM信號周期性出現,後面的數字Time Off表示低電平沒有PWM周期性變化。
這兩個組合在一起的PWM信號就是表示數字信號裡面的2個bit位,上面有提到
{600,600, 代表bit 位『0 0』n600,27000, 代表bit 位『0 1』n1200,600, 代表bit 位『1 0』n2400,600} 代表bit 位『1 1』n
所以這個紅外信號就是通過PWM的這種方法調製發射出去的,繼續上面的例子,我們要發送的數據如下。
{0xe2, 0x20,0x80,0x78,0x88,0x20,x10}n
發送數據的順序是MSB,就是從左到右開始發,比如0xe2的比特數據是
「 11100010 」n
先發11,10,00,10對應的發送時間序列對就是
2400,600n1200,600n600, 600n1200,600n
我們可以通過邏輯分析儀來看這些信號發送的情況
第一組發送的比特11
Time on 2400微秒(也就是2.4毫秒),我們觀察到按照周期性變化的PWM信號長度就是2.4毫秒,低電平的時長就是600微秒左右
第二組發送的比特10
time on時長1200微秒,time off時長600微秒
第三組發送的比特00
time on時長600,time off時長600
第四組發送的比特10
time on時長1200微秒,time off 600微秒
好了,上面我們有提到要發送的數據是7個位元組,56bit,但是只發送了26對也就是52bit,還有4bit怎麼辦,我們看最後一個位元組0x10對應的比特位是00010000
因為最後4位都是bit0,所以直接低電平補位了(猜測)。
最後在14秒左右遍歷了80組紅外信號來嘗試關閉遠端的搖控電視
外置Flash篇
我們似乎忘記了那個4MB的winbond的外置flash了,它的功能如下:
存儲一些文字介紹信息
存儲LCD文字顯示映射碼
存儲啟動的圖片
存儲了一個變數
如果dump外置flash?
先祭出我的神器FT2232h Min Module,用熱風槍把外置flash吹下來,然後夾住,連線如下圖,SPI介面一一對應好就可以了。
通過軟體flashrom來讀取flash裡面的內容
運行
flashrom –p ft2232_spi:type=2232H,port=A –r flash_cc.binn
LCD顯示是通過硬體I2C協議寫入數據,ASCII碼和UNICODE顯示邏輯如下
漢字通過UTF8解碼然後GBK編碼後存儲
所以想在顯示屏上面顯示中文漢字,只需要把漢字UTF8解碼然後GBK編碼後放到相應的位置就可以了,例如
>>> 謝君.decode(utf8).encode(gbk)nxd0xbbxbexfdn
這四個位元組寫入地址0x20001060處,然後寫回內置flash就出來如下效果了。
無線通信篇(RF)
該板子帶一個無線收發功能,中心頻率是433.92Mhz,速率50Kbps,2-GFSK方式調製,該無線功能一直處於監聽狀態,當收到服務端發過來的相應命令的數據包時,會做相應的解析,並且發相應的包響應。
這個無線功能有如下一些功能,我就挑選了幾個:
廣播請求客戶端提交你們的用戶id信息
廣播請求客戶端提交你們的通過關卡數的信息
服務端器發送無線數據格式如下:
0x00 0xaa無線通信前導碼(preamble)n0x01 數據包payload長度n0x02 請求命令n0x03-0x04 header 0x5555或者0x2b2n0x05 序列號(seq)n0x06 地址n0x07 子命令nend 兩個位元組的數據包校驗和n
客戶端發送數據格式如下:
0x00 0xaa前導碼n0x01 數據包長n0x02 請求命令n0x03-0x04頭部header 0x02 0xb2n0x05 對應服務端發過來的地址n0x06 子命令n0x7—需要提交的一些數據nend兩個位元組的校驗和n
校驗和演算法
把欄位數據包長度後面的數據,不包括校驗和欄位,每個位元組數據相加結果再和校驗和作比較。我節選了幾個數據交互對,由於我們現在不可能收到伺服器發的數據,所以只能根據逆向代碼來判斷發送的內容是什麼樣的:
recv是來自伺服器發的,send是我們的板子響應發出去的。
Seq是序列號,add是地址,各佔一個位元組
請求提交你過了多少關:
recv 0xaa 0x06 0x02 0x55 0x55 seq add 0x01 chk1 chk2 nsend 0xaa 0x08 0x03 seq 0x02 0xb2 add 0x01 0xff 0x09 chk1 chk2n
請求提交板子的用戶id,名字長度是16個位元組
recv 0xaa 0x06 0x02 0x55 0x55 seq add 0x03 chk1 chk2nsend 0x0a 0x16 0x03 seq 0x02 0xb2 add 0x03 username chk1 chk2n
其它
recv 0xaa 0x06 0x04 0x02 0xb2 seq add 0x01 chk1 chk2nsend 0xaa 0x05 0x05 seq 0x02 0xb2 add chk1 chk2n
結論
當然還有改進的空間,比如在解題演算法代碼上面,不要用明文存儲答案,經過一些演算法混淆處理,可以提高代碼分析的門檻。
硬體上面的一些反調試對抗,可以考慮一些晶元硬體特性的支持,比如今年defcon上面使用的intel在quark d2000 x86晶元,裡面有一個jtag的disable的OTP比特位,燒錄設置後jtag硬體調試就不能用了。
相信他們在設計這塊板子的時候也是付出了很多精力,逆向也是一個學習的過程,感謝。
作者:謝君(阿里IoT安全專家),更多安全類文章,請持續關注阿里聚安全的安全專欄
推薦閱讀:
※能獨立設計編寫一個加減乘除計算器屬於什麼編程水平?
※手機硬體升級一樣會重蹈PC覆轍,無力挽救的「負優化」是行業潛規則
※帶你逛西雅圖活電腦博物館(五)
※SSD的隨機讀寫與順序讀寫?
※SSD+HDD,在不運行HDD程序的前提下,HDD會不會發出聲音?