2017年8月19日土曜日

セキュリティキャンプ全国大会2017に参加しました

2017年08月14日から08月18日まで、東京都府中市で開かれたセキュリティキャンプ全国大会に参加してきました。ここでは私の参加した集中Xコースのx86OS自作ゼミでの活動について書こうと思います。
今回作ったOSは
https://github.com/ptr-yudai/osdev
にあります。(キャンプ終了時点ではバグだらけです。) もしかしたらOSに名前を付けて別リポジトリでまた0から作り始めるかもしれません。

事前学習

まずは作りたいOSについて目標設定します。これは途中で変えてもいいのですが、最初は「ディスクから削除されたファイルを救出できる」という目標を建てました。(応募時は「ディスクを読み書きできるOS」を目標にしてました。)OSは0から作るのですが、私の場合6月くらいから作り始めています。目標はともかく、32ビットOSを作るために最初にやることは大きく分けて保護モードへの移行と割り込みの有効化なのですが、これらを7月始めくらいに完成させました。(サイボウズで07/03にIDEの話をしているのでこのくらい?)そこからIDEでハードディスクを読み込むのを実装するのですが、結構難しかったのを覚えています。ですが、この辺りまでは正直osdevのwikiやforumを参考にしてサクサク作っていた感じです。(1日平均1時間くらいしか時間を取れなかった。)ここからが地獄の始まりです。ディスクを直接読むのでファイルシステムを扱う必要があるのですが、最初にFAT, NTFS, EXTのどれにするか迷いました。世界的にシェアが高いのはFATかNTFSなのですが、FATは簡単すぎると思ってNTFSを目標にしてしまいます。MBRやブートセクタは簡単でしたし、MFTと呼ばれる各ファイル(ディレクトリやその他システム設定も)のレコードの構造も仕様通りに解析していました。ディレクト以下のファイル一覧は$INDEX_ROOT($INDEX_ALLOCATION)を見れば分かるので、これでルートディレクトリのlsもできました。しかし、ここで躓きます。$INDEX_ROOT($INDEX_ALLOCATION)にはINDEX_RECORDというのが並んでいて、それぞれがディレクトリ下のファイルの情報を持っているのですが、FILENAMEという属性しか持っていないのです。てっきり「ファイル情報」+「そのファイルのレコード本体へのポインタ(クラスタ番号)」みたいなのを持っていると思ったのですが、本体の場所が分からないのでFILENAME以外の情報は分かりません。ここで1週間以上悩んで、$MFTという「全てのファイルへ参照できるファイル」というものを使えばいいんじゃないかと思い、$MFTのDATA属性を辿ると目的のファイルが見つかりました。これで一件落着したと思ったのですが、$MFTのDATA属性をどこまで辿ればいいのか分からず、またファイル数が多いときは時間かかるんじゃないか、と思っています。これは未だに線形探索の実装しているので、誰か正しい方法知っていたらここかtwitterで教えてくださいm(_ _)m
 

キャンプ一日目

基調講演でサイバーディフェンス研究所の方がフォレンジックについてお話されたので聞いていて、ファイルを削除してもデータは残るよ、と言っていたのですが残念ながらその詳しい参照方法は説明されませんでした。キャンプ終了後に聞こうと思ったのですが、すぐに帰ってしまったらしく、分からずじまいになりました。
 

キャンプ二日目

なんだかんだでとりあえずディレクトリ一覧(fls)までは作ってきたので、icatとかistatとかを初日に実装します。他には細かいバグ潰しやコマンド入力画面を少しきれにしたりしていました。また、チューターの方が"File System Forensics Analysis"という本を貸してくださり、これが結構いろんな情報が書いてあり役に立ちました。そんなこともあって当初の目的であった削除済みファイルの復元には成功しました。このころ他の参加者はみんなページングとかタスク切り替えとかOSらしいことをしていたので、一人だけこんなOS作ってていいのかと思いながら二日目終了。
 

キャンプ三日目

 このころ、自作OSにLinuxにもWindowsにも無いオリジナリティを組込むという課題(?)を与えられます。ファイル復元なんて復元ソフトでもできますし、SystemRescueCdというもっと高機能なOSもあったので、この辺からフォレンジックに特化したOSを目ざし始めます。具体的にはTSKやAutopsyなどに付いているタイムライン機能やファイルカービングを付けようと思います。この日は画面をスクロールさせる機能を付けました。それから、"File System Forensics Analysis"に$LogFileというフォレンジックっぽいファイルがあったので、それを解析する機能を付けることにしました。しかし、このファイルはまだ仕様が解明されていないようで、結局$LogFile内の特定のファイル名を探索する機能だけを付けて終わりました。Microsoftは早くNTFSの仕様公開してください。また、タイムライン機能のために時間でソートする必要があるのですが、講師の方に赤黒木を使えば速いという話を聞きます。夜にプロに赤黒木について聞いたのですが、あと1日で作るには実装コストが高かったので線形リストを使ってO(n)O(n^2)で妥協することにしました。

