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 <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.
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.
275 276 277 |
# File 'lib/metasploit/framework/ftp/client.rb', line 275 def @banner end |
#datasocket ⇒ Object (protected)
This attribute holds the banner that was read in after a successful call to connect or connect_login.
275 276 277 |
# File 'lib/metasploit/framework/ftp/client.rb', line 275 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.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/metasploit/framework/ftp/client.rb', line 68 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 |
# 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 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, 'Context' => { 'Msf' => framework, 'MsfExploit' => framework_module } ) end self.datasocket end |
#data_disconnect ⇒ Object
This method handles disconnecting our data channel
59 60 61 62 |
# File 'lib/metasploit/framework/ftp/client.rb', line 59 def data_disconnect self.datasocket.shutdown self.datasocket = nil end |
#ftp_timeout ⇒ Object
263 264 265 |
# File 'lib/metasploit/framework/ftp/client.rb', line 263 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
259 260 261 |
# File 'lib/metasploit/framework/ftp/client.rb', line 259 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.
197 198 199 200 |
# File 'lib/metasploit/framework/ftp/client.rb', line 197 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
205 206 207 208 209 210 211 212 213 214 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 |
# File 'lib/metasploit/framework/ftp/client.rb', line 205 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
120 121 122 123 124 125 126 127 |
# File 'lib/metasploit/framework/ftp/client.rb', line 120 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.
138 139 140 141 142 143 144 145 146 147 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 |
# File 'lib/metasploit/framework/ftp/client.rb', line 138 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 <pass>’ command.
104 105 106 107 |
# File 'lib/metasploit/framework/ftp/client.rb', line 104 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.
112 113 114 115 |
# File 'lib/metasploit/framework/ftp/client.rb', line 112 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.
95 96 97 98 |
# File 'lib/metasploit/framework/ftp/client.rb', line 95 def send_user(user, nsock = self.sock) raw_send("USER #{user}\r\n", nsock) recv_ftp_resp(nsock) end |