From b677524b8455166d1432d987eeea4ab1e591ec82 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Mon, 7 Apr 2025 01:53:00 -0600 Subject: [PATCH 1/6] Fix mismatched number of format string arguments --- MITMsmtp/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MITMsmtp/__main__.py b/MITMsmtp/__main__.py index 331806d..59b6155 100644 --- a/MITMsmtp/__main__.py +++ b/MITMsmtp/__main__.py @@ -52,7 +52,7 @@ def loginCallback(self, message, username, password): @type message: Message """ def messageCallback(self, message): - output = """=== Complete Message ===%s\nIP : %s\n\nUsername : %s\nPassword : %s\nClient : %s\nSender : %s\n""" % (message.clientIP, + output = """=== Complete Message ===\nIP : %s\n\nUsername : %s\nPassword : %s\nClient : %s\nSender : %s\n""" % (message.clientIP, message.username, message.password, message.client_name, From 83851f98b073e7b5e9fa72d3eecd86c6e25a5bba Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Mon, 7 Apr 2025 02:25:00 -0600 Subject: [PATCH 2/6] Replace removed ssl.wrap_socket() with ssl.SSLContext --- MITMsmtp/SMTPServer.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MITMsmtp/SMTPServer.py b/MITMsmtp/SMTPServer.py index b873735..0b9c9a0 100644 --- a/MITMsmtp/SMTPServer.py +++ b/MITMsmtp/SMTPServer.py @@ -79,11 +79,11 @@ def get_request(self): @return: Returns encrypted connection """ def wrapSSL(self, socket): - connstream = ssl.wrap_socket(socket, - server_side=True, - certfile = self.certfile, - keyfile = self.keyfile, - ssl_version = self.ssl_version) + context = ssl.SSLContext(self.ssl_version) + if self.certfile: + context.load_cert_chain(certfile=self.certfile, keyfile=self.keyfile) + connstream = context.wrap_socket(socket, server_side=True) + return connstream class SMTPServer(ThreadingMixIn, SMTPServer): pass From 1f64fa970d8c60039c7a338df369ab9a940c763b Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Mon, 7 Apr 2025 02:27:02 -0600 Subject: [PATCH 3/6] Allow MITMsmtp to be run as a module --- MITMsmtp/__main__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MITMsmtp/__main__.py b/MITMsmtp/__main__.py index 59b6155..f5cfa0f 100644 --- a/MITMsmtp/__main__.py +++ b/MITMsmtp/__main__.py @@ -72,7 +72,7 @@ def messageCallback(self, message): log.write(output + "\n\n") log.write(message.message) -def main(args=None): +def main(): # Parse arguments parser=argparse.ArgumentParser(description="MITMsmtp is an Evil SMTP Server for pentesting SMTP clients to catch login credentials and mails sent over plain or SSL encrypted connections.") parser.add_argument('--server_address', default="0.0.0.0", help='IP Address to listen on (default: all)') @@ -118,3 +118,6 @@ def main(args=None): except KeyboardInterrupt: pass server.stop() #Stop SMTPServer + +if __name__ == "__main__": + main() From 1188b4d41539fac912a5b3b978f0f55fd202b69e Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Mon, 7 Apr 2025 03:14:20 -0600 Subject: [PATCH 4/6] Add pyproject.toml and update build instructions --- README.md | 20 ++++++++++++++------ pyproject.toml | 25 +++++++++++++++++++++++++ setup.py | 28 ---------------------------- 3 files changed, 39 insertions(+), 34 deletions(-) create mode 100644 pyproject.toml delete mode 100644 setup.py diff --git a/README.md b/README.md index 3813fb0..07b9a0d 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ MITMsmtp supports the following login methods: Challenge-Response based authentication methods like CRAM-MD5, NTLM or Kerberos can't be supported as these methods require the server to know the cleartext password. ## Setup -MITMsmtp requires Python3 and setuptools. You might want to install git as well. Use the following command on Debian: +MITMsmtp requires at least Python 3.6. You might want to install git and setuptools as well. Use the following command on Debian: `apt install python3 python3-setuptools git` @@ -28,16 +28,24 @@ Now just clone the MITMsmtp repository: `git clone https://github.com/RobinMeis/MITMsmtp.git` -Change into MITMsmtp directory and start the installation: +Change into MITMsmtp directory. From there you can run the program as a module with: -`sudo python3 setup.py install` +`python -m MITMsmtp` -That's it! +or install it with setuptools by running: + +`pip install .` + +After installation, you will be able to use the `MITMsmtp` command directly from your terminal. ### Updating -`git pull` -`sudo python3 setup.py install` +From within the MITMsmtp directory run: + +``` +git pull` +pip install . +``` ## Usage *MITMsmtp can be used as standalone command line application and offers an easy to use Python3 API to integrate in your own project* diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..648a2cc --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,25 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "MITMsmtp" +version = "0.0.3-dev" +authors = [ + {name = "Robin Meis", email = "blog@smartnoob.de"}, +] +description = "An evil SMTP Server for client pentesting" +readme = "README.md" +license = "GPL-3.0-only" +license-files = ["LICENSE"] +requires-python = ">= 3.6" +classifiers = [ + "Programming Language :: Python :: 3", + "Topic :: Security" +] + +[project.urls] +GitHub = "https://github.com/RobinMeis/MITMsmtp" + +[project.scripts] +MITMsmtp = "MITMsmtp.__main__:main" diff --git a/setup.py b/setup.py deleted file mode 100644 index 7530d98..0000000 --- a/setup.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python3 - -import setuptools -import os - -with open("README.md", "r") as fh: - long_description = fh.read() - -setuptools.setup( - name="MITMsmtp", - version="0.0.3-dev", - author="Robin Meis", - author_email="blog@smartnoob.de", - description="An evil SMTP Server for client pentesting", - long_description=long_description, - long_description_content_type="text/markdown", - url="https://github.com/RobinMeis/MITMsmtp", - packages=setuptools.find_packages(), - classifiers=[ - "Programming Language :: Python :: 3", - ], - entry_points={ - 'console_scripts': [ - 'MITMsmtp = MITMsmtp.__main__:main' - ] - }, - include_package_data=True, -) From 5f6e0b9dda1cc338602c173bc045138389bb9aa2 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Mon, 7 Apr 2025 03:30:14 -0600 Subject: [PATCH 5/6] Fix several minor issues - Remove redefinition of SMTPServer class - Define username/password members in authMethod class since it is used there - Remove bad call to authSuccess method from authPlain.auth --- MITMsmtp/SMTPServer.py | 3 +-- MITMsmtp/auth/authLogin.py | 4 ++-- MITMsmtp/auth/authMethod.py | 3 +++ MITMsmtp/auth/authPlain.py | 5 ++--- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/MITMsmtp/SMTPServer.py b/MITMsmtp/SMTPServer.py index 0b9c9a0..cc355c2 100644 --- a/MITMsmtp/SMTPServer.py +++ b/MITMsmtp/SMTPServer.py @@ -6,7 +6,7 @@ """ SMTPServer wrapper class for TCPServer """ -class SMTPServer(TCPServer): +class SMTPServer(ThreadingMixIn, TCPServer): """ Creates a new SMTPServer object @param server_address: The address to listen on @type server_address: str @@ -86,4 +86,3 @@ def wrapSSL(self, socket): return connstream -class SMTPServer(ThreadingMixIn, SMTPServer): pass diff --git a/MITMsmtp/auth/authLogin.py b/MITMsmtp/auth/authLogin.py index 19d2601..d5c2741 100644 --- a/MITMsmtp/auth/authLogin.py +++ b/MITMsmtp/auth/authLogin.py @@ -17,10 +17,10 @@ class authLogin (authMethod): @returns: The authMethods name """ def __init__(self, SMTPHandler, authLine): + super().__init__(SMTPHandler, authLine) + self.SMTPHandler = SMTPHandler self.authLine = authLine - self.username = None - self.password = None self.requestUsername() self.readUsername() diff --git a/MITMsmtp/auth/authMethod.py b/MITMsmtp/auth/authMethod.py index 18e639b..e367fd4 100644 --- a/MITMsmtp/auth/authMethod.py +++ b/MITMsmtp/auth/authMethod.py @@ -18,6 +18,9 @@ class authMethod(ABC): def __init__(self, SMTPHandler, authLine): super().__init__() + self.username = None + self.password = None + """ Returns the authMethods name Has to be overwritten, otherwise authentication method can't be advertised to client! diff --git a/MITMsmtp/auth/authPlain.py b/MITMsmtp/auth/authPlain.py index 51ec77d..63ae668 100644 --- a/MITMsmtp/auth/authPlain.py +++ b/MITMsmtp/auth/authPlain.py @@ -17,10 +17,10 @@ class authPlain(authMethod): @returns: The authMethods name """ def __init__(self, SMTPHandler, authLine): + super().__init__(SMTPHandler, authLine) + self.SMTPHandler = SMTPHandler self.authLine = authLine - self.username = None - self.password = None match = re.match("AUTH PLAIN$", authLine) if (match != None): @@ -85,7 +85,6 @@ def auth(self): self.authSuccess() self.username = auth[-2] self.password = auth[-1] - authSuccess() """ Sends success reply From 55364bed63d8b75731fb23319b52df12c4ab03ca Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Mon, 7 Apr 2025 04:04:32 -0600 Subject: [PATCH 6/6] Ignore empty lines between commands --- MITMsmtp/SMTPHandler.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/MITMsmtp/SMTPHandler.py b/MITMsmtp/SMTPHandler.py index bccd9c1..3a5cea7 100644 --- a/MITMsmtp/SMTPHandler.py +++ b/MITMsmtp/SMTPHandler.py @@ -25,9 +25,12 @@ def init(self): """ Reads a line from TCP Stream @return: Read line """ - def readLine(self): - line = self.rfile.readline().strip() - if (self.server.printLines): + def readLine(self, skipBlank=True): + while True: + line = self.rfile.readline().strip() + if line or not skipBlank: + break + if self.server.printLines: print("C:" + line) return line @@ -180,7 +183,7 @@ def sendIntermediate(self): def readMSG(self): message = "" while True: - line = self.readLine() + line = self.readLine(skipBlank=False) if (line == '.'): self.message.setMessage(message) return