2016年6月27日月曜日

Practical Malware Analysis - kosen14s読書会

はじめに

この投稿は、kosen14s読書会用の記事です。

kosen14s読書会

kosen14s読書会では、何人かのメンバーが自由なジャンルの本を紹介します。私は他にブログらしきものを持っていないことと、ちょうど技術的な内容の本を紹介する予定だったので、ここに投稿しました。


Practical Malware Analysis


本記事で紹介するのは、Michael SikorskiさんとAndrew Honigさんの著書「Practical Malware Analysis: The Hands-On Guide to Dissecting Malicious Software」です。

Practical Malware Analysis

宇宙人が解剖されかけているという一見不思議な表紙ですが、これは「中身の分からないものを調査する」ということを暗示しているのだと思います。

さて、この本ではマルウェア(端的に言うとウイルス)を解析するために必要な知識を1から100まで記載した技術書で、内容がとにかく充実しています。私は自分の読みたいところだけを読む人なので、本当はこの本の内容を全て読んだ訳ではありません。しかし、さらっと読んだだけでも有用な情報が数多く書かれていたので、その中でも特に面白かったものについてのみここで取り上げようと思います。


この本との出会い

この本を初めて知ったのは高校1年生の冬、北海道で開かれたセキュリティミニキャンプという勉強会でした。その勉強会は私がコンピュータセキュリティを勉強するきっかけにもなったのですが、そのため当時は会場一の初心者でした。勉強会を通して活躍が見られた人にはこの本が貰えるとのことだったのですが、もちろん本はプロ達の手に渡っていきました。そこで、「プロが良本を手に入れるとよりプロになる」というプロサイクルを見出しました。これではいかんと思い、それから1年後にネット通販でこの本を買うことにしたのです。おしまい。


逆アセンブルとは

まず説明する前に、逆アセンブルということについて説明します。
逆アセンブルとは、実行ファイルなどの機械語を、アセンブリ言語という多少人間が読みやすい形式に変換する作業を指します。
機械語はintelやらARMやらといったプロセッサにより異なりますが、アセンブリ形式はどの種類でもある程度似ているので、普通の人がマルウェアを解析するとき、逆アセンブルされたものを読みます。この記事では、intel形式のアセンブリ言語(NASM)で書きたいと思います。

例えば

b8 77 00 00 00 50

という機械語列はさっぱり意味が分かりませんが、これを逆アセンブルして

mov eax, 0x77
push eax

にすると、あら不思議。分かりやすい。

さて、みなさんが普段使っているソフトウェアは、例えばWindowsならexeなどの実行ファイルになっていることが多いです。これが実行できるということは、このファイルの中に一連の動作を表す機械語が書かれています。マルウェアに限らず、実行ファイルを解析するときはこの機械語を逆アセンブルするのです。そして、逆アセンブルするためのツールはたくさん用意されています。個人的に代表的なのは次のツールです。

静的解析:IDA Pro, radare2
動的解析:OllyDbg, x64dbg

静的解析のツールは、先に説明したように、ただ機械語を逆アセンブルした結果を表示するツールです。ただ、こういったツールの良いところは、逆アセンブルした結果をフローチャートのようにするなど、できるだけ人間に分かりやすく整理して表示してくれるのです。動的解析のツールは、逆アセンブルをすると共に、そのプログラムを実行します。しかし、マルウェアは実行したら危ないので、今回はやりませんでした。


ANTI-DISASSEMBLY

解析を困難にする技術には大別して「ANTI-DISASSEMBLY」「ANTI-DEBUGGING」「ANTI-VIRTUAL MACHINE TECHNIQUES」「PACKERS」の4つがあります。特に3つ目の「ANTI-VIRTUAL MACHINE TECHNIQUES」 はマルウェア特有の技術ですし、「PACKERS」に関しては「ANTI-DISASSEMBLY」に含まれてもおかしくありません。ということで、個人 的には「ANTI-DISASSEMBLY」および「ANTI-DEBUGGING」に分かれるのですが、ANTI-DEBUGGINGの方は前から触ったことがあったので、そこまで驚きの技術ではありませんでした。
ということで、解析防止技術の中でも特に面白かったものが逆アセンブル自体を困難にする技術です。
そもそもなぜこんな面倒なことをするかと言うと、例えばC言語でゲームを作ったとしても、配布する時点では機械語の入った実行ファイルを公開します。そしてそれを逆アセンブルされると、理論的にはどんなプログラムでもソースコード(アセンブリ)が見られてしまいます。しかし、開発者としてはできればやめてほしいことも多いです。ゲームのストーリーからセーブデータの保存アルゴリズムまで見られてしまうのですから。ましてやパスワードやライセンスキーを要求するソフトウェアなどは解析されたらたまったものではありません。(実際に有名なソフトウェアでも解析されて構造がバレてしまうことが多々あります。)

そこで、頭の良い先人たちは、逆アセンブルを防ぐ技術(Anti-Disassembly)をいくつも考案してきました。とは言え、逆アセンブル自体は防げないので、逆アセンブルにより出力されたソースコード(アセンブリ)を、いかにツールに解析されにくく、そして人間にとって見にくくするかがポイントです。これを難読化といいます。


