第一次周练中的ciscn_s_3中有涉及到SROP知识点,复习一下
ciscn_s_3
放到gdb里看一下保护
没开什么特别的保护,丢到ida里面看看,它main函数里面只有一个vuln函数,而vuln函数就只有短短几行,但里面有两个系统调用,一处是sys_read,向栈上读取数据(0x400),一处是sys_write,向栈上写入数据(0x30),这里就存在栈溢出。
然后还发现一个gadgets函数,在这个函数中有两处出现了给rax赋值,分别赋值0x0F,0x3B,然后这个涉及到系统调用号的问题。
32位与64位 系统调用的区别:
- 传参方式不同
- 系统调用号 不同
- 调用方式 不同
32位:
传参方式:首先将系统调用号 传入 eax,然后将参数 从左到右 依次存入 ebx,ecx,edx寄存器中,返回值存在eax寄存器
调用号:sys_read 的调用号 为 3 sys_write 的调用号 为 4
调用方式: 使用 int 80h 中断进行系统调用
64位:
传参方式:首先将系统调用号 传入 rax,然后将参数 从左到右 依次存入 rdi,rsi,rdx寄存器中,返回值存在rax寄存器
调用号:sys_read 的调用号 为 0 sys_write 的调用号 为 1
stub_execve 的调用号 为 59 stub_rt_sigreturn 的调用号 为 15
调用方式: 使用 syscall 进行系统调用
然后这里的0x0F就是15,0x3B就是59,所以这边的两个64位的系统调用号都可以使用,所以就有两个方法
第一种;ret2__libc_csu_init
第一种就是利用 ret2__libc_csu_init 去构造 execve(“/bin/sh”,0,0) 来 getshell
这种方法我们就需要
- 系统调用号,即 rax 应该为 0x3B
- 第一个参数,即 rdi 应该指向 /bin/sh 的地址,其实执行 sh 的地址也可以。
- 第二个参数,即 rsi 应该为 0
- 第三个参数,即 rdx 应该为 0
通过查询
在这里面只发现了rdi_ret,这个gadget还不够,就需要我们去ida里__libc_csu_init函数里去寻找
这里的retn代表着pop rip即将当前栈顶的内容赋值给rip.r13的值会给到rdx,让rbx=0,下面call的时候会变为call [r12],会去call r12指向位置的代码,我们可以调到后面的rop执行,所以需要知道栈的地址,我们获取/bin/sh字符串时也需要知道栈地址。
exp.py
1 | from pwn import * |
第二种: SROP
第二种就是直接srop 伪造 sigreturn frame 去 构造 execve(“/bin/sh”,0,0) 来 getshell
首先利用 mov rax, 0Fh 控制rax为 15,然后 调用 syscall 即执行了 sigreturn,我们 伪造 sigreturn frame 去 执行 execve(“/bin/sh”,0,0) 即可
exp.py
1 | from pwn import * |