StudentManagement
程序保护如下
[*] '/mnt/hgfs/shared/ccsssc_final/StudentManagement/pwn'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
glibc 版本是 2.39-0ubuntu8.7
比赛的时候脑子有点乱,虽然很快审计出了uninitialized memory漏洞,但是因为题目的\0截断以及非传统堆题的交互,让我不知道怎么处理
赛后再看,其实这题本质和传统堆题没区别:没有限制用户数量,所以可以创建任意多的堆块且大小基本可控(<0x400)
程序分析
题目是一个学生管理系统,主菜单只有 3 个功能:
Reg
Login
Del
登录后则有:
View
EditBio
Logout
先贴几个关键逻辑的简化版伪代码,user结构体如下
struct user
char id[16];
char name[64];
char pass[32];
uint8_t *cont;
size_t size;
user *next;
register
void register()
user *buf; // [rsp+8h] [rbp-8h]
buf = (user *)ialloc(0x88u);
if ( buf )
puts("\n=== Registration ===");
printf("ID: ");
buf->id[read(0, buf, 0xFu)] = 0;
if ( find(buf->id) )
puts("[-] ID exists");
free(buf);
else
printf("Name: ");
buf->name[read(0, buf->name, 0x3Fu)] = 0;
printf("Pass: ");
buf->pass[read(0, buf->pass, 0x1Fu)] = 0;
buf->next = userhead;
userhead = buf;
这里已经能看到问题了,malloc(0x88) 之后只写了id\name\pass\next,但是cont\size完全没有初始化
view
void show(user *a1)
puts("\n=== Profile ===");
printf("Name: %s\nID: %s\n", a1->name, a1->id);
if ( a1->cont )
printf("Bio: %s\n", (const char *)a1->cont);
这里更致命,程序只判断了 u->cont != NULL,然后就直接把它当字符串打印
如果 cont 是个悬空指针,那就是 UAF read
如果 cont 被我们伪造成任意地址,那就是任意地址读
edit bio
unsigned __int64 __fastcall editbio(user *a1)
uint8_t *cont; // rbx
int v3; // [rsp+14h] [rbp-1Ch] BYREF
unsigned __int64 v4; // [rsp+18h] [rbp-18h]
v4 = __readfsqword(0x28u);
printf("\nNew bio size: ");
__isoc99_scanf("%d", &v3);
getchar();
if ( v3 > 0 && v3 <= 0x400 )
if ( a1->cont && a1->size < v3 )
free(a1->cont);
a1->cont = (uint8_t *)ialloc(v3);
a1->size = v3;
else if ( !a1->cont )
a1->cont = (uint8_t *)ialloc(v3);
a1->size = v3;
printf("Content: ");
cont = a1->cont;
cont[read(0, cont, v3 - 1)] = 0;
return v4 - __readfsqword(0x28u);
edit 函数这里
如果 cont 非空且 size >= n,就直接往 cont 写
如果 cont 非空但 size < n,就先 free(cont) 再 malloc(n)
delete
__isoc99_scanf("%d", &s);
getchar();
if ( s == 3 )
printf("\nID to delete: ");
buf[read(0, buf, 0xFu)] = 0;
p_next = &userhead;
ptr = 0;
while ( *p_next )
if ( !strcmp((*p_next)->id, buf) )
ptr = *p_next;
*p_next = ptr->next;
if ( ptr->cont )
free(ptr->cont);
ptr->cont = 0;
free(ptr);
printf("[+] Student %s deleted\n", buf);
break;
p_next = &(*p_next)->next;
if ( !ptr )
puts("[-] Not found");
漏洞利用
Step1 堆风水&泄露堆地址
先说思路,整个堆利用过程如下
先造一个 0x110 的 unsorted chunk
再把这个 unsorted chunk 切成几块 0x70
让切出来的小块进 fastbin
再用一次大申请触发 malloc_consolidate
等这些零散小块重新合并回 unsorted 之后,再去申请 0x90 user
这样 victim 就不会从“被清过 cont 的旧 user chunk”里出来,而是会从 重新合并后的 unsorted 里切出来,之前布好的脏数据也就正好落到了 victim->cont 的位置上。
下面按 exp 的顺序
...(已截断)
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-291360.htm
[原创]第二届软件系统安全赛决赛 StudentManagement 详解
356 浏览
0 回复
暂无回复,快来抢沙发吧!