Module: Metasploit::Framework::Ftp::Client
- Extended by:
- ActiveSupport::Concern
- Includes:
- Tcp::Client
- Included in:
- LoginScanner::FTP
- Defined in:
- lib/metasploit/framework/ftp/client.rb
Instance Attribute Summary collapse
-
#banner ⇒ Object
protected
This attribute holds the banner that was read in after a successful call to connect or connect_login.
-
#datasocket ⇒ Object
protected
This attribute holds the banner that was read in after a successful call to connect or connect_login.
Attributes included from Tcp::Client
#max_send_size, #send_delay, #sock
Instance Method Summary collapse
-
#connect(global = true) ⇒ Object
This method establishes an FTP connection to host and port specified by the 'rhost' and 'rport' methods.
-
#connect_login(user, pass, global = true) ⇒ Object
Connect and login to the remote FTP server using the credentials that have been supplied in the exploit options.
-
#data_connect(mode = nil, nsock = self.sock) ⇒ Object
This method handles establishing datasocket for data channel.
-
#data_disconnect ⇒ Object
This method handles disconnecting our data channel.
- #ftp_timeout ⇒ Object
-
#raw_send(cmd, nsock = self.sock) ⇒ Object
This method transmits a FTP command and does not wait for a response.
-
#raw_send_recv(cmd, nsock = self.sock) ⇒ Object
This method transmits a FTP command and waits for a response.
-
#recv_ftp_resp(nsock = self.sock) ⇒ Object
This method reads an FTP response based on FTP continuation stuff.
-
#send_cmd(args, recv = true, nsock = self.sock) ⇒ Object
This method sends one command with zero or more parameters.
-
#send_cmd_data(args, data, mode = 'a', nsock = self.sock) ⇒ Object
This method transmits the command in args and receives / uploads DATA via data channel For commands not needing data, it will fall through to the original send_cmd.
-
#send_pass(pass, nsock = self.sock) ⇒ Object
This method completes user authentication by sending the supplied password using the FTP 'PASS
' command. -
#send_quit(nsock = self.sock) ⇒ Object
This method sends a QUIT command.
-
#send_user(user, nsock = self.sock) ⇒ Object
This method logs in as the supplied user by transmitting the FTP 'USER
' command.
Methods included from Tcp::Client
#chost, #cport, #disconnect, #proxies, #rhost, #rport, #set_tcp_evasions, #ssl, #ssl_version
Instance Attribute Details
#banner ⇒ Object (protected)
This attribute holds the banner that was read in after a successful call to connect or connect_login.
285 286 287 |
# File 'lib/metasploit/framework/ftp/client.rb', line 285 def @banner end |
#datasocket ⇒ Object (protected)
This attribute holds the banner that was read in after a successful call to connect or connect_login.
285 286 287 |
# File 'lib/metasploit/framework/ftp/client.rb', line 285 def datasocket @datasocket end |
Instance Method Details
#connect(global = true) ⇒ Object
This method establishes an FTP connection to host and port specified by the 'rhost' and 'rport' methods. After connecting, the banner message is read in and stored in the 'banner' attribute.
15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/metasploit/framework/ftp/client.rb', line 15 def connect(global = true) fd = super(global) @ftpbuff = '' unless @ftpbuff # Wait for a banner to arrive... self. = recv_ftp_resp(fd) # Return the file descriptor to the caller fd end |
#connect_login(user, pass, global = true) ⇒ Object
Connect and login to the remote FTP server using the credentials that have been supplied in the exploit options.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/metasploit/framework/ftp/client.rb', line 78 def connect_login(user,pass,global = true) ftpsock = connect(global) if !(user and pass) return false end res = send_user(user, ftpsock) if (res !~ /^(331|2)/) return false end if (pass) res = send_pass(pass, ftpsock) if (res !~ /^2/) return false end end return true end |
#data_connect(mode = nil, nsock = self.sock) ⇒ Object
This method handles establishing datasocket for data channel
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/metasploit/framework/ftp/client.rb', line 30 def data_connect(mode = nil, nsock = self.sock) if mode res = send_cmd([ 'TYPE' , mode ], true, nsock) return nil if not res =~ /^200/ end # force datasocket to renegotiate if datasocket old_datasocket = datasocket self.datasocket = nil old_datasocket.shutdown old_datasocket.close end res = send_cmd(['PASV'], true, nsock) return nil if not res =~ /^227/ # 227 Entering Passive Mode (127,0,0,1,196,5) match = res.match(/\((\d{1,3}),(\d{1,3}),(\d{1,3}),(\d{1,3}),(\d{1,3}),(\d{1,3})\)/) return nil unless match values = match.captures.map(&:to_i) return nil unless values.all? { |value| value.between?(0, 255) } dataport = (values[4] * 256) + values[5] return nil if dataport.zero? # Prefer the original control connection host over the host advertised in the PASV response. self.datasocket = Rex::Socket::Tcp.create( 'PeerHost' => nsock.peerhost, 'PeerPort' => dataport, 'Context' => { 'Msf' => framework, 'MsfExploit' => framework_module } ) self.datasocket end |
#data_disconnect ⇒ Object
This method handles disconnecting our data channel
69 70 71 72 |
# File 'lib/metasploit/framework/ftp/client.rb', line 69 def data_disconnect self.datasocket.shutdown self.datasocket = nil end |
#ftp_timeout ⇒ Object
273 274 275 |
# File 'lib/metasploit/framework/ftp/client.rb', line 273 def ftp_timeout raise NotImplementedError end |
#raw_send(cmd, nsock = self.sock) ⇒ Object
This method transmits a FTP command and does not wait for a response
269 270 271 |
# File 'lib/metasploit/framework/ftp/client.rb', line 269 def raw_send(cmd, nsock = self.sock) nsock.put(cmd) end |
#raw_send_recv(cmd, nsock = self.sock) ⇒ Object
This method transmits a FTP command and waits for a response. If one is received, it is returned to the caller.
207 208 209 210 |
# File 'lib/metasploit/framework/ftp/client.rb', line 207 def raw_send_recv(cmd, nsock = self.sock) nsock.put(cmd) nsock.get_once(-1, ftp_timeout) end |
#recv_ftp_resp(nsock = self.sock) ⇒ Object
This method reads an FTP response based on FTP continuation stuff
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/metasploit/framework/ftp/client.rb', line 215 def recv_ftp_resp(nsock = self.sock) found_end = false resp = "" left = "" if !@ftpbuff.empty? left << @ftpbuff @ftpbuff = "" end while true data = nsock.get_once(-1, ftp_timeout) if not data @ftpbuff << resp @ftpbuff << left return data end got = left + data left = "" # handle the end w/o newline case enlidx = got.rindex(0x0a.chr) if enlidx != (got.length-1) if not enlidx left << got next else left << got.slice!((enlidx+1)..got.length) end end # split into lines rarr = got.split(/\r?\n/) rarr.each do |ln| if not found_end resp << ln resp << "\r\n" if ln.length > 3 and ln[3,1] == ' ' found_end = true end else left << ln left << "\r\n" end end if found_end @ftpbuff << left return resp end end end |
#send_cmd(args, recv = true, nsock = self.sock) ⇒ Object
This method sends one command with zero or more parameters
130 131 132 133 134 135 136 137 |
# File 'lib/metasploit/framework/ftp/client.rb', line 130 def send_cmd(args, recv = true, nsock = self.sock) cmd = args.join(" ") + "\r\n" ret = raw_send(cmd, nsock) if (recv) return recv_ftp_resp(nsock) end return ret end |
#send_cmd_data(args, data, mode = 'a', nsock = self.sock) ⇒ Object
This method transmits the command in args and receives / uploads DATA via data channel For commands not needing data, it will fall through to the original send_cmd
For commands that send data only, the return will be the server response. For commands returning both data and a server response, an array will be returned.
NOTE: This function always waits for a response from the server.
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/metasploit/framework/ftp/client.rb', line 148 def send_cmd_data(args, data, mode = 'a', nsock = self.sock) type = nil # implement some aliases for various commands if (args[0] =~ /^DIR$/i || args[0] =~ /^LS$/i) # TODO || args[0] =~ /^MDIR$/i || args[0] =~ /^MLS$/i args[0] = "LIST" type = "get" elsif (args[0] =~ /^GET$/i) args[0] = "RETR" type = "get" elsif (args[0] =~ /^PUT$/i) args[0] = "STOR" type = "put" end # fall back if it's not a supported data command if not type return send_cmd(args, true, nsock) end # Set the transfer mode and connect to the remove server return nil if not data_connect(mode) # Our pending command should have got a connection now. res = send_cmd(args, true, nsock) # make sure could open port return nil unless res =~ /^(150|125) / # dispatch to the proper method if (type == "get") # failed listings just disconnect.. begin data = self.datasocket.get_once(-1, ftp_timeout) rescue ::EOFError data = nil end else sent = self.datasocket.put(data) end # close data channel so command channel updates data_disconnect # get status of transfer ret = nil if (type == "get") ret = recv_ftp_resp(nsock) ret = [ ret, data ] else ret = recv_ftp_resp(nsock) end ret end |
#send_pass(pass, nsock = self.sock) ⇒ Object
This method completes user authentication by sending the supplied
password using the FTP 'PASS
114 115 116 117 |
# File 'lib/metasploit/framework/ftp/client.rb', line 114 def send_pass(pass, nsock = self.sock) raw_send("PASS #{pass}\r\n", nsock) recv_ftp_resp(nsock) end |
#send_quit(nsock = self.sock) ⇒ Object
This method sends a QUIT command.
122 123 124 125 |
# File 'lib/metasploit/framework/ftp/client.rb', line 122 def send_quit(nsock = self.sock) raw_send("QUIT\r\n", nsock) recv_ftp_resp(nsock) end |
#send_user(user, nsock = self.sock) ⇒ Object
This method logs in as the supplied user by transmitting the FTP
'USER
105 106 107 108 |
# File 'lib/metasploit/framework/ftp/client.rb', line 105 def send_user(user, nsock = self.sock) raw_send("USER #{user}\r\n", nsock) recv_ftp_resp(nsock) end |