Add a telnet banner grabber

git-svn-id: file:///home/svn/framework3/trunk@8108 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
HD Moore 2010-01-13 21:46:48 +00:00
parent 831833667a
commit 9bb14e1c4e
3 changed files with 331 additions and 3 deletions

View File

@ -4,7 +4,7 @@
# Behavior
require 'msf/core/exploit/brute'
require 'msf/core/exploit/brutetargets'
require 'msf/core/exploit/brutetargets'
require 'msf/core/exploit/browser_autopwn'
# Payload
@ -15,9 +15,10 @@ require 'msf/core/exploit/kernel_mode'
# Protocol
require 'msf/core/exploit/tcp'
require 'msf/core/exploit/udp'
require 'msf/core/exploit/ip'
require 'msf/core/exploit/ip'
require 'msf/core/exploit/smb'
require 'msf/core/exploit/ftp'
require 'msf/core/exploit/telnet'
require 'msf/core/exploit/ftpserver'
require 'msf/core/exploit/http'
require 'msf/core/exploit/smtp'
@ -26,7 +27,7 @@ require 'msf/core/exploit/sunrpc'
require 'msf/core/exploit/mssql'
require 'msf/core/exploit/mssql_commands'
require 'msf/core/exploit/mysql'
require 'msf/core/exploit/snmp'
require 'msf/core/exploit/snmp'
require 'msf/core/exploit/arkeia'
require 'msf/core/exploit/ndmp'
require 'msf/core/exploit/imap'
@ -52,3 +53,4 @@ require 'msf/core/exploit/oracle'
# tekniqz
require 'msf/core/exploit/fmtstr'

View File

