UnicornでWindowsAPIトレーサーみたいなものを作った

とは言っても技術的に何か特殊なことをしているとかいうわけではなくて,単純にPEローダーを頑張って実装したみたいな話.

作ったもの github.com

Unicorn

QEMUのラッパみたいなもので,CPUエミュレータフレームワークとして手軽に扱えるUnicornというライブラリがある.
つい先月v1.0がリリースされて,Go, Python, .NET, Javaの他にMSVC, VB6, Ruby, Haskellバインディングが追加された.

www.unicorn-engine.org

他に特筆すべき点としては,GDTR, IDTR, LDTRあたりのサポートが追加されて適切にセグメントレジスタを設定できるようになった(!)ことや,コンテキスト周りのサポートが入ったことが挙げられる.前者の方が結構重要で,WindowsではFSレジスタがTIBのアドレスを指しているのでマルウェアだとよく使われたりする.

PyAnaとDutas

UnicornでPEエミュレータってあるんじゃね?と思って探したら,案の定あった.

github.com

github.com

どちらもメインの機能としてWindowsAPIのトレーサーがついていて,サンプルコードを実行すると胡散臭い命令がジャンジャン呼ばれている様子を観測できる.

しかしこれらはUnicorn v0.9での動作を前提に作られていて,セグメント周りのサポートが入っていなかったためFSレジスタにメモリのアドレスを直接書き込むという荒業を使っている.

        mu.reg_write(UC_X86_REG_FS, TIB)

これをv1.0で動かすと当然クラッシュする.

また,どちらもLDR周りの整備を無理矢理やっていて,例えば別のdllを追加するのに結構労力を割かれたりする.解析する検体側でLoadLibraryが呼ばれてたりするとメモリにマッピングしてくれるのだけれど,PEが事前に別のdllを必要としていると全く動かない.

WindowsAPIフック

このように制約条件はありながらも,WindowsAPIフック機能はかなり良い感じに動作する.どうやってAPIフックを実現しているかというと,

  1. DLLに含まれる関数の先頭を\xc3 (ret) に書き換える
  2. 当該関数の先頭アドレスをフック対象に追加
  3. 関数が呼ばれるとUnicorn上で代わりにその処理を行い,スタックや戻り値などの辻褄を合わせる

という非常にシンプルなものである.
フック対象を管理しているリスト (実際はdict) では関数の先頭アドレスとWindowsAPIの名前をペアとして持っておく.代理で呼ぶ関数には予めhook_というprefixをつけておき,globals()から取得してeip, esp, uc (Unicornインスタンス)を渡して呼び出す.例えばエミュレータ上でGetProcAddressが呼ばれるとhook_GetProcAddress(eip, esp, uc)が実行される,という具合.
hook_*という関数が大量に実装されているが,もちろんされてないもののほうが多い.最初はPyAnaないしDutasにちまちまとフック関数を実装して頑張っていたのだが,結構な数になってくると見通しが悪い.あとlstrcatみたいな絶対に動作が変わらないものの処理が検体毎に複製されていくのがなんだか気持ち悪いので,ライブラリ化しておきたいという気持ちになった.

pefile

PyAnaもDutasもDLLがエクスポートした関数を列挙するのにpefileというライブラリを使っている.

github.com

これはPythonでPEを扱うなら鉄板ライブラリといえるほど動作が安定していて,実績も多い.例えばangrはPEを解析するときに内部でpefileを使っている.

しかしこのライブラリ,非常に遅い.kernel32.dll (約1.1MB) を読み込むのに6秒くらいかかる.DLL一つだけならまだ良いが,3個以上のDLLを予め読み込んだり,LoadLibraryが途中で呼ばれて追加のDLLが読み込まれたりすると,正直待ってられない.DLLが足りなくて途中で落ちたらまた20秒くらい待たされることになる. と思っていたのだが,単純にpipで入るバージョンがクソ古いだけだった.githubから最新版を落としてくるともうちょっと早く動く.それでも2秒くらいはかかる.

PythonでPEパーサーといえばもう一つ,pype32というライブラリがある.readpe.pyが有名.前は普通にサクサク使えてた印象があったのだけど,いつの間にか遅くなっていた.というかパースが終わらない.バグか?これも勘違い.正しくは exeのパースは早いがdllはクソ遅い だった.kernel32.dllで試したのだけれど,2分48秒かかった. 測り直したら1分5秒でした.論外.

PEパーサー

pefileもpype32もまともに使えない(pefileはまあ使える)ことがわかったので,自分で実装することにした.参考にしたサイトを貼っておく.

