祥云杯部分pwn (glibc-2.31下的largebin attack)
两周前打的一次比赛,一直想写wp记录一下比赛的过程,奈何杂事太多,自己也静不下心来,因此一直拖到了现在。
note
格式化字符串漏洞,漏洞点如下:
其中scanf和printf相似,所不同的是scanf中的%s可以直接写向栈上的指针指向的内存区域,因此我们就可以进行任意地址写操作。又再栈中发现_IO_2_1_stdoutd的地址,所以我们直接打stdout泄露libc_base,再利用栈中保存的栈上的地址,我们直接写入system函数地址。
完整exp:
1 | from pwn import * |
lemon_pwn
输入一串数字,如果满足要求,可以将flag写入栈中。因为没有设置种子,所以rand()是伪随机数。
利用如下脚本获得v1
1 | for buf in range(0xa7778200000,0x100000000000): |
进入主逻辑,发现有沙箱,禁用了execve函数,因此我们使用open,read,write输出flag
在color操作中发现可以对指针更改并且可以写,但只能使用一次,我们利用这次机会来控制tcache_struct。
控制tcache_struct后就是堆风水的问题了,我们连续打3次stdout,第一次获得libc_base,第二次利用libc中的environ得到stack_addr,最后一次直接泄露flag。本题能连续打三次stdout包含着很大的运气成分。
完整exp:
1 | from pwn import * |
pwdFree
常规的一道堆题,off-by-null,注意在写入数据时要和泄露出来的key异或。
exp:
1 | from pwn import * |
pwdPro(glibc-2.31下的largebin attack)
这道题就很有意思了,我们先回顾一下libc-2.26以下的largebin attack的操作,由于largebin中是按照大小存放的,假设我们的largebin chunk的大小满足在其中的largebin chunk的大小之间,那么其插入操作就是将它自己的fd和bk指针分别指向两边chunk的位置,然后更小chunk的bk指针和更大chunk的fd指针指向插入其中间的chunk;fd_nextsize,bk_nextsize指针的操作和fd,bk相似。其代码如下:
1 | [...] |
因此我们改变更小chunk的bk和bk_nextsize指针,再插入一个更大的largebin chunk,就可以修改任意地址的值(但不能指定值)。
由于libc-2.30增加了两个新的保护,如下:
1 | if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd)) |
绕过方法为:(p1)malloc(0x428);malloc(0x18);(p2)malloc(0x418);malloc(0x18);free(p1);malloc(0x438);free(p2);malloc(0x438);即可绕过,原因是如果插入的largebin chunk是最小的,那么便不会检查bk_nextsize。
因为程序只允许我们申请大于0x400的chunk,因此我们可以想到像修改global_max_fast一样的方法,在有tcache的加入后我们可以修改tcache_max_bin,是的我们释放的largebin chunk都可以放入tcache中。那么tcache_max_bin该如何寻找呢,如下图:
0x40代表着index,index=size(malloc(size))/0x10 - 1,将其值改为一个较大的数即可
完整exp:
1 | from pwn import * |