csu利用
本文最后更新于 2024年10月9日 上午
csu的利用
原理
64位的动态连接文件一般有一段万能的gadget,里面可以控制rbx,rbp,r12,r13,r14,r15以及rdx,rsi,edi的值,并且还可以call我们指定的地址。然后劫持程序执行流的时候,劫持到这个__libc_csu_init函数去执行(这个函数是用来初始化libc的)
csu在我看来分为两种,一种是通过csu泄露基地址后,跟ret2libc一样调用就可以做出,一种是往bss段里注入/bin/sh,通过调用retsyscall来实现,一般第二种较为常见,这篇文章主要详解第二种
上题 例题是leve5
基础检查,只开了NX保护
丢入ida
存在溢出
查找一下后门
并没有发现
初步认为是泄露libc
我一开始的payload构造是跟普通libc一样
后面发现
文件缺少可用的寄存器进行传参(64位传参顺序 rdi rsi rdx rcx r8 r9)
后面再ida找到了csu函数
可以看到上面两端汇编几乎囊括了传参的寄存器,而且还有call指令以及retn,我们可以利用这两段gadget来传参和调用,因为我们要先调用下面一段来传参,所以我们认为下面一段为gadget1,上面一段为gadget2
这里解释一下cmp rbx,rbp。就是检查rbx-rbp是否为0,与jnz指令配合跳转。所以再传参的时候要将rbx设置为0,rbp为1。
因此可以定义可以传参函数
1 |
|
传参的顺序按照gadget1的顺序来,其中p64(0),p64(1)分别是rbx和rbp
上面在调用了gadget1后又填充了a*8,因为寄存器是用sp指针来传参的,所以rsp要正确指向寄存器。
可以看到这里多了var_30的偏移,我们要用gdb查看var_30的大小
在gadget1下断点运行
layout asm查看汇编代码试图
layout reg 查看寄存器状态
可以看到又0x8的偏移,所以要填充a*8,不同的libc偏移会不同,具体以调试为准
在执行完gadget2后,栈顶指针rsp距离retn有0x8*7个偏移(相当于传参6个参数和前面提到的8个垃圾数据,我们只有填充完才能覆盖retn返回main,来进行接下来的操作。
所以泄露libc的代码为
1 |
|
找到相应的libc 版本(这里不详细描述)
因为在文件里找不到相应的rdi,所以我们选择用retsyscall来利用,retsyscall调用的是exceve函数
第二次溢出用read 函数将后门函数注入bss段
最后进行第三次溢出调用retsyscall
运行exp得到shell
最终exp
1 |
|