以往一直沒機會參加的駭客年會 (Hitcon),今年終於參與了!
本篇主要講一下這次有趣的 Wargame - Arduino Nano…
一到會場,報到後領取的資料袋裡面可以看到他的身影。
一條簡單的 mini usb to usb 與 Arduino Nano;從沒玩過 Arduino 的我第一次就獻給 Hitcon 了 (?)
上了 IRC 得知題目位於 iot.hitcon.org (現已下線) 後,邊聽神人 geohot 演說一邊去看題目。網頁上有三關可以下載,其實三都在同一份檔案內:一份 ans.py
剛好摸 Py 也好一陣子了,心理鬆了一口氣…不會 Py 的朋友可能光是上手就比較辛苦一點。(不過看到解答之後,應該是不會 Py 也可以的啦! 不要再說他是 Py wargame 囉!哈!)
題目
- 回答一個摩斯密碼
- 走迷宮 (9秒內)
- 四則運算 (1秒內)
正規解法
以下有 Wargame 劇透,想要自己體驗的話…不要再往下看嚕…
注意:這是我心目中的 “正規” 解法
來源:Hitcon Knowledge Base 的下方回應
一開始我是硬解了 1, 3 題,然後看到 geohot 忽然全破,嘖!想一想不對…這是 Hitcon 啊!又不是程式設計作業…於是我就想說要怎麼把 Arduino 上面的 Firmware Dump 下來。也是有找到解答中提到的 avrdude,只是下錯指令…
所以無疾而終。後來就想專心聽講,就沒有再深究下去了
當初我下錯的指令:
avrdude -p atmega328p -c stk500 -U flash:r:"/tmp/arduino.hex":r -P /dev/tty.wchusbserialfa130 -b115200 |
可以發現我連 chipset 都選錯了,噗!
正解指令:
avrdude -F -c arduino -b 57600 -P /dev/ttyUSB0 -pm328 -vv -U flash:r:program.bin:r |
Dump 下來的 program.bin 為一個 binary 的檔案,要在裡面找解答後出現的金鑰 KEY,這邊可以借助 strings 這個指令…WTF 從來沒用過這個指令,趕快 man 一下:
find the printable strings in a object, or other binary, file
怎麼有這麼神奇的小工具以前從來沒用過,一定是不夠黑!於是乎,就解出題的 Key 啦!
不正規解法
所謂不正規解法就是…乖乖寫 code 看他要你解什麼,怎麼有點像是 ACM (誤)
這邊我就不多提,看一下 HKB 吧!
Hitcon Knowledge Base 的下方回應
相關程式碼與紀錄
#!/usr/bin/python | |
# -*- coding: utf-8 -*- | |
import re | |
import serial | |
import time | |
port = None | |
lines = [] | |
def game0(line): | |
if line == 'Nano$ enter your answer:': | |
# enter you answer here | |
answer = '' | |
port.write('%s\n' % answer) | |
port.flush() | |
def game1(line): | |
if line == 'Nano$ show map': | |
global lines | |
# here is map | |
lines = lines[-3:] | |
# for line in lines: | |
# print line | |
# write you rules to send [w] [a] [s] [d] here | |
port.write('d\n') | |
port.flush() | |
else: | |
lines.append(line) | |
def game2(line): | |
if line == 'Nano$ enter your answer:': | |
global lines | |
lines = lines[-1:] | |
total = 0 | |
# write you rules to calculate answer here | |
port.write('%d\n' % total) | |
port.flush() | |
else: | |
lines.append(line) | |
def main(): | |
# enter your choice here | |
choice = '0' | |
while True: | |
line = port.readline()[:-1] | |
print line | |
if line == 'Nano$ enter your choice:': | |
port.write('%s\n' % choice) | |
port.flush() | |
if line == 'Nano$ finish': | |
port.close() | |
break | |
if choice == '0': | |
game0(line) | |
if choice == '1': | |
game1(line) | |
if choice == '2': | |
game2(line) | |
if choice == '3': | |
game3(line) | |
if __name__ == '__main__': | |
port = serial.Serial(port=3, baudrate=115200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE) | |
main() |
λ ~/ avrdude -F -c arduino -b 57600 -P /dev/tty.wchusbserialfd120 -pm328 -vv -U flash:r:program.bin:r | |
avrdude: Version 6.1, compiled on Aug 28 2015 at 13:24:58 | |
Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/ | |
Copyright (c) 2007-2014 Joerg Wunsch | |
System wide configuration file is "/usr/local/Cellar/avrdude/6.1/etc/avrdude.conf" | |
User configuration file is "/Users/zack/.avrduderc" | |
User configuration file does not exist or is not a regular file, skipping | |
Using Port : /dev/tty.wchusbserialfd120 | |
Using Programmer : arduino | |
Overriding Baud Rate : 57600 | |
AVR Part : ATmega328 | |
Chip Erase delay : 9000 us | |
PAGEL : PD7 | |
BS2 : PC2 | |
RESET disposition : dedicated | |
RETRY pulse : SCK | |
serial program mode : yes | |
parallel program mode : yes | |
Timeout : 200 | |
StabDelay : 100 | |
CmdexeDelay : 25 | |
SyncLoops : 32 | |
ByteDelay : 0 | |
PollIndex : 3 | |
PollValue : 0x53 | |
Memory Detail : | |
Block Poll Page Polled | |
Memory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack | |
----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- --------- | |
eeprom 65 20 4 0 no 1024 4 0 3600 3600 0xff 0xff | |
flash 65 6 128 0 yes 32768 128 256 4500 4500 0xff 0xff | |
lfuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00 | |
hfuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00 | |
efuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00 | |
lock 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00 | |
calibration 0 0 0 0 no 1 0 0 0 0 0x00 0x00 | |
signature 0 0 0 0 no 3 0 0 0 0 0x00 0x00 | |
Programmer Type : Arduino | |
Description : Arduino | |
Hardware Version: 2 | |
Firmware Version: 1.16 | |
Vtarget : 0.0 V | |
Varef : 0.0 V | |
Oscillator : Off | |
SCK period : 0.1 us | |
avrdude: AVR device initialized and ready to accept instructions | |
Reading | ################################################## | 100% 0.02s | |
avrdude: Device signature = 0x1e950f | |
avrdude: Expected signature for ATmega328 is 1E 95 14 | |
avrdude: safemode: lfuse reads as 0 | |
avrdude: safemode: hfuse reads as 0 | |
avrdude: safemode: efuse reads as 0 | |
avrdude: reading flash memory: | |
Reading | ################################################## | 100% 18.33s | |
avrdude: writing output file "program.bin" | |
avrdude: safemode: lfuse reads as 0 | |
avrdude: safemode: hfuse reads as 0 | |
avrdude: safemode: efuse reads as 0 | |
avrdude: safemode: Fuses OK (E:00, H:00, L:00) | |
avrdude done. Thank you. |
TRINGS(1) STRINGS(1) | |
NAME | |
strings - find the printable strings in a object, or other binary, file | |
SYNOPSIS | |
strings [ - ] [ -a ] [ -o ] [ -t format ] [ -number ] [ -n number ] [--] [file ...] | |
DESCRIPTION | |
Strings looks for ASCII strings in a binary file or standard input. Strings is useful for identifying random | |
object files and many other things. A string is any sequence of 4 (the default) or more printing characters | |
ending with a newline or a null. Unless the - flag is given, strings looks in all sections of the object | |
files except the (__TEXT,__text) section. If no files are specified standard input is read. | |
The file arguments may be of the form libx.a(foo.o), to request information about only that object file and | |
not the entire library. (Typically this argument must be quoted, ``libx.a(foo.o)'', to get it past the | |
shell.) |
λ ~/ strings program.bin | |
/_?OA__O/01 | |
$$_>O | |
$$_>O | |
g+h+i+q | |
O__O | |
O__O | |
O__O | |
._?O | |
/_?O | |
i2sB | |
i>s@ | |
<--- | |
8-)- | |
c/r/ | |
+[?O | |
,_?O | |
,_?O | |
,_?O | |
,_?O | |
!,1,B-@1 | |
H Y j { | |
COpm | |
D)U)f)w) | |
KZ_O | |
O__OoO | |
L__O! | |
?OOO_O | |
'i'x' | |
N__O$ | |
a,q,` | |
APP@ | |
APP@ | |
'J01 | |
Y/H/7/&/f | |
.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
Nano$ I WANT TO PLAY A GAME ! | |
Nano$ now, you are in (0,0) of an unknown maze. | |
Nano$ you must reach (14, 14) of this maze. | |
Nano$ you have ten seconds to reach it. | |
Nano$ the 'O' is where you are. | |
Nano$ the '.' mark is road. | |
Nano$ the '+' mark is wall. | |
Nano$ send [w] to move up | |
Nano$ send [d] to move right | |
Nano$ send [s] to move down | |
Nano$ send [a] to move left | |
Nano$ show map | |
Nano$ | |
= ? | |
HITCON 2015 NANO GAME | |
User$ my answer is | |
b347bae2bfcd1ef679aa3177d017f042e52dca2 | |
Nano$ key is 457E1A295B9D1C48 | |
Nano$ wrong answer | |
Nano$ finish | |
User$ send [ | |
Nano$ key is 3D52CB746F9E6C83 | |
Nano$ key is 273A9C1E2D380B48 | |
Nano$ [0] Morse | |
Nano$ [1] Maze | |
Nano$ [2] Calculator | |
Nano$ enter your choice: | |
User$ choice [0] Morse | |
User$ choice [1] Maze | |
User$ choice [2] Calculator | |
Nano$ activate Morse | |
Nano$ .... .. - -.-. --- -. -. .- -. --- --. .- -- . -- --- .-. ... . | |
Nano$ enter your answer: | |
Nano$ activate Maze | |
Nano$ activate Calculator | |
Nano$ timeout (9 seconds) | |
Nano$ timeout (1 seconds) | |
(/)Z | |
(/ ] | |
!P0@ | |
!P0@ | |
/_?O | |
O__OF | |
/_?O0 | |
O__OF |
心得
一開始硬解的很爽直接衝上第四名(應該很多人卡在 Driver, Python 等不熟悉的關係),後來我一看 geohot 跳上第一名我就恍然大悟知道我的解法有問題,一時半刻又摸不出怎麼 dump firmware 的方式,就留這張 screenshot 作為紀念囉 HAHA
在 IoT 時代,對於這種 firmware 可以輕易被 dump 出來,利用 strings 直接取得所有字串資料,身為開發者的我們應該要更注意這方面的防護與瞭解。