キャンプ四日目

 最終日はタイムラインを実装しました。そこでまたオリジナリティについて問われるのですが、「OSにすることでディスクダンプの手間が省ける!」と言うと「LinuxのLive Bootでツール動かしちゃダメなの?」という正論をいただきます。そこで、それに加えて省メモリを売りにすることにしました。具体的に省メモリとは何かを定義するため、x86でファイルシステムを扱うOSについて調べると、Win 95の8MBでの動作が調べた限り最小でした。私のOSは2MBでも一応動くので、これなら省メモリと言えるだろうということにしました。(実は2MBだとタイムラインでファイルパスが取得できないので、タイムラインにはファイルパスを調査しないオプションを付けてごまかしました。)四日目の後半でコマンドを使うにつれてメモリ使用量が増えていることに気付いたのですが、何をfreeし忘れているのか分からず終了。今迄もfree忘れに気づくためにfreeチェッカーみたいな機能を付けていたのですが、そもそもその機構に問題があったらしく、全然freeできていませんでした。これは修正ポイントです。ですが、削除されたファイルが復旧できるというインパクトが強いので講師の方に成果報告の発表者として選んでいただきました。
 

その他

 キャンプでは専門講義以外にもグループワークや企業プレゼンなどがあったのですが、それについては他の参加者がたくさん書いてくれているので私からは書きません。ただ、BoFで海外のセキュリティ関連イベントについて聞いて、めちゃくちゃ海外イベントに参加したくなりました。何とかお金を使わず海外イベントに参加できる方法を模索しています。誰か連れてって〜。

まとめ

 「ファイルの読み書きができるOS」という最初の目標から「フォレンジックが得意なOS」に変貌しましたが、結果良かったと思います。OSの機構についても少し学べましたし、講師の方にOS開発で便利なライブラリをいくつか教えてもらえたので今後使ってみようと思います。私はずっとNTFSでしたが、周りの人との交流もあったのでマルチタスクがどんなものか、ページングをどう設定するか、64bit難しい、などなど自分が触れていない部分も知ることができました。参加前は「選択でも良かったかな〜」とか思っていましたが、今はX-Xを選んでおいて本当に良かったと思っています。
あと、ずっとNTFSに漬かっていたので特定のファイルを見つけるくらいならバイナリエディタで読める体質になってしまいました。

期待をはるかに上回った内容のセキュリティキャンプでした。運営、協賛企業等、講師、チュータの方々は本当にありがとうございました。参加者の方々はお疲れさまでした。これからもお世話になると思うのでよろしくお願いします!

2017年3月29日水曜日

[LINUX] Simple Voice Recorder for TOEFL Speaking Test


 Since I will take TOEFL iBT several months hence, I need to prepare for the speaking part, which I can't get good marks. It'll be the first time for me to take TOEFL iBT tests. I've ever taken TOEIC once before, though.
 Anyway, to practice speaking, I need to record my voice and listen to my (poor) English. As I have no voice recorders, I made a simple python code to record my voice. It's useless for most of those who take TOEFL because it's designed for linux users, but I decided to share this program.

This code can only be run on linux. Also, you need to install python and arecord in advance. Both of them are usually pre-installed in linux. To make this code work, you have to give one argument that indicates the output file name. As it's written on the top of the code, after running this program, you will have 15 seconds to prepare for your answer. In the 15 seconds, you need to come up with what to answer, consider its reasons and some examples. It's too short, isn't it? Well, next you will have 45 seconds to answer the question. You can optionally start sound player to listen to the recorded voice, by commenting out the last line of the code. (You need VLC media player in this case.)
Since this code was written in 10 minutes, it may contain some bugs.
Anyway, I hope it will help someone....

2016年12月22日木曜日

きつねさんでもわかるLLVM - kosen14s読書会

はじめに

この投稿はkosen14s読書会用の記事です。
Kosen14s読書会
kosen14s読書会では、何人かのメンバーが自由なジャンルの本を紹介します。前回はPractical Malware Analysisについて投稿しました。


きつねさんでもわかるLLVM


本記事で紹介する本は、柏木 餅子さんと風薬さんの著書「きつねさんでもわかるLLVM ~コンパイラを自作するためのガイドブック~」です。
きつねさんでもわかるLLVM ~コンパイラを自作するためのガイドブック~
表紙とタイトルを見て、「これならコンパイラが作れそう!」と思った時期もありました......
というのも、やはり内容は難しかったです。そして私はまだ完全に理解してません。そのため今回は、電卓を例にとってプログラミング言語がどのように表現されるかについて、かいつまんで説明します。ただ、あまり細かいところを理解していないのでところどころ説明に間違いがあるかもしれません。

