Packets manipualtion
If you are here it's mean that you have tested your proxy and you liked it, I know me too 🙄
Now we are talking about packet manipulations, where the fun part begin, for this example we will leverage our previous article about proxy and it's code base, to refactor the request_handler
and response_handler
functions to manipulate FTP commands and responses
We are doing it for educational purposes OF COURSE no need to write long ethical speeches.
Packet manipulation is a fundamental concept in networking and cybersecurity that involves intercepting, modifying, and sometimes injecting network packets as they transit between a client and a server. Understanding packet manipulation can help you analyze protocols, test network security, and develop a deeper comprehension of how data is transmitted over networks.
General knowledge on packet manipulation
What is a network packet
- Definition: In networking, a packet is a unit of data formatted for transmission over a network. It contains both control information (like source and destination addresses) and user data (payload).
- Structure: Packets are structured according to the protocols in use (e.g., TCP/IP, HTTP, FTP), with headers and footers that wrap the actual data. See more about packet structure on wikipedia here 👀
Why manipulate packets
- Testing and Debugging: To test how applications handle unexpected or malformed data.
- Security Assessments: To discover vulnerabilities by injecting malicious payloads or altering data.
- Protocol Analysis: To understand how proprietary or undocumented protocols function.
- Educational Purposes: To learn about network communications and protocol behavior, that's us here 😇
Well known techniques for packet manipulation
-
Interception: Capturing packets as they pass through the network using tools like Wireshark or tcpdump.
-
Modification: Altering packet headers or payloads before forwarding them. Examples include changing HTTP headers, modifying FTP commands, or altering binary data.
-
Injection: Introducing new packets into the communication stream. This can simulate certain conditions or test how an application handles unsolicited data.
-
Reassembly and Fragmentation: Breaking packets into smaller fragments or reassembling them differently. Useful for testing how systems handle fragmented packets.
- Replay Attacks: Capturing and retransmitting packets to observe how the server responds. Often used in security testing to check for vulnerabilities.
Tools for Packet Manipulation
- Proxies:
- MITMProxy, Burp Suite: Interactive proxies that allow for real-time modification of HTTP and HTTPS traffic.
-
Custom Proxies: Like the one we're developing here, tailored to specific protocols or needs 🥷🏼
-
Packet Crafting Tools:
- Scapy: A powerful Python library for crafting and manipulating packets.
-
Hping3, Nemesis: Command-line tools for crafting TCP/IP packets.
-
Network Sniffers:
- Wireshark: Allows you to capture and analyze packets but not modify them in transit.
Improving request_handler
and response_handler
functions
To enhance your proxy's capabilities and educational value, you can implement more advanced packet manipulation techniques. Below are some ideas, along with code examples.
Protocol agnostic modifications
We can begin to design our handlers to detect and manipulate data based on the protocol in use. We can parse the data to identify the protocol and apply appropriate modifications.
Example: Automatically Detect and Modify HTTP and FTP Traffic
def request_handler(buffer):
# Attempt to decode buffer as UTF-8 text
try:
buffer_str = buffer.decode('utf-8', errors='ignore')
except UnicodeDecodeError:
return buffer # Non-text data; return unmodified
# Check if it's an HTTP request
if buffer_str.startswith('GET') or buffer_str.startswith('POST'):
# Modify HTTP requests
buffer_str = modify_http_request(buffer_str)
elif buffer_str.strip().upper().startswith('USER') or buffer_str.strip().upper().startswith('PASS'):
# Modify FTP commands
buffer_str = modify_ftp_request(buffer_str)
else:
# Other protocols or data
pass
return buffer_str.encode('utf-8')
def response_handler(buffer):
# Similar logic for responses
try:
buffer_str = buffer.decode('utf-8', errors='ignore')
except UnicodeDecodeError:
return buffer
# Check for HTTP response
if buffer_str.startswith('HTTP/'):
buffer_str = modify_http_response(buffer_str)
elif buffer_str.startswith('220') or buffer_str.startswith('230'):
buffer_str = modify_ftp_response(buffer_str)
else:
pass
return buffer_str.encode('utf-8')
Implementing Specific Modifications:
def modify_http_request(request):
# Add headers, modify paths, etc.
request = request.replace('User-Agent: ', 'User-Agent: MyCustomAgent')
return request
def modify_ftp_request(request):
# Log credentials, alter commands
if request.strip().upper().startswith('PASS'):
print(f"[Intercepted Password]: {request.strip()}")
return request
def modify_http_response(response):
# Inject content, modify status codes
if '<body>' in response:
response = response.replace('<body>', '<body><h1>Modified by Proxy</h1>')
return response
def modify_ftp_response(response):
# Change server messages
if '230' in response:
response = response.replace('230', '230-Welcome to the Proxy Server!')
return response
Binary Data Manipulation
For protocols that use binary data (e.g., images, file transfers), we can manipulate the bytes directly.
Example: Modify Binary Content
def request_handler(buffer):
# Let's say you want to corrupt the data being sent
buffer = corrupt_data(buffer)
return buffer
def corrupt_data(data):
# Flip some bits in the data
corrupted = bytearray(data)
for i in range(len(corrupted)):
corrupted[i] ^= 0xFF # Invert all bits
return bytes(corrupted)
Note: Be cautious with this, as it can lead to unexpected behavior or crashes.
Delay and Drop packets
Simulate network latency or packet loss to test how applications handle such conditions.
Example: Introduce Artificial Delay
import time
def request_handler(buffer):
# Introduce a 2-second delay
time.sleep(2)
return buffer
def response_handler(buffer):
# Randomly drop packets
import random
if random.randint(0, 10) < 2: # 20% chance to drop
print("[Dropped Packet]")
return b'' # Return empty buffer to simulate packet drop
return buffer
Implement SSL/TLS interception
We can also upgrade our proxy to handle encrypted traffic by acting as a man-in-the-middle for SSL/TLS connections. This will be an other story 😈
This requires generating and installing root certificates and has significant ethical and legal implications. Use only in controlled environments.
Advanced Content Manipulation**
Use regular expressions or parsing libraries to perform complex modifications.
Example: Using Regular Expressions
import re
def response_handler(buffer):
try:
buffer_str = buffer.decode('utf-8', errors='ignore')
except UnicodeDecodeError:
return buffer
# Remove sensitive information using regex
buffer_str = re.sub(r'password=.*?(&|\s)', 'password=******\\1', buffer_str, flags=re.IGNORECASE)
return buffer_str.encode('utf-8')
Protocol Parsing Libraries
Use existing libraries to parse and reconstruct protocol data structures.
Example: Parsing HTTP with http
Module
from http.server import BaseHTTPRequestHandler
from io import BytesIO
def request_handler(buffer):
class HTTPRequest(BaseHTTPRequestHandler):
def __init__(self, request_text):
self.rfile = BytesIO(request_text)
self.raw_requestline = self.rfile.readline()
self.error_code = self.error_message = None
self.parse_request()
request = HTTPRequest(buffer)
# Now you can access request.method, request.path, etc.
if request.command == 'GET':
print(f"Intercepted GET request to {request.path}")
# Modify the request as needed
# Reconstruct the request back to bytes
# (You'll need to manually rebuild the request string)
return buffer # Placeholder
The above example is non-trivial and requires careful handling to rebuild the request. This also will be for an other story 😇
Encryption and Decryption
If you're dealing with custom protocols that implement encryption like in our previous example with FTP, we can implement decryption and encryption within our proxy. Below a simple example of decrypting custom encrypted payloads.
Example: Decrypting custom encrypted payloads
from Crypto.Cipher import AES
def request_handler(buffer):
# Decrypt the payload
decrypted_data = decrypt_payload(buffer)
# Modify the decrypted data
modified_data = decrypted_data.replace('secret', '******')
# Re-encrypt the data
encrypted_data = encrypt_payload(modified_data)
return encrypted_data
def decrypt_payload(data):
# Placeholder for decryption logic
return data
def encrypt_payload(data):
# Placeholder for encryption logic
return data
Note: Handling encryption requires knowledge of the encryption method and keys, and should only be done with authorization.
Logging and alerting
We can also use this proxy by implement detailed logging and alerting mechanisms, like for preventing an SQL injection.
Example: Log Suspicious Activity
def request_handler(buffer):
buffer_str = buffer.decode('utf-8', errors='ignore')
# Check for SQL injection patterns
if re.search(r"(\%27)|(\')|(\-\-)|(\%23)|(#)", buffer_str):
print("[Alert] Potential SQL Injection detected")
log_alert(buffer_str)
return buffer
def log_alert(data):
with open('alerts.log', 'a') as f:
f.write(f"{datetime.now()} - {data}\n")
Refactoring our request_handler
and response_handler
functions
Let's update our functions and perform basic packet manipulations specific to FTP traffic like we're talking.
Update request_handler
The request_handler
will now manipulate the FTP commands sent from the client to the server
def request_handler(buffer):
# Decode the buffer to a string for manipulation
try:
buffer_str = buffer.decode('utf-8', errors='ignore')
except UnicodeDecodeError:
return buffer # Return unchanged if decoding fails
# Log the FTP command
print(f"[Request] {buffer_str.strip()}")
# Example 1: Block certain commands (e.g., DELE to prevent file deletion)
if buffer_str.strip().upper().startswith('DELE '):
# Replace 'DELE' with 'NOOP' to prevent deletion
buffer_str = 'NOOP\r\n'
print("[Modified Request] Blocked DELE command")
# Example 2: Modify a command parameter (e.g., change directory path)
if buffer_str.strip().upper().startswith('CWD '):
# Change the directory to '/home/user'
buffer_str = 'CWD /home/user\r\n'
print("[Modified Request] Changed directory to '/home/user'")
# Example 3: Inject a custom command (e.g., send a NOOP before the actual command)
buffer_str = 'NOOP\r\n' + buffer_str
print("[Modified Request] Injected NOOP command before the actual command")
# Encode the string back to bytes
return buffer_str.encode('utf-8')
Like you can see above we have put many comments in the script in order to facilitate the understunding. In summary we observe the ftp commands sent by the client, block DELE command.
If the client tries to delete a file using DELE, the command is replaced with NOOP (No Operation), preventing the deletion. If the client changes the working directory using CWD, the directory is changed to /home/user, regardless of what the client requested.
We also prepends a NOOP command before each command sent by the client because this is a fun injection 🤓
Update response_handler
def response_handler(buffer):
# Decode the buffer to a string for manipulation
try:
buffer_str = buffer.decode('utf-8', errors='ignore')
except UnicodeDecodeError:
return buffer # Return unchanged if decoding fails
# Log the FTP response
print(f"[Response] {buffer_str.strip()}")
# Example 1: Modify the welcome message
if buffer_str.startswith('220'):
# Append a custom message to the welcome banner
buffer_str = buffer_str.strip() + '\r\n220-This is a proxy server for educational purposes.\r\n'
print("[Modified Response] Added custom welcome message")
# Example 2: Mask server information
if 'vsftpd' in buffer_str.lower():
# Replace server software information with generic text
buffer_str = buffer_str.replace('vsftpd', 'FTP Server')
print("[Modified Response] Masked server software information")
# Example 3: Inject a custom response after the original response
buffer_str += '230-Note: This session is being monitored.\r\n'
print("[Modified Response] Injected custom response message")
# Encode the string back to bytes
return buffer_str.encode('utf-8')
In summary
Packet manipulation is a powerful technique that can greatly enhance your understanding of network protocols and security. By improving our request_handler
and response_handler
functions, we can now simulate real-world scenarios, test application resilience, and explore the intricacies of network communication.
⚠️ Always remember to use these tools ethically and responsibly, ensuring that you respect privacy and legal boundaries ! ⚠️
Hope you learn some new things and enjoyed one more step to be a hacker shinobi 🥷🏼