IDA Proを使い始めた

およそ2ヶ月前くらいにIDA Proのメジャーアップデートが行われ,7.0がリリースされた.約一年ぶりのアップデートとなったが,もっとも大きな変更点はついにIDA Proそのものが64bitアプリケーションになったことである.かねてより購入機会を伺っていた僕は,これを機にMac版のNamed Licenseを購入することにした.

IDA Pro Named License購入チャレンジ

ところがquotation systemを見ればわかる通り,現在IDA Pro Named Licenseは全てのプラットフォームにおいて販売されていない.詳しいことは不明だが,知り合い曰くバージョン7.0がリリースされた直後に本体およびデコンパイラのライセンスがリークされ,それを受けての対応ではないかとのこと.
当初Google CTFのfinalsが直前に迫っており,せっかくならここに間に合わせたいということで急遽メールで交渉することにした.

欲しいライセンスは IDA Pro Named License [Mac] なんだけど,
なんか今全部のNamed Licenseが買えないみたいなんですよ.
新しくNamed License売ってくれない?w

みたいなことを書いて sales[at]hex-rays.com にメールを送った. すると半日くらいで返信が来て,

会社のメールアドレスから送ってくれや.

僕はまだ学生なわけで当然会社のメールアドレスは持っていない.とりあえず大学のメールアドレスを使って再度送信.

OKわかった.欲しいライセンスはお前に紐付く個人ライセンスでいいんだな?
quoteは用意できる.請求先住所を教えてくれ.

とまあ意外とすんなり通った.
あとはメールアドレスを変えたい旨を伝えたら最初のメールアドレスで手続きしてもらえたので,そのまま普段のメールアドレスをライセンスに紐づけることができた.

とにかくHex-Raysの人の対応が早くて,営業時間内なら1,2時間程度で返事が返ってきた.おかげで東京を出発する日にメール手続きを始めたにも関わらずフランスでのトランジット中にダウンロードリンクが降ってきて,そのまま空港の回線を使ってIDAを雑にインストールするといったことをしてた (回線を圧迫したけど深夜だったし許して) . 実はクレカの限度額が足りなくて急遽デビッドカードに切り替えたり,3Dセキュアに対応してないカードはrejectされるため羽田空港の搭乗口で3Dセキュアを有効化したりドタバタしていたんだけどそれはまた別の話.

エクストリームIDA購入チャレンジめいたものに見事勝利したわけだが,結局Google CTFでは使わなかった.

macOSでIDA Pythonをいい感じに使いたい

話は変わって,現実逃避をするために最近少し余裕が出て来たのでIDA Pluginをいくつか試してみることにした. まず最初に試そうと思ったのはPonceだったがこれはまだ7.0に対応しておらず,僕自身プラグイン開発の知見も全くないので諦めた.他に何かないか探していたところ,たまたまTwitterkeypatchが流れてきたのでまずこれを導入することにした.keypatchにはkeystoneが必要なので,まずIDA Pythonでkeystoneを使えるようにする.

