-
-
[原创]srop基本利用教程
-
发表于: 2021-4-17 11:30 11122
-
参考链接
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
赞赏
- [原创][KCTF]第十三题 共存之道 WP 9328
- [原创]docker-remoter-api渗透 1057
- [原创]赛棍pwn课程(结束了共计9天) 24161
- [分享]pwn部分简单堆利用记录 21565