Cunning with CNG: Soliciting
Secrets from Schannel

“Black Hat Sound Bytes”
What you get out of this talk Ability to decrypt Schannel TLS connections that use ephemeral key exchanges
 Ability to decrypt and extract private certificate and session ticket key directlyfrom memory
 Public Cert/SNI to PID/Logon Session MappingAgenda A very short SSL/TLS Review
 A background on Schannel & CNG
 The Secret Data
 The Forensic Context
 Demo >.>Disclaimer
 This is NOT an exploit It’s just the spec :D
 …and some implementation specific oddities

 Microsoft has done nothing [especially] wrong
 To the contrary, their documentation was actually pretty great Windows doesn’t track sessions for processes that load their own TLS libs
 I’m looking at you Firefox and Chrome Windows doesn’t track sessions for process that don’t use TLS…
 That’d be you TeamViewer...

Background
TLS, Schannel, and CNG

The infamous TLS Handshake

Initial Connection

TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

The infamous TLSDR; Handshake

Session ResumptionPerfect Forward Secrecy
What we want to do One time use keys, no sending secrets!
What TLS actually does
 Caches values to enable resumption
 recommends `An upper limit of 24 hours is suggested for session ID lifetimes` When using session ticket extension, sends the encrypted state over the network
 basically returning to the issue with RSA, but using a more ephemeral key...
What implementations also do Store symmetric key schedules (so you can find the otherwise random keys...) Cache ephemeral keys and reuse for a while...

Schannel & CNG
Secure Channel

The CryptoAPI-Next Generation (CNG) It’s TLS -> the Secure Channel for Windows!

 Introduced in Vista (yes you read correctly)

 A library that gets loaded into the “key isolation
process” and the “client” process Provides Common Criteria complianceTechnically a Security Support Provider (SSP) Spoiler: the Key Isolation process is LSASS Used to store secrets and ‘crypt them

Storage via the Key Storage Providers (KSPs)



Generic data encryption via DPAPI

Also brings modern ciphers to Windows (AES for
example) and ECC

 Importantly, ncrypt gets called out as the “keystorage router” and gateway to the CNG KeyIsolation service

Schannel Prefered Cipher Suites

Windows Vista
Windows 7

Windows 10*ListCipherSuites sample code found here: https://technet.microsoft.com/en-us/library/bb870930.aspx

Microsoft’s TLS/SSL Docs
 ClientCacheTime: “The first time a client connects to a server through the Schannel SSP, a full TLS/SSL
handshake is performed.”
 “When this is complete, the master secret, cipher suite, and certificates are stored in the session cache on
the respective client and server.”* ServerCacheTime: “…Increasing ServerCacheTime above the default values causes Lsass.exe to consume
additional memory. Each session cache element typically requires 2 to 4 KB of memory”*
 MaximumCacheSize: “This entry controls the maximum number of cache elements. […] The default value
is 20,000 elements.” **TLS/SSL Settings quoted from here: https://technet.microsoft.com/en-us/library/dn786418(v=ws.11).aspx

Schannel Ops

Diagram based on: https://technet.microsoft.com/en-us/library/dn786429.aspx

CNG Key Isolation

Diagram based on: https://msdn.microsoft.com/en-us/library/windows/desktop/bb204778.aspx

Background Summary
Were Looking HereFor These

Because of That

LSASS.exe

What are we trying to accomplish?
We want to be able to see data that has been protected with TLS/SSL and subvert efforts
at implementing Perfect Forward Secrecy
We want to gather any contextual information that we can use for forensic purposes,
regardless of whether or not we can accomplish the above
We (as an adversary) want to be able to get access to a single process address space andbe able to dump out things that would enable us to monitor/modify future traffic, or
possibly impersonate the target
 We want to do this without touching disk

Secrets

The Keys+Session Keys

Master Secret

Session Ticket Key*

Pre-Master Secret

Ephemeral Private Key*

Persistent Private Key(Signing)

The Keys? What do they get us?

=
=
=
=

a single connection
a single session
multiple sessions
multiple sessions + identity

The Keys? We got ’em…all.
CSslUserContext+0x18, +0x20*

CSessionCache<type>Item+0xF0

CSessionCacheServerItem+0xF0

msprotectkey

NcryptSslkey+0x10CEphemKeyData+0x48

CSslContext*

NcryptsslpSessionKey+0x18

NcryptSslKey+0x10

