By: unvariant

Tags: pwn AmateursCTF-2023

Problem Description:

Every programmer should read the Intel Software Developer Manuals at least once.


Reveal Hints None

Provided Files

  • chal.c
  • chal
  • Dockerfile


#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/seccomp.h>
#include <seccomp.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>

void setup_seccomp () {
    scmp_filter_ctx ctx;
    ctx = seccomp_init(SCMP_ACT_KILL);
    int ret = 0;
    ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
    ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
    ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
    ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
    ret |= seccomp_load(ctx);
    if (ret) {
        errx(1, "seccomp failed");

int main () {
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);


    int fd = open("flag.txt", O_RDONLY);
    if (0 > fd)
        errx(1, "failed to open flag.txt");

    char * flag = mmap(NULL, 0x1000, PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
    if (flag == MAP_FAILED)
        errx(1, "failed to mmap memory");

    if (0 > read(fd, flag, 0x1000))
        errx(1, "failed to read flag");

    // make flag write-only
    if (0 > mprotect(flag, 0x1000, PROT_WRITE))
        errx(1, "failed to change mmap permissions");

    char * code = mmap(NULL, 0x100000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
    if (code == MAP_FAILED)
        errx(1, "failed to mmap shellcode buffer");

    printf("> ");
    if (0 > read(0, code, 0x100000))
        errx(1, "failed to read shellcode");


    ((void(*)(char *))code)(flag);


In the provided source file, the code does a few things

  1. writes the contents of flag.txt into a mmapped buffer
  2. mprotects the flag memory to PROT_WRITE
  3. mmaps shellcode
  4. setups up seccomp sandbox
  5. executes shellcode

The intended solution is to simply print out the contents of the flag. Even though the memory is set to PROT_WRITE, on x64 there is not concept of write-only memory. On x64 write implies read, so even though the memory protection is set to write-only we can still read the flag.


flag.txt fd is not closed

I forgot to close the flag.txt fd before executing the shellcode, which meants that you could simply read from the flag fd and get the flag.