PE(Portable Executable)ファイルフォーマットの概要

Portable Executable カテゴリーの記事一覧 - 鷲ノ巣

DOSヘッダからセクションヘッダまでなら前者,IMAGE_DATA_DIRECTORY以降の話なら後者がわかりやすい.
これらを参考にしつつ,MSDNのサイトPeering Inside the PE: A Tour of the Win32 Portable Executable File Formatを見ながらctypesでごりごりとパーサーを書いた.

今回必要な機能は

  • EXEがインポートしているDLL, 関数名/RVA列挙
  • DLLがエクスポートしている関数名/RVA列挙
  • PEがメモリ上へ展開された後のイメージ
  • PEの各種情報 (ImageBase, EntryPointなど)

で,IMAGE_DIRECTORYのうちサポートするインポートはIMAGE_DIRECTORY_ENTRY_IMPORTのみ.
この位まで機能を絞ると案外実装しやすくて,速度も出た.

github.com

A Tour of the Win32 Portable Executable File Formatとあるように,32bitまでしか対応してないので現状64bitは未対応.気が向いたらやる.

TIB周り

WindowsのプロセスにはTIB (Thread Information Block) というのがあって,プロセス・スレッド自身の情報を保持している.プロセス起動時にFSレジスタがこの構造体の先頭アドレスを指すようになっており,これを辿ることで各情報にアクセスできる.
特に対解析機能として難読化をかけてるコードやパッキングしているようなコードは,元のバイナリが使用しているWindowsAPIのアドレスを動的に解決する必要があるため,PEBのLDRからモジュールのリストを辿ってLoadLibrary,GetProcAddress (kernel32.dll) のアドレスを取得し,そこから必要な関数をもってくる,といったことをよくする.

そのためTIB周りをちゃんとセットアップしてやらないと動かない検体が結構あって,実装することにした.PyAnaもDutasも見かけ上はLDRまでやってるけど,オフセットも決め打ちで,用意するLDRのリンクも真面目に繋いでないので,ちょっと別経路を辿ると動かなかったりする.具体的に言うと,ロードされたモジュールはLoadOrder, MemOrder, InitOrderの3種類の順番で辿ることができるが,LoadOrderの部分しか繋いでないとMemOrderを辿る検体が動かない,という具合.LDR_MODULEについては Understanding the PEB_LDR_DATA Structure がわかりやすい.
ちなみにTIB周りの構造体は Welcome to WinAppDbg 1.5! — WinAppDbg 1.5 documentation を拝借して流用している.素のままだとUnix環境で動かないので適当に手を加えた.

セグメントレジスタ周り

UnicornはあくまでもCPUエミュレータなので,アーキテクチャの設計に対して忠実に処理を書かなければならない.最初ここを理解してなくて,FSレジスタを設定するだけでsegv起こしたり,mapしたはずのスタック領域がunmapped扱いになったりした.
ざっくり説明すると,セグメントレジスタを設定するときはGDT (Global Discriptor Table) をあらかじめ設定しておく必要があって,その中のインデックス番号,メモリ上の範囲,各種フラグを含んだ値 (selectorという) をセグメントレジスタに書き込む.selectorを書き込む段階でGDTのセットアップが終わってないとsegvする.
GDTについては Global Descriptor Table - OSDev Wikiプロテクトモードのセグメント機構 を参照した.

他にハマりどころとして,Windows (x86環境) ではGS, ES, DS, SSが全て同じ値 0x002B (index:5, range:0x00000000-0xffffffff, flags: gr=1, sz=1, pr=1, privl=3, ex=0, dc=0, rw=1, ac=1, rpl=3) に設定されているのだけれど,Unicornではこの値だとスタックがうまく扱えなくて,正しくはSSに設定するフラグを gr=1, sz=1, pr=1, privl=0, ex=0, dc=1, rw=1, ac=1, rpl=0 にしてあげる必要がある.違いはgdt entryの特権レベルとselectorの要求特権レベルが0 (kernel) になっているのと,dc (Direction bit/Conforming bit) が1 (segment grows down) になっている点.dc bitは全然気づかなかった.
セグメント周りの設定はこのへんでやってる.indexが露骨に調整してあるのはWindowsをマネしたため.

フック