@ -0,0 +1,288 @@
module Msf
require 'msf/core/exploit/tcp'
###
#
# This module exposes methods that may be useful to exploits that deal with
# servers that speak the telnet protocol.
#
###
module Exploit::Remote::Telnet
include Exploit::Remote::Tcp
# Borrowing constants from Ruby's Net::Telnet class (ruby license)
IAC = 255.chr # "\377" # "\xff" # interpret as command
DONT = 254.chr # "\376" # "\xfe" # you are not to use option
DO = 253.chr # "\375" # "\xfd" # please, you use option
WONT = 252.chr # "\374" # "\xfc" # I won't use option
WILL = 251.chr # "\373" # "\xfb" # I will use option
SB = 250.chr # "\372" # "\xfa" # interpret as subnegotiation
GA = 249.chr # "\371" # "\xf9" # you may reverse the line
EL = 248.chr # "\370" # "\xf8" # erase the current line
EC = 247.chr # "\367" # "\xf7" # erase the current character
AYT = 246.chr # "\366" # "\xf6" # are you there
AO = 245.chr # "\365" # "\xf5" # abort output--but let prog finish
IP = 244.chr # "\364" # "\xf4" # interrupt process--permanently
BREAK = 243.chr # "\363" # "\xf3" # break
DM = 242.chr # "\362" # "\xf2" # data mark--for connect. cleaning
NOP = 241.chr # "\361" # "\xf1" # nop
SE = 240.chr # "\360" # "\xf0" # end sub negotiation
EOR = 239.chr # "\357" # "\xef" # end of record (transparent mode)
ABORT = 238.chr # "\356" # "\xee" # Abort process
SUSP = 237.chr # "\355" # "\xed" # Suspend process
EOF = 236.chr # "\354" # "\xec" # End of file
SYNCH = 242.chr # "\362" # "\xf2" # for telfunc calls
OPT_BINARY = 0.chr # "\000" # "\x00" # Binary Transmission
OPT_ECHO = 1.chr # "\001" # "\x01" # Echo
OPT_RCP = 2.chr # "\002" # "\x02" # Reconnection
OPT_SGA = 3.chr # "\003" # "\x03" # Suppress Go Ahead
OPT_NAMS = 4.chr # "\004" # "\x04" # Approx Message Size Negotiation
OPT_STATUS = 5.chr # "\005" # "\x05" # Status
OPT_TM = 6.chr # "\006" # "\x06" # Timing Mark
OPT_RCTE = 7.chr # "\a" # "\x07" # Remote Controlled Trans and Echo
OPT_NAOL = 8.chr # "\010" # "\x08" # Output Line Width
OPT_NAOP = 9.chr # "\t" # "\x09" # Output Page Size
OPT_NAOCRD = 10.chr # "\n" # "\x0a" # Output Carriage-Return Disposition
OPT_NAOHTS = 11.chr # "\v" # "\x0b" # Output Horizontal Tab Stops
OPT_NAOHTD = 12.chr # "\f" # "\x0c" # Output Horizontal Tab Disposition
OPT_NAOFFD = 13.chr # "\r" # "\x0d" # Output Formfeed Disposition
OPT_NAOVTS = 14.chr # "\016" # "\x0e" # Output Vertical Tabstops
OPT_NAOVTD = 15.chr # "\017" # "\x0f" # Output Vertical Tab Disposition
OPT_NAOLFD = 16.chr # "\020" # "\x10" # Output Linefeed Disposition
OPT_XASCII = 17.chr # "\021" # "\x11" # Extended ASCII
OPT_LOGOUT = 18.chr # "\022" # "\x12" # Logout
OPT_BM = 19.chr # "\023" # "\x13" # Byte Macro
OPT_DET = 20.chr # "\024" # "\x14" # Data Entry Terminal
OPT_SUPDUP = 21.chr # "\025" # "\x15" # SUPDUP
OPT_SUPDUPOUTPUT = 22.chr # "\026" # "\x16" # SUPDUP Output
OPT_SNDLOC = 23.chr # "\027" # "\x17" # Send Location
OPT_TTYPE = 24.chr # "\030" # "\x18" # Terminal Type
OPT_EOR = 25.chr # "\031" # "\x19" # End of Record
OPT_TUID = 26.chr # "\032" # "\x1a" # TACACS User Identification
OPT_OUTMRK = 27.chr # "\e" # "\x1b" # Output Marking
OPT_TTYLOC = 28.chr # "\034" # "\x1c" # Terminal Location Number
OPT_3270REGIME = 29.chr # "\035" # "\x1d" # Telnet 3270 Regime
OPT_X3PAD = 30.chr # "\036" # "\x1e" # X.3 PAD
OPT_NAWS = 31.chr # "\037" # "\x1f" # Negotiate About Window Size
OPT_TSPEED = 32.chr # " " # "\x20" # Terminal Speed
OPT_LFLOW = 33.chr # "!" # "\x21" # Remote Flow Control
OPT_LINEMODE = 34.chr # "\"" # "\x22" # Linemode
OPT_XDISPLOC = 35.chr # "#" # "\x23" # X Display Location
OPT_OLD_ENVIRON = 36.chr # "$" # "\x24" # Environment Option
OPT_AUTHENTICATION = 37.chr # "%" # "\x25" # Authentication Option
OPT_ENCRYPT = 38.chr # "&" # "\x26" # Encryption Option
OPT_NEW_ENVIRON = 39.chr # "'" # "\x27" # New Environment Option
OPT_EXOPL = 255.chr # "\377" # "\xff" # Extended-Options-List
NULL = "\000"
CR = "\015"
LF = "\012"
EOL = CR + LF
#
# Creates an instance of a Telnet exploit module.
#
def initialize(info = {})
super
# Register the options that all Telnet exploits may make use of.
register_options(
[
Opt::RHOST,
Opt::RPORT(23)
], Msf::Exploit::Remote::Telnet)
register_advanced_options(
[
OptInt.new('TelnetTimeout', [ true, 'The number of seconds to wait for a reply from a Telnet command', 10]),
OptInt.new('TelnetBannerTimeout', [ true, 'The number of seconds to wait for the initial banner', 25])
], Msf::Exploit::Remote::Telnet)
register_autofilter_ports([ 23 ])
register_autofilter_services(%W{ telnet })
end
#
# This method establishes an Telnet connection to host and port specified by
# the RHOST and RPORT options, respectively. After connecting, the banner
# message is read in and stored in the 'banner' attribute. This method has the
# benefit of handling telnet option negotiation.
#
def connect(global = true, verbose = true)
fd = super(global)
self.banner = ''
# Wait for a banner to arrive...
begin
Timeout.timeout(datastore['TelnetBannerTimeout']) do
while(true)
buff = recv_telnet(fd)
self.banner << buff if buff
if(self.banner =~ /login|user|welcome|pass|\$|\#/i)
break
end
end
end
rescue ::Timeout::Error
end
self.banner.strip!
# Return the file descriptor to the caller
fd
end
#
# Handle telnet option negotiation
#
def recv_telnet(fd, timeout=datastore['TelnetTimeout'])
data = fd.get_once(-1, timeout.to_i)
return nil if not data
# combine CR+NULL into CR
data.gsub!(/#{CR}#{NULL}/no, CR)
# combine EOL into "\n"
data.gsub!(/#{EOL}/no, "\n")
data.gsub(/#{IAC}(
[#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]|
[#{DO}#{DONT}#{WILL}#{WONT}]
[#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}]|
#{SB}[^#{IAC}]*#{IAC}#{SE}
)/xno) do
m = $1
if m == IAC
IAC
elsif m == AYT
fd.write("YES" + EOL)
elsif m[0,1] == DO
if(m[1,1] == OPT_BINARY)
fd.write(IAC + WILL + OPT_BINARY)
else
fd.write(IAC + WONT + m[1,1])
end
''
elsif m[0,1] == DONT
fd.write(IAC + WONT + m[1,1])
''
elsif m[0,1] == WILL
if m[1,1] == OPT_BINARY
fd.write(IAC + DO + OPT_BINARY)
elsif m[1,1] == OPT_ECHO
fd.write(IAC + DO + OPT_ECHO)
elsif m[1,1] == OPT_SGA
fd.write(IAC + DO + OPT_SGA)
else
fd.write(IAC + DONT + m[1,1])
end
''
elsif m[0,1] == WONT
fd.write(IAC + DONT + m[1,1])
''
else
''
end
end
end
#
# Connect and login to the remote telnet server using the credentials
# that have been supplied in the exploit options.
#
def connect_login(global = true, verbose = true)
telsock = connect(global, verbose)
if !(user and pass)
print_status("No username and password were supplied, unable to login")
return false
end
print_status("Authenticating as #{user} with password #{pass}...") if verbose
res = send_user(user, telsock)
if (res !~ /^(331|2)/)
print_status("The server rejected our username") if verbose
return false
end
if (pass)
print_status("Sending password...") if verbose
res = send_pass(pass, telsock)
if (res !~ /^2/)
print_status("The server rejected our password") if verbose
return false
end
end
return true
end
#
# This method logs in as the supplied user by transmitting the username
#
def send_user(user, nsock = self.sock)
raw_send("#{user}\r\n", nsock)
recv_tel_resp(nsock)
end
#
# This method completes user authentication by sending the supplied password
#
def send_pass(pass, nsock = self.sock)
raw_send("#{pass}\r\n", nsock)
recv_tel_resp(nsock)
end
#
# This method sends one command with zero or more parameters
#
def send_cmd(args, recv = true, nsock = self.sock)
cmd = args.join(" ") + "\r\n"
ret = raw_send(cmd, nsock)
if (recv)
return recv_tel_resp(nsock)
end
return ret
end
#
#
# This method transmits a telnet command and does not wait for a response
#
def raw_send(cmd, nsock = self.sock)
nsock.put(cmd)
end
##
#
# Wrappers for getters
#
##
#
# Returns the number of seconds to wait for a telnet reply
#
def tel_timeout
(datastore['TelnetTimeout'] || 10).to_i
end
protected
#
# This attribute holds the banner that was read in after a successful call
# to connect or connect_login.
#
attr_accessor :banner
end
end

View File

@ -0,0 +1,38 @@
##
# 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/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::Telnet
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
def initialize
super(
'Name' => 'Telnet Service Banner Detection',
'Version' => '$Revision$',
'Description' => 'Detect telnet services',
'Author' => 'hdm',
'License' => MSF_LICENSE
)
end
def run_host(ip)
begin
res = connect
print_status("#{ip}:#{rport} TELNET #{banner.gsub(/[\r\n\x1b]/, ' ')}")
rescue ::Rex::ConnectionError
rescue ::Exception => e
print_error("#{e} #{e.backtrace}")
end
end
end