-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Felipe Molina de la Torre
committed
Aug 14, 2024
1 parent
4b168d7
commit d26bab0
Showing
20 changed files
with
1,932 additions
and
385 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"name": "Maitm Dev Container", | ||
"dockerFile": "../Dockerfile", | ||
"context": "..", | ||
"build": { | ||
"args": {} | ||
}, | ||
"customizations": { | ||
"vscode": { | ||
"settings": { | ||
"terminal.integrated.shell.linux": "/bin/sh" | ||
}, | ||
"extensions": [ | ||
"ms-python.python", | ||
"ms-azuretools.vscode-docker", | ||
"ms-python.debugpy" | ||
] | ||
} | ||
}, | ||
"workspaceFolder": "/Maitm", | ||
"postCreateCommand": "apk add git --no-cache && apk add openssh --no-cache", | ||
"remoteUser": "root", | ||
"workspaceMount": "source=${localWorkspaceFolder},target=/Maitm,type=bind" | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.DS_Store | ||
config/prod | ||
config/*prod* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -126,3 +126,9 @@ config*.yaml | |
*.pyc | ||
*.old | ||
*.drawio | ||
|
||
config/prod/* | ||
|
||
attachments/ | ||
|
||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,31 @@ | ||
FROM alpine:3.16 | ||
FROM alpine:3.20 | ||
LABEL name="Maitm" | ||
LABEL "com.example.vendor"="Orange Cyberdefense Sensepost Team" | ||
LABEL org.opencontainers.image.authors="Felipe Molina de la Torre" | ||
|
||
COPY *.py /Maitm/ | ||
COPY Pipfile* /Maitm/ | ||
COPY Pipfile /Maitm/ | ||
COPY Maitm /Maitm/Maitm | ||
COPY config /Maitm/config | ||
RUN apk update && \ | ||
apk add python3 && \ | ||
apk add py3-pip && \ | ||
pip install pipenv && \ | ||
cd /Maitm && \ | ||
pipenv install --python=3.10 | ||
# If flags $FORWARD and $NEWONLY are provided, add the flags | ||
apk add gcc && \ | ||
apk add python3-dev && \ | ||
apk add libc-dev && \ | ||
apk add libffi-dev && \ | ||
apk add pipx && \ | ||
apk add yaml-dev | ||
# Uninstalling setuptools as it produces this error: https://github.com/pypa/setuptools/issues/4483 | ||
# It will be installed later during pipenv install command | ||
# Update the path to have pipx tools available in the command line | ||
ENV PATH="$PATH:/root/.local/bin" | ||
RUN pipx install pipenv | ||
WORKDIR /Maitm | ||
# RUN cd /Maitm | ||
RUN pipenv install --python=3.12 | ||
|
||
# The user has to provide the parameters in Docker invocation, such as: | ||
# docker run --rm -ti maitm -h | ||
# docker run --rm -ti maitm -c config/config.yml -f -n | ||
ENTRYPOINT [ "pipenv", "run", "python", "./mail-in-the-middle.py" ] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
from imap_tools.message import MailMessage as ImapMessage | ||
from email import message_from_string | ||
from email.message import EmailMessage as PythonEmailMessage | ||
from email.mime.image import MIMEImage | ||
from exchangelib import Message as ExchangeMessage, FileAttachment, Account as ExchangeAccount, HTMLBody, Mailbox as ExchangeMailbox | ||
import mimetypes | ||
import base64 | ||
import logging.config | ||
import os | ||
import yaml | ||
import email | ||
from email import policy | ||
from email.parser import BytesParser | ||
|
||
""" | ||
MailConverter class is used to convert mail from one format to another. | ||
It accepts exchangelib and imap_tools mail objects and converts it to python native email object. | ||
It cannot do the reverse conversion to imap_tools message format, as it has immutable fields and is not needed to send out emails. | ||
""" | ||
class MailConverter: | ||
def __init__(self, exchangelib_mail: ExchangeMessage=None, exchange_account: ExchangeAccount=None, imap_tools_mail=None, clone_cc=False, clone_bcc=False, logfile="logs/mailconverter.log"): | ||
self.init_logging(log_filename=logfile) | ||
self.exchange_account = exchange_account | ||
self.exchange_mail = exchangelib_mail | ||
self.imap_mail = imap_tools_mail | ||
self.python_mail = PythonEmailMessage() | ||
self.clone_cc = clone_cc | ||
self.clone_bcc = clone_bcc | ||
|
||
def init_logging(self,log_filename): | ||
# Ensure the 'logs' directory exists | ||
os.makedirs(os.path.dirname(log_filename), exist_ok=True) | ||
|
||
# Load the logging configuration from a YAML file | ||
with open('config/logging.yml', 'r') as f: | ||
config = yaml.safe_load(f.read()) | ||
# Update the filename in the configuration | ||
config['handlers']['file_handler']['filename'] = log_filename | ||
logging.config.dictConfig(config) | ||
|
||
# Example usage | ||
self.logger = logging.getLogger() | ||
|
||
""" | ||
This function transforms an imap_tools message to a Python EmailMessage | ||
""" | ||
def convert_from_imapmessage(self, msg: ImapMessage): | ||
raw_email = msg.obj.as_bytes() | ||
|
||
# Parse the raw email data | ||
self.python_mail = BytesParser(policy=policy.default).parsebytes(raw_email) | ||
# Add the UID attribute as well from the IMAP library | ||
self.python_mail['uid'] = msg.uid | ||
# Remove the Copied and BCC recipients | ||
del self.python_mail['cc'] | ||
del self.python_mail['bcc'] | ||
# Remove the 'received' header which may disclose our mail server address | ||
del self.python_mail['Received'] | ||
del self.python_mail['Authentication-Results'] | ||
del self.python_mail['Delivered-To'] | ||
# Remove the 'spam' headers | ||
for header in list(self.python_mail.keys()): | ||
if 'spam' in header.lower(): | ||
del self.python_mail[header] | ||
|
||
return self.python_mail | ||
|
||
""" | ||
This function transforms an exchangelib message to a Python EmailMessage | ||
""" | ||
def convert_from_exchangemail(self, msg: ExchangeMessage): | ||
raw_mime_content = msg.mime_content | ||
|
||
# Parse the raw MIME content | ||
self.python_mail = BytesParser(policy=policy.default).parsebytes(raw_mime_content) | ||
self.python_mail['uid'] = msg.id+"-"+msg.changekey | ||
# Remove the Copied and BCC recipients | ||
del self.python_mail['cc'] | ||
del self.python_mail['bcc'] | ||
# Remove the 'received' header which may disclose our mail server address | ||
del self.python_mail['Received'] | ||
del self.python_mail['Authentication-Results'] | ||
del self.python_mail['Delivered-To'] | ||
# Remove the 'spam' headers | ||
for header in list(self.python_mail.keys()): | ||
if 'spam' in header.lower(): | ||
del self.python_mail[header] | ||
|
||
return self.python_mail | ||
|
||
""" | ||
This function transforms a Python EmailMessage to an exchangelib message format | ||
""" | ||
def convert_to_exchange_message(self, msg: PythonEmailMessage, exchage_account: ExchangeAccount = None): | ||
# Create a new ExchangeMessage object | ||
if exchage_account: | ||
self.exchange_account = exchage_account | ||
if not self.exchange_account: | ||
self.logger.error("Exchange account is not provided") | ||
return None | ||
self.exchange_mail = ExchangeMessage(account=self.exchange_account) | ||
|
||
self.exchange_mail.body = HTMLBody(msg.get_body(preferencelist=('html',)).get_content()) | ||
self.exchange_mail.subject = msg['Subject'] | ||
self.exchange_mail.to_recipients = [ExchangeMailbox(email_address=addr) for addr in msg.get_all('To', [])] | ||
# TODO: Not sure if I can spoof the sender with exchangelib. Proably need to use the account's email address | ||
self.exchange_mail.sender = ExchangeMailbox(email_address=msg['From']) | ||
|
||
# Handling CC and BCC if needed | ||
# TODO: Change the CC and Bcc handing | ||
if msg.get_all('Cc', []): | ||
self.exchange_mail.cc_recipients = [ExchangeMailbox(email_address=addr) for addr in msg.get_all('Cc', [])] | ||
if msg.get_all('Bcc', []): | ||
self.exchange_mail.bcc_recipients = [ExchangeMailbox(email_address=addr) for addr in msg.get_all('Bcc', [])] | ||
|
||
# Add attachments | ||
for part in msg.iter_parts(): | ||
if part.get_content_disposition() == 'attachment': | ||
content_type = part.get_content_type() | ||
maintype, subtype = content_type.split('/') | ||
attachment = FileAttachment( | ||
name=part.get_filename(), | ||
content=part.get_payload(decode=True), | ||
content_type=content_type | ||
) | ||
self.exchange_mail.attach(attachment) | ||
|
||
return self.exchange_mail |
Oops, something went wrong.