フックの仕組みはPyAnaやDutasと同じく,関数の先頭をretに書き換えてUnicorn側で代わりの処理を呼ぶ.トレーサーとフック処理の接点をUnitracerインスタンスだけに抑えるため,hookを呼ぶ時にselfを渡すというちょっと変なことをやっている.WindowsAPIが行う処理はアーキテクチャに依らず同じ結果を返してほしいので,フック処理ではなるべくUnicornの都合を意識しなくて済むような設計にしたかったのだが,現状はできてない.多分呼び出し規約をWindowsクラス側で一意に扱えるようにしないと実現できない気がする.
実際にUnitracerを使うときは絶対に挙動が変わらない処理はlib/windows/hooks以下に書いておいて,挙動を変えたい時に[Unitracerインスタンス].hooksに直接関数を追加して動かすみたいな使い方を想定している.これでとりあえず当初の目的であったフック処理のライブラリ化に関しては達成できたとは思う.

現状

ここまで長々と書いてしまったけど,とりあえずAPIトレーサとしては十分動くと思う.
まだTIB周りが弱くて,サンプル (samples/Wincalc.sc) が動かない!w [17/03/11]PEパーサーのバグだった.現在は修正済み. あとフックを全然実装してないのでちょくちょく追加していく予定.

Advent Calendarに遅刻しないために

この記事はMMA Advent Calendar 2016の18日目の記事です.(遅刻回避)

僕はMMAでは無いのですが,

というわけで書きます.

皆さん,Advent Calendarって登録してても忘れますよね?

忘れない方法として,通知を行うというソリューションがありますが,どのようにしたら良いでしょうか.

結論

iCal形式でダウンロードできるので,カレンダーにインポートしましょう

これで忘れていてもカレンダーから通知が飛んできますね

今後活用していきたいと思います

f:id:icchyr:20161218235156p:plain

僕からは以上です

クソギャグの作り方

この記事はMCC Advent Calendar 2016 の10日目の記事(大遅刻)です.
前日はid:hu__huによるベトナムで拉致されそうになったときの話でした.

僕といえばつまらないクソギャグを投下することで有名なわけですが(?),今回はクソギャグを生み出すときの思考プロセスという大変どうでも良いことについてお話しします.

クソギャグとは

クソギャグとはクソとギャグを合わせたもので,すなわちクソなギャグです.ギャグとは,Google先生曰く,

ギャグ
映画・演劇などで、観客を笑わせる、その場当たりのせりふ・しぐさ。
▷ gag

らしいですが,ここでは単純にダジャレのことを指します.

ダジャレとは言葉遊びの一種で,一つの文に似たような音を複数回登場させることでそこに面白さなどを見出すわけですが,なぜこれが笑いを引き起こすかということはよくわかりません.おそらく,同じ音が繰り返されるものの言葉自体は異なるものを指しているため頭が混乱する,みたいなものだと思っています.ダジャレを発した後に流れるなんとも形容しがたい空気が面白いとも言えます.

ダジャレを作る意味

意味はありません.ただ,出来の良い物が完成すると発信したくなるのが人間の性です.絵と同じです.

ダジャレができるまで

では実際にどのようにしてクソギャグ,クソダジャレができていくのか見ていきましょう.ここではひとつの文の中に2回似たような音をもつ文字列が登場するタイプのものを例にします.
僕の中では,主に以下のようなプロセスを経て生成されます.

  • 元となるアイデアを見つける,思いつく
  • 2つの文字列を自然に含むような単語,文を考える
  • 全体の調整を行う

実際には2番目や3番目の工程が行われずに,直接ダジャレが誕生することもあります.

例1

元となるアイデアを探す

解かれることを前提としている問題のように,ダジャレにも元となるアイデアがあって,それを加工していくことがあります.
例えば,以下のダジャレを見てみましょう.

このダジャレでは,飛行機を利用することで得られるマイレージポイントを示すマイルと,行くという意味の動詞の謙譲語参るの音が同じであるという事実が根底にあります.

2つの文字列を自然に含むような単語,文を考える

ではマイル参るを含むような単語,文を考えましょう.マイルは飛行機で移動する描写があれば自然に登場させることができます.参るは,どこかに行く描写があればこれも自然に登場させることができます.幸いにも,マイル参るも移動に関連した語であるため,同時に,かつ自然に登場させるのは難しく無さそうです.

全体の調整を行う

ここまでくれば後は簡単です.飛行機で移動する機会があれば自然な流れの中にクソギャグを埋め込むことができます.この場合中国に飛行機で行くというイベントが発生しているため,その目的の一部にマイルを貯めることを取り込んであげることでダジャレの完成です.

