globalのgitignoreの設定をdotfilesでやるようにした
新しいPCにglobalのgitignoreを入れ忘れてたからdotfilesの中でやるようにした。
以下のシェルスクリプトで、github/gitignoreからダウンロードしてきたgitignoreを~/.gitignore
に設置している。
if [ "$(uname)" = 'Darwin' ]; then curl -fL 'https://raw.githubusercontent.com/github/gitignore/master/Global/macOS.gitignore' >> ~/.gitignore else curl -fL 'https://raw.githubusercontent.com/github/gitignore/master/Global/Linux.gitignore' >> ~/.gitignore fi echo '' >> ~/.gitignore echo '# VisualStudioCode' >> ~/.gitignore curl -fL 'https://raw.githubusercontent.com/github/gitignore/master/Global/VisualStudioCode.gitignore' >> ~/.gitignore echo '' >> ~/.gitignore echo '# Vim' >> ~/.gitignore curl -fL 'https://raw.githubusercontent.com/github/gitignore/master/Global/Vim.gitignore' >> ~/.gitignore
Xcode Command Line ToolsやHomebrewのインストール、Homebrewやcaskで入るツールのインストールもdotfilesの初期設定スクリプトでやるようにしていて、それぞれをセットアップするかどうかを尋ねてくれるようにしている。便利!
$ git clone https://github.com/tkmru/dotfiles.git $ cd dotfiles $ ./init.sh Do you setup global .gitignore? [y/N] y ... Do you setup Xcode Command Line Tools? [y/N] y xcode-select: note: install requested for command line developer tools Do you setup Homebrew? [y/N] y Do you setup some tools by Homebrew and Homebrew cask? [y/N] y ...
dotfilesの配置にはMitamaeを使っている。これはプロビジョニングツールのitamaeのmruby実装で、シングルバイナリで動作するため、rubyの環境を整えることなく使えるところが便利。
GhidraのScriptまわりについて
はじめに
先日、NSAがリバースエンジニアリングツールのGhidraを公開した。 OSSであることや、Hex-rays社が高価で販売しているようなデコンパイラがついていることから注目されている。 SREを「Site Reliability Engineering」ではなく「Software Reverse Engineering」としてSRE frameworkを標榜しているのもかっこいい!!!!!
IDAでいうIDAPythonのように、GhidraでもJavaやJythonとしてのPythonで解析に役立つScriptを動かすことができる。
docs/GhidraAPI_javadoc.zip
にAPIリファレンスがあり、それらのAPIを扱える。
この記事では、そんなGhidraのScriptまわりを見ていこうと思う。
Pythonインタプリタ
CodeBrowserのツールバーのWindow->PythonよりPythonインタプリタを起動できる。 APIの挙動をシュッと確認できて便利。
上では、currentProgram.getName()
でバイナリのファイル名を取得し、
askString()
でポップアップを出し、ユーザーからの入力を受け取っている。
Script Manager
Code Browser上の再生ボタンのような▷のボタンを押すとScript Managerが開かれる。
ダウンロードしてきたScriptを読み込むにはScript Directories
のボタンを押して、Scriptがあるディレクトリを追加してあげるとよさそう。
Create New Script
ボタンを選択するとScript Managerの右側に簡易的なエディタが出現する。
Script Manager上でコードを書けるので便利そう。
ここで作成したScriptはデフォルトでは~/ghidra_scripts
に保存される。
参考になりそうなScript
Ghidra/Features/
以下にJavaやPythonのScriptがたくさん置かれている。
Script Mangerを開くとExamplesというディレクトリがあり、ここにあるScriptを読んでいくとチュートリアル代わりになりそう。
ExamplesというディレクトリがあるかのようにUI上では表示されるが、これはカテゴリのようなもののようで、実際には全然違うディレクトリにあるので注意。
$ find . -name ghidra_basics.py ./Ghidra/Features/Python/ghidra_scripts/ghidra_basics.py
便利そうなScript
ghidraninja/ghidra_scriptsというghidraのscriptがいくつか置かれたリポジトリがある。早い。
binwalkを走らせて見つけたアドレスをBookmarkに登録するbinwalk.py
や、暗号に使われる定数を見つけるyara.py
、
swiftの関数名をdemangleしてくれるswift_demangler.py
、stripped Go binaryにシンボルをつけ直すgolang_renamer.py
があり便利そう。
Nginxのalias traversalについて
Nginxのalias traversalとは
Nginxではaliasディレクティブを使って
locationディレクティブで指定したURIのパスをファイルシステム上のパスに対応させることができます。
以下の例のようにconfigを書くと、/var/www/app/static/
以下にあるファイルに/static/ファイル名
のようなパスでアクセスできます。
location /static { alias /var/www/app/static/; }
しかし、このようにlocationのパスの末尾が/
で終わっていない場合、..
を使うことで、開発者が意図していない上位のディレクトリへのアクセスが可能になってしまいます。
このケースだと、/static../setting.py
のようにパスを指定することで、aliasで指定したディレクトリより上位のディレクトリである/var/www/app
以下のsetting.pyにアクセスすることができます。これがNginxのalias traversalです。
以下のようにlocationで指定するパスの末尾に/
を書いておくことで防ぐことができます。
location /static/ { alias /var/www/app/static/; }
Nginxは、alias traversalを脆弱性として扱っておらず、Nginx側で修正されることはありません。
初出は2016年のHCTFの問題のようです。 http://momomoxiaoxi.com/2016/11/29/HCTF2016/#10%E4%BD%A0%E6%B2%A1%E8%B5%B0%E8%BF%87%E7%9A%84%E5%A5%97%E8%B7%AF
ぼくはCODEBLUE 2018でorangeさんのBreaking Parser Logic - Take Your Path Normalization Off and Pop 0days Outを聞いて知りました。 ちなみに、この発表はDEFCON26やBlack Hat 2018やHack.lu 2018でも行われています。ぼくもつよいexploit手法を見つけたら海外カンファレンス巡業したい。
実例
hackeroneでは以下のようなものが見つかっていました。
- #312510 [mobs.mail.ru] nginx path traversal via misconfigured alias
- #317201 [vulners.com] nginx alias_traversal
やってみる
alias traversalの問題があるNginxサーバーを立てることができるDockerfileを書きました。
このリポジトリは以下のファイルから構成されています。
nginx-alias-traversal-sample$ tree . . ├── Dockerfile ├── LICENSE.md ├── README.md ├── index.html ├── screenshots │ ├── flag.png │ └── top.png └── vulnerable.conf 1 directory, 7 files
$ docker build -t nginx-traversal . $ docker run -d -p 3000:80 nginx-traversal:latest
上のコマンドでdocker runすると、http://localhost:3000でNginxサーバーが動きます。
http://localhost:3000/static/がalias traversal可能なパスになっています。
alias traversalを利用して、aliasで指定されたディレクトリの一つ上の階層にあるflagを読み出すことができました。
発見するのに使えるツール
Nginxのconfigにアクセスすることができる開発者側であれば、 gixyというNginxのconfigの静的解析ツールを使って、alias traversalを検出することができます。
$ gixy vulnerable.conf ==================== Results =================== >> Problem: [alias_traversal] Path traversal via misconfigured alias. Description: Using alias in a prefixed location that doesn't ends with directory separator could lead to path traversal vulnerability. Additional info: https://github.com/yandex/gixy/blob/master/docs/en/plugins/aliastraversal.md Pseudo config: server { server_name localhost; location /static { alias /var/www/app/static/; } } ==================== Summary =================== Total issues: Unspecified: 0 Low: 0 Medium: 0 High: 1
また、脆弱性を発見するペンテスターはBurpの拡張を使って検出することができます。
自分向けDockerコマンドのメモ
Dockerは便利だけど、ぼくにとっては普段そんなに使うツールではなくて、よくコマンドを忘れてしまう。 覚えられるように、すぐ見返せるように、メモしておく。
Dockerイメージに関するコマンド
一覧
$ docker images
ビルド
直下にあるDockerFileからビルド。
$ docker build ./ -t example
削除
イメージIDを指定して削除。複数のイメージIDを指定できる。
$ docker rmi IMAGE-ID IMAGE-ID IMAGE-ID
すべてのイメージを削除
$ docker rmi -f $(docker images -q)
Dockerコンテナに関するコマンド
一覧
$ docker ps -a
ビルド
イメージからコンテナをビルド。
-t
は、Dockerコンテナ内の標準出力とホスト側の出力をつなげるオプション。-i
は逆にホスト側の入力とコンテナの標準入力をつなげるオプション。
$ docker run -it IMAGE-ID /bin/bash
-p
は外部からアクセスされるポート番号:コンテナ側のポート番号
を指定し、ポートフォワーディングするオプション。
-d
はデーモンとしてバックグラウンドで実行するオプション。
$ docker run -d -p 3000:80 IMAGE-ID
コンテナの中に入る
起動済みのコンテナの中に入る。ビルドする際との違いはrunがexecになって、イメージIDがコンテナIDになっている点。
$ docker exec -it CONTAINER-ID /bin/bash
停止
コンテナIDを指定して停止。
$ docker stop CONTAINER-ID
再開
コンテナIDを指定して再開。
$ docker start CONTAINER-ID
削除
コンテナIDを指定して削除。複数のコンテナIDを指定できる。
$ docker rm CONTAINER-ID CONTAINER-ID CONTAINER-ID
停止しているコンテナをすべて削除。
$ docker container prune
状態に関わらず、すべてのコンテナを削除。
$ docker rm -f $(docker ps -aq)
その他Tips
no Space Left on Deviceの対処法
空き容量不足によるエラー。単純にディスクが不足している以外に、Dockerに割り当てられている仮想ディスクの容量不足が原因のことがある。 不要なイメージやコンテナを消すか、仮想ディスクの容量を増やしてあげると解決する。
ISUCONがきっかけでSinatraにコントリビュートした話
ISUCON8の予選へ向けてSinatraで作られたwebアプリケーションを高速化する方法を模索する最中、 ErubisというERBテンプレートエンジンが使われているコードを見かけました。 これがきっかけでより高速なeRubyテンプレートエンジンであるErubiをサポートするためのコードをSinatraにコミットしました。この記事ではその詳細について説明したいと思います。
ISUCONというのはお題となるWebサービスを決められたレギュレーションの中で限界まで高速化を図るチューニングバトルです。
ErubisとErubi
eRubyのテンプレートエンジンはRubyの標準ライブラリのERB
以外にも存在し、ErubisとErubiといったものがあります。
ErubisはERB
より高速に動作し、Rails 5.0.xまではデフォルトのeRubyテンプレートエンジンとして使われていましたが、2011年ごろからメンテされていませんでした。
ErubiはErubisより高速に動作し、現在もメンテされています。
Railsでは5.1からデフォルトのeRubyテンプレートエンジンがErubisからErubiに変更されました。 github.com
どんなコードをコミットしたのか
Erubiを動作させるためのコードをごりごり書くつもりだったのですが、 Sinatraの内部で使われているTiltという複数のeRubyテンプレートエンジンへのインターフェースを提供するライブラリが 既にErubiに対応済みでした。
これによって、 SinatraのREADMEではErubiを使えると書かれていないものの、すでにErubiを使用可能であるという状況になっていました。 というわけでテストコードとドキュメントの修正を行いました。 最終的にマージされたプルリクエストはこれです。
結果として、テストコードとドキュメントの修正しかすることがなかったですが、SinatraがErubiをサポートしていることが明確になってよかったと思います。今年のISUCON9からはErubiを使えますね!!!
IDAの便利プラグイン3選!!!
これはセキュリティツール系 Advent Calendar 2018 の25日目の記事です。
この記事では便利なIDAのプラグインを3つ紹介したいと思います。
findCrypt
findCryptは暗号に使われる定数をgrepすることで、どんな暗号が使われているか判別するIDAプラグインです。
使い方
IDAにバイナリを読み込ませた状態で、メニューバーのFile->Script file...
からfindcrypt.pyを実行することで使えます。
実行すると以下のようにOutput windowにスキャンの結果が出力されます。以下の例ではRijndaelで用いられている定数が見つかっていますね。
また、見つけた定数に名前をつけてくれるので、ディスアセンブル結果が表示されているIDA View-A
上からも定数を確認しやすいです。
シュッと用いられている暗号がわかって便利ですね。定数を使わないようにカスタムされた暗号が用いられている場合はこのプラグインでは見つけられないので、自力でがんばる必要があります。
LazyIDA
LazyIDAはMake your IDA Lazy!
を目指しているプラグインです。
いくつか機能がありますが、データをC/C++の配列やPythonのlistに変換してくれる機能が便利です。
使い方
IDAのplugins
ディレクトリ以下にLazyIDA.pyを配置すると使えるようになります。
IDAの画面上で左クリックすると、Convert
というメニューが追加されていると思います。ここから好きなフォーマットを選択し変換することができます。
ここでは、先ほどfindCryptで見つけたRijndaelの定数をLazyIDAでPythonのlistに変換してみます。
変換した結果はOutput windowに出力され、これをコピペしてPythonスクリプトから扱うことができます。
これはエンコードされたデータをデコードするときや、暗号化を解くときのスクリプトを書くときに便利です。
KeyPatch
IDAにはx86/x64を対象にしたアセンブラが組み込まれていますが、他のアーキテクチャを対象としたものはありません。 Keypatchは軽量なmulti-platform, multi-architecture assembler frameworkである Keystone – The Ultimate Assemblerを使って、IDA上で様々なアーキテクチャへのアセンブルを実現し、x86/x64以外のバイナリへパッチを当てやすくするプラグインです。
このプラグインはHex-Raysが行っているPlug-In Contest 2016で3位になっています。
使い方
Keystoneをインストールし、
IDAのplugins
ディレクトリ以下にkeypatch.pyを配置すると使えます。
macOS上のIDAPythonは/usr/bin/python
を使っているため、普段macOSのデフォルトではないPython(pyenvでインストールしたPythonなど)を使っている場合は、
IDAPythonからpipでインストールしたライブラリを使えません。
その場合はpipでインストールしたライブラリをIDAのディレクトリの中にコピーする必要があります。
わたしはpyenvでインストールしたPythonを使っているので以下のようなコマンドになりました。パスは適宜変更してください。
$ sudo cp -r ~/.pyenv/versions/2.7.15/lib/python2.7/site-packages/keystone /Applications/IDA\ Pro\ 7.2/ida.app/Contents/MacOS/python/
インストールに成功していると、IDAの画面上で左クリックして出るメニューにKeypatch
が追加されています。ここからPatcherを選択することでKeyPatchのWindowが出現します。
ここではMOV R0, R3
というARMのアセンブリをMOV R0, 1
に変更しています。
以下はパッチを当てたあとの様子です。コメントにパッチを当てる前のアセンブリが残されていて親切ですね。
このプラグインを使わずに、現状のIDAでx86/x64以外のバイナリに対しパッチを当てるには機械語のパッチを当てることになります。 このプラグインのおかげでARMなどのバイナリにパッチを当てる作業は楽になりました。
リアルモードでも32bitのレジスタを使うことができる
この記事は自作OS Advent Calendar 2018の21日目の記事です。
自作OSのアドカレなので、まずは作っているCPUエミュの話をしましょう。
CPUエミュを作っている話
そもそもなぜCPUエミュを作っているのかというと、 Golangで書かれたファミコンのエミュのコードを読んでめっちゃおもしろいなって思ったのが、 CPUエミュを作ってみようと思い始めたきっかけでした。
それで一番馴染みがあるアーキテクチャであるx86を対象にGolangでx86のCPUエミュ「cibo」を作りはじめました。 x86/x64を対象にしたソフトウェアエミュレータは、Type1ハイパーバイザーがあるのであまり需要がない気はしますが、 はじめて作るCPUエミュは親しみのあるアーキテクチャの方がいいでしょう。 ciboという名はBLAMEの生電社の主任科学者シボさんから取っています。 「久しぶりだな頭取!」って言って霧亥を助けに来るシーン、かっこいいですよね。 github.com
ひとまずQEMUとBochsで使われているBIOSである、SeaBIOSを動作させることを目標に開発しています。 今のところ、NASMでアセンブルされた簡単なバイナリを走らせることができるくらいの進捗です。早くVGAあたりをエミュレートしてカラーの画面を出したいですね
$ cibo --debug ./samples/asm/simple_call EIP = 0x7C00, Opcode = 0xB8 EIP = 0x7C05, Opcode = 0xBB EIP = 0x7C0A, Opcode = 0xE8 EIP = 0x7C14, Opcode = 0x89 EIP = 0x7C16, Opcode = 0xB8 EIP = 0x7C1B, Opcode = 0xC3 EIP = 0x7C0F, Opcode = 0xE9 No mapping area: 0x0 ==================== registers ==================== 01: EAX = 0x1011 02: ECX = 0x0 03: EDX = 0x0 04: EBX = 0xF1 05: ESP = 0x7C04 06: EBP = 0x0 07: ESI = 0x0 08: EDI = 0x0 09: EIP = 0x0 10: CS = 0x0 11: DS = 0x0 12: SS = 0x0 13: ES = 0x0 14: FS = 0x0 15: GS = 0x0 16: EFLAGS = 0x2 (00000000000000000000000000000010) 17: MM0 = 0x0 18: MM1 = 0x0 19: MM2 = 0x0 20: MM3 = 0x0 21: MM4 = 0x0 22: MM5 = 0x0 23: MM6 = 0x0 24: MM7 = 0x0
また、Unicornのようにコードからも操作できるようにしています。
package main import ( "github.com/tkmru/cibo/core" ) func main() { beginAddress := 0x7c00 emu := cibo.NewEmulator(32, beginAddress, 29, false, true) cpu := emu.CPU reg := &cpu.X86registers emu.RAM = []byte{0xb8, 0x01, 0x00, 0x00, 0x00, 0x3d, 0x02, 0x00, 0x00, 0x00, 0x75, 0x05, 0xe9, 0xef, 0x83, 0xff, 0xff, 0xb8, 0x02, 0x00, 0x00, 0x00, 0x3d, 0x02, 0x00, 0x00, 0x00, 0x74, 0xef} /* mov eax, 0x1 cmp eax, 0x2 jnz not_equal equal: jmp 0 not_equal: mov eax, 0x2 cmp eax, 0x2 jz equal */ reg.Init() emu.Run() }
テストはmulti-architecture assembler frameworkであるKeystoneのGolangバインディングと標準パッケージのtestingを使って書いています。 Golangを使ってCPUエミュのテストを書くにはこれがいいと思います。実際のテストコードはこれです。
うっかり自作CPUエミュの話が長くなってしまいましたが、自作OSのアドカレの記事なのでまあよしとしましょう。 そろそろ本題に入ります。
BIOSとは
特に説明をせずBIOSについて言及していましたが、ここで説明していきます。 BIOSというのは、Basic Input/Output Systemの略でPCの電源を入れた直後の初期化や HDDから最初のプログラムローダをメモリに読み出す役割を持つプログラムです。
BIOSはリアルモードという16bitで動作するモードで動き、 周辺機器に関する処理を行ったあと、MBR(Master Boot Record)やPBR(PartiPartition Boot Record)といったブートセクタを読み出し、 32bit/64bitで動くOSに動作を移します。
このようなBIOSですが、16bitでしか動作しないので、32bit/64bitで動作するUEFIに取って代わられようとしています。 Intel CPUでは 2020年までに CSM (BIOS 互換機能) を撤廃して UEFI に完全移行する方針のようで、 近いうちにBIOSが搭載されたデバイスは見かけなくなってしまうようです。
なぜ、そのうちなくなるであろうBIOSを自作CPUエミュで動かそうとしているのかというと、いきなりx64のエミュを実装するのは大変かなと思ったからです。ところで、seabiosを自作CPUエミュで動かそうと思うと、seabios内で使われている命令すべてを自作エミュ上で動作するようにしておく必要があります。そのため、どんな命令が使われているのか知るためにIDAでseabiosのバイナリをディスアセンブルしてみたところ、リアルモードでも32bitのレジスタは読み書きされていることに気づきました。
リアルモードで32bitのレジスタ???
下の画像を見ると32bitのレジスタを使っている命令は先頭に0x66
というopcodeがついているのが分かると思います。
0x66
というopcodeはOperand-size override prefix
という役割を持っていて、オペランドのサイズを上書きできる接頭辞です。
つまり、リアルモードではopcode 0x66
を使うことで32bitのレジスタを読み書きできるのです!!
これを知って、私の好きなopcodeは0x66
になりました。
16bitで動作している環境で32bitのレジスタが使えるというのはとてもおもしろいですね。
わたしはこれを自分で発見してとても驚いたのですが、
Wikipediaに書かれていたので自明なことだったようです....