CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/metasploit/framework/telnet/client.rb
Views: 11784
1
require 'metasploit/framework/tcp/client'
2
3
module Metasploit
4
module Framework
5
module Telnet
6
module Client
7
extend ActiveSupport::Concern
8
include Metasploit::Framework::Tcp::Client
9
include Msf::Auxiliary::Login
10
11
attr_accessor :banner
12
13
#
14
# CONSTANTS
15
#
16
# Borrowing constants from Ruby's Net::Telnet class (ruby license)
17
IAC = 255.chr # "\377" # "\xff" # interpret as command
18
DONT = 254.chr # "\376" # "\xfe" # you are not to use option
19
DO = 253.chr # "\375" # "\xfd" # please, you use option
20
WONT = 252.chr # "\374" # "\xfc" # I won't use option
21
WILL = 251.chr # "\373" # "\xfb" # I will use option
22
SB = 250.chr # "\372" # "\xfa" # interpret as subnegotiation
23
GA = 249.chr # "\371" # "\xf9" # you may reverse the line
24
EL = 248.chr # "\370" # "\xf8" # erase the current line
25
EC = 247.chr # "\367" # "\xf7" # erase the current character
26
AYT = 246.chr # "\366" # "\xf6" # are you there
27
AO = 245.chr # "\365" # "\xf5" # abort output--but let prog finish
28
IP = 244.chr # "\364" # "\xf4" # interrupt process--permanently
29
BREAK = 243.chr # "\363" # "\xf3" # break
30
DM = 242.chr # "\362" # "\xf2" # data mark--for connect. cleaning
31
NOP = 241.chr # "\361" # "\xf1" # nop
32
SE = 240.chr # "\360" # "\xf0" # end sub negotiation
33
EOR = 239.chr # "\357" # "\xef" # end of record (transparent mode)
34
ABORT = 238.chr # "\356" # "\xee" # Abort process
35
SUSP = 237.chr # "\355" # "\xed" # Suspend process
36
EOF = 236.chr # "\354" # "\xec" # End of file
37
SYNCH = 242.chr # "\362" # "\xf2" # for telfunc calls
38
39
OPT_BINARY = 0.chr # "\000" # "\x00" # Binary Transmission
40
OPT_ECHO = 1.chr # "\001" # "\x01" # Echo
41
OPT_RCP = 2.chr # "\002" # "\x02" # Reconnection
42
OPT_SGA = 3.chr # "\003" # "\x03" # Suppress Go Ahead
43
OPT_NAMS = 4.chr # "\004" # "\x04" # Approx Message Size Negotiation
44
OPT_STATUS = 5.chr # "\005" # "\x05" # Status
45
OPT_TM = 6.chr # "\006" # "\x06" # Timing Mark
46
OPT_RCTE = 7.chr # "\a" # "\x07" # Remote Controlled Trans and Echo
47
OPT_NAOL = 8.chr # "\010" # "\x08" # Output Line Width
48
OPT_NAOP = 9.chr # "\t" # "\x09" # Output Page Size
49
OPT_NAOCRD = 10.chr # "\n" # "\x0a" # Output Carriage-Return Disposition
50
OPT_NAOHTS = 11.chr # "\v" # "\x0b" # Output Horizontal Tab Stops
51
OPT_NAOHTD = 12.chr # "\f" # "\x0c" # Output Horizontal Tab Disposition
52
OPT_NAOFFD = 13.chr # "\r" # "\x0d" # Output Formfeed Disposition
53
OPT_NAOVTS = 14.chr # "\016" # "\x0e" # Output Vertical Tabstops
54
OPT_NAOVTD = 15.chr # "\017" # "\x0f" # Output Vertical Tab Disposition
55
OPT_NAOLFD = 16.chr # "\020" # "\x10" # Output Linefeed Disposition
56
OPT_XASCII = 17.chr # "\021" # "\x11" # Extended ASCII
57
OPT_LOGOUT = 18.chr # "\022" # "\x12" # Logout
58
OPT_BM = 19.chr # "\023" # "\x13" # Byte Macro
59
OPT_DET = 20.chr # "\024" # "\x14" # Data Entry Terminal
60
OPT_SUPDUP = 21.chr # "\025" # "\x15" # SUPDUP
61
OPT_SUPDUPOUTPUT = 22.chr # "\026" # "\x16" # SUPDUP Output
62
OPT_SNDLOC = 23.chr # "\027" # "\x17" # Send Location
63
OPT_TTYPE = 24.chr # "\030" # "\x18" # Terminal Type
64
OPT_EOR = 25.chr # "\031" # "\x19" # End of Record
65
OPT_TUID = 26.chr # "\032" # "\x1a" # TACACS User Identification
66
OPT_OUTMRK = 27.chr # "\e" # "\x1b" # Output Marking
67
OPT_TTYLOC = 28.chr # "\034" # "\x1c" # Terminal Location Number
68
OPT_3270REGIME = 29.chr # "\035" # "\x1d" # Telnet 3270 Regime
69
OPT_X3PAD = 30.chr # "\036" # "\x1e" # X.3 PAD
70
OPT_NAWS = 31.chr # "\037" # "\x1f" # Negotiate About Window Size
71
OPT_TSPEED = 32.chr # " " # "\x20" # Terminal Speed
72
OPT_LFLOW = 33.chr # "!" # "\x21" # Remote Flow Control
73
OPT_LINEMODE = 34.chr # "\"" # "\x22" # Linemode
74
OPT_XDISPLOC = 35.chr # "#" # "\x23" # X Display Location
75
OPT_OLD_ENVIRON = 36.chr # "$" # "\x24" # Environment Option
76
OPT_AUTHENTICATION = 37.chr # "%" # "\x25" # Authentication Option
77
OPT_ENCRYPT = 38.chr # "&" # "\x26" # Encryption Option
78
OPT_NEW_ENVIRON = 39.chr # "'" # "\x27" # New Environment Option
79
OPT_EXOPL = 255.chr # "\377" # "\xff" # Extended-Options-List
80
81
#
82
# This method establishes an Telnet connection to host and port specified by
83
# the RHOST and RPORT options, respectively. After connecting, the banner
84
# message is read in and stored in the 'banner' attribute. This method has the
85
# benefit of handling telnet option negotiation.
86
#
87
def connect(global = true, verbose = true)
88
@trace = ''
89
@recvd = ''
90
fd = super(global)
91
92
self.banner = ''
93
# Wait for a banner to arrive...
94
begin
95
Timeout.timeout(banner_timeout) do
96
while(true)
97
buff = recv(fd)
98
self.banner << buff if buff
99
if(self.banner =~ @login_regex or self.banner =~ @password_regex)
100
break
101
elsif self.banner =~ @busy_regex
102
# It's about to drop connection anyway -- seen on HP JetDirect telnet server
103
break
104
end
105
end
106
end
107
rescue ::Timeout::Error
108
end
109
110
self.banner.strip!
111
112
# Return the file descriptor to the caller
113
fd
114
end
115
116
# Sometimes telnet servers start RSTing if you get them angry.
117
# This is a short term fix; the problem is that we don't know
118
# if it's going to reset forever, or just this time, or randomly.
119
# A better solution is to get the socket connect to try again
120
# with a little backoff.
121
def connect_reset_safe
122
begin
123
connect
124
rescue Rex::ConnectionRefused
125
return :refused
126
end
127
return :connected
128
end
129
130
def recv(fd=self.sock, timeout=telnet_timeout)
131
recv_telnet(fd, timeout.to_f)
132
end
133
134
#
135
# Handle telnet option negotiation
136
#
137
# Appends to the @recvd buffer which is used to tell us whether we're at a
138
# login prompt, a password prompt, or a working shell.
139
#
140
def recv_telnet(fd, timeout)
141
142
data = ''
143
144
begin
145
data = fd.get_once(-1, timeout)
146
return nil if not data or data.length == 0
147
148
# combine CR+NULL into CR
149
data.gsub!(/#{CR}#{NULL}/no, CR)
150
151
# combine EOL into "\n"
152
data.gsub!(/#{EOL}/no, "\n")
153
154
data.gsub!(/#{IAC}(
155
[#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]|[#{DO}#{DONT}#{WILL}#{WONT}]
156
[#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}]|#{SB}[^#{IAC}]*#{IAC}#{SE}
157
)/xno) do
158
m = $1
159
160
if m == IAC
161
IAC
162
elsif m == AYT
163
fd.write("YES" + EOL)
164
''
165
elsif m[0,1] == DO
166
if(m[1,1] == OPT_BINARY)
167
fd.write(IAC + WILL + OPT_BINARY)
168
else
169
fd.write(IAC + WONT + m[1,1])
170
end
171
''
172
elsif m[0,1] == DONT
173
fd.write(IAC + WONT + m[1,1])
174
''
175
elsif m[0,1] == WILL
176
if m[1,1] == OPT_BINARY
177
fd.write(IAC + DO + OPT_BINARY)
178
# Disable Echo
179
elsif m[1,1] == OPT_ECHO
180
fd.write(IAC + DONT + OPT_ECHO)
181
elsif m[1,1] == OPT_SGA
182
fd.write(IAC + DO + OPT_SGA)
183
else
184
fd.write(IAC + DONT + m[1,1])
185
end
186
''
187
elsif m[0,1] == WONT
188
fd.write(IAC + DONT + m[1,1])
189
''
190
else
191
''
192
end
193
end
194
195
@trace << data
196
@recvd << data
197
fd.flush
198
199
rescue ::EOFError, ::Errno::EPIPE
200
end
201
202
data
203
end
204
205
#
206
# Wrappers for getters
207
#
208
209
def banner_timeout
210
raise NotImplementedError
211
end
212
213
def telnet_timeout
214
raise NotImplementedError
215
end
216
217
end
218
end
219
end
220
end
221
222