Merlin Goes OPAQUE for Key Exchange

Aug 20 2019
Share
By: Russel Van Tuyl • 0 min read

This post will introduce the implementation of the password authenticated key exchange OPAQUE protocol into Merlin to ultimately encrypt message traffic. If you’re not familiar with Merlin, you can read the introductory post here. In short, Merlin is a post-exploit Command and Control (C2) used during authorized penetration tests or red team assessments.

Merlin has relied on Transport Layer Security (TLS) and ephemeral cipher suites with Perfect Forward Secrecy (PFS) to keep the contents of message traffic between the agent and server encrypted. The actual HTTP body has always been a plain-text JSON message. This works OK for traffic moving across the internet but has obstacles when an internal network proxy is introduced. Normally Merlin traffic inspection is not possible with proxies that perform inline SSL/TLS inspection by decrypting traffic with a key. This is due to the use of ephemeral cipher suites that require a session key only known to the client and the server. However, some organizations leverage a SSL/TLS proxy that terminates a TLS connection so that the message contents can be inspected. After inspection, a new (second) TLS connection is established from the proxy to the Merlin server. Because of this, I wanted to find a way to encrypt HTTP payload messages to prevent defensive tools from reading Merlin message traffic in plain-text.

My first attempt was to have both the server and the agent generate a new RSA key pair, exchange public keys, and then begin encrypting message traffic using those keys. This seemed sound to me because public keys are meant to be public and there shouldn’t be any risk associated with someone recovering the public keys. What I didn’t account for were attacks against distributing the public keys. One of the main problems is that a prepositioned attacker could modify the public keys during the initial exchange so that both parties use a public key the attacker controls. To combat this vulnerability, tools such as Apfell, Covenant, and Empire leverage Encrypted Key Exchange (EKE).

Encrypted Key Exchange (EKE)

EKE at a high level starts with Alice first encrypting her asymmetric public key with a symmetric pre-shared key (a password), shown as Kw, and sends it to Bob. Because the password was shared out-of-band, hence the pre-shared part, an attacker would not be able to decrypt the message and tamper with the public key. This assumes a strong password was used and an attacker would not be able to brute force it. Next Bob generates a key pair and then derive a new symmetric session key (K) using Alice’s public key. Bob will send his public key and a challenge to Alice’s encrypted with the PSK. Alice is now able to derive the same symmetric session key (K) using Bob’s public key. Both parties will now use the session key (K) to encrypt all further messages.

An alternative to transfering asymmetric key encrypted with a PSK is to pre-share the asymmetric keys so there is no distribution to attack. This can be seen in other tools like Cobalt Strike. I wanted the flexibility to use any compiled Merlin agent binary to communicate with the server in the name of ease of use. This would preclude the need to generate new executables per Merlin server instance.

During my research to understand EKE, I discovered that it is a subset of the Password Authenticated Key Exchange (PAKE) concept. I wanted to understand PAKE at a deeper level to ensure that EKE was the best choice. There are two main categories of PAKE, balanced and augmented. EKE is a balance PAKE where the same password is used to negotiate and authenticate a shared key to encrypt subsequent communications[1]. Augmented PAKE (aPAKE) is when the server does not store a user’s password in any form (plain-text or hash). Based on this information, I decided that I wanted to use an augmented PAKE. Additional research showed that there were multiple implementations of aPAKE and each had their pros and cons. I was initially drawn to Secure Remote Protocol (SRP), used with Apple’s iCloud KeyChain[2] until I stumbled across a paper titled OPAQUE: An Asymmetric PAKE Protocol Secure Against Pre-Computation Attacks by Stanislaw Jarecki, Hugo Krawczyk, and Jiayu Xu. The main advantages of OPAQUE according to a draft protocol specification are:

“…supports mutual authentication in a client-server setting without any reliance on PKI. OPAQUE is the first PKI-free aPAKE to accommodate secret salt and therefore it is the first to be secure against pre-computation attacks upon server compromise. In contrast, prior aPAKE protocols did not use salt and if they did, the salt was transmitted in the clear from server to user allowing for the building of targeted pre-computed dictionaries. OPAQUE security has been proven by Jarecki et al. (Eurocrypt 2018) in a strong and universally composable formal model of aPAKE security. In addition, the protocol provides forward secrecy and the ability to hide the password from the server even during password registration.”

There is a great article by Prof Bill Buchanan OBE that explains OPAQUE in an easy to digest manner to include a short video presentation. The main advantages I wanted to utilize were forward secrecy and the use of an encrypted “envelope” that can only be decrypted with knowledge of the information used during registration. Additionally, I found the OPAQUE RFC as the best place for a first stop into the technical details of the protocol. It does a good job of explaining things along with the associated math behind each step without getting too academic.

The augmented Password Authenticated Key Exchange OPAQUE protocol has been implemented into Merlin to derive a symmetric encryption key that is used to encrypt all subsequent message traffic. The protocol is composed of two main steps, registration and authentication.

Registration

 

OPAQUE Registration — Step 1