電卓を作ってみる

こんな記事に辿り着く人はコンパイラを使ったことがある人がほとんどだと思います。コンパイラは入力されたソースコードを解析し、中間言語を生成したり実行ファイルを生成したり、とにかく人間が読めるコードを機械が解釈できるコードに変換するツールです。本書で使用するLLVMでは、ソースコードをレキシカルアナライザと呼ばれるプロセッサでトークンと呼ばれる意味を持った単語に分割されます。例えば次のような入力ソースコードがあったとします。
「4 / 3 * 3.14 * 10 ** 2」
レキシカルアナライザはこれを次のように分割します。
「4」「/」「*」「3.14」「*」「10」「**」「2」
そして、lex/yaccという言語(?)を使うと自分がどんな言語を作りたいかを規定するだけでこのトークン分割を自動でやってくれるのです。電卓程度ならこれを規定するのが非常に簡単です。例えば足し算「+」を定義したければ次のように書きます。
"+" {
    return OPERATOR_ADD;
}



OPERATOR_ADDなども別ファイルで自分で定義するので、四則演算だけでなく、複雑な演算やオリジナルの演算子を簡単に定義できてしまうのです。また、演算子以外にも「整数とは何か」や「小数とは何か」も定義する必要があります。例えば小数は次のように定義されます。
[0-9] *\.[0-9]* {
    double temp_box;
    sscanf(yytext, "%lf", &temp_box);
    yylval.double_value = temp_box;
    return DOUBLE_LITERAL;
}



先程の足し算より長くなりましたが、これは計算時に具体的な数字を参照するためにyytextなどを設定する必要があるからです。詳しくはぜひ本を読んでみてください。


このように「足し算とは」「整数とは」「文字列とは」「変数とは」「関数とは」などなど、トークンについて全て定義します。次にこれらトークンを解釈するのがパーサと呼ばれるプロセッサです。例えば「1+2*3」を計算するとき、人間は掛け算を優先します。また、「*は乗算である」だけでなく、「乗算とは何か」という具体的な処理を解釈するのがこのパーサyaccです。さらに、パーサはコンパイルエラーを出す必要があります。例えば「1+2*3*」という計算式はエラーとなります。ではエラーでない乗算とは何かというと、「A*B」のように「*」の両側に数字が付いていることです。数字というより、最終的に数字になる式がAやBにあたります。例えば「(1+2)*(3*4+1)」の場合、(1+2)と(3*4+1)をそれぞれA,Bとして認識させる必要があります。そういった表現の定義はBNFという記法で書かれます。先の例でAやBをtermとして定義します。(もちろんこれも自分で定義するのでtermじゃなくてhogeとかでもいいです。)
term
: primary_expression
| term OPERATOR_MUL primary_expression
{
    $$ = $1 * $3;
}
| term OPERATOR_DIV primary_expression
{
    $$ = $1 / $3;
}
;
一行目は「termとは何か」の定義開始です。二行目は「termとはprimary_expressionである」という意味です。ちなみにprimary_expressionは後で定義する「値」を表すものです。ここまでで「式termとは値primary_expressionである」と定義されました。三行目は「もしくはterm * primary_expressionである」という意味です。OPERATOR_MULは前にレキシカルアナライザのところで定義しました。ここで注目したいのが、termの定義にtermが入っているということです。これだとずっと自分自身を参照しそうですが、一行目の「termとはprimary_expressionである」があることにより、いつかはprimary_expressionに移るのです。「term * primary_expression」を宣言しましたが、これが返す具体的な値を各必要があります。これが四行目から六行目の括弧内にある「$$ = $1 * $3;」で、「返す値 = term * primary_expression」という意味です。$1とか$3は今解析しているトークンから何番目のトークンであるかを示します。同様にして除算も定義しました。加算や減算は優先順位が低いのでexpressionとして定義します。(最後に全体のコードを示します。)
さて、 「termとはprimary_expressionである」と定義したので、今度はprimary_expressionも定義します。これはただの値(今回は小数のみ)なので、次のようにかけます。
primary_expression
: DOUBLE_LITERAL
;
ここで始めてその項の評価が終わります。(ツリーの葉に到達する。)
詳しく知りたい方は是非本を読んでみることをおすすめしますが、今回の電卓の全体像を載せておきます。

実行するとこんな感じで計算できます。



ついでに括弧付き計算や累乗にも対応したバージョンです。

実行するとこんな感じで計算できます。

さいごに

数年前にもこの本を手に取ったのですが、当時は何一つ分からずに放置していました。しばらくして読んでみると内容が全然違うとうに思えて面白いですね。まだまともな変数も実装できないですが、ちょっとずつ勉強して、いつかまともな言語を作れたらと思います。

2016年12月11日日曜日

SECCON 2016 Online予選に参加しました