BcryptKey+0x10

MSSymmetricKey+0x18

MSSymmetricKey+0x18

NcryptsslpMasterKey+0x30

NcryptSslkey+0x10

CSslCredential+0x48

BcryptKey+0x10

NcryptSslpEphemKey+0x18

CSslServerKey+0x08

NcryptSslKey+0x10

NcryptKey+0x10

NcryptsslpKey
pair +0x18

KPSPK
+0x60

EccKey+0x18

NcryptKey
+0x10

KPSPK
+0xD0

Session Keys Smallest scope / most ephemeral Required for symmetric encrypted comms
 Not going to be encrypted
Approach Premise: Start with AES
 AES keys are relatively small and pseudo-random
 AES key schedules are larger and deterministic
 … they are a “schedule” after all.
 Key schedules usually calculated once and stored* Let’s scan for matching key schedules on both
hosts
FindAES from: http://jessekornblum.com/tools/

Session Keys
_SSL_SESSION_KEY_BCRYPT_KEY_HANDLE

4

cbStructLength4

cbStructLength4dwMagic [“ssl3”]

4dwMagic [“UUUR”]

4

dwProtocolVersion

4/8

pvBcryptProvider

4/8

pvCipherSuiteListEntry

4/8

pvBcryptSymmKey

4

IsWriteKey

4/8

pvBcryptKeyStruct_MS_SYMMETRIC_KEY

CSslUserContext

Look familiar? Bcrypt keys are used a lot: think Mimikatz

4

cbStructLength4dwMagic [“MSSK”]

4

dwKeyType

...

...

4

KeyLength?

SymmetricKey?

SymmKeySchedule

The Ncrypt SSL Provider (ncryptsslp.dll)
Ncryptsslp Validation function Symbols

These functions do three things:
 Check the first dword for a size value
 Check the second dword for a magic ID
 Return the passed handle* if all is good
*Handles are always a pointer here

Ncryptsslp Validation function Symbols

The Ncrypt SSL Provider (ncryptsslp.dll)
SSL Magic

Size (x86)

Size (x64)

Validation Functions

ssl1

0xE4

0x130

SslpValidateProvHandle

ssl2

0x24

0x30

SslpValidateHashHandle

ssl3

?

?

<none>

ssl4

0x18

0x20

SslpValidateKeyPairHandle

ssl5

0x48

0x50

SslpValidateMasterKeyHandle

ssl6

0x18

0x20

SslpValidateEphemeralHandle

ssl7

?

?

<none>

ssl3 was already discussed,
appears in the following functions:
TlsGenerateSessionKeys+0x251
SPSslDecryptPacket+0x43
SPSslEncryptPacket+0x43
SPSslImportKey+0x19a
SPSslExportKey+0x76
Ssl2GenerateSessionKeys+0x22c

Pre-Master Secret (PMS) The ‘ssl7’ struct appears to be used specificallyfor the RSA PMS
 As advised by the RFC, it gets destroyed quickly,
once the Master Secret (MS) has been derived

Functions where ssl7 appears:
ncryptsslp!SPSslGenerateMasterKey+0x75
ncryptsslp!SPSslGenerateMasterKey+0x5595
ncryptsslp!SPSslGeneratePreMasterKey+0x15e
ncryptsslp!TlsDecryptMasterKey+0x6b

 Client generates random data, populates the
ssl7 structure, and encrypts
 In ECC the PMS is x-coordinate of the sharedsecret derived (which is a point on the curve), so
this doesn’t /seem/ to get used in that case

Bottom line:
It’s vestigial for our purposes - it doesn’t doanything another secret can’tMaster Secret Basically the Holy Grail for a given connection
 It always exists
 It’s what gets cached and used to derive
the session keys
 Structure for storage is simple - secret isunencrypted (as you’d expect) This + Unique ID = decryption, natively in tools
like wireshark
So...how do we get there?

_SSL_MASTER_SECRET
4cbStructLength4dwMagic [“ssl5”]

4dwProtocolVersion

0/4

dwUnknown1* [alignment?]

4/8

pCipherSuiteListEntry

4

bIsClientCache

48

rgbMasterSecret

4

dwUnknown2 [reserved?]Master Secret_SSL_MASTER_SECRET
4cbStructLength4dwMagic [“ssl5”]

4dwProtocolVersion

0/4

dwUnknown1* [alignment?]

4/8