しかしこれがなかなかやっかいで,IDA Pythonはシステム標準のもの (/usr/bin/python) を使う.僕は普段pyenvを使っているためmacOSのpipを一切整えておらず,いざ導入してもSIP (System Integrity Protection) に阻まれて一切のパッケージをインストールできない.もちろんSIPを無効化する方法 (http://icchy.hatenablog.jp/entry/2016/05/16/121630) もあるのだが,なんだか面倒なのでpyenvをうまく使う方法を考えた.

まずIDA Pro本体のディレクトリ (macOSでは/Applications/IDA Pro 7.0/ida.app/Contents/MacOS) におけるファイル・ディレクトリは次のようになっている.

...
cfg/ # 各バイナリ用のIDA設定ファイル
dbgsrv/ # 各種アーキテクチャ用のdbgsrvバイナリ
ida # 32bitバイナリ用IDA
ida64 # 64bitバイナリ用IDA
idc/ # idcスクリプト
plugins/ # プラグイン
python/ # IDA Python用ライブラリ
sig/ # シグネチャデータ
...

プラグインにとって重要なのはpluginsおよびpythonディレクトリで,pluginsにはプラグイン本体のプログラムが,pythonにはIDA Pythonから使用するライブラリが入っている. 原理的にはpythonにimportしたいものがあれば良いので,そこに~/.pyenv/versions/2.7.14/lib/python2.7/site-packages/keystoneへのシンボリックリンクを張ればちゃんとimportできる.ただしライブラリをインストールするたびに作業が発生するので面倒だし,大量のライブラリに依存するパッケージがあったらかなり手間がかかる.

そこでpyenv-virtualenvに着目する.virtualenvは本来特定のディレクトリ以下にpythonのライブラリを閉じ込めるもので,site-packagesの位置をコントロールすることでライブラリの名前空間を切り替えている.普通はshellのsourceコマンドなどでactivateするが,もちろんpythonのプログラム中からvirtualenvをactivateする方法はあって,bin/activate_this.pyを実行すればよい. これでida用のvirtualenvを切って,そこに必要なライブラリを入れていけば普段の環境は汚さずに済むしちゃんとpipでインストールできるので解決する. あとはこれをidaの起動時に実行されているようにしなければならないが,python以下を眺めていたらinit.pyというファイルを見つけた.このファイルの最後の方に

# Load the users personal init file
userrc = os.path.join(ida_diskio.get_user_idadir(), "idapythonrc.py")
if os.path.exists(userrc):
    ida_idaapi.IDAPython_ExecScript(userrc, globals())

こんなコードがあって,いろいろ調べるとどうやら起動時に$HOME/.idapro/idapythonrc.pyを実行してくれることがわかった.あとはこのファイルの中にpyenv-virtualenvの適当な環境をactivateするコードを書けばよい.

activate_this = '/Users/icchy/.pyenv/versions/2.7.14/envs/ida/bin/activate_this.py'
execfile(activate_this, dict(__file__=activate_this))

これでpyenvのidaという名前の環境がIDA Pythonに適用され,無事にkeypatchを導入することができた. ただし一つだけ注意しておく必要があるのはIDA Pythonの実行バイナリが変わっていないため,実行されるpythonのバージョンが必ずしもライブラリの導入環境と一致するわけではないということ.もちろんpyenv側でsystemと同じものを用意して,その下にvirtualenvを切ればよい話なんだけどまあ2.7系だし多分大丈夫でしょう.みたいな気持ち.

idasecを導入する

あとntddkのブログにidasecの7.0用パッチを書いた話をたまたま見かけて,貼られていた動画が面白そうだったので導入することにした.

これもハマりまくって結構時間を溶かしたんだけど,細かく書くのが面倒になってきたので要点だけ述べると,

  • binsecを動かすのに結構ライブラリが必要なのでntddk/binsec-vagrantを丸パクリしてbinsec-dockerを書いた
  • PyQt5の導入をするときにbrewでやるとpython3用が入ってIDAから使えなくなるのでbrew install pyqt5 --without-python3でやるとうまくいく
  • idasecのディレクトリでmakeを叩くのを忘れない (UIが生成されない)
  • pip install protobuf pyzmq capstone graphviz pyparsing enum path.py plotly
  • idasecはライブラリになっていないのでIDAのpython以下にidasecを配置しておく

ちなみに適当なバイナリでidasec試したんだけど,pythonが途中でUnicodeEncodeError吐いてIDAがハングアップした.pythonはカス

ICPC 国内予選 2017

今年もICPC国内予選に参加していました.
ブログには2014年の以外一切書いてませんでしたが一応ずっとnocowで出ていて,2013と合わせるとnocowのメンバーは全員5回目ということで最後の参加になります.

詳しいことはosrehunが書いてくれたのですが, osrehun.hatenadiary.jp 一応最後なので参加記を残しておきます.

メンバーは3年前から同じ

  • hec (@osrehun)
  • nokoTaro (@xthexworldx)
  • icchy (@icchyr)

で,上2人がコーダー,僕は環境構築担当です.

~15:00

練習セッションの存在を完全に忘れていて,僕だけリモート参加

f:id:icchyr:20170715094635p:plain

L問題が残っていたので先にそっちだけやった

M問題は例年通りだと,1回目は何回か試せば通って2回目でほぼ確実に落ちるようになっていたと記憶しているが,今年は1回目が100ケースくらいあって,そもそも手動だとキツイみたいな感じだった.
あと順位表をみると数十回WAしてACしたチームとかがちらほらいたので,Data1が通せればそのままData2も通せるんじゃないかと思った.適当に100通り全探索するスクリプトを書こうと思ったけど,これはCTFではないしサーバーに負荷をかけるのが躊躇われたのでやめた.

15:00~16:00

会場入りして,諸々の準備をした.
チームで使う環境を一新したのでプリンタの設定に手こずった.プリンタの型番と同じドライバが存在しなかったが,適当に似た番号にしたら行けるということをhecが覚えていたのでプリンタ設定AC.

16:00~16:30

僕が急に「やっぱり印刷投げるのいい感じに自動化したい」と言い出す(は?)

  • lprコマンドでhtmlを印刷 → キレイなhtmlソースが出てくる(それはそう)
  • Javascriptwindow.printで印刷ダイアログを自動で出していく(別チームのメンバーが考案) → クリックが面倒なのでダメ

結局htmlを印刷するにはWebブラウザによるレンダリングが必要なので,ブラウザ無しではできない
→ Headless Chrome使えばいいんじゃね?

Chromeにはバージョン59からヘッドレスモードというのが加わって,これがPhatomJSにトドメを刺した.
ざっくり言うとGUIのウィンドウを作らずにブラウザを立ち上げる機能で,パフォーマンス良くブラウジングを自動化できる.最近ではGoogle CTFのXSS問題とかで使われたりした.

コマンドで書くと

~$ google-chrome --headless --disable-gpu [OPTIONS] [URL]

が基本で,簡単な操作についてはそもそもオプションで使えたりする.

developers.google.com

今回は--print-to-pdfを使ってPDFを生成し,それを印刷する感じにした.

ちなみにICPCの国内予選は提出したり順位表を見るのにはログインが必要だが,問題を見ること自体は認証無しで可能(これは練習セッションで確認済み)だった. このおかげでログイン処理を書く必要が無く,URLをそのまま直に叩けば問題ページが降ってきた.

~$ for d in {A..H}
> do
> google-chrome --headless --disable-gpu --print-to-pdf http://********/${d}_ja.html
> lpr output.pdf
> done

という感じにするとA~H問題までの問題が印刷される.今回はうちの大学から3チーム出ていたので,lpr output.pdfだけfor文で回した.

↑のコマンドを書いてメモったのが開始5分前で,提案しつつ「事故っても責任は持てないよ」と逃げ道を作っておく.🚩

16:30~17:00

競技開始.
まず問題文を印刷するコマンドを打つ.

プリンタの側で待機している問題文配布担当から出されるNG🙅.

Not Found

The requested URL /********/_ja.html was not found on this server.


Apache/2.4.7 (Ubuntu) Server at icpc.yamagula.ic.i.u-tokyo.ac.jp Port 80

こうして僕たちの最後のICPCは幕を閉じた.
(完)






















フラグ🚩回収に成功したとこで気を取り直して再度コマンドを打つ.今度は大丈夫そう.

僕がやらかしてる間にhecがターミナルの後ろにあるブラウザの画面からA問題を読み取っていて,とりあえずテンプレート等を打ってすぐ交代する.

ちょっとデバッグに手こずって開始10分後くらいでAC.大学内で一番遅かったらしい.
nokoTaroがBを詰め終わっていたのでコーディング交代.hecがCを読み終わって解法を詰めているところなので僕はDを読む.
一瞬で読み終わったのでEをちら見する.これも一瞬で読み終わる.
hecにDの概要を伝えたらO(1)で解法が降ってきた.Bのサンプルが合わなくて紙デバッグに移る.同時にhecがCの実装を開始.

Bのデバッグがすぐ終わったのでCをコーディングしてる途中で交代して修正してAC.
そのあとhecがCを通してそのままDの実装に移る.この時点で30分くらいだったと思う.

17:00~17:30

Eが読み終わってるので僕はFを読む.これも一瞬で読み終わるが,頭が弱いので折りたたみの様子を完全にイメージできず,メモ用の紙を使って小道具を作った.

これが後に大きく活躍したらしい.

nokoTaroがGの方針が思い浮かばないとのことなので,一旦Fを一緒に考えてもらう.
途中でDのデバッグ作業に呼ばれてsegvの箇所を特定するなどした.間もなくしてDが通る.

17:30~18:00

Eの概要をhecに伝えたがちょっと方針に確信が持てないのでFを手伝ってもらう.
3人でウンウン唸った後hecがよくわからない方法で通してた.

18:00~19:00

hecと適当に相談して,制約を見るとどうやらevaluatorを作ってぶん回せば行けそう(雑)ということがわかったのでそのままコーディングしてもらう.
nokoTaroがやはりGの方針が浮かばないとのことなので問題を見る.探索する近傍に優先順位をつけて反時計周りに辿れば良さそうということに気づくが,G問題ということもあり流石にそれはないでしょwみたいなやり取りを数回繰り返す.
途中でHを見て,幾何だけどなんとなく行けそうな匂いがしてしまう.しかし過去の経験上,幾何に手を付けて時間を溶かしてオワリみたいな展開が幾度となくあったのでGに戻る.
やはり先ほどの解法で反例が見つからないので強く主張する.悩んだ結果とりあえずコーディングだけしてみよう,ということに.
Eのバグ取りに手こずっていたようなので,一旦交代してnokoTaroにコーディングしてもらう.適当にバグを取ってサンプルも通ったのでsubmitする.WA.
Eの実装に戻ってもらいつつ,Gのテストケースを軽く印刷してもらう.18:30くらいに反例が見つかった.ここで右手法を使えば良いということに気づいて,nokoTaroに解法を伝える.

Eのバグが取れてサンプルも通ったとのことなので,Data1を処理している間にGのコーディングをしてもらう.いくつかバグを踏みつつ,EのData1の処理が終わったので提出.Correctで盛り上がる.
そのままGのコーディングを続けてもらい,バグが取れたところでEのData2の処理が終わる.提出してAC.6完で勝ちを確信する.

19:00~19:30

まあ解法雑だし最悪通らなくてもいいや…という気持ちでGを投げてもらう.AC.7完でかなり盛り上がる.

順位表を確認すると東大に挟まれていて笑う.その時点では4位だったのでshuriken通してくれ〜みたいな謎の祈りをしながら一応Hを見る.
完全に解法は詰めきれていなかったが,とりあえず幾何ライブラリを写経していた.
Hを考える気力が残っていなかったのであとは適当に順位表を眺めていたら,shurikenがGを通して4位になったので√29を確信する.

競技終了.7完5位という過去最高の結果だった.hecは神.僕はカス.

その後は会場の撤収作業を済ませ,適当に酒を飲むなどした.

おわりに

今回はそこそこ役に立てたので良かった.

Headless Chromeを使うと問題文印刷がかなり楽になるので来年度以降是非活用して下さい.typoをすると404 Not Foundなページが30枚近く出てくることになるので気をつけましょう.

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