ちなみに飛行機で移動するなんてイベントは頻繁に発生しないため,マイル目的というのはウソです.自然に紛れ込ませることができれば良いのです.
また,実際にダジャレを発信するときはギャグをベースに考えているのではありません.身近な出来事の中にクソギャグの可能性を見つけた時,それらしい理由をつけて発信します.上の例の場合,マイルと参るをかける,というアイデアは飛行機で移動するイベントが発生した時に湧いてくるのであり,ギャグが先にあるわけではないのです.

例2

次の例を見てみましょう.

元となるアイデアを探す

ここでは和装という名詞と,弱そうという形容詞+助動詞の口語が同じわそうという音を含んでいるというアイデアがあります.

2つの文字列を自然に含むような単語,文を考える

和装, 弱そうは後者が形容詞をベースとした語であるため,単純に並べてあげるだけで自然な文になります.考える必要はありません.

全体の調整を行う

今回の場合は調整の必要もありません.2番目の工程と同様にスキップされます.

ではこのダジャレはどのような経緯で生まれたかというと,

このツイートをみて思いつきました.
内輪の話になってしまいますが,ここで登場するhhc0nullという人物はよくイジられる対象であるため,弱そうという少し攻撃的なフレーズを向ける対象としてはもってこいなわけです.和装という,普段の会話では登場ないような単語が出てきたため,それに言及したことを示すのは難しくありません.すなわち,ツイートにリプライしなくても意図が伝わるため,このくだらないギャグをより多くの人に届ける目的で僕はこのツイートをしたわけです.リプライにすると両方をフォローしている人しか見えなくなってしまいますからね.

より洗練されたダジャレを求めて

上の例では,いずれもベースとなるアイデアに含まれる語を適当に並べるだけで完成しているため,あまり面白味がありません.ここでは,より高度なダジャレについて紹介します.

ムダの無い構成を持つダジャレ

以下の例を見てみましょう.

このツイートのベースとなる部分はナイス椅子ですが,助詞であるを間に挟むことでムダのない(ダジャレを構成する語以外の文字列が存在しない)ものに仕上がっています.通常このようなギャグは聞いただけは即座に理解されにくいです.というのも,複数の文節にまたがって同じ音が登場している場合,ダジャレ部分を予測しづらいためです.例えば,先ほどの例1において,

マイルを溜めに中国へ参る

このダジャレの場合,勘のいい人であれば中国への部分で「次に参るが来るな」と予想ができてしまいます.これはダジャレ部分が各文節内で完結しているためで,音を被らせている部分が把握しやすいのです.
一方,ナイスな椅子ではそもそも椅子にまたがってないすという音が存在しているため,この部分をひとまとまりとして認識しない限りダジャレに気づくことはできません.

これは僕の経験則ですが,複数文節にまたがって音を構成するタイプのダジャレでは,助詞が使われることが多いです. 類似した例として,以下のようなものがあります.

さて,ここでナイスな椅子をパワーアップさせることを考えてみましょう.
ないすという音を含み,かつ近い文字数を持つものを探すと,NAIST(奈良先端科学技術大学院大学)の日本語読みないすとというものがあります.幸いにして,はみ出た部分のは助詞として用いることができるため,ナイスとNAISTのように簡単にダジャレを構成することができます.ここまでくれば簡単で,ベースとなったないすにはナイスな椅子というダジャレが既に存在するので,

という2重のダジャレが誕生します.

しかしながら,この文は全くもって意味不明です.ナイスな椅子だけでも不自然なのに,そこに全く関係ないNAISTという単語が登場するため,何を言いたいのかさっぱりわかりません.ですがそれで良いのです.言葉遊びとはそういうものです.意味の通る流れにできれば尚良しですが,音をしっかり被らせることができてさえいればダジャレとして成立します.

自然な文の中に投下するダジャレ

最初の方に挙げたまいるや,わそうは明らかにダジャレであることがわかってしまいます.前者では参る,後者では和装という普段使わない表現や単語を用いているため,どことなく生じる違和感を払拭することができないためです.では自然なダジャレの例を見てみましょう.

https://twitter.com/icchyr/status/520037527638376448 f:id:icchyr:20161212211148p:plain

お気づきでしょうか?これは一見すると何らかのフォーマット,プロトコルを読んだ感想にしか見えませんが,仕様しようがかかっているのです.あまりにも自然すぎて一切のリアクションが無いことからもこの文章が自然であることを示しているとも言えます.実は皆気づいていて,あえてスルーしているなんて可能性はありますが.

この文がダジャレだと気づかれにくくするためには,ダジャレの最大要素である音の被らせ具合を大きくし過ぎないことです.一般的に被らせている文字数が少ないとダジャレとしての評価は低くなりがちですが,自然体であることも重要な要素の一つです.また,文の長さをそれなりに確保することで音が被っている部分の割合を小さくし,認識されにくくすることができます.
被っている文字数が2文字の場合,さらに気づかれにくくすることができます.

