whctf2017 pwn题wp
今天做题的时候无意做了一道buu上的whctf2017 stackoverflow,做完之后发现另外几道whctf2017的题目也很不错,就打算全做了都学习一下,题目全部在buu上都可以找到
总结
简单总结一下这四道题,它们分别考察了如下的知识点:
第一题考察了scanf函数最终的输入是在内部的count = _IO_SYSREAD(fp, fp->_IO_buf_base, fp->_IO_buf_end - fp->_IO_buf_base);
这行代码,只要能控制这几个字段并且对其他一些字段进行绕过,就可以实现IO的任意地址写
第二题考察了条件竞争漏洞,在多线程的操作中访问同一个全局变量没有加锁,在delete函数中让全局指针被减到了位于got表的位置,从而malloc申请堆块的地址写入了got表里,没有开NX导致堆可执行,从而劫持got表跳转到堆的shellcode上
第三题考察的是snprintf执行中的格式化字符串漏洞,snprintf是一个字符一个字符来处理的,可能是采取了一种循环遍历的方式,所以即使最初调用snprintf的时候format是%s,但后续的操作中format被改变了,然后再取格式化字符的时候触发了漏洞。snprintf拷贝字符的时候可能存在溢出
第四题考察的是未初始化漏洞,在打印之前,没有对操作的指针进行初始化,从而使用了栈里的残留数据,泄露出了canary,配合gets的栈溢出漏洞,ret2libc获取shell
whctf2017_stackoverflow
保护策略
漏洞所在
第一个漏洞点是往栈里输入数据之后没有0截断,并且使用了%s打印数据,从而可以泄露栈里存储的libc地址(如下)
第二个漏洞是v2和size可以不一样,如果size大于0x300000的话,可以重新输入size(但是v2没有被更新),而malloc函数申请大于128KB(0x20000 bit)的内存时会调用mmap在内存共享区映射出来一块内存,这片内存和libc里的地址存在固定偏移,我们提前控制一个v2的话就可以向任意一个libc地址写入一个0(如下)
利用思路
scanf的调用流程为scanf->vfscanf->__uflow->_IO_default_uflow()->underflow->_IO_file_underflow()
在最后的这个函数中有段代码调用了read 如下
count = _IO_SYSREAD(fp, fp->_IO_buf_base, fp->_IO_buf_end - fp->_IO_buf_base);
如果我们可以控制IO_buf_base,并且保证_IO_buf_end - _IO_buf_base不为0,就能实现地址任意写的目的。
不过需要绕过下面的检查,也就是要IO_read_ptr等于IO_read_end
if (fp->_IO_read_ptr < fp->_IO_read_end) |
我们的思路是向_IO_buf_base的地址里写入一个0,从而去再次控制_IO_buf_base字段。如下
此时的buf_base中的地址末尾已经被篡改为了00,所以下次可以向0x7f8d614a3900这个地址里写入(buf_end-buf_base)个字节的数据,该地址是_IO_write_base字段,下次输入的话,我们控制buf_base为malloc_hook的地址,而buf_end至少要为malloc_hook-8(因为buf_end-buf_base就是下次往malloc_hook里写入的字节数)
篡改后的buf_base和buf_end如下,此时还无法往malloc_hook里写入数据,因为_IO_read_ptr和_IO_read_end并不相同。而当前函数被不断循环,其中IO_getc(stdin)函数可以刷新_IO_read_ptr,让其从输入缓冲区中读入一个字节的数据,并且让read_ptr指针加1,因此我们随便输入数据,触发getc函数39次就可以让read_ptr和read_end相同,从而往malloc_hook里写入one_gadget,在之后调用malloc函数的时候即可获取shell
EXP
from tools import * |
whctf2017_note_sys
保护策略
漏洞所在
本题是有一个add函数和delete函数,不过都是去创建了一个子进程来调用函数。
在两个函数中都涉及到了对同一个全局变量进行操作,在add函数中malloc申请堆块后将地址存入了202080指向的位置(这个位置是2020C0),每次执行add函数的时候都会将202080指向的地址+8,也就是执行完当前函数再执行add函数,就是将malloc返回的地址写入2020c8里
而执行delete函数则是每次执行完都让202080指向的地址-8(如下),但需要注意的是先在202080指向的地址-8之后有一个usleep(这里会休眠两秒钟),而后再去执行下面的free函数部分
利用思路
核心点是delete函数在子进程中被执行,并且父进程里没有pthread_join函数,这意味着我们可以趁着子进程执行delete函数的空隙,让父进程再次调用delete函数,让202080指向的地址2020c0不断去-8,减到got表的位置。再执行add函数,malloc申请一个堆块,向堆块里写入shellcode,此时malloc返回的地址被写入到了free的got表里,最终调用free函数的时候触发shellcode
正常情况下去free掉got地址会报错,但此处的条件竞争是在执行free函数前不断开启多个子进程对一个全局变量进行操作,还没有执行到free函数崩溃前就已经把shellcode写到了free的got表里获取了shell
循环22次也很好算 (0x2020c0-0x202018-8)/8=22 (这里不能直接写free的got地址,应该再减8字节,因为最后add的时候是先加了八字节)
EXP
from tools import * |
whctf2017_easypwn
保护策略
漏洞所在
v3可被覆盖控制,而v3是format参数,可控就代表着存在格式化字符串漏洞。
snprintf会将s的数据拷贝0x7d0到v2上面,但是s和v2仅相离0x400,也就是说如果s写入0x400的话,拷贝到v2里面的时候就会溢出0x18个字节(v2和v3仅相距0x3e8个字节)从而控制v3,触发格式化字符串漏洞。
利用思路
relro保护开的是partial relro,这意味着可以篡改GOT表,而程序的此处莫名其妙的出现了一个free函数(如下),并且free掉堆块的内容可控,很明显是想让我们劫持free的got表为system,然后堆块里面写入/bin/sh最后执行free获取shell
利用的时候有几个点需要注意一下:
1 就是格式化字符串利用的时候,发现0x3e8后不能直接触发漏洞,需要填充两个字符串才能利用(这里是试出来的,原因未知)
2 本题属于snprintf执行中的格式化字符串漏洞,snprintf是一个字符一个字符来处理的,可能是采取了一种循环遍历的方式,所以即使最初调用snprintf的时候format是%s,但后续的操作中format被改变了,然后再取格式化字符的时候触发了漏洞。
3 snprintf函数的format是在第三个参数的位置,所以算栈顶偏移的时候不是和以前加6,而是加4。
4 我这里是跑了三次循环,每次改写free函数的got表两个字节,三次下来就写了system的6字节地址。
5 这里写入数据的话,肯定是要减去前面发送的垃圾数据0x3e8个a,但是后面的0x16不知道咋来的,但这里也是可以试出来的,先减去0x3e8后,发现自己要写的值和实际写入的值差了0x16,那就在exp里多减0x16就能得到正确的值。
PS:exp不是一定能打通,因为如果libc地址的低位比较小的话,会导致payload后面没有对齐,不过这个概率不大,没打通的话多跑两次就行
EXP
from tools import * |
whctf2017_rc4
保护策略
漏洞所在
这里存在了一个无法触发的格式化字符串漏洞,因为v1取的是一个字节的数据,但是rand生成的随机数是四字节的,无论如何也无法通过这个If检查触发格式化字符串漏洞
这里存在一个未初始化漏洞,如果进入这个函数不选择a b或者c的话,那么会跳转到LABEL_12的地方,而v2这个位置则是一个canary(这里我是先看roderick师傅写的wp,说可以利用这里泄露出来canary,然后调试了一下发现确实如此,如果单纯看代码的话确实无法发现这里是一个canary)
这个canary又被放到了*0x6020D8的位置,而后有个打印函数将0x6020D0开始16个字节进行了泄露,由此得到了canary
下图展示的代码部分还存在一个明显的栈溢出漏洞
利用思路
先泄露canary,然后利用栈溢出打ret2libc,我这里选择返回的是bss段上,进行了一个栈迁移,最后迁移过去的执行流是调用了execve(“/bin/sh\x00”,0,0) 当时用system发现没打通,索性就换成execve系统调用了
EXP
from tools import * |
参考文章
(whctf2017_stackoverflow ha1vk的博客-CSDN博客_whctf2017stackoverflow
IO FILE 之任意读写 « 平凡路上 (ray-cp.github.io)
[WHCTF 2017 note_sys | giantbranch’s blog](https://www.giantbranch.cn/2017/12/11/WHCTF 2017 note_sys/)