結果

既に本選参加権は持っていたので、今回はいつものメンバーと分断して気楽にチームdogeとして参加しました。得点は700点で順位は125位でした。オンライン予選は初参加ですが、予想以上に難しかったです。今回は自分が解いた「VoIP」「Memory Analysis」「Anti-Debugging」「randomware」について軽くWriteupを書きます。

VoIP

タイトル通りVoIPを使用した電話のパケットを記録したデータを解析する問題です。Wiresharkにはこれを解析する機能が備わっているので、それで通話内容を再生できます。(LinuxのWiresharkでは再生機能がありませんでした。)あとは喋っているフラグを聞けばいいのですが、「V」を「B」と聞き間違えていたので結構時間がかかりました。気付くまでの間は次のMemory Analysisに取り組んでいました。
フラグ:FLAG{9001IVR}

Memory Analysis

これもタイトル通りで、Windowsのメモリダンプを解析する問題です。どれかというとForensicが得意分野なので何としても解かなければならない問題です。問題文は、「偽物のsvchost.exeが接続しようとしている宛先はどこですか」というものです。

$ volatility --file=forensic_100.raw imageinfo
[snip]
Suggested Profile(s) : WinXPSP2x86, WinXPSP3x86 (Instantiated with WinXPSP2x86)
[snip]
まぁ問題文から分かりますが、Windowsだそうです。とりあえずsvchost.exeについて調べる訳ですが、pstreeすると結構たくさんのsvchost.exeがありました。
$ volatility --file=forensic_100.raw --profile=WinXPSP2x86 pstree
上のコマンドの実行結果より、svchost.exeという名前のプロセスはPIDが1036,936,1088,848,1320,1776,1704の7個あります。次にこれらのプロセスのうち偽物を判別するために、dlllistを使用します。
 $ volatility --file=forensic_100.raw --profile=WinXPSP2x86 dlllist --pid=1036,936,1088,848,1320,1776,1704
すると、PIDが1776のsvchost.exeはパスが他と違って"C:\Windows\svchost.exe"である他、ロードされているDLLも他と大きく異なります。そこでこれをダンプして、stringsで接続先が見つからないかを試します。
$ volatility --file=forensic_100.raw --profile=WinXPSP2x86 procdump --pid=1776 -D ./
$ strings executable.1776.exe | grep http
C:\Program Files\Internet Explorer\iexplore.exe http://crattack.tistory.com/entry/Data-Science-import-pandas-as-pd
それらしいものが見つかりました。しかし、このサイトにはデータは存在しません。そこでhostsファイルを調べます。
$ volatility --file=forensic_100.raw --profile=WinXPSP2x86 filescan | grep hosts
0x000000000217b748      1      0 R--rw- \Device\HarddiskVolume1\WINDOWS\system32\drivers\etc\hosts
$ volatility --file=forensic_100.raw --profile=WinXPSP2x86 dumpfiles -Q 0x000000000217b748 --name -D ./
$ cat file.None.0x819a3008.hosts.dat
[snip]
153.127.200.178    crattack.tistory.com
実際の接続先が153.127.200.178であることが判明したので、こちらの方にアクセスします。ファイルをダウンロードすると中にフラグが書いてあります。
フラグ:SECCON{_h3110_w3_h4ve_fun_w4rg4m3_}

Anti-Debugging

アンチデバッグ系にはそこそこ慣れていたので簡単でした。ひたすらアンチデバッグ技術が登場するので、それらを掻い潜るとフラグを表示してくれます。普通に実行したらダメなの?と思いましたがVMware上にしかWindowsを持っておらず、VMware検知もあったのでデバッガで回避することに。OllyDbgやらIDAやらをいろんな方法で検知してきますが、ひたすらZFを変更し続けるとスキップできます。最後に0除算(?)で例外を発生させているので注意。(フラグは忘れました。)

randomware

これもフォレンジックなので個人的に解きたかった問題です。開始18時間くらいでうっかり寝ていて、起きたらスッキリして解けました。これはQEMUのディスクイメージが渡されるのですが、とりあえずrawに変換してFTKで中身を見ました。いろいろ見ていると「h1dd3n_s3cr3t_f14g.jpg」と「getflag」というファイルがあったのでここから着手することに。h1dd3n_s3cr3t_f14g.jpgの方はバイナリはJPEGのものとは大きく異なり、0から0xFFでXORしてみるも全てfileコマンドではdataとなりました。getflagはLinux用の32bitバイナリで、IDA Proで解析しました。問題を解くのに必要な大体の流れば次のようになります。

1) /dev/urandomから0x400バイトを取得 --> encrypt_keyに格納
2) 再帰的に特定の条件にマッチするファイルを選ぶ
3) 2)のファイル全体を0x400バイトのencrypt_keyでXOR