https://twitter.com/icchyr/status/777520528017887236 f:id:icchyr:20161212211229p:plain

やはり自然すぎると普通の文にしか見えないため,気づいてもらえないことがほとんどです.

おわりに

いかがでしたでしょうか? 普段僕がクソギャグ,特にダジャレを考えるときに頭の中で行っていることを無理矢理書き出して整理してみましたが,人間の脳はこういうプロセスを意識することなくいろんなことを考えることができるんだなあと,少し感動しました.

ちなみにこの記事を書くにあたって,過去ツイートからダジャレっぽいものを列挙するためにdajarepというプログラムを使わさせていただきましたが,結構ノイズが多くて自然言語処理の難しさを実感しました.また,検知できたものだけを目で見て絞り込んだだけでも314個のギャグが出てきて,改めて自分のダジャレを発する頻度の高さを認識し同時に呆れました.他にやること無いのか.

最後まで読んでくださった方,長文&駄文にお付き合い頂きありがとうございました.きっと「時間を無駄にした」と後悔されてることでしょう.

明日は@ougai_quantumの記事の予定だったらしいので,そのうち上がることを期待しましょう.MCC Advent Calendar 2016は既に25日分すべての枠が埋まっており素晴らしいですね.どうか最後までお楽しみいただければと思います.

HITCON CTF 2016 Finals参加記

この記事はCTF Advent Calendarの4日目です.

まだ欠けているところがあるのでとりあえず速報版ということで…
12/07: 残りの写真などを貼りました.

12/2-12/3の2日間,台湾にてHITCON CTF 2016の決勝戦が開催され,TokyoWesternsとして参加してきました.
今回の遠征において起こったことを時系列順に書いていきます.

飛行機の遅延

我々は当初11:45に成田を出る飛行機に乗る予定だったのですが,前日の夜22時頃に突然メールが来て,

Flight Delay Notification

11:45発予定が19:00に変更?????
このままだと台湾につくのは22時過ぎ(現地時刻)になり,移動が極めて面倒なことになりそう,という結論に.
とりあえず問い合わせて,払い戻しが可能かどうかを聞くことにしました.(時間帯的に窓口が英語しか対応してなくて,非常にしんどかった)

どうやら払い戻しは可能っぽいので,実際に手続きをするのは翌朝に日本語の窓口が対応しているときにしよう,ということで急遽別の飛行機を予約するという話になりました (この時点で夜中の1時を過ぎており,寝落ちした→他の人より航空券が少し高くついた).

まあなんやかんやで無事に飛行機に乗れたので良しということで.

台湾着

台湾に着いて適当にSIMカードを購入したりして,ホテルまでのルートを調べました.
今回運営が用意してくれたホテルは結構良い所らしく,なんと空港からバス一本でたどり着くことができて感動しました.
ちなみにバスの券を販売しているところのPCにXPが写っていたり,発券された乗車券の時刻がクソ適当だったりといろいろ怪しい点は多かったものの,特にトラブルもなくホテルまで着き,先に来ていたhhc0nullと合流してすき家で食事を取りました.

f:id:icchyr:20161207230733j:plain:w200 f:id:icchyr:20161207230634j:plain:w300

あとLTEがクソ早くて感動した

f:id:icchyr:20161207230510p:plain

会場

今年のFinalsはHITCON Pacificと同時開催らしくて,Taipei New Horizonという所の最上階でした. f:id:icchyr:20161207230916j:plain

f:id:icchyr:20161207231020j:plain

f:id:icchyr:20161207231047j:plain

設営もめちゃくちゃ手が込んでいて,各チームのテーブルには看板が設置してありました.

f:id:icchyr:20161207231235j:plain:w300

…? 何か足りないですね…

ところでこれは某CTFの名札です

f:id:icchyr:20161207231815j:plain:w300

今年はチーム名を間違えられる呪いにでもかけられたんでしょうか.

Finals

去年に続き素晴らしい大会で,今年のA&DはPwnable3問,Web3問でした. 競技はday1 10:00 ~ 18:00, day2 8:30 ~ 15:30で,day2の12:30までは1ラウンド5min, それ以降は1ラウンド2minという設定でした. Pwnable問題は公開されてからは最後まで動いていて,Web問題は各問題が別々の時間に公開されて2つ以上の問題が同時に動くことはありませんでした.そのかわりWeb問題にはfirst bloodがあり,1500, 1000, 500, 300, 100という具合に解いた順にボーナスポイントが与えられました.