In order to establish an “account” with a server, a user must first complete the OPAQUE registration. In the case of this post, the user is a Merlin agent. A user will begin registration by choosing a password (PwdU) along with a private key (PrivU) and a public key (PubU) used later with a key exchange protocol during authentication. These are Edwards-curve Digital Signature Algorithm (EdDSA) Curve25519 (Ed25519) elliptic curve keys. The Merlin implentation generates PwdU by creating a random 30-character string and running it through 5,000 iterations of PBKDF2. It is important to note that user’s password (PwdU) is never transmitted across a network.

Next, the user will take the password (PwdU) and a cryptographic generator as inputs to a hash function that will result in a cryptographic point in a public-key group known as Alpha. Registration begins with the user sending Alpha and its user ID to the server. For Merlin, the user ID is the agent’s UUID created at run time.

The message containing the user ID and Alpha is encrypted with a Pre-Shared Key (PSK) that was established through an out-of-band communication channel. Encrypting the message payload is only a feature of Merlin and is not required for the OPAQUE protocol. The PSK provides an initial method to authenticate the agent to the server. If the wrong PSK is used, the server will not be able to decrypt the message and therefore not able to process the message. If the server is able to decrypt the message, then both parties are using the previously agreed upon PSK.

The default PSK is merlin and is unique per Merlin server interface instance. All agents will use this PSK when performing registration. The PSK can be changed for both the server interface and agent at run time.

An attacker could attempt to brute-force the PSK and retrieve the contents of the message (UserID and Alpha). However, OPAQUE assumes that an attacker is able to recover Alpha and doing so has no impact on the ability to recover PwdU.

OPAQUE Registration — Step 2

The server begins registration by creating private key (PrivS), public key (PubS), and a per-user OPRF key (kU), also known as a secret salt. OPAQUE is resistant against pre-computation attacks due to this secret salt that is unique to each user and never transmitted across a network. This key (kU) is used to compute salt2, known as V. Salt2, sometimes called vU, is like a public key to the private key kU.

The server calculates Beta using the Alpha value provided by the user and the key (kU). The server’s public key (PubS), salt2 (V), and Beta are encrypted using the PSK and returned to the user. OPAQUE assumes that an attacker is able to recover PubS, Beta, and V.

OPAQUE Registration — Step 3

The user executes an Oblivious Psuedo-Random Function(OPRF) providing its password (PwdU) along with the Beta and V values returned by the server as inputs. The OPRF outputs a random password (RwdU) only known to the user. It is important to note that the server never has the user’s password and is unable to calculate RwdU.

The user’s private key (PrivU), the user’s public key (PubU), and the server’s public key (PubS) are encrypted with RwdU into a single “envelope” denoted as EnvU. The user sends its public key (PubU) and the encrypted envelope (EnvU) to the server for storage. The a diagram of the complete OPAQUE registration process is below:

OPAQUE Registration

Authentication

A user can now use OPAQUE to authenticate to the server having previously completed registration. Registration only occurs once but the authentication process occurs each subsequent time the user wants to establish a session with the server. The authentication process is also used as an authenticated Diffie-Hellman key exchange mechanism, using the SIGMA-I protocol, to derive a shared secret (S). The technical details of the SIGMA-I key exchange messages can be found in the OPAQUE RFC but will not be discussed in detail in this post.

OPAQUE Authentication — Step 1

The user will start the authentication process only knowing the password (PwdU) and without having its private (PrivU) and public (PubU) keys generated during registration. This follows the traditional authentication process where a user only knows their password and wants to authenticate to a service at some time after registration. The Merlin implementation only performs registration and authentication once at the time of instantiation. If the agent dies, registration and authentication will start over.

To begin authentication, the user will generate Alpha using the same method defined in registration; by using the password (PwdU) as input to a hashing function. The first message in the SIGMA-I protocol key exchange (K1) will be created and sent to the server along with Alpha and user’s ID. These values are encrypted using the Merlin PSK and is only a feature of Merlin and is not required for the OPAQUE protocol.

OPAQUE Authentication Step 2

The server receives Alpha from the user and calculates Beta using the same method defined in registration. The server will look up the per-user OPRF key (kU) and use it to generate salt2 (V). The server will also look up the encrypted envelope (EnvU) provided by the user during OPAQUE registration by the provided UserID. Additionally, the server will calculate the second key exchange message (K2) using its private key (PrivS) and K1 as is inputs. Beta, V, EnvU, and K2 are sent to the user. The server is able to derive the secret (S) at this point from the material in the SIGMA-I Diffie-Hellman key exchange messages one (K1) and two (K2).

OPAQUE Authentication — Step 3

The user receives Beta and V from the server and calculates RwdU using the same method defined in registration; by running the OPRF function. The encrypted envelop (EnvU) is decrypted using RwdU, allowing the user to extract their private key (PrivU), public key (PubU), and the server’s public key (PubS). The user derives a symmetric key (S) using its private key (PrivU) extracted from EnvU along with K2 sent by the server. To finish authentication, the user will send the third, and last, key exchange message (K3) to the server. This message is encrypted with the symmetric key (S) instead of the PSK.

The server and the client have both established a symmetric key (S) that will be used to encrypt all further communications between the server and agent.

OPAQUE Authentication