pCipherSuiteListEntry

4

bIsClientCache

48

rgbMasterSecret

4

dwUnknown2 [reserved?]Master Secret Mapped to Unique Identifier The Master Key is linked back to a unique ID
through an “NcryptSslKey”
 The NcryptSslKey is referenced by an“SessionCacheItem”
 The SessionCacheItem contains either the
SessionID, or a pointer and length value for a
SessionTicket
 Instantiated as either client or serveritem
At this point, we can find cache items, and extract
the Master Secret + Unique ID… Houston, we has plaintext.

_SSL_MASTER_SECRET_SESSION_CACHE_CLIENT_ITEM
4/8

pVftable

…

…

@0x10
…
@0x88
…

4

cbStructLength4dwMagic [“ssl5”]

4dwProtocolVersion

0/4

dwUnknown1* [alignment?]

4/8

pCipherSuiteListEntry

4

bIsClientCache

48

rgbMasterSecret

4

dwUnknown2 [reserved?]

pMasterKey…
rgbSessionID[0x20]…

@0x128

pSessionTicket@0x130cbSessionTicketLength_NCRYPT_SSL_KEY_HANDLE
4

cbStructLength4dwMagic [“BDDD”]

4/8

pNcryptSslProvider

4/8

pNcryptSslKey

Master Secret Mapped to Unique Identifier
Wireshark SSL Log Format
RSA SessionID:97420000581679ae7a064f3e4a350682dca9e839ebca07075b1a944d8b1b71f7 MasterKey:897adf533d0e87eadbc41bc1a13adb241251a56f0504
35fad0d54b1064f83c50cedb9d98de046008cde04a409779
5df2
RSA SessionID:f5350000be2cebcb15a38f38b99a20751ed0d53957890
1ddde69278dbbf9738e MasterKey:716a1d493656bf534e436ffb58ff2e40000516b735db
d5dfaff93f37b5ac90ba1c3a25ba3e1505b8f3aa168a657e
007b
RSA SessionID:bcb3aff3581fccb9fe268d46f99f5e2c6cc9e59e51c67
14d70997e63b9c6fe73 MasterKey:e45e18945197c2f0a2addb901a9558f194241d2b488c
dc3d1f81e1271acb4dc776e3c772177c7d0462afeca57a3d
9cb2
RSA SessionID:c7d0f952fb3fc4999a692ce3674acb1a4b2c791ece2c6
d1621af95e6414ec3b0 MasterKey:db93026b71e0323b60e2537f0eeebf4fc321094b8a9a
6ccd8cf0f50c7fa68c294f6c490d5af3df881db585e2a10a
0aea
Wireshark SSL input formats found here: https://github.com/boundary/wireshark/blob/master/epan/dissectors/packet-ssl.c

Ephemeral & Persistent Private Keys Both share the same structure Both store secrets in a Key Storage Provider
Key struct (KPSK) The “Key Type” is compared with different
values

ssl6 gets compared with a list stored inbcryptprimitives
ssl4 gets compared with a list stored in
NCRYPTPROV The Key Storage Provider Key (KPSK) is
referenced indirectly through an “NcryptKey” struct**NcryptKey not to be confused with NcryptSslKey_KSP_KEY_SSL_KEY_PAIR

4

cbStructLength4

cbStructLength4dwMagic [ “KSPK” ]4

dwMagic [ “ssl4” | “ssl6” ]4

dwKeyType4

dwKeyType

...

...

4

dwUnknown1 [alignment?]

@0x60

pMSKY

4/8

pKspProvider@0xD0

pDpapiBlob

4/8

pKspKey@0xD8dwDpapiBlobLength_NCRYPT_KEY_HANDLE
4

cbStructLength4dwMagic [ 0x44440002 ]4

dwKeyType4

dwUnknown1 [alignment?]

4/8

pKspProvider

4/8

pKspKeyEphemeral Private Key
 For performance, reused across connections
 Given the public connection params, we canderive the PMS and subsequently MS

 Stored unencrypted in a LE byte array
 Inside of MSKY struct The curve parameters are stored in the KPSK Other parameters (A&B, etc) are stored in MSKY
w/ the key

 Verified by generating the Public & comparing The Public Key is also stored in the first pointerof the CEphemData struct that points to “ssl6”
In-line with suggestion of this paper: http://dualec.org/DualECTLS.pdf