次のアセンブリを見てください。これは逆アセンブル結果ではなく、開発者が書くコードです。単純にSleep関数を実行するだけなのですが、これがバレたくない開発者は、コードに難読化を施します。

    jmp short obfuscation
    db 0xE8
obfuscation:
    push 0x2A
    call Sleep

このコードの説明は次のような感じです。

1行目:ラベル"obfuscation"にジャンプ(そこを実行)
2行目:機械語にしたときに、ちょうどここに0xE8という1バイトのデータを埋め込む
3行目:"obfuscation"というラベルを作る
4行目:メモリに0x2Aというデータを入れておく
5行目:Sleep関数を呼び出す。(引数は上の0x2Aとなる)

つまり実行すると、
「obfuscationにジャンプ」 -> 「Sleep(0x2A)を実行」
となるだけのコードです。

このコードを機械語にし、さらに逆アセンブルすると次のようになります。(あくまでも出力例)

    jmp short near ptr loc_2+1
loc_2:
    call near ptr 0x15ff2a71
    or [ecx], dl
    inc eax
    db 0


本来なら前に書いたコードがそのまま結果として出力されてほしいのですが、見たところ全く違うものが出てきました。もう一度オリジナルのコードを書きます。

    jmp short obfuscation
    db 0xE8
obfuscation:
    push 0x2A
    call Sleep

全然違いますね。ここで重要となるのは「db 0xE8」です。0xE8はintelのx86アーキテクチャの機械語において、call命令の最初のバイトです。したがって、逆アセンブルツール(逆アセンブラ)が機械語を解析する際、この0xE8をcall命令として読んでしまい、さらに次の機械語まで巻き込んでしまいます。

つまり本来なら次のように区切って解析してほしいのですが、

| 0xEB 0x01 (jmp) | 0xE8 (db) | 0x6A 0x2A (push) | 0xE8 ... (call) | ...

逐次的に解析するツールは次のように区切ってしまいます。

| 0xEB 0x01 (jmp) | 0xEB 0x6A 0x2A 0xE8 ... (call) | ... (or) | ... (inc) | ...

これだけの説明ではちょっと分かりにくいですが、このようにゴミデータを入れることによって、単純に上から解析するタイプのツールから、ある程度コードを守ることができます。(このように上から解析する逆アセンブリを"Linear Disassembly"と呼んでいます。)

今回紹介した本では、上述のような逆アセンブル防止技術だけでも、他にも様々な種類の技術が詳しく記載されています。


さいごに

この本の分かりやすいところは、たいてい実例を示して詳細に書かれていることです。
それでいて必要なポイントだけがまとめられているので、この本一冊からたくさんの情報を得ることができます。
それから、マルウェアについての解析を中心としているので、各種技術が身に付くとともに、マルウェアの仕組みについても分かります。

残念ならが、調べた限りでは日本語版はありませんが、マルウェア解析技術の本としては海外でも非常に評価の高い一冊です。さらに、kosen14s所属の古月くんもこの本の電子書籍版を持っており、いかにこの本が凄いかを証明しています。

表紙の上で解剖されんとする宇宙人を見た際には、是非一度手にとって読んでみてください。

2016年2月7日日曜日

katagaitai CTF 2016 関西 med に参加しました

2016年02月06日(土曜日)に大阪で開かれたkatagaitai CTFの中級者向け勉強会に参加しました。内容は暗号とエクスプロイトで、私は脱初心者を目指して参加しました。
暗号はCSAW CTF 2014 Crypto300のfeal.pyを、エクスプロイトはCodeGate 2015 Pwnable400のbeef_steakを中心にハンズオンで講義が行われました。
いずれも惜しくも時間内には解けませんでしたが、また時間に余裕がある時に解法コードを作って載せられたらと思います。(試験のすぐ前なので今は時間が無いです)

暗号 - feal.py

暗号問題は、サーバーで動作しているpythonコード(feal.py)が渡され、そこに接続します。
・第一段階
まず、指定された文字列(ランダムな16文字)から始まり、sha1の最終16ビットが全て1になるような文字列を送信しなくてはなりません。つまり、
h = sha1(str_rnd + something)
について、
h[:-1] == h[-2] == 0xFF
であれば通過できます。
これは単純にsomethingにブルートフォースしたら簡単に通りました。
ここまでは家で解いてきたのですが、その後はでっていう状態でした。

・第二段階
次に暗号化されたフラグが渡されます。これは保存しておきます。今回使用されている暗号は、タイトルの通りFEAL暗号ですが、よく見ると、

return ((x << 2) | (x >> 6)) & 0xff

であるはずのシフト関数が、

return ((x << 3) | (x >> 5)) & 0xff

になっていました。本来の仕様との違いはこれだけです。
今回使用する攻撃はDifferential Cryptanalysis(差分解読法)とかいう聞いたこともない方法で、要するに
「入力A, BについてFEAL(A), FEAL(B)が求まっていて、その出力差分FEAL(A) ^ FEAL(B)が一定ならX ^ Y == A ^ B(入力差分がA,Bと等しい)ような入力に対して、その出力の差分はFEAL(A) ^ FEAL(B)となる」
みたいな感じでした。(間違ってたらすいません)
なんとなーく分かったのですが、実際にコードを書くと何かしっくりこなかったです。それに、後から知ったのですが、pythonで書くと十数時間かかるようで、C言語で書く必要があったそうです。ずっとpythonで買いてパソコンのファンを鳴らしていました。

