鬱猫のつぶやき

鬱猫が日々思っていることをつづります

Practical Binary Analysisを読み始めた 1

先週の連休からPractical Binary Analysisを読み始めた。

www.amazon.co.jp

会社の先輩に進められて読み始めたが、なかなか良い。最初のチャプターでCのソースコードコンパイルして実行ファイルが生成されるまで書いてあるのは良かった。

その他、bdf libraryの使ってのELF/PEの自作パーサーの作成、ディスアセンブリが逆アセンブルする仕組み、コードインジェクションの手法などが書かれているみたいである。(まだ、そこまでは読んでいない。)

知っていることも多いので、拾い読みしていく予定。

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というオフセット値が変わってしまったのだと予想される。

github.com

まとめると、昨日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

『うつを甘く見ていました』を読んだ。

鬱病のこともそうだが、それよりも結婚するとか家族になるってどういうことだろうということの方を考えさせる内容だった。

漫画の内容に関して、旦那さんの非難が集まっていたらしいが、正直そこまで責めるべきでもないような気がする。(筆者もあとがきで夫を非難する内容にしたわけではないと書いてはいるのだけども。)

楽しい時をシェアできるよりも辛い場合にしっかり支え合えるのかとか、そういうことが結婚する相手に求められるべきなんだなと思った。

https://www.amazon.co.jp/dp/B07GSSHLCC/

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を再起動すると、LCDCanaan Kendryte K210が表示される。

f:id:tsunekoh:20190714105534j:plain

ドキュメントが結構充実しているので、これを見ながらもっと遊んでみることにしよう。

こういう端末買うの初めてなので、わかっていなかったのだが、標準出力に出た内容を確認する場合は、

$ cat /dev/ttyUSB0

で一応取得できる。

はじめまして

本日からはてなブログをやることになりました。

これまでブログの代わりとしてQiitaを利用していましたが、プログラミング以外のことも投稿したいということがあったこと、はてなでもMarkdown記法が使えての記事投稿ができるということがあり、移行することとしました。

適当に普段触れている技術的な記事を投稿する用途で使っていきたいと思います。

予約記事投稿機能を使って、できる限り毎日投稿できるようにしていきます。