`##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
##
# dsniff was helping me very often. Too bad that it doesn't work correctly
# anymore. Psnuffle should bring password sniffing into Metasploit local
# and if we get lucky even remote.
#
# Cheers - Max Moser - [email protected]
##
class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Capture
def initialize
super(
'Name' => 'pSnuffle Packet Sniffer',
'Description' => 'This module sniffs passwords like dsniff did in the past',
'Author' => 'Max Moser <mmo[at]remote-exploit.org>',
'License' => MSF_LICENSE,
'Actions' =>
[
[ 'Sniffer', 'Description' => 'Run sniffer' ],
[ 'List', 'Description' => 'List protocols' ]
],
'PassiveActions' => [ 'Sniffer' ],
'DefaultAction' => 'Sniffer'
)
register_options [
OptString.new('PROTOCOLS', [true, 'A comma-delimited list of protocols to sniff or "all".', 'all']),
]
register_advanced_options [
OptPath.new('ProtocolBase', [true, 'The base directory containing the protocol decoders',
File.join(Msf::Config.data_directory, 'exploits', 'psnuffle')
]),
]
deregister_options('RHOSTS')
end
def load_protocols
base = datastore['ProtocolBase']
unless File.directory? base
raise RuntimeError, 'The ProtocolBase parameter is set to an invalid directory'
end
allowed = datastore['PROTOCOLS'].split(',').map{|x| x.strip.downcase}
@protos = {}
decoders = Dir.new(base).entries.grep(/\.rb$/).sort
decoders.each do |n|
f = File.join(base, n)
m = ::Module.new
begin
m.module_eval(File.read(f, File.size(f)))
m.constants.grep(/^Sniffer(.*)/) do
proto = $1
next unless allowed.include?(proto.downcase) || datastore['PROTOCOLS'] == 'all'
klass = m.const_get("Sniffer#{proto}")
@protos[proto.downcase] = klass.new(framework, self)
print_status("Loaded protocol #{proto} from #{f}...")
end
rescue => e
print_error("Decoder #{n} failed to load: #{e.class} #{e} #{e.backtrace}")
end
end
end
def run
check_pcaprub_loaded # Check first
# Load all of our existing protocols
load_protocols
if action.name == 'List'
print_status("Protocols: #{@protos.keys.sort.join(', ')}")
return
end
print_status 'Sniffing traffic.....'
open_pcap
each_packet do |pkt|
p = PacketFu::Packet.parse(pkt)
next unless p.is_tcp?
next if p.payload.empty?
@protos.each_key do |k|
@protos[k].parse(p)
end
true
end
close_pcap
print_status 'Finished sniffing'
end
end
# End module class
# Basic class for taking care of sessions
class BaseProtocolParser
attr_accessor :framework, :module, :sessions, :dport, :sigs
def initialize(framework, mod)
self.framework = framework
self.module = mod
self.sessions = {}
self.dport = 0
register_sigs
end
def parse(pkt)
nil
end
def register_sigs
self.sigs = {}
end
#
# Glue methods to bridge parsers to the main module class
#
def print_status(msg)
self.module.print_status(msg)
end
def print_error(msg)
self.module.print_error(msg)
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: self.module.myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: self.module.fullname,
username: opts[:user],
private_data: opts[:password],
private_type: opts[:type]
}.merge(service_data)
if opts[:type] == :nonreplayable_hash
credential_data.merge!(jtr_format: opts[:jtr_format])
end
login_data = {
core: self.module.create_credential(credential_data),
status: opts[:status],
proof: opts[:proof]
}.merge(service_data)
unless opts[:status] == Metasploit::Model::Login::Status::UNTRIED
login_data.merge!(last_attempted_at: DateTime.now)
end
self.module.create_credential_login(login_data)
end
def report_note(*s)
self.module.report_note(*s)
end
def report_service(*s)
self.module.report_service(*s)
end
def find_session(sessionid)
purge_keys = []
sessions.each_key do |ses|
# Check for cleanup abilities... kills performance in large environments maybe
# When longer than 5 minutes no packet was related to the session, delete it
if ((sessions[ses][:mtime] - sessions[ses][:ctime]) > 300)
# too bad to this session has no action for a long time
purge_keys << ses
end
end
purge_keys.each {|ses| sessions.delete(ses) }
# Does this session already exist?
if (sessions[sessionid])
# Refresh the timestamp
sessions[sessionid][:mtime] = Time.now
else
# Create a new session entry along with the host/port from the id
if (sessionid =~ /^([^:]+):([^-]+)-([^:]+):(\d+)$/s)
sessions[sessionid] = {
:client_host => $1,
:client_port => $2,
:host => $3,
:port => $4,
:session => sessionid,
:ctime => Time.now,
:mtime => Time.now
}
end
end
sessions[sessionid]
end
def get_session_src(pkt)
return "%s:%d-%s:%d" % [pkt.ip_daddr,pkt.tcp_dport,pkt.ip_saddr,pkt.tcp_sport] if pkt.is_tcp?
return "%s:%d-%s:%d" % [pkt.ip_daddr,pkt.udp_dport,pkt.ip_saddr,pkt.udp_sport] if pkt.is_udp?
return "%s:%d-%s:%d" % [pkt.ip_daddr,0,pkt.ip_saddr,0]
end
def get_session_dst(pkt)
return "%s:%d-%s:%d" % [pkt.ip_saddr,pkt.tcp_sport,pkt.ip_daddr,pkt.tcp_dport] if pkt.is_tcp?
return "%s:%d-%s:%d" % [pkt.ip_saddr,pkt.udp_sport,pkt.ip_daddr,pkt.udp_dport] if pkt.is_udp?
return "%s:%d-%s:%d" % [pkt.ip_saddr,0,pkt.ip_daddr,0]
end
end
`
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation