Security of Things: 駭客年會 NANO Wargame 心得

以往一直沒機會參加的駭客年會 (Hitcon),今年終於參與了!
本篇主要講一下這次有趣的 Wargame - Arduino Nano…

一到會場,報到後領取的資料袋裡面可以看到他的身影。

一條簡單的 mini usb to usb 與 Arduino Nano;從沒玩過 Arduino 的我第一次就獻給 Hitcon 了 (?)

上了 IRC 得知題目位於 iot.hitcon.org (現已下線) 後,邊聽神人 geohot 演說一邊去看題目。網頁上有三關可以下載,其實三都在同一份檔案內:一份 ans.py

剛好摸 Py 也好一陣子了,心理鬆了一口氣…不會 Py 的朋友可能光是上手就比較辛苦一點。(不過看到解答之後,應該是不會 Py 也可以的啦! 不要再說他是 Py wargame 囉!哈!)

題目

  1. 回答一個摩斯密碼
  2. 走迷宮 (9秒內)
  3. 四則運算 (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()
view raw ans.py hosted with ❤ by GitHub
λ ~/ 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.
view raw avrdude.log hosted with ❤ by GitHub
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.)
view raw manstrings hosted with ❤ by GitHub
λ ~/ 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
view raw strings.log hosted with ❤ by GitHub

心得

一開始硬解的很爽直接衝上第四名(應該很多人卡在 Driver, Python 等不熟悉的關係),後來我一看 geohot 跳上第一名我就恍然大悟知道我的解法有問題,一時半刻又摸不出怎麼 dump firmware 的方式,就留這張 screenshot 作為紀念囉 HAHA

在 IoT 時代,對於這種 firmware 可以輕易被 dump 出來,利用 strings 直接取得所有字串資料,身為開發者的我們應該要更注意這方面的防護與瞭解。