問題 時間 ジャンル 概要
digimon day1 10:00 ~ pwnable デジモンをモチーフにしたゲーム.ショップの番号に制限が無くて任意メモリの書き換えが可能(らしい)
rabbit day1 10:00 ~ 14:00 web zabbixが動いている./jsrpc.phpSQL injectionの脆弱性があり,Adminのセッションを奪うことができる.Adminはzabbixの機能でスクリプト実行が可能なのでflagを読む.
criticalheap_revenge day1 14:00(?) ~ pwnable よく読んでないけどFSBがあったらしい
webrop day1 14:00 ~ day2 12:30 web SugarCRMとphpMyAdminが置いてあるだけ.詳しくは後述します.
fx-1337 day2 9:30 ~ pwnable 電卓を模したアプリケーション.BackSpaceの回数に制限が無くて任意のアドレスにジャンプすることのできる脆弱性があった(らしい)
myide day2 12:30 ~ web flask製のテキスト共有システム.詳しくは後述.

僕がメインで取り組んでいたのはWebの3問で,前半2問(rabbit, webrop)はいずれも実際に使われているソフトウェアを用いており,オイオイ0dayゲーか〜???と思いましたが,3問目はお手製のflaskアプリでした. 実際にはrabbit, webropはCVEの付いている脆弱性を抱えており,それを用いて攻撃が可能,というものでした.

webrop

phpMyAdminとSugarCRMが置かれているが,phpMyAdminの指しているホストが126.0.0.1と128.0.0.1のみ選べるため,全く意味ない.ように見える.SugarCRMは普通の設定で,適当なユーザーでのログインはできる状態. この問題は1日目は全く動きが見られず,2日目に持ち越されたため結局first bloodは無効になりました. 我々のチームではytokuさんが一日目の夜に0dayの脆弱性を発見し,それを用いてexploitを作成していったところうまく刺さりました(もちろん数チームには途中から対策されました). 他にも0dayを見つけたチームがいて,CTFerの恐ろしさを見せつけられました. ちなみに競技終了後に運営に想定解を聞いたのですが,phpMyAdmin脆弱性によってセッションの上書きが可能であり,それを用いてSugarCRMで権限昇格を行う,というものだったそうです.PPPはこの方法で攻撃したそうです. 途中までは全部のチームからflagを取れていたのですが,PPPはログインをできなくしたせいで攻撃が刺さらなくなったにも関わらずSLAはALIVEになっていて,なるほど. 去年はSLAがクソ厳しかった上に,事前のルール説明に「脆弱性部分以外のパッチで防ぐのはやめろ」みたいなことが書いてあったため,どのチームも割とパッチに苦労してたと思うのですが… 結果的には結構な点を取れたと思います.

myide

flask製のアプリケーションで,一番最初に用いられた脆弱性はpath traversalでした.普通に任意ファイルを読むことができる感じ. テンプレートエンジンにjinja2を使っていたので案の定template injectionがあり,任意コードの実行が可能でした.ただしこの問題のみ,ソースコードに対するパッチが当てられなかった(当てても再起動する手段が無かった)ため,終わりの方はDOSの打ち合いという地獄絵図が広がっていました.

結果

最終結果はCykor, LC/BC, PPP, Shellphishに続いて5位でした!!!

決勝のA&Dでは今までの中で一番良い結果を残せたと思います.

余談

終了後の会場に良い話が転がっていました.

f:id:icchyr:20161207232458j:plain

終わりに

クソ適当な記事ですみませんでした.CTF Advent Calendarにはまだまだ空きがあるので是非書きましょう.
明日はyamaguchiさんのTSGCTFwriteupです.

El Capitanでtsocksを使う

コマンドを実行するとき,必ずSOCKSプロキシを通るようにするためのツールtsocksというものがあって,Linuxではもちろん,OSX Mavericksでも動くのでよく使っていました.

ところが,先日El Capitanにアップデートした途端動かなくなり,いろいろ調べてるうちに解決したのでそのメモ.

OSXでのインストール方法

標準のhomebrewには含まれておらず,homebrew用のスクリプトを用意してやる必要があります.

norisu0313.hatenablog.com

ここを参考に,

github.com

に含まれているスクリプト/usr/local/Library/Formula/に配置します.

~$ cat -> /usr/local/Library/Formula/tsocks.rb
require 'formula'

