# from 2022.4.18 *ctf pwn examination
# 保护:
1 | dreamcat@ubuntu:~/Desktop/*ctf/examin$ checksec --file=examination |
# 过程
程序,进行了不同的模式,teacher 或者 student,
# 重要的结构体
1 | 00000000 student struc ; (sizeof=0x20, mappedto_8) /chunksize=0x31 |
按照惯例,我们首先要看的就是对于堆块的输入是否存在着溢出,
在 teacher 模式下,可以写 commend,但是因为要求你写入 size,并根据 size 大小 calloc,这里目前是不存在溢出的
另外一个是在 student 模式下 set mode,这里 calloc 0x20 大小的 chunk,然后读入 0X20 数据,也不存在溢出。
但是我们审计这里发现,判断程序是进行读入 mode 还是预测 pray score,是根据 student 结构体中的 type 判断,而 type 又可以利用 pray 进行操作,type^=1。同时 pray sore 保存的地址与 mode 保存地址一致。所以这里存在任意地址写。
1 | unsigned __int64 __fastcall set_mode(int a1) |
当我们继续继续审计代码,发现 student 的 check rewiew 存在任意地址加一。
1 | unsigned __int64 __fastcall checkfor_rewiew(int a1) |
看到这里时,我有想到将 student comment 的 size 进行加一,或者将 student win 加(但是没啥用好像)。
再来,我们还需要关注 free,程序只给了我们三次机会,而且只是将 list 中保留的 student 结构体指针清空,而没有清空其他的数据。
1 | puts("which student id to choose?"); |
接下来思考程序对于堆块数据的输出。只有在 student 模式的 check review 可以输出 comment。
# 着手漏洞
# 泄露地址
check review 有机会直接输出 student 的地址,但是分数需要够 96, 但是正常情况下是不可以的,因为 question 只能是 0~6,但是我们发现,如果学生进行过 pre,再次打分,就会被扣 10 分,而且数据比较的时候是无符号数,所以只要 question 数为 1,在 pray,被扣 10 分就会成为一个大数。输出 chunk 的地址。这里也解决了一个问题就是,因为我们释放次数有限,而且堆块大小也不可以超过 0x3ff,free 后 chunk 全部进入 tcache,没法泄露 libc,所以我们利用任意地址(一字节的数据类型)加 1,可以将一个 chunk 变得很大,free 后就可以进入 unsortedbin,后面可以申请出来,即使 tcache, 存在,也会优先使用 unsortedbin. 所以我们只要后面 write review 的时候,size<=8, 就可以保留 bk 指针不被修改。但是这里我们可以用更简单的方式,直接将 size 变得更大,(两个方法都要修改保存的 comment size),直接越界输出 main_arena。
后面就是一个常规的想法,因为 chunk 上有 comment 的指针,所以我们利用上面的溢出,将指针改写为 free_hook,然后再编辑该 review,把 onegadget 写入。最后 free 实际就是调用 execve ().
# exp
1 | from pwn import * |