結局私のコードで答えは出ずに、解答だけ聞いて終了してしまいました。暇なときにコードを書きます。


エクスプロイト - beef_steak
エクスプロイトと聞いてうわぁって感じだったのですが、内容はとても面白かったです。とにかくスライドが詳しく書かれていました。(暗号のスライドも図が多くて分かりやすかったですが、こちらは300ページ程度ありました)
beef_steakでは、steakというLinux x86_64のバイナリが渡され、それを実行しているサーバーを攻略するという問題です。家で解析しておきましょうという指令が出ていたので、C言語のコードに直したのですが、その時はStack BOFがあるだけで、フラグが読めそうとは思いませんでした。というのも、Stack Canaryが付いており、オーバーフローしてもすぐに終了してしまうのです。

・第一段階
家で解析したときのCコードを以下に示します。

RC4で暗号化されたデータを復号化するのが目的です。オーバーフローというとret2libcやROPのイメージが強かったので、今回は全く分からない状態からスタートしました。
ここで新たに学んだのは、"argv[0] leak"という手法です。(正式名称でない?)これは、Stack CanaryのStack Smashingメッセージが表示されることを利用し、内部のデータを取得するという方法です。
具体的には、オーバーフローを起こした際の
*** stack smashing detected ***: ./steak terminated
というおなじみのメッセージの
./steak
を取得したい変数に変更します。そのためASLRが有効な場合は固定アドレスに存在するデータが取得する対象となります。今回のCコードを読めば分かるように、key、state、output等のデータはアドレスが固定されています。
どうやって"./steak"の部分を変えるかですが、__stack_chk_fail関数では、普通にargvの内容からargv[0]のファイル名を表示しているそうです。(詳しくはkatagaitai CTFの資料を参考に。)つまり、十分にオーバーフローできる場合、argv[0]のポインタがある部分を取得したいデータのアドレスに書き換えてやります。
これを聞いてさっそく
"\xe0\x20\x60\x00\x00\x00\x00\x00" * 40
みたいなデータ(keyのアドレスを繰り返し)を送ろうと考えたのですが、よく考えたらkeyは使用した直後にmemsetで0にクリアされています。ということでstateを取得したら見事取得できました。と思ったら256バイトあるはずのデータを途中までしか取れていません。これはstateの途中に0x00が存在するのが原因で、
 接続→stateを取得(lengthバイト)→切断→接続→state+lengthを取得(lengthバイト)...
みたいに何度か接続するようにして全てのデータを取得しました。

・第二段階
もともと"What's your favorite food?"という質問に対して答えが正しければ通ります。取得したstateを元に、バイナリから取得した暗号化済みデータを復号化し、それを送りました。ここで新たなバグを使用します。steakは入力の文字数をstrlenで取得し、その分暗号化しているのですが、入力の最初に0x00を持ってくることで、暗号化処理をスキップできます。そうしてチェックを通過すると、自由にメッセージを"./message"に書き込むことができるようになります。
ここで使用するのがShared Library Injectionという手法で、これはLD_PRELOADで自前のライブラリを使用することで攻撃できます。したがって、今回のように自由にファイルをアップロードできる状態か、sshのような形式でないと利用できません。今回は、systemをexecve("/bin/sh", 0, NULL);に変更するようなライブラリを作りました。(messageへの書き込みにsystem関数が呼び出される。)messageに保存できたら、これを利用したいのですが、ライブラリmessageを読み込ませる手段が必要です。

・第三段階
messageを読み込ませるには、環境変数LD_PRELOADを./messageにする必要があります。つまり、オーバーフローを使用してenvp[0]のアドレスを"LD_PRELOAD=./message"を指すアドレスにすればよいのです。こんなコードを作って実行したのですが、ローカルでは「ライブラリをロードできません」みたいなメッセージが出て、リモートではそもそも何も起こりませんでした。ちょっとよく分からないので暇な時にやります。

この他にも様々なexploit tipsを教えていただきました。

まとめ
katagaitai CTFの勉強会に参加させていただくのは今回が初めてでしたが、内容は難しかったものの、その技術は(なんとなく)分かったので、非常に有意義な勉強会だったと言えます。どちらも全く知らなかった攻撃揃いだったので、自分でコードを作りながらも新鮮な感じがしました。難しかったとはいえ、このくらいのレベルはやってて楽しいので、次回も同じレベルの勉強会があれば是非参加したいです。

2016年1月31日日曜日

SECCON 2015 Final Intercollegeに参加しました

2016年01月30日(土)に東京電機大学でSECCON 2015 Final Intercollegeが開催されました。1チーム4人までで、中学生から大学院生までで構成された18チームが参加しました。私のチームはinsecureで、
初めてA&Dに参加したので、何をすればいいかが分からず、かなり戸惑いましたが、その上での感想と軽いwrite upをしようと思います。

