Class: Rex::Proto::Ftp::Client
- Inherits:
- 
      Object
      
        - Object
- Rex::Proto::Ftp::Client
 
- Defined in:
- lib/rex/proto/ftp/client.rb
Overview
Acts as a client to an FTP server See the RFC: www.w3.org/Protocols/rfc959/
Instance Method Summary collapse
- 
  
    
      #cd(path)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Function implementing ‘cd’ or change directory command. 
- 
  
    
      #connect  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    This method estabilishes a connection to the host on the port defined in opts{}, if the connection is successful, the method returns a socket which can be used to communicate with the client. 
- 
  
    
      #connect_login  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    This method uses the senduser and sendpass methods defined below in order to login to the ftp server. 
- 
  
    
      #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. 
- 
  
    
      #download(filename)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Function implementing download command. 
- 
  
    
      #initialize(host, port = 21, ssl = nil, ssl_version = nil, proxies = nil, username = '', password = '', verbose = false)  ⇒ Client 
    
    
  
  
  
    constructor
  
  
  
  
  
  
  
    Creates a new client instance. 
- 
  
    
      #ls  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Function implementing ‘ls’ or list files command. 
- 
  
    
      #pwd  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Function implementing ‘pwd’ or present working directory command. 
- 
  
    
      #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. 
- 
  
    
      #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 <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 <user>’ command. 
- 
  
    
      #upload  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Function implementing upload command. 
Constructor Details
#initialize(host, port = 21, ssl = nil, ssl_version = nil, proxies = nil, username = '', password = '', verbose = false) ⇒ Client
Creates a new client instance.
| 18 19 20 21 22 23 24 25 26 27 28 | # File 'lib/rex/proto/ftp/client.rb', line 18 def initialize(host, port = 21, ssl = nil, ssl_version = nil, proxies = nil, username = '', password = '', verbose = false) self.hostname = host self.port = port.to_i self.context = context self.ssl = ssl self.ssl_version = ssl_version self.proxies = proxies self.username = username self.password = password self.verbose = verbose end | 
Instance Method Details
#cd(path) ⇒ Object
Function implementing ‘cd’ or change directory command
| 314 315 316 | # File 'lib/rex/proto/ftp/client.rb', line 314 def cd(path) send_cmd(["cwd " + path]) end | 
#connect ⇒ Object
This method estabilishes a connection to the host on the port defined in opts{}, if the connection is successful, the method returns a socket which can be used to communicate with the client
| 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | # File 'lib/rex/proto/ftp/client.rb', line 35 def connect nsock = Rex::Socket::Tcp.create( 'PeerHost' => self.hostname, 'PeerPort' => self.port, 'LocalHost' => "0.0.0.0", 'LocalPort' => 0.to_i, 'SSL' => self.ssl, 'SSLVersion' => self.ssl_version, 'Proxies' => self.proxies ) self.sock = nsock self. = recv_ftp_resp(nsock) print_status("Connected to target FTP server.") if self.verbose nsock end | 
#connect_login ⇒ Object
This method uses the senduser and sendpass methods defined below in order to login to the ftp server
| 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | # File 'lib/rex/proto/ftp/client.rb', line 127 def connect_login ftpsock = connect if !(self.user && self.pass) print_error("No username and password were supplied, unable to login") return false end print_status("Authenticating as #{user} with password #{pass}...") if self.verbose res = send_user(user, ftpsock) if res !~ /^(331|2)/ print_error("The server rejected our username") if self.verbose return false end if pass print_status("Sending password...") if self.verbose res = send_pass(pass, ftpsock) if res !~ /^2/ print_error("The server rejected our password") if self.verbose return false end end true end | 
#data_connect(mode = nil, nsock = self.sock) ⇒ Object
This method handles establishing datasocket for data channel
| 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | # File 'lib/rex/proto/ftp/client.rb', line 176 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 self.datasocket.shutdown if self.datasocket != nil res = send_cmd(['PASV'], true, nsock) return nil if not res =~ /^227/ # 227 Entering Passive Mode (127,0,0,1,196,5) if res =~ /\((\d+)\,(\d+),(\d+),(\d+),(\d+),(\d+)/ # convert port to FTP syntax datahost = "#{$1}.#{$2}.#{$3}.#{$4}" dataport = ($5.to_i * 256) + $6.to_i self.datasocket = Rex::Socket::Tcp.create( 'PeerHost' => datahost, 'PeerPort' => dataport ) end self.datasocket end | 
#data_disconnect ⇒ Object
This method handles disconnecting our data channel
| 204 205 206 207 | # File 'lib/rex/proto/ftp/client.rb', line 204 def data_disconnect self.datasocket.shutdown if self.datasocket self.datasocket = nil end | 
#download(filename) ⇒ Object
Function implementing download command
| 321 322 323 324 325 326 327 328 329 | # File 'lib/rex/proto/ftp/client.rb', line 321 def download(filename) datasocket = data_connect send_cmd(["retr", filename]) output = datasocket.get file = File.open(filename, "wb") file.write(output) file.close data_disconnect end | 
#ls ⇒ Object
Function implementing ‘ls’ or list files command
| 296 297 298 299 300 301 302 | # File 'lib/rex/proto/ftp/client.rb', line 296 def ls datasocket = data_connect send_cmd(["list"]) output = datasocket.get data_disconnect output end | 
#pwd ⇒ Object
Function implementing ‘pwd’ or present working directory command
| 307 308 309 | # File 'lib/rex/proto/ftp/client.rb', line 307 def pwd send_cmd(["pwd"]) end | 
#raw_send(cmd, nsock = self.sock) ⇒ Object
This method transmits a FTP command and does not wait for a response
| 109 110 111 112 | # File 'lib/rex/proto/ftp/client.rb', line 109 def raw_send(cmd, nsock = self.sock) print_status("FTP send: #{cmd.inspect}") if self.verbose 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.
| 118 119 120 121 | # File 'lib/rex/proto/ftp/client.rb', line 118 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
| 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | # File 'lib/rex/proto/ftp/client.rb', line 54 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 !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 !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 !found_end resp << ln resp << "\r\n" if ln.length > 3 && ln[3, 1] == ' ' found_end = true end else left << ln left << "\r\n" end end if found_end @ftpbuff << left print_status("FTP recv: #{resp.inspect}") if self.verbose return resp end end end | 
#send_cmd(args, recv = true, nsock = self.sock) ⇒ Object
This method sends one command with zero or more parameters
| 212 213 214 215 216 217 218 219 | # File 'lib/rex/proto/ftp/client.rb', line 212 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 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.
| 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 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | # File 'lib/rex/proto/ftp/client.rb', line 238 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 !type return send_cmd(args, true, nsock) end # Set the transfer mode and connect to the remove server return nil if !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 <pass>’ command.
| 168 169 170 171 | # File 'lib/rex/proto/ftp/client.rb', line 168 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.
| 224 225 226 227 | # File 'lib/rex/proto/ftp/client.rb', line 224 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 <user>’ command.
| 159 160 161 162 | # File 'lib/rex/proto/ftp/client.rb', line 159 def send_user(user, nsock = self.sock) raw_send("USER #{user}\r\n", nsock) recv_ftp_resp(nsock) end | 
#upload ⇒ Object
Function implementing upload command
| 334 335 336 337 338 339 340 341 342 | # File 'lib/rex/proto/ftp/client.rb', line 334 def upload datasocket = data_connect file = File.open(filename, "rb") data = file.read file.close send_cmd(["stor", filename]) datasocket.write(data) data_disconnect end |