class Tsocks < Formula
  # The original is http://tsocks.sourceforge.net/
  # This GitHub repo is a maintained fork with OSX support
  homepage 'http://github.com/pc/tsocks'
  head 'https://github.com/pc/tsocks.git'

  depends_on 'autoconf' => :build if MacOS.xcode_version.to_f >= 4.3

  def install
    system "autoconf", "-v"
    system "./configure", "--prefix=#{prefix}", "--disable-debug", "--disable-dependency-tracking", "--with-conf=#{config_file}"

    inreplace("tsocks") { |bin| bin.change_make_var! "LIBDIR", lib }

    system "make"
    system "make install"

    etc.install "tsocks.conf.simple.example" => "tsocks.conf" unless config_file.exist?
  end

  def test
    puts 'Your current public ip is:'
    ohai `curl -sS ifconfig.me 2>&1`.chomp
    puts "If your correctly configured #{config_file}, this should show the ip you have trough the proxy"
    puts 'Your ip through the proxy is:'
    ohai `tsocks curl -sS ifconfig.me 2>&1`.chomp
  end

  def config_file
    etc / 'tsocks.conf'
  end
end
[EOF]
~$

tsocksのしくみ

tsocksのソースコードを読むとわかるのですが,ライブラリ関数のフックを用いてこの機能を実現しています.LinuxならLD_PRELOAD, OSXならDYLD_INSERT_LIBRARIESおよびDYLD_FORCE_FLAT_NAMESPACEといった具合です.tsocks本体のスクリプト環境変数に共有ライブラリを追加するためのラッパーで,実際には生成されたlibtsocksというライブラリが仕事をしています.

El Capitanでの問題

どうやらSystem Integrity Protection (SIP) が悪さ (セキュリティ的には良い挙動ですが) をしているらしく,DYLD_INSERT_LIBRARIESによるフックが無効化されていました.
SIPの無効化はリカバリーモードでcsrutil disableとか打つと良いのですが,影響を及ぼさないシステム保護まで解除してしまうため,必要なものだけを無効化します.

~$ csrutil disable
~$ csrutil enable --without debug

これによってApple InternalDebugging Restrictionsのみが無効化され,fsなどの保護は生きたままになります.

~$ csrutil status
System Integrity Protection status: enabled (Custom Configuration).

Configuration:
    Apple Internal: disabled
    Kext Signing: enabled
    Filesystem Protections: enabled
    Debugging Restrictions: disabled
    DTrace Restrictions: enabled
    NVRAM Protections: enabled

This is an unsupported configuration, likely to break in the future and leave your machine in an unknown state.

これでtsocksが使えるようになります.

~$ ssh -fND 1080 home
~$ tsocks curl 192.168.1.X

Linuxでunzipすると文字化けする

今年度が始まるちょっと前くらいに新しくバイトを始め,楽しくやっています.どこでバイトしているかは言えないので察していただきたいのですが,毎日楽しく業務をこなしています.
業務中に得られた小さな知見を公開できる範囲で共有したいと思います.

タイトル通り,Windowsで作成したzipファイルをそのままunzipすると悲惨なことになります.現在のディレクトリに展開された場合は削除するのも面倒です.
このような悲劇を生まないために,unzip -O cp932 hoge.zipしましょう.

TMCTF Writeup (Analysis Others 100, Analysis Offensive 300)

Trend Micro Inc.が主催するTrendMicroCTFにTokyoWesternsのお荷物担当として参加してきました.

このCTFは本来8月に開催される予定だったのですが,イベント用スコアサーバの設定に一部誤りがあり、一時的に競技で使われる問題、回答にアクセスが可能な状態となっていたため,不運にもISUCONと重なる日に延期されました.
問題のオープン形式はDEFCON同様得点の小さいものから順番に開くが,オープンする問題は選べるのではなくそのジャンルの次の問題,という仕組みでした.(事前に聞いていたのと違う…?)
また開始直後はスコアサーバが激重で僕以外のメンバーが繋がらず,Programming 100は早速サービスが落ちていました.

ちなみに僕が解いたのはAnalysis Others 100, Analysis Offensive 300 (partially)の二問だけという悲しい結果に終わりました.腹いせにWriteupを書きます.

Analysis Others 100

PDFが与えられ,fix meとか言われるのでとりあえずexiftoolにかける.

~$ exiftool fix_my_pdf.pdf
ExifTool Version Number         : 9.96
File Name                       : fix_my_pdf.pdf
Directory                       : .
File Size                       : 32 kB
File Modification Date/Time     : 2015:09:26 12:44:33+09:00
File Access Date/Time           : 2015:09:27 02:24:28+09:00
File Inode Change Date/Time     : 2015:09:27 02:18:29+09:00
File Permissions                : rw-r--r--
File Type                       : PDF
File Type Extension             : pdf
MIME Type                       : application/pdf
PDF Version                     : 1.3
Linearized                      : No
Warning                         : Invalid xref table