各チームに一台のサーバーが割り当てられ、チームメンバーはあらかじめ渡されたパスワードで管理者(root)としてsshでログインできます。開始からしばらくはIPもユーザーも分からなかったので、全員何もできない状態でしたが、しばらくして運営から説明がありました。
サーバーでは3つのサービスを稼働させることができ、私はvulnerable_blogとsbox2015を担当しました。vulnerable_blogはブログの記事を投稿できるサービスです。サイトを見ると、XSSとSQL Injectionの脆弱性がありました。また、SQL Injectionの際のエラーがそのまま出力されます。とりあえず自分のチームのSQLiの脆弱性を修正し、Webアプリの設定をdevelopmentからproductionに変更してエラー出力を無くしました。チームでやったDefenseらしい行動はこれだけで、この防御力が後に悪く影響しました。
ORDER BY等で調べた結果からUNION SELECTを使用しました。

hoge') UNION SELECT 0,0,load_file("/var/www/html/vulnerable_blog/keycode"),0,0#

これにより管理者のパスワードを取得できます。また、自チームのkeycodeが初期状態で"test"だったので、"abc123password"みたいなのに変更しました。これで管理者になり、記事のログの削除キーにボットが登録したフラグが見つけられました。この時点でSQLiを修正していたり、keycodeを変更していたり、何かしら修正していたチームは半分以上あったと思います。
次にsbox2015の脆弱性を探し始めます。sbox2015でruby, php, pythonのコードを投稿すると、ランダムな数字が返され、その数字を同じアプリに渡すとコードが実行できるようになる。とりあえすlsを実行して一覧を取得し、何か無いかを探しました。vulnerable_blogのSQLiが修正されたサーバーについては、sbox2015のコード実行でkeycodeを取得しました。一部のチームはコード実行をできなくしたり、管理者ページにアクセスできなくしたりしていました。
チームメンバーがsbox2015により攻撃された際のコードを保存しておいてくれたので、それと同じ方法で他のチームに攻撃を開始しました。攻撃はmysqlコマンドをrootで実行することにより、他の問題のデータベースの内容を取得しました。自チームではrootでの実行を禁止することで対策しました。(チームメンバーがやってくれました)

他の問題などで脆弱性を突かれて防御点が大きく原点されていたようで、8000点以上の攻撃点を得たものの防御点は-7000点以上になっており、結果は18チーム中の15位でした。

今回のA&Dで分かったことは以下のことです。
・防御専門のメンバーを作る
・フラグの取得は自動化する
・サービスを中途半端に止めるなら、ずっと稼働させておく方が良い
・相手の攻撃から攻撃手法を知ることもできる
・相手の攻撃よりも先に自分のサーバーの修正をする
・上位チームを狙った方が点数はかなり稼ぎやすい

・チームで全部の問題を同時に担当する。(1つでも放置しておくと、それを通して他の問題のフラグも取られる)

とにかく難しかったですが、新しいことばかりで面白かったです。それから可視化システムは相変わらず格好良かったです。参加者のみなさん、運営のみなさん、その他関連している方々、お疲れ様でした。(internationalの方もお疲れさまです。)

2015年11月9日月曜日

SECCON福島大会 サイバー甲子園に参加しました

2015年11月07日(土)に福島の会津で開催されたサイバー甲子園(SECCON予選)に出場しました。10チームが抽選で選ばれ、私(ptr-yudai)のチーム名はinsecureで、theoldmoon0602殿と一緒に参加しました。

結果は2位で決勝の出場権を貰いました。以下が上位3位までの最終スコアです。
 CTF事情を知っている方によると、どうやら1位の方はプロだそうです。
以下は得点の推移です。(上位3チームまでチーム名を残しています)

とりあえず、自分が解いた問題の中で、覚えているもののwriteupを書こうと思います。

