mirror of
https://github.com/kingk85/uFTP.git
synced 2025-07-25 13:16:12 +03:00
139 lines
6.0 KiB
Python
139 lines
6.0 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
Created on Sat Jul 19 18:15:07 2025
|
|
|
|
@author: ugo
|
|
"""
|
|
|
|
import socket
|
|
import ssl
|
|
import ftplib
|
|
from io import BytesIO
|
|
|
|
def log_command(direction, command, response=None):
|
|
"""Log FTP commands and responses"""
|
|
if direction == "C":
|
|
print(f"C: {command}")
|
|
elif direction == "S":
|
|
print(f"S: {response}")
|
|
elif direction == "ERROR":
|
|
print(f"ERROR: {command}")
|
|
elif direction == "INFO":
|
|
print(f"INFO: {command}")
|
|
|
|
def verify_rest_violations():
|
|
"""
|
|
Verify REST-related sequence and implementation violations.
|
|
"""
|
|
HOST = '127.0.0.1'
|
|
PORT = 21
|
|
USER = 'username'
|
|
PASS = 'password'
|
|
FILE = "test_rest.txt"
|
|
CONTENT = b"1234567890"
|
|
|
|
print("\n--- Verifying Rules: REST Command Sequence and Implementation ---")
|
|
print("Test Objective: Verify that the REST command correctly limits subsequent commands and handles offsets")
|
|
|
|
try:
|
|
with ftplib.FTP() as ftp:
|
|
# Enable debug mode to show all FTP interactions
|
|
ftp.set_debuglevel(0) # We handle display ourselves
|
|
|
|
log_command("INFO", f"Connecting to {HOST}:{PORT}")
|
|
ftp.connect(HOST, PORT, timeout=5)
|
|
|
|
log_command("C", f"USER {USER}")
|
|
ftp.login(USER, PASS)
|
|
log_command("INFO", "Login successful")
|
|
|
|
log_command("C", "TYPE I")
|
|
resp = ftp.sendcmd("TYPE I")
|
|
log_command("S", resp)
|
|
|
|
# Upload test file
|
|
log_command("C", f"STOR {FILE}")
|
|
ftp.storbinary(f"STOR {FILE}", BytesIO(CONTENT))
|
|
log_command("INFO", f"File uploaded successfully, content: {CONTENT} (length: {len(CONTENT)})")
|
|
|
|
print("\n" + "="*60)
|
|
# Scenario 1: Verify if RETR correctly handles the offset set by REST
|
|
print("[+] Scenario 1: Verify if RETR correctly handles the offset set by REST")
|
|
print(" RFC Requirement: RETR should start transferring from the byte position specified by REST")
|
|
|
|
# Reset REST point
|
|
rest_offset = 5
|
|
log_command("C", f"REST {rest_offset}")
|
|
try:
|
|
response_rest2 = ftp.sendcmd(f"REST {rest_offset}")
|
|
log_command("S", response_rest2)
|
|
|
|
if not response_rest2.startswith('350'):
|
|
print(f" REST {rest_offset} failed: {response_rest2}")
|
|
print(f" Expected: 350 Restarting at {rest_offset}")
|
|
return
|
|
else:
|
|
print(f" REST set offset to byte {rest_offset}")
|
|
except ftplib.error_perm as e:
|
|
log_command("ERROR", f"REST {rest_offset} failed: {e}")
|
|
return
|
|
|
|
# Download file
|
|
log_command("C", f"RETR {FILE}")
|
|
out = BytesIO()
|
|
ftp.retrbinary(f"RETR {FILE}", out.write)
|
|
retrieved_content = out.getvalue()
|
|
|
|
# Detailed analysis of results
|
|
print(f"\n Transfer Result Analysis:")
|
|
print(f" Original File Content: {CONTENT} (length: {len(CONTENT)})")
|
|
print(f" REST Offset: {rest_offset} (starting from byte {rest_offset})")
|
|
print(f" Expected Transferred Content: {CONTENT[rest_offset:]} (length: {len(CONTENT[rest_offset:])})")
|
|
print(f" Actual Transferred Content: {retrieved_content} (length: {len(retrieved_content)})")
|
|
|
|
if len(retrieved_content) == len(CONTENT):
|
|
print("\n VIOLATION CONFIRMED: RETR implementation ignored the offset set by REST")
|
|
print(" Actual Result: Downloaded the entire file, ignoring the REST offset")
|
|
print(f" Expected Result: Should only download {CONTENT[rest_offset:]} ({len(CONTENT[rest_offset:])} bytes)")
|
|
print(" Violation Explanation: Violates RFC 959 regarding the REST command")
|
|
elif len(retrieved_content) == len(CONTENT) - rest_offset:
|
|
if retrieved_content == CONTENT[rest_offset:]:
|
|
print(" No violation detected. RETR correctly handled the REST offset.")
|
|
else:
|
|
print(" VIOLATION CONFIRMED: Content mismatch, REST offset handled incorrectly")
|
|
print(f" Actual Content: {retrieved_content}")
|
|
print(f" Expected Content: {CONTENT[rest_offset:]}")
|
|
print(" Violation Explanation: Incorrect REST offset calculation")
|
|
elif len(retrieved_content) > len(CONTENT):
|
|
print(" VIOLATION CONFIRMED: Retrieved data length exceeds original file size")
|
|
print(f" Actual Length: {len(retrieved_content)} bytes")
|
|
print(f" Expected Maximum Length: {len(CONTENT)} bytes")
|
|
print(f" Expected Length after REST: {len(CONTENT[rest_offset:])} bytes")
|
|
print(" Violation Explanation: Severe data transfer anomaly")
|
|
else:
|
|
print(f" VIOLATION CONFIRMED: Unexpected retrieved content length")
|
|
print(f" Actual Length: {len(retrieved_content)} bytes")
|
|
print(f" Expected Length: {len(CONTENT[rest_offset:])} bytes")
|
|
print(" Violation Explanation: Problem with REST command implementation")
|
|
|
|
# Clean up test file
|
|
try:
|
|
log_command("C", f"DELE {FILE}")
|
|
#ftp.delete(FILE)
|
|
log_command("INFO", "Test file cleanup completed")
|
|
except:
|
|
log_command("ERROR", "Failed to cleanup test file")
|
|
|
|
except Exception as e:
|
|
print(f"\nError occurred: {e}")
|
|
import traceback
|
|
print("Detailed error information:")
|
|
traceback.print_exc()
|
|
print("\nPossible causes:")
|
|
print(" - Server connection issues")
|
|
print(" - Insufficient permissions")
|
|
print(" - Server does not support certain commands")
|
|
|
|
if __name__ == "__main__":
|
|
verify_rest_violations() |