2022TQLCTF WP
unbelievable_write
程序没开PIE,GOT表也是可写的
C1
C2
C3
这题关键就是过掉C3的check,也就是能往target上写值
C2给了一次free任意地址的机会,v0 = ptr,ptr是init的时候malloc的,v1可以是负值
理论上通过C2free掉目标地址,然后用C1分配回来实现任意写,但是由于C1malloc之后紧跟着就会free掉,而free会有check的,所以也不能任意地址写
这题的思路是向前free掉tcache struct,由于tcache_struct本身就是一个chunk,所以后面修改它再free也不会有什么问题
通过C1修改tcache_struct,在tcachelist上填入两个地址,一个是free的got地址,一个是target的地址,首先修改free的got为puts的plt地址,这样后面就可以过掉free这个限制,然后再分配到target实现任意地址写
以释放掉一个0x40的堆块做测试
tcache的结构是 从0x405040开始是0x20 0x30 0x40………………的tcache entries
100000 是 00 00 01代表0x20 0x30 0x40chunks的数量,没什么问题
我们要改的地址是0x404018
给他转向到这里就行了0x4010F0
exp + 简要分析
exp如下
1 | from pwn import * |
具体写到那哪个大小的tcache entries上无所谓,只要构造对就行了,
这里还有个小细节是覆盖got表时是
C1(0x110,p64(0x4010F0)+p64(0x0401040))
为了达到目的只需要覆盖free的got为0x4010F0就行,但是由于取出tcache的时候,会清空chunk的前0x16字节,所以导致puts的got被改成0了,如果我们这里不多写个p64(0x0401040)把他恢复的话,会导致puts不能用,free也就错了
EZVM
非常费劲的一个题
题目分析
程序开始会读入我们传的shellcode,但是shellcode里面不能有10,所以后面操作数里面有10的时候得变换一下
然后会创建一个unicorn虚拟机,架构是x86_64,虽然这里写的是i386
创建了两块内存,一块是代码段数据段,一块是堆栈,紧接着把我6们传入的code写到代码段,
uc_hook_add是添加hook函数,这里是针对系统调用hook,UC_X86_INS_SYSCALL是我解析的unicorn的头文件
ps:运行结束后的打印我做了patch,打印的不再是ecx和edx,而是eip和esp,这样方便后面查错
hook函数对open write read close都进行了重写
open_hook
这里mem_read参数没显示,就是从src中读data到buf里面,是unicorn虚拟机和物理机之间的交互
sub_1A66
这里实际上是自己实现的类似于Linux中的FILE结构,所有的selfFILE结构呈数组存放在unk_5020处,一个selfFILE的大小是72,
offset0处存放的是fileno,8处存放的是filename,4*8处有一个data_ptr,模拟磁盘文件,对这个文件的读写都是往这个dataptr里面写,
然后是自己写的read write close
self_file_read
a1传的是fd,a1+40是这个文件数据区的大小,这里进行了严格比较,所以没漏洞
self_file_write
这里realloc的使用也没什么问题,逻辑就是将data拷贝数据区
self_file_close
都清零了所有是没UAF的,但是内容没清零,所以可以重新分配回来泄露libc
另外程序初始也是预置提供了标准输入输出
分析完其自实现的文件描述符机制,后面hook的write read close实际就是调用上面虚表中的self函数
这些函数都没什么问题,本题漏洞在于strcpy的使用,这里filename的长度是0x18,紧跟着是data_ptr
strcpy拷贝时会多拷贝一个0,所以这里存在一个offbyone,利用就很清晰了,可以offbyone也就可以打chunkoverlapping,然后可以打tcache attack到_free_hook之后就是orw(以后看题一定要看是否开了沙箱,忘了orw真的很浪费时间)
tcache attack
tcache entry -> chunk1 -> chunk2
tcache entry -> chunk1 -> target
就是修改chunk1中的指针到target然后就能分配到了,这里必须是先有两个chunk
不能是
tcache entry -> chunk1 -> null
tcache entry -> chunk1 -> target
这种情况下,tcache的counts是1,所以是分配不出来target的,(分配出chunk1之后count为0,就没法分配了)
利用
可以把基础操作封装成上面这种,我对操作fd为10的时候辽特判,主要是为了避免shellcode里存在10
另外在构造code的时候,unicorn在执行的时候老是有个内存错误,至今查不出来错误在哪,这个点卡了我巨长时间,后来我是在每个函数后面
加了个nop,就过了
exp
贴下nu1l的标准exp
1 |
|
orw
总结下ORW,做题还是发现自己ORW写的太慢了
setcontext+orw - 狒猩橙 - 博客园 (cnblogs.com)
setcontext部分我们可以用pwntools里的SigreturnFrame去构建
SigreturnFrame就是根据这里rdi的偏移构造数据的,比如sig.rsp就会把数据填到offset 0xA0处
主要是方便我们构造
一次控制流劫持后,后面大体有两种利用方法,第一种是直接控制程序执行流去执行ROP链,因此关键在于得找一片地方存放ROP链,一般就是在堆中,另外要用setcontext修改rsp,
第二种是先用mprotect开辟一片可读可写可执行的内存,然后通过read把shellcode读到上面来执行
timezone_challenge
挺离谱的一个漏洞点,文件就不分析了,就是接收命令然后执行zic,那就只能看zic了
zic - man pages section 8: System Administration Commands (oracle.com)
翻一下16.04的zic man手册
这里存在一个命令注入,代码中确实也有这个点
那下面就是构造数据了,man里面有example,我们只要修改下type就行
最终构造出来是这个,Rule中设置一个type是command,然后要有一个zone引用到这个Rule,要不然不会触发
1 | # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S |