binary100
Linuxの32bit実行ファイルが渡されたので、gdbで起動しました。スタックに1を入れて、直後にその値が2より大きいかを調べて分岐しています。setでEIPを変更して続行すると「SECCON{Can Uread me?」と表示されましたが、送信してもポイントゲットならず。色々試して、「SECCON{Can U read me?}」を送ったら正解でした。

binary200:
Linuxの32bit実行ファイルが渡されたので、gdbで起動しました。重要な部分をCっぽく直すと、

gets(s);
for(i=0; i<32; i++) {
  tmp = esp_2C + s[i];
  foo = 0xFF ^ (char)tmp;
  bar = cipher[i];
  if ( bar == foo ) // OK
}


つまり、入力から1文字ずつNOTをとり、それを予め用意されたデータ(cipher)と比較しています。cipherをメモリから出力し、pythonでNOTをとるとフラグになりました。「SECCON{XOR_encryption_message}

network100
パケットデータが渡されます。ファイル無いので覚えてないですが、認証みたいなのがあるので、見るとBase64文字列があります。デコードしたらフラグでした。(たぶん)

network100
パケットデータが渡されます。なんかエラーが連なっているところがあったので、そこらへんのIPの192.168.44.161でSYNフラグが立っている部分をwiresharkでフィルター(ip.src==192.168.44.161 && tcp.flags.syn==1)します。出て来たパケットを上から見ると、各パケットのオフセット0x12に連続してフラグが1バイトずつ書かれていました。「SECCON{Data_is_included_NOT_ONLY_in_payload_but_also_header_field.}

net300
パケットデータが渡されます。wiresharkで見るとメールのプロトコルが使われており、中にいくつか送信されたデータがありました。まず目に止まったのが、何行にもわたるbase64文字列です。メールの添付ファイルだなと思ってデコードすると、zipファイルが出てきます。解凍しようとするとパスワードが求められます。メールの送信データの中にパスワードっぽいフレーズがいくつかあったので、試すと開きました。中にあったファイルはComposite Document Fileというもので、theoldmoon0602殿の助言でLibreで開くと、またパスワードを求められます。これもメール内の別のフレーズで試すと開き、フラグが表示されました。「SECCON{Sending_File_Password_with_Followed_Mail_is_bogus.}


crypt100
「U0VDQ09Oe1VyOXdnbWZZWXh5N2VvOFFnTDJWfQ==」というbase64文字列が渡されるので、デコードすると「SECCON{Ur9wgmfYYxy7eo8QgL2V}」になります。


programming100
turtleとかいうライブラリを使用したpythonのコードが渡されます。windowsのpythonには標準で入っていたので、draw_flag関数を実行すると、亀が絵を書き始めます。ちょっと遅かったので早くし、最後に停止ルーチンを挟むと、国旗が表示されました。theoldmoon0602殿がすぐにミャンマーの国旗であると知らせてくれました。「SECCON{MYANMAR}


web100
アクセスすると同じページがロードされるので、wiresharkで見るとフラグが受信されていました。

web100
ログインページでしたが、何を入力してもサーバー側でエラーになります(出題ミス?)。Fiddlerで見ると、レスポンスの最後にgzipデータがあったので、抽出して展開するとフラグのページが現れました。

misc100
Excelデータの各セルの背景色が色分けされており、SECCONの「突破」マークがドット絵みたいになっていました。Libreで開くと中央らへんに左三角がたくさん並んでいました。調べた結果から、excelのリスト機能と思って調査しました。とりあえず重たいので背景色を全て削除し、リスト内に「#」が書いているところと書いていないところを区別しようと閉じて、再度開くとなぜか三角が減っており、それらがフラグをAAのように表示していました。「SECCON{NIRVANA_KA1}


misc100
「作者は誰か」という問題で、短いアルファベット羅列が渡される。ダブルクオーテーションで囲って調べると、たくさんのサイトがヒット。一番上のサイトを読むと、ベートーベンの楽曲のリズム(だったかな?)であることが判明。形式が指定されていなかったので、いろいろ入力しましたが、最終的にtheoldmoon0602殿が正しい形式で送ってくれました。


感想
CTF歴は1年ちょっとで、SECCON決勝を大きな目標として必死に勉強してきましたが、初の予選で決勝への出場権を貰えて嬉しいです。これからしばらくはAttack&Defenceの勉強をする予定です。
問題はちょうど良い難易度で、CTF4bでの講義が結構役に立ちました。
theoldmoon0602殿のプログラミング力は凄く、何やってるのか分かりませんでした。
まだまだ勉強しないと......

2015年10月26日月曜日

TUMCTFに参加しました

2015年10月24日の22:00(日本時間)から24時間開催されたTUMCTFにオンラインで参加しました。
3人でチームを組んで、睡眠も取って15時間以上は参加できたと思います。
世界から455チームが挑戦して(最低でも244チームは1問以上解いていました)、私達のチームは65ポイントで58位でした。

問題はCrypt, Web, Rev, Recon, Misc, Exploitから各5,6問程度ずつ出ました。今回は、私が解いた問題の内、覚えているwhitebox, bad_appleについてwriteupを書きます。

whitebox crypt - rev - 20[pt]
問題文:
Do not panic, it's only XTEA! I wonder what the key was...
ctf.link/assets/downloads/rev/xtea
問題ファイルをobjdumpで見ると、まずstrlenでargv[1]が16文字かをチェックしています。
そこで適当な16文字を渡していき、ブラックボックス的にテストすると、後半の8文字は出力に影響が無いことが分かりました。
さらに、問題文のXTEAで調べると、wikipediaに辿り着き、これを参考に解析を開始します。
wikiによると、暗号化の途中で sum + key[sum & 3] を行うのですが、keyがバレないように、この値は全て予め書き込まれています。
こんな感じ:
  4005a7:       89 ca                   mov    edx,ecx
  4005a9:       89 c8                   mov    eax,ecx
  4005ab:       c1 ea 05                shr    edx,0x5
  4005ae:       c1 e0 04                shl    eax,0x4
  4005b1:       31 d0                   xor    eax,edx
  4005b3:       01 c8                   add    eax,ecx
  4005b5:       35 68 78 70 7b          xor    eax,0x7b707868
  4005ba:       03 07                   add    eax,DWORD PTR [rdi]
  4005bc:       41 89 c2                mov    r10d,eax
  4005bf:       89 c2                   mov    edx,eax
  4005c1:       c1 e0 04                shl    eax,0x4
  4005c4:       41 c1 ea 05             shr    r10d,0x5
  4005c8:       41 31 c2                xor    r10d,eax
  4005cb:       41 01 d2                add    r10d,edx
  4005ce:       41 81 f2 2e ea 58 1b    xor    r10d,0x1b58ea2e
  4005d5:       45 8d 1c 0a             lea    r11d,[r10+rcx*1]



ということで、この sum + key[sum & 3] にあたる値を収集しました。

そのあと、なぜかこのencipherをC言語で書いたのですが、sumやkeyは入力に影響しないと気付いて、すぐにkeyの計算に取りかかりました。
wikiのdecipherを参考に、
・delta = 0x9E3779B9 で固定。
・sum = delta * num_round でnum_roundは今回の場合32個分あった。
・sum -= delta を繰り返す。
・keyは4要素ある32bit整数の配列
と分かりました。
すぐに解読コードを書きました:
#include <stdio.h>
#include <stdint.h>


int main()
{
  int num_rounds = 32, i;
  uint32_t delta = 0x9E3779B9, sum = delta * num_rounds;
  uint32_t l[64] = {0x7b707868, 0x1b58ea2e, 0xba9ae30, 0x9bd661db, 0x9bd661db, 0x4818a1a2, 0x57c7dda0, 0xf44e5f4c, 0xf44e5f4c, 0x9285d905, 0x84879514, 0x326e4acb, 0x14b448bf, 0xb2ebc278, 0xd0a5c484, 0x5f2e023f, 0x6d2c4630, 0xb63bfe9, 0xfd657bf8, 0xa99b39a2, 0x8d922fa3, 0x4983ab68, 0x4983ab68, 0xca012315, 0xe60a2d14, 0x764362dc, 0x764362dc, 0x147adc95, 0x6701687, 0xc0b09a3f, 0xc261924c, 0x60990c05, 0x5ee813f8, 0xe11683b2, 0xef2149c0, 0x8d58c379, 0x7f4dfd6b, 0x2b903d32, 0x3b3f7930, 0xd7c5fadc, 0xd7c5fadc, 0x77ae6ca, 0x67ff30a4, 0xf82be44f, 0xf82be44f, 0xa46e2416, 0xb41d6014, 0x42a59dcf, 0x50a3e1c0, 0xeedb5b79, 0xe0dd1788, 0x8ec3cd3f, 0x7109cb33, 0xf4144ec, 0x2cfb46f8, 0xad78bea5, 0xc981c8a4, 0x59bafe6c, 0x59bafe6c, 0x5f0bc16, 0xe9e7b217, 0xa5d92ddc, 0xa5d92ddc, 0x2656a589};
 
  uint32_t key[4] = {0,0,0,0};
 
  for(i = 0; i < num_rounds; i++) {
    key[(sum >> 11) & 3] = l[63 - i*2] - sum;
    sum -= delta;
    key[sum & 3] = l[62 - i*2] - sum;
  }

  printf("%08x %08x %08x %08x\n", key[3], key[2], key[1], key[0]);

  return 0;
}


出力結果をasciiにし、エンディアンを直したら、}!pu_gnimr4w{pxhとなりました。
これを逆にして、hxp{w4rming_up!}

bad_apple - Crypt -  15[pt]
問題文:
Baby's 1st

ctf.link/assets/downloads/cry/bad_apple.tar.xz

try:
    ncat 1.ctf.link 1027 < good.bin
expect:
    "hello"
xzにはgood.binとbad_apple.pyが含まれていました。
以下がbad_apple.pyです:
#!/usr/bin/env python3
import sys, binascii
from Crypto.Hash import SHA256

key = open('key.bin', 'rb').read()

message = sys.stdin.buffer.read(0x100)
if len(message) < SHA256.digest_size:
  print('len')
  exit(0)

tag, message = message[:SHA256.digest_size], message[SHA256.digest_size:]

if SHA256.new(key + message).digest() != tag:
  print('bad')
  exit(0)

if b'hello pls' in message:
  print('hello')
elif b'flag pls' in message:
  print(open('flag.txt', 'r').read())
送信されたファイルをハッシュ(tag)と文字(message)に分け、sha256(key + message)とtagの値が等しいことを確認します。
さらにmessageが"flag pls"ならフラグが取得できます。
不明な文字を足してハッシュを取る、というプログラムの時点で頭の中はhashpumpだけだったので、hashpumpを使う方向で解きました。
さて、good.binの中の前半のハッシュは「2628455f6617ecea024895a48578ebce00fa9204983d09b6d1757d05dc430567」で、文字は「hello pls」でした。
これを元に、flag plsを付け足したハッシュを作ります。
keyの長さが分からなかったのでpythonでループしました:
import commands
import binascii
i = 32
for i in range(1, 1024):
    ret = commands.getoutput("hashpump -s 2628455f6617ecea024895a48578ebce00fa9204983d09b6d1757d05dc430567 -d \"hello pls\" -a \"flag pls\" -k " + str(i))
    get = ret.split("\n")
    _hash_ = binascii.unhexlify(get[0])
    data = get[1].decode('string_escape')
    buf = _hash_ + data
    f = open("data", "wb")
    f.write(buf)
    f.close()
    ret = commands.getoutput("nc 1.ctf.link 1027 < data")
    print(str(i) + " : " + ret)
    if ret == "len" : continue
    if ret == "bad" : continue
    if ret == "hello" : continue
    break
32回目でフラグが返ってきましたとさ...。
hxp{M3rkL3_D4mg4rd_h4s_s0m3_Pr0bl3mZ}

全体を通して難しかったです。Web30とRev10とExploit10が解けなかったのが非常に悔しいです。あとは上級者向けが多く、1人〜3人程度しか解いていない問題ばかりで、難易度がすごい分かれていました。
もしかしたら暗号が向いているのかなぁ...

CTFで思ったのは、まず、Reconを予告しておきながら、最後の最後で0[pt]の答え無しのページにした運営に驚きました。あと、web20の問題の答えが後半でIRCに書き込まれたせいか、20[pt]にも関わらず145人もの人が後半でこのポイントを獲得しています。

ちょっと難しかったですが、解けたときは楽しかったです。

2015年10月4日日曜日

Arduino UNOを使ってみた

入門者向けキット付きのArduino UNOの互換ボードを安く買ったので、使用してみました。osoyooという所のを買ったのですが、URLのリンクが切れていました。環境はCent OS 7です。
とりあえず公式サイトからlinux 64bitsのIDEをダウンロードして解凍します。arduinoというELFファイルがあったので、実行したらそのまま動作しました。

Arduino自体が電子回路などの入門者向けで、簡単に回路を作ることが可能です。そのため僅か数時間で液晶ボードに文字を表示させるに至りました。いくつか詰まった点を適当に書いていきます。

まず、IDEはルート権限で起動しないと書き込めませんでした。それから、プロジェクトを「main」という名前にしていたらコンパイルできませんでした。その辺で一旦つまづいたところで、まずはLEDを点滅させる回路を作りました。LEDを13番とGNDに直で繋ぎ、プログラムを書き込みます。
書き込む前にメニューバーの「ツール」->「ボード」みたいなところを選択しておかないといけません。届いたキットにマニュアルは付いていないし、製造元サイトも閉鎖されてたので困りましたが、どうやら普通のarduinoと全く同じ方法でやればいいようです。

void setup() {
  pinMode(13, OUTPUT);
}
void loop() {
  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
  delay(1000);
}

言語仕様も非常に分かり易いです。コンパイルして書き込みすると、LEDが点滅しました。わーい。
それだけでは物足りなかったので、セットに付いていたI2D 1602 LCDに文字を表示させようと考えました。かなり前にPIC kitとマイコンでやろうとして、一瞬で挫折した記憶があるLCDに挑戦です。
まずはライブラリをいれます。こちらからライブラリをダウンロードして展開します。これを、~/Arduino/にフォルダごといれ、IDEを再起動するとライブラリが使用できます。
その後もいろんなサイトを参考にしながら、
VCC - 5V
GND - GND
SDA - Analog 4
SCL - Analog 5
に接続して、サンプルのHello, world!を書き込みましたが、液晶画面が光だけで何も起こりません。ここで暫く詰まったのですが、いろいろ見ていると、LCDのアドレスとやらを調べないといけないらしいです。こちらのコードを書き込んで、シリアルモニタでアドレスを確認します。サンプルは0x27だったのに対し、自分のは0x3Fでした。これに書き換えて最初のHello, world!を書き込みました。すると、初期化処理で画面が暗くなる反応を見せたものの、文字は表示されません。さらに調べると、裏にコントラスト調整用の部品がありました。これを回転させると文字が表示されました。

最後に作った電光掲示板もどき。初めての言語なので汚いコードかもしれません。使用する際はLCDのアドレスや画面サイズを適宜変更してください。
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

void display(String buf, int y);
LiquidCrystal_I2C lcd(0x3F,16,2);

int offset = 0;

void setup()
{
  lcd.init();
  lcd.backlight();
}

void loop()
{
  lcd.clear();
  display("Hello, world!", 0);
  delay(300);
}

void display(String buf, int y)
{
  lcd.setCursor(16 - offset, y);
  if ( offset > 16 ) {
    lcd.print(buf.substring(offset - 16));
  } else {
    lcd.print(buf);
  }
  offset = (offset + 1) % (16 * 2);
}

参考:
http://arduino.umemoto.org/home/i2c-lcd
http://forum.arduino.cc/index.php?topic=128635.0






2015年9月13日日曜日

ctf4b熊本に参加しました

2015年09月12日(土)に熊本の東海大学熊本キャンパスで開かれた「ctf for ビギナーズ 熊本」に参加しました。55人が参加しており、学生から大人までいろんな人が参加されていました。
WebとNetworkの講習があり、資料や問題としてはBinaryジャンルもありました。
講習では、CTFの問題を解くにあたっての説明や、各種ツールの使い方などを分かり易く説明していただきました。
CTFでは問題を解いたらランプが点灯しブザーが鳴るようになっていたので、ブザーが鳴るたびに焦りました。あとTDUよりは少なかったですが、変な動画も流れました。

さて、この記事ではCTFの方で問題が残っているものや、覚えているもののWriteupをします。
まず、最終のスコアボード:

わたしはptr-yudaiで2位でした。1〜3位までは同得点なので1位という扱いになりました。正直こんなにとれるとは思ってませんでした。

Other

1:練習問題 (100pt)

ctf4b{〜〜}みたいなのが書いてあるので、そのまま送信します。

6:Universal Web Page(笑) (500pt)

php://filterを使うのかと思ったのですが、上手くいかずに諦めました。500ptだからもっと難しいのでしょうが、誰も解けてませんでした。

Web

2:Can you login as admin? (100pt)

定番のSQLiで、「' OR '1'='1」をパスワードとして入力するとadminになりました。1番上をadminにしている作者さん優しいです。

3:Find the flag (200pt)

どんな問題か忘れました。ディレクトリトラバーサルだったかな?

4:1M4G3 V13W3R (300pt)

私の苦手なファイルアップロード問題です。php送ったりタイプをimage/jpegに偽装したりしましたが、できませんでした。ディレクトリトラバーサル等も確認できず、分かりませんでした。

5:SQL Injection Level 2 (400pt)

SQLiですが、ORが使えません。ORを削除していると予想して「' OORR '1'='1」を送ったら通りました。ちなみに正攻法はUNION SELECTする方法です。

Binary
7:matryoshka (100pt)
問題ファイルはこれです。fileコマンドで種類を調べるとisoだったので、mountでマウントすると、flagというファイルが出てきました。flagはzipだったので解凍すると、またflagが出てきました。これはmicrosoft cabinet的なファイルだったので、linuxのファイルマネージャで開くと、またファイルが出てきました。今度はPNGだったので、見ると、フラグが見つかります。

8:読めますか? (200pt) 【たぶんこんなタイトル】

問題ファイルはこれです。PNGファイルなのですが、Linuxでは開けませんでした。(解説のときはフラグがギリギリ見えない画像が映ってました)中身はぐちゃぐちゃだったので、しばらく悩みましたが、stringsでctfを探すとフラグが見つかりました。

9:Jump (300pt)

問題ファイルは後であげます。実行ファイルなのでIDA Proで見ると、argvを確認しているらしき部分がありました。順番に「ctf」「is」「so」「fun」(だったかな?)をチェックしているので、argvだなと思って、引数を指定して起動するとフラグが表示されました。

10:Readit (400pt)

アセンブリが渡されて、結果の数字を答える問題。疑似言語みたいなのに訳して、面倒そうだったので飛ばしたら最後までやりませんでした。
これです:
mov     [ebp+var_4], 0
mov     [ebp+var_8], 0
jmp     loc_40101F

loc_40101F:
cmp     [ebp+var_8], 0C8h
jge     short loc_40103C
mov     ecx, [ebp+var_4]
add     ecx, [ebp+var_8]
mov     [ebp+var_4], ecx
mov     edx, [ebp+var_4]
sub     edx, 0Ah
mov     [ebp+var_4], edx
jmp     short loc_401016
mov     eax, [ebp+var_8]
add     eax, 1
mov     [ebp+var_8], eax
jmp    loc_40101F:

loc_40103C:
mov     eax, [ebp+var_4]
push    eax
push    offset Format   ; "%d"
call    ds:printf

11:Checkit (500pt)

問題ファイルはこれです。フラグを入力したら正解かを確認するプログラムです。これに時間をとられてしまった上に解けませんでした。丁度このときにタイタニックの笛の動画が流れ始めて、投げ出しました。

Network

12:Insecure Protocol (100pt)

問題ファイルはこれです。telnetしてたので、telnetを見ると、フラグが書いてました。

13:Insecure Protocol 2 (200pt)

問題ファイル無いです。12番のtelnetと同じですが、フラグの部分が埋められていました。そこで、telnet先のサーバーにtelnetで接続して、パケットから抽出したユーザー名とパスワードを入力するとフラグが返ってきました。

14:File Transfer Protocol (300pt)

これも問題ファイル無いです。たしか、FTP-DATAを見たらフラグが見つかったような......。

15:This quiz is a NETWORK challenge (400pt)

問題ファイルはこれです。実行すると、しばらくして文字が表示されたので、ネットに接続していると予想し、wiresharkでパケットを取得しました。すると、basic認証でwebからファイルを取得していたので、ブラウザでアクセスしてbasicを認証して、フラグのファイルへアクセスしました。なんと逆解析して難読化されたコードを読んだ猛者もいました。

16:Oldies Communication (500pt)

パケットファイルなのですが開けませんでした。ヘッダが壊れていたので、別問題のヘッダを参考に修復して開きました。TCPで何かしているのですが、何をしているのか分からず、フラグもスペースで上書きされていて、IPも存在しなかったので解けませんでした。

以上、概要だけですが、writeupでした。
今回、会場に集まるようなCTFはTDUに続き2回目でしたが、好成績を修められてよかったです。とはいえ、SECCONではもっと難しい問題が出るので、まだまだ勉強するつもりです。

お疲れさまでした。