+51
-2
lines changedFilter options
+51
-2
lines changed Original file line number Diff line number Diff line change
@@ -2585,3 +2585,12 @@ separator key, with ``&`` as the default. This change also affects
2585
2585
functions internally. For more details, please see their respective
2586
2586
documentation.
2587
2587
(Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.)
2588
+
2589
+
Notable changes in Python 3.7.11
2590
+
================================
2591
+
2592
+
A security fix alters the :class:`ftplib.FTP` behavior to not trust the
2593
+
IPv4 address sent from the remote server when setting up a passive data
2594
+
channel. We reuse the ftp server IP address instead. For unusual code
2595
+
requiring the old behavior, set a ``trust_server_pasv_ipv4_address``
2596
+
attribute on your FTP instance to ``True``. (See :issue:`43285`)
Original file line number Diff line number Diff line change
@@ -104,6 +104,8 @@ class FTP:
104
104
welcome = None
105
105
passiveserver = 1
106
106
encoding = "latin-1"
107
+
# Disables https://bugs.python.org/issue43285 security if set to True.
108
+
trust_server_pasv_ipv4_address = False
107
109
108
110
# Initialization method (called by class instantiation).
109
111
# Initialize host to localhost, port to standard ftp port
@@ -333,8 +335,13 @@ def makeport(self):
333
335
return sock
334
336
335
337
def makepasv(self):
338
+
"""Internal: Does the PASV or EPSV handshake -> (address, port)"""
336
339
if self.af == socket.AF_INET:
337
-
host, port = parse227(self.sendcmd('PASV'))
340
+
untrusted_host, port = parse227(self.sendcmd('PASV'))
341
+
if self.trust_server_pasv_ipv4_address:
342
+
host = untrusted_host
343
+
else:
344
+
host = self.sock.getpeername()[0]
338
345
else:
339
346
host, port = parse229(self.sendcmd('EPSV'), self.sock.getpeername())
340
347
return host, port
Original file line number Diff line number Diff line change
@@ -94,6 +94,10 @@ def __init__(self, conn):
94
94
self.rest = None
95
95
self.next_retr_data = RETR_DATA
96
96
self.push('220 welcome')
97
+
# We use this as the string IPv4 address to direct the client
98
+
# to in response to a PASV command. To test security behavior.
99
+
# https://bugs.python.org/issue43285/.
100
+
self.fake_pasv_server_ip = '252.253.254.255'
97
101
98
102
def collect_incoming_data(self, data):
99
103
self.in_buffer.append(data)
@@ -136,7 +140,8 @@ def cmd_pasv(self, arg):
136
140
sock.bind((self.socket.getsockname()[0], 0))
137
141
sock.listen()
138
142
sock.settimeout(TIMEOUT)
139
-
ip, port = sock.getsockname()[:2]
143
+
port = sock.getsockname()[1]
144
+
ip = self.fake_pasv_server_ip
140
145
ip = ip.replace('.', ','); p1 = port / 256; p2 = port % 256
141
146
self.push('227 entering passive mode (%s,%d,%d)' %(ip, p1, p2))
142
147
conn, addr = sock.accept()
@@ -698,6 +703,26 @@ def test_makepasv(self):
698
703
# IPv4 is in use, just make sure send_epsv has not been used
699
704
self.assertEqual(self.server.handler_instance.last_received_cmd, 'pasv')
700
705
706
+
def test_makepasv_issue43285_security_disabled(self):
707
+
"""Test the opt-in to the old vulnerable behavior."""
708
+
self.client.trust_server_pasv_ipv4_address = True
709
+
bad_host, port = self.client.makepasv()
710
+
self.assertEqual(
711
+
bad_host, self.server.handler_instance.fake_pasv_server_ip)
712
+
# Opening and closing a connection keeps the dummy server happy
713
+
# instead of timing out on accept.
714
+
socket.create_connection((self.client.sock.getpeername()[0], port),
715
+
timeout=TIMEOUT).close()
716
+
717
+
def test_makepasv_issue43285_security_enabled_default(self):
718
+
self.assertFalse(self.client.trust_server_pasv_ipv4_address)
719
+
trusted_host, port = self.client.makepasv()
720
+
self.assertNotEqual(
721
+
trusted_host, self.server.handler_instance.fake_pasv_server_ip)
722
+
# Opening and closing a connection keeps the dummy server happy
723
+
# instead of timing out on accept.
724
+
socket.create_connection((trusted_host, port), timeout=TIMEOUT).close()
725
+
701
726
def test_with_statement(self):
702
727
self.client.quit()
703
728
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
1
+
:mod:`ftplib` no longer trusts the IP address value returned from the server
2
+
in response to the PASV command by default. This prevents a malicious FTP
3
+
server from using the response to probe IPv4 address and port combinations
4
+
on the client network.
5
+
6
+
Code that requires the former vulnerable behavior may set a
7
+
``trust_server_pasv_ipv4_address`` attribute on their
8
+
:class:`ftplib.FTP` instances to ``True`` to re-enable it.
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4