ということで、明らかにXORされたっぽいファイルを探します。「h1dd3n_s3cr3t_f14g.jpg」以外に、「blocklist.xml」「revocations.txt」「user-extension-html.xml」などのファイルがXORされていました。問題は、いずれも平文が無いということです。元の文が無いと数学的に考えて解読できないじゃないか!と思っていましたが、例えばXMLの最初が「<?xml version...」みたいな文字で始まることを考えると最初の部分のencrypt_keyは取得できます。
次のポイントは、blocklist.xmlおよびrevocations.txtはfirefox等が作成するファイルで、作者が用意したものではないという点です。実際これらのファイル名で調べると、内容はサイトによってバラバラであるものの、「だいたいこういうことが書いてある」ということは分かります。また、user-extension-html.xmlについては結構最初の部分が固定されているので、これで100バイトくらいはencrypt_keyを求められることになります。
これだけencrypt_keyを求められたら、反対にblocklist.xmlおよびrevocations.txtの最初の100バイトくらいも復元できます。解いてるときはこの辺で時間かかったのですが、ここでは最終的に確立したやり方だけを説明します。
revocations.txtは内容がBase64です。また、ファイル全体をBase64エンコードしている訳ではなく、意味のあるブロックごとにエンコードしています。したがって、例えばencrypt_keyにより最初の数バイト「MMGExCzAJ」くらいさえ分かれば、ネット上に転がっているrevocations.txtから同じブロックを探して、続きを予測することができます。続きが分かるということは、反対にencrypt_keyの分からなかった部分が徐々に分かっていくということです。この「blocklist.xml」<--encrypt_key-->「revocations.txt」のやりとりを繰り返すことでencrypt_keyを0x400バイト全て求めることができました。
正攻法かは分かりません。
フラグ:SECCON{This is Virtual FAT too} (お肉の写真とともに)

まとめ

挑戦した中でも「checker」なんかは解き方が分かってたのにコードでミスしてて諦めてしまいました。(「動かない」+「300pt」=「自分が間違ってる」)他にも「こんなの解けたじゃん」みたいな問題が500pt分くらいはあったので、もったいないなぁという感じでした。何はともあれ楽しかったです。運営のみなさん、参加者のみなさん、お疲れ様でした!


2016年8月29日月曜日

katagaitaiCTF#5 関西medに参加しました

本日(08月28日)に大阪で開催されたkatagaitai CTF勉強会(med)に参加してきました。

内容は午前はCryptography, 午後はPwnでした。Cryptographyはハッシュ関数に関する攻撃をやりました。問題はhack you 2014のhashmeと、ebCTF 2013のmd5collidingを中心に勉強しました。どうも講師の方がこのwriteupを読む可能性があるようなので、今回はしっかり書こうと思います。ちなみに一番前の中央に座っていました。[ ^o^]
katagaitaiCTFの5周年おめでとうございます。

午前 - Cryptography

Length extension attackやハッシュ衝突系の問題は昔勉強したことがあったので、今回のCryptographyはあまり資料を見なくても解けました。

hashme

ユーザー名を登録すると、「login=[username]&role=anonymous」で登録されます。ログインする際にroleにadministratorが入っていればフラグが表示されます。しかし、ログインするには登録時に生成される認証コードが必要です。認証コードは
s = "login=[username]&role=anonymous"
base64( xor( s + hashme(SALT + s), KEY ) )
で生成されます。
ただし、SALTとKEYはサーバー側にあり、不明です。(ローカルで実行する際はSALT="HOGE", KEY="\x01\x02\x03\x04"にしました)
ここでhashmeという独自実装のハッシュ関数がありますが、md5のように32バイトのhexdigestを出力するハッシュ関数で、ハッシュでごちゃごちゃにした各4バイトのA, B, C, DをB, A, D, Cの順にくっつけて出力しています。

(1)KEYを取得
とりあえずKEYは単純なxorで使われており、入出力はどちらも取得できるので、まずKEYを計算します。方法として、認証コード(cert)をbase64デコードし、それと"login=[username]&role=anonymous"をxorすれば、KEYの最初の方から復号化できます。さらに、[username]の長さを長くすると、それだけKEYを長く復号化できます。xorではKEYを繰り返してxorしているので、同じパターンの繰り返しが出た時点でそこまでが実際のKEY値です。

(2)length extension attackを実行
本日まではhashpumpしか使えなかったのですが、今回の講義を通して原理が分かったので実装することができました。ハッシュ関数は、ある時点で(A, B, C, D)が計算され、それをもとに次の(A, B, C, D)を計算する、という動作を繰り返しています。したがって、最終的に出力された(A, B, C, D)を使って、次の(A, B, C, D)を計算することで、hashme(A)の結果だけからhashme(A+B)が作れるということです。ただし、(A, B, C, D)の計算内には現在のバイトインデックスも含まれるので、Aの長さも必要です。今回の場合、 s = "login=[username]&role=anonymous"のときのhashme(SALT + s)が取得できるので、それをもとにhashme(SALT + s + "&role=administrator")を作ります。
しかし、SALTの長さは分からないので、ここは1から順番に仮定して、成功するまで繰り返します。