“Persistent” Private Key
 The RSA Key that is stored on disk
 Unique instance for each private RSA Key – bydefault, the system has several
 E.g. one for Terminal Services

 RSA Keys are DPAPI protected Lots of research about protection / exporting Note the MK GUID highlighted from the Blob The Key is linked to a given Server Cache Item Verified by comparing the DPAPI blob inmemory to protected certificate on disk
 Also verified through decryptionDecrypting Persistent Key - DPAPI
 Can extract the blob from memory and decrypt w/ keys
from disk
 DPAPIck / MimikatzOR Can decrypt directly from memory :D
 MasterKeys get cached in Memory
 On Win10 in: dpapisrv!g_MasterKeyCacheList
 See Mimilib for further details
 Even though symbols are sort of required, we
could likely do without them

There are only two Bcrypt key pointers in lsasrv’s.rdata section (plus one lock)

Identifying the IV is more challenging
Cached DPAPI MK + Params to DecryptDecrypting Persistent Key - DPAPI

Session Tickets
 Not seemingly in widespread use with IIS?
 Comes around w/ Server 2012 R2
 Documentation is lacking.
 Enabled via reg key + powershell cmdlets?
 Creates an “Administrator managed”
session ticket key
 Schannel functions related to Session Tickets
load the keyfile from disk
 Export-TlsSessionTicketKey :D

Reference to DISABLING session tickets in Win8.1 Preview release notes: https://technet.microsoft.com/en-us/library/dn303404.aspx

Session Ticket Key
 Keyfile contains a DPAPI blob, preceded by a
SessionTicketKey GUID + 8 byte value Key gets loaded via schannel
 The heavy lifting (at least in Win10) is done
via mskeyprotect
 AES key derived from decrypted blob via
BCryptKeyDerivation() Key gets cached inside mskeyprotect!
 No symbols for cache : / No bother, we can just find the Key GUID
that’s cached with it :D

Possibly Salt or MAC?
Session Ticket Key GUID
Size of ensuing DPAPI Blob
DPAPI Blob (contains it’s own fields)

Decrypting Session Tickets
 Session Ticket structure pretty much follows the
RFC (5077), except:
 MAC & Encrypted State are flipped (makes
a lot of sense) After extracting/deriving the Symm key, it’s juststraight AES 256
 Contents of the State are what you’d expect: Timestamp Protocol/Ciphersuite info
 MS struct

Key GUIDIV
MAC
Encrypted
TLS
State

Decrypting Session Tickets

Master SecretSecrets are cool and all...
But Jake, what if I don’t have a packet capture?
(And I don’t care about future connections?)

The Context

Inherent Metadata TLS Provides
Core SSL/TLS functionality

TLS Extensions

 Timestamps

 Server Name Indication (SNI) Virtual hosts The random values *typically* start with a 4-bytetimestamp (if you play by the RFCs)

 Identity / fingerprinting
 Public Key Session ID*
 Offered Cipher Suites / Extensions

 Session ID’s are arbitrary, but are not always
random -> Schannel is a perfect example
 uses MaximumCacheEntries parameter when creating
the first dword of the random, leading to a(nimperfect) fingerprint of two zero bytes in 3/4th byte**Referenced in this paper: http://dualec.org/DualECTLS.pdf

 Application-Layer Protocol Negotiation (ALPN)
 Limited, but what protocol comes next
 fingerprinting?
 Session Tickets
 Key GUID

Schannel Caching Parameters
Parameters:

HOWEVER: The following control upper-limit of cache time: Schannel is the library, the process has control

m_dwClientLifespanm_dwServerLifespanm_dwSessionTicketLifespan All of which:are set to 0x02255100 (10hrs in ms)
 Also of Interest:

m_dwMaximumEntries (set to 0x4e20 or 20,000

entries by default)

m_dwEnableSessionTicket controls use of
session tickets (e.g. 0, 1, 2)
m_dwSessionCleanupIntervalInSeconds (setto 0x012c or 300 seconds by default)

 Proc can purge its own cache at will
 For example, IIS reportedly* purges after
around two hours
 Schannel maintains track of process, frees cache
