Practical Binary Analysisを読み始めた 1
hope-RIPEを使ってみる その2
昨日、hope-RIPEをSpikeシミュレーターで動かしてみたんだが、Stack Buffer Overflowを利用したROPが成功しないという不可解な現象に遭遇した。SSPが有効になっているからかと思ったけども、Makefileを見る限りではそうではないみたいだし、これは何だろうということで詳しく調べてみた。
失敗したケースのうち、以下のケースを取り上げる。
ripe_attack_generator -t direct -i rop -c ret -l stack -f memcpy
デバッガーで原因を探る
デバッガーで追ってみたところ、ropでjumpする先のアドレスを間違えていることが原因でセグフォしていることがわかった。
逆アセンブルの内容
0000000000010e00 <perform_attack>: ... 11b84: 78813083 ld ra,1928(sp) <-- ここで return address を書き換える 11b88: 78013403 ld s0,1920(sp) <-- ここに breakpoint を貼って、p $raしてみる 11b8c: 79010113 addi sp,sp,1936 11b90: 8082 ret 0000000000011ec8 <rop_target>: // <-- jump先ターゲット 11ec8: 1141 addi sp,sp,-16 11eca: e406 sd ra,8(sp) 11ecc: e022 sd s0,0(sp) 11ece: 0800 addi s0,sp,16 11ed0: 67cd lui a5,0x13 11ed2: 7d878513 addi a0,a5,2008 # 137d8 <.annobin_elf_init.c_end+0x73e> 11ed6: c3bfe0ef jal ra,10b10 <puts@plt> 11eda: 4501 li a0,0 11edc: c55fe0ef jal ra,10b30 <exit@plt>
デバッガーの出力
(gdb) b *0x11b88 Breakpoint 1 at 0x11b88 (gdb) r Starting program: /root/hope-RIPE/build/ripe_attack_generator -t direct -i rop -c ret -l stack -f memcpy Missing separate debuginfos, use: dnf debuginfo-install glibc-2.28.9000-24.fc30.riscv64 tech: 100 attack: 202 code ptr: 300 location: 400 function: 500 Breakpoint 1, 0x0000000000011b88 in perform_attack () (gdb) p $ra $1 = (void (*)()) 0x11ed8 <rop_target+16>
<rop_target+16>
がちゃんと命令の先頭アドレスとなっていれば良いが、そうなっていない。0x11ed8なので、jal ra,10b10
という命令の"ど真ん中に"ジャンプしてしまう。で、decodeができずIllegal Instructionで落ちていることがわかった。
以下の箇所がjump先を決めているところだが、コンパイラのバージョンが変わったことにより、この16というオフセット値が変わってしまったのだと予想される。
まとめると、昨日hope-RIPEを実行してFAILと表示されたケースは、SSPなどが働いて脆弱性攻撃に失敗したというわけではなく、単純に攻撃コードのバグによって失敗しているということだった。
ということで、修正してプルリクを出しておくのが良さそうである。
hope-RIPEを試してみる その1
Runtime Intrusion Prevention Evaluator (RIPE) という、脆弱性攻撃に対する防御のカバレッジを測定するためのツールがある。これを用いると種々のパラメータを変化させながら種々の脆弱性攻撃用コードを生成、そのコードを実行し脆弱性攻撃の成否をレポートしてくれる。 RIPEのもとの論文はここからダウンロードできる。
このRIPEだが、RISC-V向けにポートしたものが昨年リリースされていたので、試してみた。hope-RIPEと呼ぶらしい。
以下では、RISC-V toolsがインストールされており、パスが通してあることを前提として話をすすめる。
build & run
基本的に普通にmakeで問題なくビルドできた。
$ git clone https://github.com/draperlaboratory/hope-RIPE.git $ cd hope-RIPE $ make
すべてのテストケースを実行するためにpythonスクリプトが用意されている。pythonスクリプトの中身を見ると
for attack in attacks: for tech in techniques: for loc in locations: for ptr in code_ptr: for func in funcs: os.system('rm -f out/out.text') cmdargs = 'build/ripe_attack_generator ' + '-t ' + tech + ' -i ' + attack + ' -c ' + ptr + ' -l ' + loc + ' -f ' + func cmdline= run_cmd + ' ' + cmdargs + ' 1> out/out.text 2>/dev/null' if is_attack_possible (attack, tech, loc, ptr, func) == 0: total_np += 1
となっており、要はすべてのパラメータの組み合わせについてRIPEを実行するだけとなっている。
テストを実行した結果は以下の通り。
... ('build/ripe_attack_generator -t direct -i rop -c longjmpdata -l data -f memcpy', 0) ('build/ripe_attack_generator -t direct -i dataonly -c bof -l stack -f memcpy', 1) ('build/ripe_attack_generator -t direct -i dataonly -c iof -l stack -f memcpy', 1) ('build/ripe_attack_generator -t direct -i dataonly -c leak -l stack -f memcpy', 0) ('build/ripe_attack_generator -t direct -i dataonly -c bof -l heap -f memcpy', 1) ('build/ripe_attack_generator -t direct -i dataonly -c iof -l heap -f memcpy', 1) ('build/ripe_attack_generator -t direct -i dataonly -c leak -l heap -f memcpy', 0) ('build/ripe_attack_generator -t direct -i dataonly -c bof -l bss -f memcpy', 1) ('build/ripe_attack_generator -t direct -i dataonly -c iof -l bss -f memcpy', 1) ('build/ripe_attack_generator -t direct -i dataonly -c leak -l bss -f memcpy', 0) ('build/ripe_attack_generator -t direct -i dataonly -c bof -l data -f memcpy', 1) ('build/ripe_attack_generator -t direct -i dataonly -c iof -l data -f memcpy', 1) ('build/ripe_attack_generator -t direct -i dataonly -c leak -l data -f memcpy', 0) ('build/ripe_attack_generator -t indirect -i dataonly -c bof -l stack -f memcpy', 1) ('build/ripe_attack_generator -t indirect -i dataonly -c bof -l bss -f memcpy', 1) ('build/ripe_attack_generator -t indirect -i dataonly -c bof -l data -f memcpy', 1) SUMMARY ---------------------------------------------------------------- Total OK: 123 Total FAIL: 57 Total Attacks Executed: 180
OKは攻撃に成功したことを示し、FAILは攻撃に失敗したことを示す。攻撃に成功した場合には、標準出力に success. **** function reached.
というメッセージが表示される(****
には攻撃の手法の名前が入る)。
57件FAILしているわけだが、どういうことなのか。。。SSPによって守られているとかかな?
気になってMakefileを見てみると、
# Makefile for RIPE # @author John Wilander & Nick Nikiforakis # Modified for RISC-V by John Merrill #Depending on how you test your system you may want to comment, or uncomment #the following CFLAGS= -fno-stack-protector -z execstack CC=riscv64-unknown-elf-gcc all: ripe_attack_generator clean: rm -rf build/ out/ ripe_attack_generator: ./source/ripe_attack_generator.c mkdir -p build/ out/ $(CC) \ ./source/ripe_attack_generator.c -o ./build/ripe_attack_generator
となっており、バッチリ-fno-stack-protector
が入っている。
FAILしている原因調査は後日行うこととするが、ひとまずFAILしていたテストケースとして何があったかだけ調べたので、以下に掲載しておく。
パット見、direct rop stack ret memcpyとかで失敗しているが、このケースでの失敗はちょっと考えにくい。RISC-Vのポーティングを間違えている可能性が高そう。
direct shellcode funcptrbss bss memcpy direct shellcode structfuncptrbss bss memcpy direct shellcode longjmpbss bss memcpy direct shellcode funcptrdata data memcpy direct shellcode structfuncptrdata data memcpy direct shellcode longjmpdata data memcpy indirect shellcode ret bss memcpy indirect shellcode funcptrstackvar bss memcpy indirect shellcode funcptrstackparam bss memcpy indirect shellcode funcptrheap bss memcpy indirect shellcode funcptrbss bss memcpy indirect shellcode funcptrdata bss memcpy indirect shellcode structfuncptrstack bss memcpy indirect shellcode structfuncptrheap bss memcpy indirect shellcode structfuncptrdata bss memcpy indirect shellcode structfuncptrbss bss memcpy indirect shellcode longjmpstackvar bss memcpy indirect shellcode longjmpstackparam bss memcpy indirect shellcode longjmpheap bss memcpy indirect shellcode longjmpdata bss memcpy indirect shellcode longjmpbss bss memcpy indirect shellcode ret data memcpy indirect shellcode funcptrstackvar data memcpy indirect shellcode funcptrstackparam data memcpy indirect shellcode funcptrheap data memcpy indirect shellcode funcptrbss data memcpy indirect shellcode funcptrdata data memcpy indirect shellcode structfuncptrstack data memcpy indirect shellcode structfuncptrheap data memcpy indirect shellcode structfuncptrdata data memcpy indirect shellcode structfuncptrbss data memcpy indirect shellcode longjmpstackvar data memcpy indirect shellcode longjmpstackparam data memcpy indirect shellcode longjmpheap data memcpy indirect shellcode longjmpdata data memcpy indirect shellcode longjmpbss data memcpy indirect returnintolibc structfuncptrbss bss memcpy indirect returnintolibc structfuncptrdata data memcpy direct rop ret stack memcpy direct rop funcptrstackvar stack memcpy direct rop funcptrstackparam stack memcpy direct rop structfuncptrstack stack memcpy direct rop longjmpstackvar stack memcpy direct rop longjmpstackparam stack memcpy direct rop funcptrheap heap memcpy direct rop structfuncptrheap heap memcpy direct rop longjmpheap heap memcpy direct rop funcptrbss bss memcpy direct rop structfuncptrbss bss memcpy direct rop longjmpbss bss memcpy direct rop funcptrdata data memcpy direct rop structfuncptrdata data memcpy direct rop longjmpdata data memcpy direct dataonly leak stack memcpy direct dataonly leak heap memcpy direct dataonly leak bss memcpy direct dataonly leak data memcpy
『うつを甘く見ていました』を読んだ。
鬱病のこともそうだが、それよりも結婚するとか家族になるってどういうことだろうということの方を考えさせる内容だった。
漫画の内容に関して、旦那さんの非難が集まっていたらしいが、正直そこまで責めるべきでもないような気がする。(筆者もあとがきで夫を非難する内容にしたわけではないと書いてはいるのだけども。)
楽しい時をシェアできるよりも辛い場合にしっかり支え合えるのかとか、そういうことが結婚する相手に求められるべきなんだなと思った。
Maixduino を使ってみる
先日、Amazonで注文していたSipeed Maixduinoキットが届いたので、遊んでみる。
開発環境のセットアップ
gnu-toolchain があるので、これを落としてきてビルドする。
$ git clone --recursive https://github.com/kendryte/kendryte-gnu-toolchain $ cd kendryte-gnu-toolchain $ mkdir build $ cd build $ ../configure --prefix=/opt/kendryte-toolchain --with-cmodel=medany --with-arch=rv64imafc --with-abi=lp64f $ make $ sudo make install
makeにはなかなか時間がかかる。
あと、Maixduino のflashにプログラムを書き込むためのツールを入れる必要がある。これはpipで導入することが可能。
$ sudo pip3 install kflash
サンプルプログラムのビルド
まず、standalone-sdkを手元にクローンしてくる。次に、いくつか用意されているサンプルプログラムを手元にクローンしてくる。サンプルプログラムに関しては、standalone-sdkのsrcファイル以下に展開するのが良い。standalone-sdkのsrcディレクトリの下にサンプルプログラムのリポジトリに含まれる aes_128_test
などのプログラムが入った状態になれば準備完了。
standalone-sdkのディレクトリに入り、サンプルプログラムのうち lcd をビルドする。
$ cd kendryte-standalone-sdk $ mkdir build $ cd build $ cmake ../ -DPROJ=lcd -DTOOLCHAIN=/opt/kendryte-toolchain/bin $ make
flashへの書き込み
ビルドしたバイナリをflashに書き込むにはkflashを使う。( 私の環境では/dev/ttyUSB0
を指定して上手くいったが、環境によってはデバイスファイル名は違うはず。)
$ kflash -p /dev/ttyUSB0 -B goE lcd.bin
書き込みに失敗する場合は、sudo
をつけるか、
$ sudo usermod -a -G dialout $(whoami)
を実行する。(参考: GitHub - kendryte/kflash.py: kflash, A Python-based cross-platform Kendryte K210 UART ISP Utility)
書き込みを実行すると以下のような出力が端末に表示される。
[INFO] COM Port Selected Manually: /dev/ttyUSB0 [INFO] Default baudrate is 115200 , later it may be changed to the value you set. [INFO] Trying to Enter the ISP Mode... * [INFO] Greeting Message Detected, Start Downloading ISP Downloading ISP: |=========================================================================================================================================================================| 100.0% 10kiB/s [INFO] Booting From 0x80000000 [INFO] Wait For 0.1 second for ISP to Boot [INFO] Boot to Flashmode Successfully [INFO] Selected Flash: On-Board [INFO] Initialization flash Successfully Programming BIN: |=========================================================================================================================================================================| 100.0% 10kiB/s [INFO] Rebooting...
Maixduinoを再起動すると、LCDにCanaan Kendryte K210が表示される。
ドキュメントが結構充実しているので、これを見ながらもっと遊んでみることにしよう。
こういう端末買うの初めてなので、わかっていなかったのだが、標準出力に出た内容を確認する場合は、
$ cat /dev/ttyUSB0
で一応取得できる。