これらを実装したpython2のコードを載せます。ただし、pwntoolsというライブラリを使用しています。

今まで完全に闇の世界だったlength extension attackの原理が理解できたときは、かなり感動しました。

md5colliding

これ系も実は昔やったことがあり、そのときfastcollを使ったのも覚えていますが、2つまでしか同じハッシュを持つファイルが作れないなぁと思っていてそのままでした。今回の講義で少しステップアップした使い方ができるようになったかな。
さて、この問題は、指定された5つの文字列をそれぞれ出力するようなexeファイルを5つ作る、という問題です。ただし、5つのファイルは全てmd5が同じである必要があり、sha1が異なる必要があります。
fastcollというツールを使うと、
$ fastcoll A -o B C
でA+paddingという内容で、異なるpadding、同じmd5ハッシュ値を持つBとCが出力されます。ここから3つ以上同じハッシュを持つファイルの作り方が分からなかったのですが、
$ fastcoll B -o D E
としてCとD(もしくはE)との差分(追加分)をCに付けたせば良いようです。(なぜなら、hashmeで言ったように、サイズさえ一致すれば、それより前のバイナリは後のハッシュ値に影響しないからです。)
次にexeが異なる出力を持つ必要があるのですが、argv[0][0]などハッシュ値に影響しない部分を利用すれば良いようです。(もしファイル名が自動で割り当てられる場合はどんな方法がベストかな...?) とにかく今回はargv[0]で1から5までの出力を振り分けるのですが、Windows起動が面倒だったのでx86用のelfでやりました。
実行ファイル用のコードは次のようにしました。(linuxでは"./main"のように実行するのでargv[0][0]ではなくargv[0][2]を判定に使っています。) 実行ファイル用のCコードと、衝突生成用のpython2のコードを載せておきます。

同じmd5ハッシュ、異なるsha1ハッシュが出力され、出力内容も指定通りでした。コードは5個に限らず自由な個数だけ衝突ファイルを生成できるように工夫しています。

parlor

この問題はそもそも問題文を理解しておらず、時間内には解けませんでしたが、家でやったのでwriteupしておきます。
入力に対して条件を通過すれば賭け金だけ増え、失敗すれば賭け金が消えるゲームです。条件というのが
md5(hoge + input) % odds == 0
であることです。ちなみに問題文ではもうちょっと分りにくかったです。また、この「+」は文字列の結合で、hogeは16進数形式のダイジェストなのですが、バイナリとして結合されます。ここで数値加算してみたり文字列そのまま結合してみたりして時間取られました。さらに、inputには改行コードが最後に付いてくるっぽいのでそこにも注意。
この問題でユーザーが指定できるのはlog_2(odds)の整数とinputのバイナリです。hogeはランダムでサーバー側に保存されています。oddsの指数は100まで指定できるので、最大で2**100まで設定可能です。一回成功すればそれを繰り返せば良さそうなのですが、一度送ったinputは二度と送れません。

(1)md5(hoge + x)を知りたい
md5(hoge + x)が求まれば、md5(hoge + x + y)も求まります。しかし、md5(hoge + x)は最大でも下位100bitまでしか残りません。ということでbrute force attackで残りの28bitを探すことにしました。
...と書きながらコードを書いて実行したらあまりの重さにパソコンが止まったので今日はここまで。

午後 - Pwn

なんか凄いことやってるなぁって感じでした。
1つ1つのプロセスで何やってるのかは分かりましたし、資料にソースコードや構造体、サンドボックスの命令などが書かれていたので良かったものの、実際にソースコードも無い状態であれを解けと言われたら確実に捨てます。

tp

最後まで分からなかったこと(自分の書いた攻撃コードに関する疑問):
  • fastbinsに繋がったりbinsに繋がったり。その辺の設計もうろ覚えでした。 
  • 0x1337という数が分かりませんでした。idなら10とか20とかでもいいはず?
  • shellstormのshellcodeが動きませんでしたが、あれはseccompが原因だったのかな?
  • どうやってあんなに長いアセンブリを読む気になれるのか。

でも、やっぱりヒープ苦手だなと実感しました。もっと勉強してきます。

(2)習得したこと:
  • malloc, seccompなどの設計が少し分かりました。
  • main_arena以外にthread_arenaなるものがあるとは......
  • gdbでアタッチしたりダンプしたりするのが便利でした。
  • DynamicROP(?)の復習になりました。
