From 1d9f751bd2c1bc245d28a10b2992f9a867e6fd86 Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Fri, 7 Jun 2019 15:09:23 -0500 Subject: [PATCH] Land #11798, Add Extended Passive Mode for FTP client Merge remote-tracking branch 'upstream/pr/11798' into upstream-master --- lib/msf/core/exploit/ftp.rb | 51 +++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/lib/msf/core/exploit/ftp.rb b/lib/msf/core/exploit/ftp.rb index b8bdc6076f87..5096d26c881c 100644 --- a/lib/msf/core/exploit/ftp.rb +++ b/lib/msf/core/exploit/ftp.rb @@ -31,7 +31,8 @@ def initialize(info = {}) register_advanced_options( [ OptInt.new('FTPTimeout', [ true, 'The number of seconds to wait for a reply from an FTP command', 16]), - OptBool.new('FTPDEBUG', [ false, 'Whether or not to print verbose debug statements', false ]) + OptBool.new('FTPDEBUG', [ false, 'Whether or not to print verbose debug statements', false ]), + OptBool.new('PassiveMode', [ false, 'Set true for extended passive (EPSV) ftp mode.', false]) ], Msf::Exploit::Remote::Ftp) register_autofilter_ports([ 21, 2121]) @@ -67,6 +68,8 @@ def connect(global = true, verbose = nil) # This method handles establishing datasocket for data channel # def data_connect(mode = nil, nsock = self.sock) + pass_mode = datastore['PassiveMode'] + if mode res = send_cmd([ 'TYPE' , mode ], true, nsock) return nil if not res =~ /^200/ @@ -75,20 +78,40 @@ def data_connect(mode = nil, nsock = self.sock) # 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' => self } - ) + # Need to be able to do both extended and normal + # passive modes. normal passive mode is default + # details of EPSV are in RFC2428 + # pass_mode = true is EPSV; false is PASV + if pass_mode + res = send_cmd(['EPSV'], true, nsock) + return nil if not res =~ /^229/ + # 229 Entering Passive Mode (|||port|) + if res =~ /\(\|\|\|(\d+)\|\)/ + # convert port to FTP syntax + datahost = "#{rhost}" + dataport = $1.to_i + self.datasocket = Rex::Socket::Tcp.create( + 'PeerHost' => datahost, + 'PeerPort' => dataport, + 'Context' => { 'Msf' => framework, 'MsfExploit' => self } + ) + end + else + 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' => self } + ) + end end + self.datasocket end