33c3-babyfengshui150

看到风水二字,虽然不知道是不是传说中的风水,先做做再说~

分析

查看保护,只有nx与canary:

然后有一个小结构体:

1
2
3
4
00000000 myuser          struc ; (sizeof=0x80, mappedto_8)
00000000 desciption dd ? ; offset
00000004 username db 124 dup(?)
00000080 myuser ends

接着就是程序主体了,普通的选单:
add

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct myuser *__cdecl add(size_t size)
{
void *desciption; // ST24_4
struct myuser *user; // ST28_4

desciption = malloc(size);
memset(desciption, 0, size);
user = (struct myuser *)malloc(0x80u);
memset(user, 0, 0x80u);
user->desciption = (char *)desciption;
ptr[gi] = user;
printf("name: ");
readN(ptr[gi]->username, 0x7C);
update(++gi - 1);
return user;
}

其中readN也没什么漏洞:

1
2
3
4
5
6
7
8
9
10
11
12
unsigned int __cdecl readN(char *buf, int len)
{
char *v3; // [esp+18h] [ebp-10h]
unsigned int v4; // [esp+1Ch] [ebp-Ch]

v4 = __readgsdword(0x14u);
fgets(buf, len, stdin); // 读取len-1个并添加结束符,保留换行符
v3 = strchr(buf, '\n');
if ( v3 )
*v3 = 0;
return __readgsdword(0x14u) ^ v4;
}

delete

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

v2 = __readgsdword(0x14u);
if ( i < gi && ptr[i] )
{
free(ptr[i]->desciption); // 也算不上uaf
free(ptr[i]);
ptr[i] = 0;
}
return __readgsdword(0x14u) ^ v2;
}

display

1
2
3
4
5
6
7
8
9
10
11
12
unsigned int __cdecl diaplay(unsigned __int8 i)
{
unsigned int v2; // [esp+1Ch] [ebp-Ch]

v2 = __readgsdword(0x14u);
if ( i < gi && ptr[i] )
{
printf("name: %s\n", ptr[i]->username);
printf("description: %s\n", ptr[i]->desciption);
}
return __readgsdword(0x14u) ^ v2;
}

update

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

v4 = __readgsdword(0x14u);
if ( i < gi && ptr[i] )
{
len = 0;
printf("text length: ");
__isoc99_scanf("%u%c", &len, &v2);
if ( &ptr[i]->desciption[len] >= &ptr[i][-1].username[120] ) //这个检查会存在问题
{
puts("my l33t defenses cannot be fooled, cya!");
exit(1);
}
printf("text: ");
readN(ptr[i]->desciption, len + 1);
}
return __readgsdword(0x14u) ^ v4;
}

如上,在编辑的时候,可以指定长度,按照原来意图,编辑的长度不应该大于最初分配的长度,否则程序直接退出,但是这里的检查会有问题,在非连续分配时,就可以控制堆绕过这种检查造成堆溢出,而溢出的堆里面存在指针可以实现任意位置读写。

利用

结果

参考

[0] https://github.com/ctfs/write-ups-2016/blob/master/33c3-ctf/pwn/babyfengshui-150/