最終的にflag1は取得できたので良かったですが、flag2については手も足も出ない状態です。特にヒープのところの動作がいまいち分かってないので解説みたいなのは書けませんが、書いた攻撃コードを載せておきます。(Ubuntuで書いたので日本語で書けませんでした。)

最初にひっかかったのはremote_readで、payloadを書き込んですぐにsendしなければならないのですが、remote_read内にrecvがあったので、次のステップに進めないままrecvで止まっていました。次にひっかかったのはpayloadのROP gadgetで、「pop esi; ret」を使ってるつもりが「pop esi; rep ...」みたいなのを使ってました。目grepが足りない。最後にひっかかったのがshellcodeで、shellstormからコピーしたものは動きませんでした。たぶんseccompのせいかな?
個人的にtpはflag1だけを集中的に説明しても良かったんじゃないかなとも思います。(そうするとプロが困るのかも。)

さいごに

今回はCryptography, Pwnいずれも前回のmedに比べるとかなり成長した状態で挑戦できたと思っています。(前のmedは1つも解けなかった。)
いつもkatagaitaiCTFではたくさんの知識を習得させてもらっています。講師のみなさん、NRIさんなど、運営してくださっている方々、本当にありがとうございます。
今後も参加したいと思っているので、よろしくお願いします!

2016年8月13日土曜日

katagaitaiCTF#6 関西easyに参加しました

本日(08月13日)に大阪で開催されたkatagaitai CTF勉強会(easy)に参加してきました。

内容は午前はWeb, 午後はReversingでした。WebはHack.lu CTF 2014のHotCows Datingという問題で、ReversingはCSAW CTF 2013のcrackmeという問題をそれぞれ解きました。正直Webの方はBurpの設定が上手くいかずにあまり付いていけませんでした。一応フラグは取得できたもののイマイチ「なんで?」というところが多いので、今回はcrackmeの方を中心にWriteUpを書こうと思います。

crackmeは32bitのLinux用バイナリで、とりあえずWindowsを起動してIDA Pro Freeで解析を開始しました。bindやaccpetなどから単体でサーバーとして動作するプログラムだと分かったので、とりあえずポート番号だけメモして動作しました。crackmeへ接続すると、パスフレーズを聞かれます。パスワードが合っていないと終了してしまいます。あまりIDAを使ったことの無い私は文字列検索で文字列を送信(表示)している部分を見つけ、その周辺から解析を始めました。その結果、明らかに分岐している部分があったので、その上の関数にverifyという名前を付けて関数を見ます。ちょっと前に変数名とコメントを付ける機能を知ってからはじゃんじゃん使ってるので解説が始まる前には解析が終わってたと思います。verify関数(仮)をC言語にすると次のようになりました。

int verify(char* input)
{
  char chr = input[0];
  int hash = 0x539;
  char *pass = input;
  int tmp;
 
  for(; *pass != 0; pass++) {
    tmp = chr + (hash << 5);
    chr = *(pass + 1);
    hash += tmp;
  }
 
  return hash;
}

あらためて見るといかにC言語が苦手かが分かります......
さて、とりあえず自分で解こうと思って6桁くらいまでのブルートフォースを書きましたが一向に終わらないので別の方針を立てることにしました。
そこで、入力を「A」「AA」「AAA」「AAAA」...のように試すと、徐々にハッシュ値が増加していることが分かりました。(4バイトを超えたらまた小さくなる感じでした。)
入力が長く、ASCII値が大きいほどハッシュ値も大きくなるので、二分探索(手動)で0xEF2E3558に徐々に近づけていきました。(でも5分程度で下2桁以外は揃いました。)
6桁でハッシュ値が答えに近づき、最後の方は揃わなそうだったので、最後の1文字だけブルートフォースアタックしました。その結果「aSA6>6」で通りそうだったので送ったらフラグが表示されました。

勉強会が終わった今では頭の悪い解き方です。はい。

ということで、勉強会ではkleeとz3pyを使う方法をやったので、その内勉強会中ずっとやってたz3による解法についてもWriteUpします。z3pyは条件式に当てはまるような入力を見つけてくれるモジュールです。文字列を探す方法は分からなかったのでIntVectorでやってましたが実行できず。スライドを読むとBitVecなら上手くいくそうなので時間がかかりましたが書いてみました。

実行すると入力条件に当てはまるような文字列を見つけて表示してくれます。講師の方の書かれたコードでは40秒程度かかりましたが、このコードでは1秒前後で実行できました。私は講師の方のコードをリストにして初期化に入力、hashともにBitVecを使っただけなのですが、なぜここまで違いが出たのかは全く分かりません......

easyとはいえ、今回の勉強会を通して知らなかったことをたくさん学ぶことができたので、大変有意義な1日でした。主催者やNRI Secureの皆様、ありがとうございます!次のmedも参加する予定なのでよろしくお願いします。

2016年7月17日日曜日

SECCON 2016 九州大会のWrite Upと感想

