bpo-43285 Make ftplib not trust the PASV response. (GH-24838) · python/cpython@0ab152c

GitHub

GitHub CopilotWrite better code with AI | MCP RegistryIntegrate external tools | ActionsAutomate any workflow | CodespacesInstant dev environments | IssuesPlan and track work | Code ReviewManage code changes | Code QualityEnforce quality at merge | Why GitHub | Marketplace | View all features | Enterprises | Small and medium teams | Startups | View all use cases | View all industries | View all solutions | AI | Software Development | DevOps | Security | View all topics | Customer stories | Events & webinars | Ebooks & reports | Business insights | Trust center | Partners | View all resources

@@ -103,6 +103,10 @@ def __init__(self, conn, encoding=DEFAULT_ENCODING):

103103self.next_retr_data=RETR_DATA

104104self.push('220 welcome')

105105self.encoding=encoding

106+# We use this as the string IPv4 address to direct the client

107+# to in response to a PASV command. To test security behavior.

108+# https://bugs.python.org/issue43285/.

109+self.fake_pasv_server_ip='252.253.254.255'

106110107111defcollect_incoming_data(self, data):

108112self.in_buffer.append(data)

@@ -143,7 +147,8 @@ def cmd_port(self, arg):

143147defcmd_pasv(self, arg):

144148withsocket.create_server((self.socket.getsockname()[0], 0)) assock:

145149sock.settimeout(TIMEOUT)

146-ip, port=sock.getsockname()[:2]

150+port=sock.getsockname()[1]

151+ip=self.fake_pasv_server_ip

147152ip=ip.replace('.', ','); p1=port/256; p2=port%256

148153self.push('227 entering passive mode (%s,%d,%d)'%(ip, p1, p2))

149154conn, addr=sock.accept()

@@ -707,6 +712,26 @@ def test_makepasv(self):

707712# IPv4 is in use, just make sure send_epsv has not been used

708713self.assertEqual(self.server.handler_instance.last_received_cmd, 'pasv')

709714715+deftest_makepasv_issue43285_security_disabled(self):

716+"""Test the opt-in to the old vulnerable behavior."""

717+self.client.trust_server_pasv_ipv4_address=True

718+bad_host, port=self.client.makepasv()

719+self.assertEqual(

720+bad_host, self.server.handler_instance.fake_pasv_server_ip)

721+# Opening and closing a connection keeps the dummy server happy

722+# instead of timing out on accept.

723+socket.create_connection((self.client.sock.getpeername()[0], port),

724+timeout=TIMEOUT).close()

725+726+deftest_makepasv_issue43285_security_enabled_default(self):

727+self.assertFalse(self.client.trust_server_pasv_ipv4_address)

728+trusted_host, port=self.client.makepasv()

729+self.assertNotEqual(

730+trusted_host, self.server.handler_instance.fake_pasv_server_ip)

731+# Opening and closing a connection keeps the dummy server happy

732+# instead of timing out on accept.

733+socket.create_connection((trusted_host, port), timeout=TIMEOUT).close()

734+710735deftest_with_statement(self):

711736self.client.quit()

712737