This document summarizes a presentation about pentesting custom TLS stacks. It discusses using the scapy-ssl_tls tool to craft and analyze TLS packets in order to evaluate the security of custom TLS implementations. The presentation covers TLS protocol basics, features of scapy-ssl_tls like packet parsing and crypto hooks, and techniques for analyzing areas like supported versions/ciphers, the TLS state machine, Diffie-Hellman parameters, side channels, fragmentation, and more. It aims to provide a way to efficiently reproduce TLS attacks and help test responses to vulnerabilities.
2. Who am I?
• Security engineer at Citrix
• Interest in low level topics (crypto, fuzzing,
exploit dev)
• "the views expressed herein are personal and
stated in my individual capacity and in no way
a statement or position of my employer”
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
1
3. Agenda
1. TLS attacks timeline
2. Difficulty in reproducing attacks
3. Quick refresher on TLS
4. Scapy-ssl_tls goals
5. Quick demo of scapy-ssl_tls capabilities
6. Custom TLS stacks, what to look for?
7. Scapy-ssl_tls crypto
8. Demo: detecting Poodle
9. Fuzzing capabilities
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
2
4. Introduction
• TLS is a critical protocol to the internet
• Very few alternatives
• Session layer protocol for other protocols
• Very complex
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
3
5. Introduction
• Protocol under scrutiny
• Growth of the number of attacks
• General lack of tooling
• Attacks are developed ad-hoc:
– Extensions of OpenSSL
– …
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
4
7. Introduction
• Protocol under scrutiny
• Growth of the number of protocol level
attacks
• Numerous implementation bugs
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
6
11. Problems
• Understand the attack properly
• Practical impact (as opposed to theoretical
problem)
• Reproducibility
• Fix (dev + Q&A)
• Fix for good (regression)
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
10
12. Response
• Customers do not always understand the practical impact
• Your response team has to provide a definite answer
• 2 solutions for custom implementations:
– Crypto code review:
• Lack of comparison point
• Hard to get the full picture when deep into a crypto routine
– PoC:
• Lack of tooling
• Big difference between regular lib and security focused lib
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
11
14. Basics
• TLS is session layer (layer 5)
• Performs a handshake then provides crypto
• Transparent to protocol
• High RTT (at least 4 packets, 2 RTT for handshake)
• Offers session resumption
• Can authenticate both client and server
• Provides integrity and confidentiality
• Relies on TCP for packet delivery and ordering
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
13
15. Message format
• Has sub-protocols within the protocol:
1. Handshake (negotiate parameters)
2. Change Cipher Spec (signal a cipher change)
3. Alert (error handling)
4. Application data (move data)
• Each of these sub-protocols are encapsulated in a Record header
which holds:
– Proto version
– Payload length
– Payload type
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
14
16. TLS Record
• In charge of transporting the sub-protocols
• Record is always cleartext
• Payload length is not completely protected in TLS
• Records can be “stacked” inside a packet:
Version
Size
Length
Handshake, Data, …
Record Handshake, Data, … Record Handshake, Data, …
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
15
17. Handshake
• In charge of negotiating:
– Compression
– Crypto parameters
– Initiating crypto material
• In charge of ensuring handshake is free of in
transit tampering (finish message)
• Extensible (through TLS extensions)
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
16
18. Handshake quirks
• Max size: 2**16, can be TLS fragmented
• Some messages can have arbitrary trailing data
(support for unknown extensions)
• Doesn’t need a certificate (anonymous RSA, DH
and ECDH)
• Can have “stacked” handshakes in a record (Java)
Record Handshake Handshake Handshake
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
19
19. Application Data
• Encrypted + authenticated packets
• Cleartext is HMACd then padded => MAC then
encrypt…
Padding is not protected by the MAC
• Stream ciphers:
Record Cleartext HMAC padding
Padding
length
Encrypted
Record Cleartext HMAC
Encrypted
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
21
21. Introduction
• TLS & DTLS attack stack built above scapy
• Stateless (as much as possible)
• Packet crafting and dissecting
• Crypto session handling
• Sniffing (wire, pcap, …)
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
24
22. Why bother?
• TLS stacks are built to be robust
• Enforce input parameters to be valid
• Tear down connection on error
• Not very flexible
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
25
23. Goals
• Easy to install and use
• Simplify discovery and exploitation of TLS vulnerabilities
• Allow full control of any TLS field
• Tries very hard to maintain absolutely no state
• Good documentation and examples
• No checks or enforcements (up to user if desired)
• Sane defaults
• Transparent encryption
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
26
24. Features
• Full support:
– SSLv3, TLS 1.0, TLS 1.1, TLS1.2 and DTLS
– RSA, DHE, ECDHE key exchanges with all available ciphers
– RSA and DSA signature
– All TLS records and extensions
– Transparent decryption of TLS traffic
– Client certs
• Missing:
– AES-GCM and CCM
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
27
25. Installation
• Stable branch (v1.2.2 today):
– pip install scapy-ssl_tls
• Dev branch (latest features + examples):
– git clone https://github.com/tintinweb/scapy-ssl_tls
– Or pip install git+https://github.com/tintinweb/scapy-
ssl_tls@master
• Feature branches:
– Replace @master by @branch
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
28
26. Concepts
• Start scapy
• All classes start with TLS:
– Allows easy autocomplete
• What fields are available in a given TLS record?
– ls(TLSClientHello)
• TLSSocket() is used to wrap the TCP socket
– This is your base element to send/recv traffic
• Build packets scapy style:
– p = TLSRecord()/TLSHandshake()/TLSClientHello()
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
29
33. Recon
• Fingerprint possible fork
• OpenSSL empty plaintext fragment
• JSSE stacked handshake
• Difference in Alert type when tampering with
Finish message
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
36
34. State machine
• Tricky testing: mostly manual work and
knowledge of RFC
• Automated testing: FlexTLS:
– Example: mono FlexApps.exe -s efin --connect
localhost:8443
• Gives a good starting point for manual testing
• Lot of legacy stuff: server-gated cryptography
anyone?
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
37
35. Diffie Hellman
• Check the validity of server (EC)DH params
– Group size
– Primality
– Subgroup confinement attack (e.g: Off curve test (EC))
– Signature algo used
– …
• Send random values (small, non-prime, …)
• Scapy-ssl_tls uses TinyEC for EC calculation
• Allows to perform EC arithmetic
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
38
36. Side channels (RSA)
• Pre Master Secret is decrypted
• TLS mandates PKCS1 v1.5 for padding
• This needs to be constant time, see classic
Bleichenbacher
• Time and Check for response difference on invalid
padding (alert vs tcp reset)
• Can use pybleach pkcs1_test_client.py to
generate faulty padding for your PMS
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
39
37. Side channels (ciphers)
• Padding and MAC checks must be constant
time
• Alert type must be identical
• Time and check response when flipping bytes
in padding and MAC
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
40
38. Proper byte checking
• Some implementation only verify a few bytes
of padding, MAC and verify_data (finish hash)
• All bytes must be checked for obvious reasons
• Send application data packets with flipped
padding, MAC and verify_data
• Make sure you always get an alert
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
41
39. DDoS
• DTLS is UDP
• Returns a certificate chain on first packet
• DTLS hello => 64 bytes
• DTLS response => can be several kB
• Protection is built into the protocol, but is a MAY =>
HelloVerifyRequest
• Make sure to check cookie is returned upon multiple
spoofed requests
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
42
40. Fragmentation
• Any packet above 2**14 (16384) bytes must be fragmented
• But any fragment size can be chosen
• Few stacks support TLS re-assembly
• Can be used to bypass devices which parse TLS, but fail-
open
• Server can be requested to fragment using the Maximum
Fragment Length Negotiation extension
• DTLS allows to specify the fragment offset in the handshake
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
43
42. tls_to_raw
• Scapy-ssl_tls exposes tls_to_raw()
• Calculates all crypto material for the packet
• Exposes some hooks:
– At compression time
– Pre and post encryption
• Allows to act on pre-calculated padding and MACs
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
45
to_raw(pkt, tls_ctx, include_record=True, compress_hook=None, pre_encrypt_hook=None,
encrypt_hook=None)
43. Crypto container
• All crypto material stored in a
CryptoContainer:
– IV, mac, padding, padding length
• Passed to and returned by crypto hooks:
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
46
def modify_padding(crypto_container):
padding = crypto_container.padding
byte_flip = chr(ord(padding[index]) ^ 0xff)
crypto_container.padding = "%s%s%s" % (padding[:index], byte_flip, padding[index + 1:])
return crypto_container
tls_to_raw(TLSPlaintext(data=data), tls_socket.tls_ctx, pre_encrypt_hook=modify_padding)
44. Usage
• Very useful to modify crypto state
• Without keeping track of PRF, ciphers, MACs,…
• Allows to easily reproduce attacks on crypto
material
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
47
49. Strengths
• Scapy-ssl_tls can speed up PoC development
• PoC can be re-used as part of testing QA and
regression
• Valuable to reproduce findings & develop
mitigations
• Help in learning & experimenting with TLS
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
52
50. Thanks
• Thanks to tintinweb who started the project
• Bugs: https://github.com/tintinweb/scapy-
ssl_tls/
• Contact:
– Github: alexmgr
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
53
53. Fuzzing
• Provides basic fuzzing through scapy
• Tries to be smart by preserving semantically necessary
fields
• Use fuzz() function on any element
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
56
fuzz(TLSRecord()/TLSHandshake(type=TLSHandshakeType.SUPPLEMENTAL_DATA)/TLSAlert()).show2()
###[ TLS Record ]###
content_type= handshake <= preserved
version= 0x7391 <= fuzzed
length= 0x6 <= preserved
###[ TLS Handshake ]###
type= supplemental_data <= overriden
length= 0x2 <= preserved
###[ Raw ]###
load= '(r’ <= fuzzed
54. Fuzzing
• Only good for basic fuzzing
• Simple to plug in your own fuzzer
• Just generate data, scapy-ssl_tls takes care of
the rest
• Good targets: TLS extensions, certificates, …
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
57
55. Examples
• The example section contains some useful base tools:
– RSA session sniffer: given a cert, can decrypt wire traffic
(like Wireshark)
– Security scanner: a rudimentary TLS scanner (versions,
ciphers, SCSV, …)
– Downgrade test
– …
• Just baselines to write your own tools
1/16/16
Alex Moneger - Pentesting custom TLS
stacks
58
Notes de l'éditeur
I’m quite slow, so to fully understand something, I need to repro and play with it
Customer don’t always understand the practical impact. No kidding, sometimes as a security engineer it takes you a few hours/days
But your response team has to provide a statement quickly
Both approaches require you to understand the issue in depth. But it’s harder to make a mistake with a PoC. It’s also easier to perform code review with a PoC
PoC provides reproducibility, which provides Q&A and regression for free
CCS encrypts one byte under the current cipher state. Next packet will be encrypted with the new cipher
All attacks on 1 handshake or 4 app data
No attacks on record layer
Compression is not a good idea. See CRIME
Crypto parameters:
- Kex (what is used to exchange the PMS)? ECDH, DH, RSA, …
- Sig (what is used to sign the Kex)?
- Cipher used (stream, CBC)
- HMAC hash algo to generate the MAC
Notice that signature method for Kex is not specified. Hardcoded as MD5+SHA in the spec. Configured through TLS extension in TLS 1.2
tLS finish message is the first encrypted message and carries the hash of previous messages. Assures that both client and server agree about messages exchanged.
ALPN tells the server which upper layer protocol is negotiated (http2, speedy, …)
SNI tells which hostname the TLS connection is destined to. Allows the server to return the right cert when TLS sites are co-hosted
PRF is a mixing function which uses MD5+SHA1 until TLS 1.2
TLS 1.2 uses SHA256
Fragment size is 2**14, so a handshake payload can be fragmented across several records
This is an interesting edge case, especially for DTLS where one can specify both the fragment sequence and offset. Exposes interesting attacks, very similar to IP fragmentation
Arbitrary trailing data, Sloth used pre-images in md5 TLS 1.2 to MITM TLS connections (+ known weak DH params)
Stacked handshakes can be used to fingerprint TLS stacks to some extent
Source of problems that we know of, poodle, poodle2…
Explicit IVs are the cause of the delay in migration to TLS 1.1 I think
Force to reset the state of the cipher
Writing an offensive stack is very different.
All recommendations you normally provide to devs should be ignored. Do not validate length, format, signatures, … All validation is up to you, scapy-ssl_tls only reports data
cd /Users/amoneger/projects/contrib/scapy-ssl_tls
tests/integration/openssl_tls_server.sh tls1_2
Enter TLS and press tab to autocomplete
Craft a TLSRecord with a TLSHandshake. Do a show(), do a ls()
Modify length field of the record
Talk about tls_context and the various crypto parameters
import socket
version = TLSVersion.TLS_1_2
ciphers = [TLSCipherSuite.ECDHE_RSA_WITH_AES_128_CBC_SHA]
host = ("localhost", 8443)
app_payload = "GET / HTTP/1.1\r\nHOST: example.com\r\n\r\n"
socket_ = socket.socket()
socket_.connect(host)
tls_socket = TLSSocket(socket_, client=True)
# Handshake
tls_do_handshake(tls_socket, version, ciphers)
# Application data
tls_socket.sendall(to_raw(TLSPlaintext(data=app_payload), tls_socket.tls_ctx))
response = tls_socket.recvall()
response.show()
print(tls_socket.tls_ctx)
For ciphers, check SCSV for downgrade prevention
Custom stacks seem to generally be forks of OSS projects at one stage.
It is interesting to try and fingerprint where it comes from, to then try and look for known implementation vulnerabilities on the stack
You can probably pinpoint to the version with some research
FlexTLS is based on miTLS which is A Verified Reference Implementation of TLS
It implements a number of know attacks against the TLS state machine.
Source code was only very recently released. A great reference tool to go after TLS state machine
server-gated cryptography: client renegotiation based on server cert
Mention that PMS should start by handshake client version. Prevents rollback attacks
Padding in TLS can be any length upto 255 bytes.
Check that implementation respects that.
DTLS is like IP from the old days ;)
Possible values start at 2**9 = 512. Only active after Server Hello is received.