本日2016年07月17日(日)に、福岡県の博多にある富士通株式会社 九州支部で、IoT CTFが開催されました。このCTFは過去に参加してきたCTFと違い、電子回路やハードウェア関連の問題が出題されます。今回は部活のチーム4人で、チームinsecureとして参加しました。最終的なスコアテーブルの上位3位は以下の通りです。(他チームはぼかし処理済み)


ということで、何とか優勝してSECCON本戦出場権を獲得することができました。今回はチームでかなり協力し、労力を分散させて挑戦することができたのが良かったと思います。また、CTFとしては、過去にやったことの無いタイプでしたが、今までほとんど触れたことのない分野だけあって、非常に勉強になりました。

今回のCTFの概要

大会直前までどんな形式か全く分からず、「ブレッドボード回路が渡されるんじゃないか」とか「配線の写真からデコーダを書くんじゃないか」とか事前にいろいろ考えてきました。会場に入ると、各チームのテーブルにRaspberry Pi 2、ブレッドボード、配線、各種IC、テスタ、ニッパーなどが用意されていました。
問題は大問で4問、小問を含めて5問ありました。全て100[pt]です。insecureは3問(300[pt])を正解し、最初の1問がFirst Bloodだったので追加で10[pt]を獲得しました。今回は、どんな問題が出題されたのかと、解いた問題についてのWrite Upを書きます。



問題1

水道局員の人数が足りないから自動で制御しよう、という問題。用意された部品を使って、1秒毎にモータがON,OFFを繰り返す回路を作る。優しいことに、回路図が用意されていたので、回路の方はそのまま実装しました。なお、使用した機器は「Raspberry Pi 2」「モータ」「ダイオード」「抵抗」「MOSトランジスタ」です。
Raspberry Pi 2の3番ピンから1秒ごとに出力と入力を切り換えるようなコードを書いて実行します。正しく動作していることと、その入力をオシロスコープで示した上で、担当の方を呼んで動作確認してもらいます。実行結果が正しいと判断されたら、フラグが貰えました。
ここのオシロスコープの波形がかなりひどい状態でしたが、運営の方の優しさでフラグが貰えました。ありがとうございました。この問題がFirst Bloodでした。


問題2.a

スパイとして活動しているとき、任務内容を8PINのICで渡されるという問題です。8PINのICは24LC256で、これはEEPROMです。EEPROMについては調べてきて、Pickit2のも持って来たのですが、なぜかリードが正しくできずに挫折。その後、同じチームのtheoldmoon0602が、持って来たArduino互換機で挑戦し、見事データの抽出に成功。データのヘッダが1F 8Bで、一目見てtar.gzだと分かったので、解凍するとフラグのテキストが出てきました。


問題2.b

上と同じです。ここで、上の問題ではEEPROMの最初の方しか取り出しておらず、それに気付くのにかなり時間が取られました。結局最後までデータを取ると、回路図のjpgとRaspberry Pi用のコードがあり、回路図を構成してコードを実行するとフラグが取得できます。プログラムで回路をエミュレートしたものの、終了数分前だったのでダメでした。


問題3

1分ごとにエアコンのリモコンが使えなくなる原因を探ってほしい、という問題。会場の前後に回路が置いてあり、そこから赤外線が発生していました。(それはデバッグ用で、実際には運営に頼んで赤外線を定期的に発生させるボードを借りてくる。)この問題では、Raspberry Piのmode2コマンドを使って赤外線の波形データを取得しました。さらに、エアコンのリモコンの赤外線の仕様書を調べ、それに従って不要な部分をカットしました。しかし、このプロトコルは製造会社によって結構違い、どれを使えばいいか迷ってる間に時間切れでした。今思えば「SECCON{~~}」の「ECC」のところは取得できていたので、もう少し頑張れば解けたかもしれません。個人的には赤外線モジュールについて勉強できたので、非常に楽しい問題でした。


問題4

テロリストのUSB機器がどんな動作をするか確認する、という問題。この問題については私は全く触っておらず、チームメンバーが解いてくれたので詳細は知りません。チームメンバーの解き方としては、用意されたAVRマイコンに配布されたhexデータを書き込み、さらにUSBに変換する謎の機器とを接続し、それをパソコンに繋いだとのこと。すると、一定周期でキーボードが勝手に入力され、フラグが書かれたそうです。この問題は全チームが解いていました。すごい。
個人的に自分で作ってみたいので今後教えてもらおうかな。

感想

とにかく色んなことが勉強できて素晴らしかったです。企画してくださった運営の皆様、会場やパーツ等を提供してくださった協賛社の方々、本当にありがとうございます。それから今回出場されたチームの方々もお疲れ様でした。
細かい部品は持って帰っても構わないということで赤外線モジュールとEEPROM等をいただきました。家で勉強させていただきます。m(_ _)m