So, I did my own research, and here are my findings:
So the first message being sent is always the Pre-Login (§2.2.1.1):
Before a login occurs, a Pre-Login handshake occurs between client and server, setting up contexts such as encryption and MARS-enabled. For more details, see section 2.2.6.5.
The very first message is a Pre-Login Message, which include the clients version number and a set of Pre-Login Option Tokens, among which is token 0x01 ENCRYPTION
, which has the following values for the client:
ENCRYPT_OFF = 0x00
: Encryption is available but off.
ENCRYPT_ON = 0x01
: Encryption is available and on.
ENCRYPT_NOT_SUP = 0x02
: Encryption is not available.
ENCRYPT_REQ = 0x03
: Encryption is required.
After this, the server responds with a Pre-Login Response, which mostly contains the server's version number, as well as its own set of Pre-Login Option Tokens, which also contain the server's Encryption capabilities.
The following table describes the behavior, depending on what both client and server have negotiated:
Client |
Value returned from server is ENCRYPT_OFF |
Value returned from server is ENCRYPT_ON |
Value returned from server is ENCRYPT_REQ |
Value returned from server is ENCRYPT_NOT_SUP |
ENCRYPT_OFF |
Encrypt login packet only |
Encrypt Entire Connection |
Encrypt Entire Connection |
No Encryption |
ENCRYPT_ON |
Error (Terminate Connection) |
Encrypt Entire Connection |
Encrypt Entire Connection |
Error (Terminate Connection) |
As you can see, even if both server and client have encryption disabled (both send 0x00
as their encryption capabilities), they still send the LOGIN7 stream described in §2.2.6.4 encrypted via TLS, encapsulated within a PRE-LOGIN packet. This process is described in §2.2.6.5.
A downgrade attack
By intercepting the communication between the client and the server, the value of the encryption token can be set to 0x02 ENCRYPT_NOT_SUP
, which works when both client and server don't require fully encrypted connections.
The client will believe they support encryption, but the server doesn't, so it falls back to the case where nothing will be encrypted. The server will also believe they support encryption, but the client doesn't, and will thus also fall back to fully unencrypted connections. Note that this only works when the client natively sends ENCRYPT_OFF
. If the client sends ENCRYPT_ON
, then downgrading the server's response to ENCRYPT_NOT_SUP
will lead to connection termination.
After the connection has successfully been downgraded to plain text, then the process described in gowenfawr's answer can be used to retrieve the credentials.
For server administrators
This attack can be prevented by configuring both clients and servers to always use encryption and refuse any connection attempt that is not encrypted.