2013-11-12 11:47:33 +00:00
|
|
|
##
|
|
|
|
# This module requires Metasploit: http//metasploit.com/download
|
|
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
|
|
##
|
|
|
|
|
|
|
|
require 'msf/core'
|
|
|
|
require 'rex'
|
|
|
|
|
|
|
|
class Metasploit3 < Msf::Post
|
|
|
|
|
|
|
|
include Msf::Post::File
|
|
|
|
|
|
|
|
|
|
|
|
def initialize(info={})
|
|
|
|
super( update_info( info,
|
2013-11-13 07:57:50 +00:00
|
|
|
'Name' => 'OSX VPN manager',
|
2013-11-12 11:47:33 +00:00
|
|
|
'Description' => %q{
|
|
|
|
This module lists VPN connections and tries to connect to them using stored credentials.
|
|
|
|
},
|
|
|
|
'License' => MSF_LICENSE,
|
|
|
|
'Author' =>
|
|
|
|
[
|
|
|
|
'Peter Toth <globetother[at]gmail.com>'
|
|
|
|
],
|
|
|
|
'Platform' => [ 'osx' ],
|
2013-11-13 00:54:42 +00:00
|
|
|
'SessionTypes' => [ 'shell', 'meterpreter' ],
|
|
|
|
'Actions' => [
|
2013-11-12 11:47:33 +00:00
|
|
|
[ 'LIST', { 'Description' => 'Show a list of VPN connections' } ],
|
|
|
|
[ 'CONNECT', { 'Description' => 'Connect to a VPN using stored credentials' } ],
|
|
|
|
[ 'DISCONNECT', { 'Description' => 'Disconnect from a VPN' } ]
|
|
|
|
],
|
|
|
|
'DefaultAction' => 'LIST'
|
|
|
|
))
|
|
|
|
|
|
|
|
register_options(
|
|
|
|
[
|
2013-11-13 00:54:42 +00:00
|
|
|
OptString.new('VPN_CONNECTION', [true, 'Name of VPN connection. `set ACTION LIST` to get a list.', 'OSX_VPN']),
|
|
|
|
OptString.new('SCUTIL_PATH', [true, 'Path to the scutil executable.', '/usr/sbin/scutil']),
|
|
|
|
OptString.new('NETWORKSETUP_PATH', [true, 'Path to the networksetup executable.', '/usr/sbin/networksetup'])
|
2013-11-12 11:47:33 +00:00
|
|
|
], self.class)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2013-11-13 00:54:42 +00:00
|
|
|
STR_CONNECTED = '* (Connected)'
|
|
|
|
STR_DISCONNECTED = '* (Disconnected)'
|
|
|
|
|
2013-11-12 11:47:33 +00:00
|
|
|
def run
|
|
|
|
fail_with("Invalid action") if action.nil?
|
|
|
|
|
2013-11-14 12:44:49 +00:00
|
|
|
scutil_path = datastore['SCUTIL_PATH'].shellescape
|
|
|
|
networksetup_path = datastore['NETWORKSETUP_PATH'].shellescape
|
|
|
|
vpn_name = datastore['VPN_CONNECTION']
|
|
|
|
|
|
|
|
if not file?(scutil_path)
|
|
|
|
print_error("Aborting, scutil binary not found.")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if not file?(networksetup_path)
|
|
|
|
print_error("Aborting, networksetup binary not found.")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
# Fetch the list of configured VPN connections
|
|
|
|
cmd_list = "#{scutil_path} --nc list"
|
|
|
|
vprint_status(cmd_list)
|
|
|
|
vpn_data = cmd_exec(cmd_list)
|
|
|
|
connected_names = parse_vpn_connection_names(vpn_data, :connected)
|
|
|
|
disconnected_names = parse_vpn_connection_names(vpn_data, :disconnected)
|
|
|
|
|
2013-11-13 00:54:42 +00:00
|
|
|
if action.name == 'LIST'
|
|
|
|
if connected_names.length > 0
|
|
|
|
print_status("VPN Connections Status: UP")
|
|
|
|
connected_names.each do |vpn_name|
|
|
|
|
print_good(' ' + vpn_name)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if disconnected_names.length > 0
|
|
|
|
print_status("VPN Connections Status: DOWN")
|
|
|
|
disconnected_names.each do |vpn_name|
|
|
|
|
print_good(' ' + vpn_name)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
elsif action.name == 'CONNECT'
|
2013-11-14 12:44:49 +00:00
|
|
|
if connected_names.include?(vpn_name)
|
|
|
|
print_status("#{vpn_name} already connected")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
unless disconnected_names.include?(vpn_name)
|
|
|
|
print_error("#{vpn_name} not found")
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
cmd_up = "#{networksetup_path} -connectpppoeservice '#{vpn_name}'"
|
|
|
|
vprint_status(cmd_up)
|
|
|
|
cmd_exec(cmd_up)
|
2013-11-13 00:54:42 +00:00
|
|
|
elsif action.name == 'DISCONNECT'
|
2013-11-14 12:44:49 +00:00
|
|
|
if disconnected_names.include?(vpn_name)
|
|
|
|
print_status("#{vpn_name} already disconnected")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
unless connected_names.include?(vpn_name)
|
|
|
|
print_error("#{vpn_name} not found")
|
|
|
|
return false
|
|
|
|
end
|
2013-11-12 11:47:33 +00:00
|
|
|
|
2013-11-14 12:44:49 +00:00
|
|
|
identifier = parse_vpn_connection_identifier(vpn_data, vpn_name)
|
|
|
|
unless identifier
|
|
|
|
print_error("Could not parse #{vpn_name} identifier")
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
cmd_down = "#{scutil_path} --nc stop #{identifier}"
|
|
|
|
vprint_status(cmd_down)
|
|
|
|
cmd_exec(cmd_down)
|
|
|
|
end
|
2013-11-12 11:47:33 +00:00
|
|
|
end
|
|
|
|
|
2013-11-13 13:13:40 +00:00
|
|
|
def parse_vpn_connection_names(data, type= :connected)
|
|
|
|
lines = data.lines
|
|
|
|
connection_names = []
|
|
|
|
comp_str = type == :connected ? STR_CONNECTED : STR_DISCONNECTED
|
2013-11-12 11:47:33 +00:00
|
|
|
|
2013-11-13 00:54:42 +00:00
|
|
|
lines.each do |line|
|
2013-11-13 13:13:40 +00:00
|
|
|
line.strip!
|
|
|
|
parts = line.split('"')
|
|
|
|
connection_names << parts[1] if line.start_with?(comp_str) && parts.length > 1
|
2013-11-12 11:47:33 +00:00
|
|
|
end
|
2013-11-13 00:54:42 +00:00
|
|
|
return connection_names
|
2013-11-12 11:47:33 +00:00
|
|
|
end
|
|
|
|
|
2013-11-14 12:44:49 +00:00
|
|
|
def parse_vpn_connection_identifier(data, vpn_name)
|
2013-11-13 13:13:40 +00:00
|
|
|
lines = data.lines
|
2013-11-13 00:54:42 +00:00
|
|
|
lines.each do |line|
|
2013-11-13 13:13:40 +00:00
|
|
|
line.strip!
|
|
|
|
next if line.empty?
|
|
|
|
parts = line.split('"')
|
|
|
|
if (parts.length >= 2 && parts[1] == vpn_name)
|
|
|
|
potential_ids = line.split(' ')
|
|
|
|
if potential_ids.length >= 3
|
|
|
|
identifier = potential_ids[2]
|
2013-11-14 12:44:49 +00:00
|
|
|
return identifier
|
2013-11-12 11:47:33 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2013-11-14 12:44:49 +00:00
|
|
|
return nil
|
2013-11-12 11:47:33 +00:00
|
|
|
end
|
|
|
|
end
|