Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

vsftpd returns 0,0,0,0 in response to PASV

I set up an FTP server on AWS EC2 (Ubuntu16.04) with passive mode (PASV), but it doesn't work. However, it works with EPSV, don't know why. I searched around but find no answers, any body can help me with this?

1. vsftpd config

anonymous_enable=NO
local_enable=YES
write_enable=YES
chroot_local_user=YES
pasv_enable=YES
pasv_min_port=13000
pasv_max_port=13100
port_enable=YES
pasv_address=[public ip address of AWS EC2 instance]
allow_writeable_chroot=YES
seccomp_sandbox=NO

2. AWS EC2 Firewall

security groups (Inbound) setting

3. Test through FireFTP

Without IPV6 selected

With PASV mode, I cannot connect to FTP server, the log is:

220 (vsFTPd 3.0.3)
USER sensor
331 Please specify the password.
PASS (password not shown)
230 Login successful.
CWD /
250 Directory successfully changed.
TYPE A
200 Switching to ASCII mode.
PASV
QUIT

However, with it works with EPSV (with IPV6 checkbox selected), the log as below:

220 (vsFTPd 3.0.3)
USER sensor
331 Please specify the password.
PASS (password not shown)
230 Login successful.
PWD
257 "/" is the current directory
TYPE A
200 Switching to ASCII mode.
EPSV
229 Entering Extended Passive Mode (|||13082|)
LIST
150 Here comes the directory listing.
226 Directory send OK.

4. Test through Python ftplib

from ftplib import FTP
contents = []
ftp = FTP(host=xxx, timeout=3000)
ftp.login(user=xxx, passwd=xxx)
ftp.set_debuglevel(2)
ftp.retrlines("NLST", contents.append)
ftp.quit()

The log as below:

*cmd* 'TYPE A'
*put* 'TYPE A\r\n'
*get* '200 Switching to ASCII mode.\n'
*resp* '200 Switching to ASCII mode.'
*cmd* 'PASV'
*put* 'PASV\r\n'
*get* '227 Entering Passive Mode (0,0,0,0,50,245).\n'
*resp* '227 Entering Passive Mode (0,0,0,0,50,245).'
ConnectionRefusedError: [Errno 111] Connection refused
like image 601
codefluxer Avatar asked Dec 08 '16 18:12

codefluxer


People also ask

What is Pasv command in FTP?

The PASV command tells the server to enter a passive FTP session rather than Active. This allows users behind routers/firewalls to connect over FTP when they might not be able to connect over an Active (PORT) FTP session. PASV mode has the server tell the client where to connect the data port on the server.

What is passive mode in Vsftpd?

Passive mode can sometimes resolve certain clients ability to connect to the FTP server which may have been blocked by firewalls. If you are having issues connecting remotely, would like you to try to to enable passive connections in you will need to edit vsftpd.


1 Answers

It looks like a bug in vsftpd to me.

From the code it looks like, it will always send the 0,0,0,0, if the public pasv_address is set, but the server has a (local) IPv6 address.

To fix this, make sure the server does not listen on IPv6 address (what is the default behavior, which you are overriding by setting listen_ipv6=YES):

listen_ipv6=NO
listen=YES

The only other solution is removing a private IPv6 address, if it is possible in EC2.

Or use another FTP server, e.g. ProFTPD.

Or make ftplib ignore the IP address returned by the server.
See Cannot list FTP directory using ftplib – but FTP client works


To prove that this is indeed a bug, check this code of the latest vsftpd release (3.0.3):

handle_pasv in postlogin.c:

int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr);

...

if (tunable_pasv_address != 0)
{
  vsf_sysutil_sockaddr_alloc_ipv4(&s_p_sockaddr);
  /* Report passive address as specified in configuration */
  if (vsf_sysutil_inet_aton(tunable_pasv_address, s_p_sockaddr) == 0)
  {
    die("invalid pasv_address");
  }
}
else
{
  vsf_sysutil_sockaddr_clone(&s_p_sockaddr, p_sess->p_local_addr);
}
str_alloc_text(&s_pasv_res_str, "Entering Passive Mode (");
if (!is_ipv6)
{
  str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntop(s_p_sockaddr));
}
else
{
  const void* p_v4addr = vsf_sysutil_sockaddr_ipv6_v4(s_p_sockaddr);
  if (p_v4addr)
  {
    str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntoa(p_v4addr));
  }
  else
  {
    str_append_text(&s_pasv_res_str, "0,0,0,0");
  }
}

where the vsf_sysutil_sockaddr_ipv6_v4 returns 0, if the s_p_sockaddr is not IPv6, what it never is, when the pasv_address is set.

sysutil.c:

const void*
vsf_sysutil_sockaddr_ipv6_v4(const struct vsf_sysutil_sockaddr* p_addr)
{
  static unsigned char pattern[12] =
      { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
  const unsigned char* p_addr_start;
  if (p_addr->u.u_sockaddr.sa_family != AF_INET6)
  {
    return 0;
  }
  if (vsf_sysutil_memcmp(pattern, &p_addr->u.u_sockaddr_in6.sin6_addr, 12))
  {
    return 0;
  }
  p_addr_start = (const unsigned char*)&p_addr->u.u_sockaddr_in6.sin6_addr;
  return &p_addr_start[12];
}

Imho, the code is wrong. It works (and makes sense), when the IP address is "autodetected" from p_sess->p_local_addr, but fails, when the pasv_address address is used.

Consider reporting this to the author of vsftpd.


Keeping an original explanation of the PASV vs. EPSV:

Just to explain the difference between the PASV and the EPSV: The PASV returns an IP address in the response. That information is in 99.9% redundant. And it commonly causes problems, when the server is not aware of its external IP address.

The EPSV was introduced later than the PASV, when it was clear that the IP address presence in the response is problematic. So with the EPSV, only a port number is included. And the client connects to the FTP server IP address implicitly.

If the server really returns 0,0,0,0 in a response to the PASV command, it's clear why the client cannot connect to the server, when the PASV is used.

like image 193
Martin Prikryl Avatar answered Sep 27 '22 16:09

Martin Prikryl