Invalid xref tableとあるので,xrefがちゃんとリンクされてなくて表示されないコンテンツがあるんだろうな〜と思いつつpdfextractをかます.
いかにも怪しい<xmpGImg:image>というタグが見つかり,中は/9j/で始まるJPEGbase64 encodeしたような文字列なのでbase64で戻す.途中に&#xA(改行コード)が含まれているのでそれを置換するなり削除しておく. f:id:icchyr:20150928100452j:plain

TMCTF{There is always light behind the clouds.}

Analysis Offensive 300

脅威タイプ診断と称したWebアプリケーション.

f:id:icchyr:20150928102755p:plain

適当な名前を入れると

あふれる情熱が止まらないあなたは「バッファオーバーフロー」タイプです。

COOLな診断結果を返してくれる.  

下の方にコンタクトフォームへのリンク(contact.php)があって,名前とコメントを送信することができる.

意味わかんね〜って悩んでいると@ytokuさんがnameパラメータがvalidationされておらず,XSSできることを発見する.
ちなみにresult.php及びcontact.phpに対してGETパラメータとしてnameを渡すとあらかじめ名前が書き込まれた状態となる.(http://ctfquest.trendmicro.co.jp:40100/737c08b6f0ea477cb4ce3eb1b8e81a87/contact.php?name=hogehoge)

これはhttps://twitter.com/intent/tweet?text=text%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BFと同様の挙動である.

しかしこのページはvalidationがほとんどされていない(scriptが一回削除されるだけである)ため, http://ctfquest.trendmicro.co.jp:40100/737c08b6f0ea477cb4ce3eb1b8e81a87/contact.php?name="><scrscriptipt>alert(1);</scrscriptipt> とかやると簡単に発火する.

いろいろ試しているうちにPHPSESSIDでnameを保持していることがわかり,どうやらXSSで管理者のPHPSESSIDを奪う問題らしい.

想定されるシナリオは

  1. 適当なCookieを取得
  2. XSSを利用し,自分のCookieを使用してresult.phpnameパラメータに漏洩させる情報(Cookie)を入れて,GETさせる
  3. 先ほどのCookieを用いてresult.phpにアクセスすると,nameに漏洩した情報がある

という流れ.
ただし一つ罠があって,管理者に踏ませるリンクはlocalhost(or 127.0.0.1)じゃないとアクセスできない.(ネットワークの外に出られないようになっている?)
以上を踏まえて,
nameパラメータに

"><scrscriptipt>tmp=document.cookie;
document.cookie='PHPSESSID=0ufcvu21seft5sn3l2sllni896';
location.href='result.php?name='+tmp</scripscriptt>

をURLエンコードしたものを渡した http://localhost:40100/737c08b6f0ea477cb4ce3eb1b8e81a87/contact.php?name=%22%3E%3Cscrscriptipt%3Etmp%3Ddocument.cookie%3B%0D%0Adocument.cookie%3D%27PHPSESSID%3D0ufcvu21seft5sn3l2sllni896%27%3B%0D%0Alocation.href%3D%27result.php%3Fname%3D%27%2Btmp%3C%2Fscripscriptt%3E
というURLを用意し,contact.phpcommentに入力して送信した.

その後result.phpに再度アクセスするとname{Cookie};PHPSESSID={Cookie}に書き換わり(Cookie保存し忘れた),得られたCookieを用いてresult.phpにアクセスするとflagが得られる.

余談

漏洩させたCookieを使うとnameがflagになっているのだが,threat_typeはXSS(Cross Site Scripting)になっていた.
今思い返してみると,threat_typeで確認できたのは 標的型攻撃,水飲み場型攻撃,バッファオーバーフローランサムウェアSQLインジェクション だったのでXSSが現れない,というのは大きなヒントだったのかもしれない.


CTFではそもそも脆弱性はあまり関係なかったり,「こんな脆弱性ありえないでしょw」みたいな問題が割と多いと思いますが,TMCTFではセキュリティ企業ならではの現場に即した対応能力が求められる問題(def300とか,PEバイナリとか)が多かったように思います.どちらかというと実戦的かなと.

TokyoWesternsは @nomeaning さんがかなりの数の問題を解いてくださったので6位という好成績に終わり,無事決勝戦に進めそうです.
決勝のA&Dは4人までなので,戦力に数えてもらえたら是非参加したいです.