Attacks

A prepositioned attacker that captures the Alpha, Beta, and V values that traverse the network will not be able to derive RwdU. Without RwdU an attacker can’t decrypt a captured EnvU, the envelope containing the user’s public key. Without the user’s private key, the symmetric encryption key (K) can’t be derived.

The only way an attacker can calculate RwdU is to know the user’s password (PwdU) in addition to capturing Alpha, Beta, and V. An attacker can’t reasonably brute force the user’s password (PwdU) only having Alpha, Beta, and V. It would be like trying to recover a private key only having the public key.

If an attacker compromises a server and recovers the encrypted envelope (EnvU) and the secret salt (kU), then an offline brute-force attack could be conducted. The attacker would need to generate Alpha, Beta, and V

If an attacker attempts an online attack by guessing PwdU, then the generated Alpha value will be wrong. The server will return a wrong Beta value because it is derived from Alpha. Without the right PwdU, Alpha, Beta, and V values, an attacker could not decrypt EnvU. The ability to successfully decrypt EnvU could be used to verify PwdU was successfully recovered. This online attack also requires the attacker to first know a valid user ID in order for the server to find the previously stored EnvU. For merlin, the user ID is a Universally Unique ID (UUID).

Due to Merlin’s implementation, each guess would at the user’s password (PwdU) will also endure 5,000 rounds of the PBKDF2 hashing algorithm. The attacker will also need to have brute-forced, or recovered, the PSK used to encrypt the OPAQUE message traffic.

Prism

Starting with Merlin version 0.8.0, the Pre-Shared Key (PSK) used to encrypt OPAQUE traffic is simply merlin. If you download and run the server and agent, without any configurations, this is the PSK that will be used. This is good for ease of use because you can get started with encrypted messages without having to do a thing. However, this is extremely bad for Operations Security (OPSEC) for an actual assessment. The PSK is now publicly known, meaning anyone is able to decrypt message traffic containing OPAQUE registration and authentication messages. As an operator you should change the PSK to basically anything other than Merlin. This can be done at run time with the -psk command line flag or at compile time using the PSK=PASSWORD argument when using the Make file.

In order to deter operators from using the stock “merlin” PSK, I’m also releasing PRISM. The PRISM tool continues the HTTP/2 magic connection string storyline by providing a way to fingerprint Merlin server’s using a stock configuration. The application sends an OPAQUE registration request to the target server, encrypting the payload with the provided PSK. If the server responds with a message PRISM can decrypt, then target server is verified as running an instance of the Merlin server. The PSK that PRISM uses can be changed at run time with the -psk command line argument.

PRISM Output

I also extended this to fingerprint Merlin v0.7.0 and earlier instances. This is done by creating a Merlin StatusCheckIn message, JSON encoding it, and sending it to the target server. If the agent receives a valid Merlin AgentControl message from the server, then the target server is verified as running Merlin.

Conclusion

This update to Merlin brings with it message payload encryption. The augmented Password Authenticated Key Exchange (aPAKE) OPAQUE protocol is used to establish an authenticated session with the server and derive a symmetric encryption key. The derived key is subsequently used to encrypt all Merlin payload traffic.

The OPAQUE protocol affords many advantages precluding the server from storing a user’s password and by leveraging a secret salt. An attacker could intercept the OPAQUE message traffic but would not be able to impact or derive the symmetric encryption key used to encrypt message traffic.

This release is a big step forward in OPSEC by encrypting HTTP payload message traffic. This means that intercepting proxies might be able to see the HTTP connection information and headers but will not be able to see the actual Merlin messages and data. The PRISM binary can be used to enumerate Merlin servers, especially those using the default PSK. This is a gentle nudge to continue good OPSEC by not using a stock configuration.

References

[1]http://cryptowiki.net/index.php?title=Password-authenticated_key_agreement

[2]https://hackmag.com/uncategorized/in-the-depths-of-icloud-keychain/

OPAQUE: An Asymmetric PAKE Protocol Secure Against Pre-Computation Attacks https://eprint.iacr.org/2018/163.pdf

Empire Staging https://www.powershellempire.com/?page_id=147

Stack Overflow: Encrypted Key Exchange understanding https://stackoverflow.com/questions/15779392/encrypted-key-exchange-understanding

Let’s talk about PAKE https://blog.cryptographyengineering.com/2018/10/19/lets-talk-about-pake/

Towards a More OPAQUE World … Where Passwords or Hashed Password Are Not Stored On Servers https://medium.com/asecuritysite-when-bob-met-alice/towards-a-more-opaque-world-where-passwords-or-hashed-password-are-not-stored-on-servers-dfe200496595

The OPAQUE Asymmetric PAKE Protocol draft-krawczyk-cfrg-opaque-02 https://tools.ietf.org/html/draft-krawczyk-cfrg-opaque-02

SIGMA: the ‘SIGn-and-MAc’ Approach to Authenticated Diffie-Hellman and its Use in the IKE Protocols http://webee.technion.ac.il/~hugo/sigma-pdf.pdf

Edwards-Curve Digital Signature Algorithm (EdDSA) https://tools.ietf.org/html/rfc8032