items after client proc terminates : < Haven’t looked at the exact mechanism As you’ll see, the upside is that the Process
ID is stored in the CacheThis is your Schannel Cache (x64)'_SSL_SESSION_CACHE_CLIENT_ITEM': [ 0x148, {'Vftable': [0x0, ['pointer64', ['void']]],‘MasterKey': [0x10, ['pointer64', ['void']]],'PublicCertificate': [0x18, ['pointer64', ['void']]],'PublicKey': [0x28, ['pointer64', ['void']]],'NcryptSslProv': [0x60, ['pointer64', ['void']]],'SessionIdLen': [0x86, ['short short']],'SessionId': [0x88, ['array', 0x20, ['unsigned char']]],'ProcessId': [0xa8, ['unsigned long']],'MaxLifeTime': [0xB0, ['unsigned long']],'CertSerializedCertificateChain': [0xB0, ['pointer64', ['void']]],'UnkList1Flink': [0xB8, ['pointer64', ['void']]],'UnkList1Blink': [0xC0, ['pointer64', ['void']]],'UnkCacheList2Flink': [0xC8, ['pointer64', ['void']]],'UnkCacheList2Blink': [0xD0, ['pointer64', ['void']]],'ServerName': [0x108, ['pointer64', ['void']]],‘LogonSessionUID': [0x110, ['pointer64', ['void']]],'CSessCacheManager': [0x120, ['pointer64', ['void']]],'SessionTicket': [0x138, ['pointer64', ['void']]],'SessionTicketLen': [0x140, ['int']],}],This is your Schannel Cache (x64)'_SSL_SESSION_CACHE_SERVER_ITEM': [ 0x110, {'Vftable': [0x0, ['pointer64', ['void']]],'NcryptKey': [0x10, ['pointer64', ['void']]],'NcryptSslProv': [0x60, ['pointer64', ['void']]],'SessionId': [0x88, ['array', 0x20, ['unsigned char']]],'ProcessId': [0xa8, ['unsigned long']],'MaxLifeTime': [0xB0, ['unsigned long']],'LastError?': [0xE8, ['unsigned long']],'CSslCredential': [0xF0, ['pointer64', ['void']]],}],

This is your Schannel Cache on Drugs Vista'_SSL_SESSION_CACHE_CLIENT_ITEM': [ 0xf0, {'Flink': [0x0, ['pointer', ['void']]],'Blink': [0x4, ['pointer', ['void']]],'ProcessId': [0x8, [['unsigned long']],'MasterKey': [0x14, ['pointer', ['NcryptSslKey']]],'CipherSuiteId': [0x1C, ['pointer', ['void']]],'ECCurveParam': [0x20, ['pointer', ['void']]],'NcryptSslProv': [0x28, ['pointer', ['void']]],'PublicCertificate': [0x2C, ['pointer', ['void']]],'PublicCert2': [0x34, ['pointer', ['void']]],'PublicKeyStruct': [0x3C, ['pointer', ['void']]],'PublicCertStruct3': [0x44, ['pointer', ['void']]],'ServerName': [0x80, ['pointer', ['void']]],'SessionIdSize': [0x94, ['short short']],'SessionId': [0x98, ['array', 0x20, ['unsigned char']]],'ErrorCode': [0xEC, ['pointer64', ['void']]],}],

Automating itVolatility / Rekall Plugins for both – by default (no args) they: Find LSASS Scan Writeable VADs / Heap for Master Key
signature (Volatility) or directly for
SessionCacheItems (Rekall) Dump out the wireshark format shown
earlier Hoping to have functional powershell module ormaybe incorporation into mimikatz? (Benjamin
Delphy is kinda the man for LSASS)

Limitations
 We’re working with internal, undocumented structures
 They change over time -- sometime around April 2016, an element appears to have been inserted incache after the SessionID and before the SNI Not a huge deal, except when differences amongst instances of same OS (e.g. ones that haveand have not been updated) Relying on symbols for some of this MS giveth and can taketh away.
 Still, can be done without them, just slightly less efficiently.

 You need to be able to read LSASS memory
 Not a huge deal in 2016, but still merits mention -- you need to own the system If you own the system, you can already do bad stuff (keylog / tap net interface) This is why it’s probably most useful in a forensic context

Demo

Fin.

@TinRabbit_

Questions?

Special Thanks
For general support, helpful comments, their time, and encouragement.

Áine Doyle - Badass Extraordinaire (OCSC)
Dr. John-Ross Wallrabenstein - Sypris Electronics
Dr. Marcus Rogers - Purdue Cyber Forensics Laboratory
Michael Hale Ligh (MHL) - Volexity
Tatiana Ringenberg - Sypris Electronics