Needham-Schroeder Replay Attacks (EC)
The goals of this assignment are to:
- Gain experience with key agreement protocols for symmetric key exchange over untrusted networks
- Implement a “stolen ticket” attack against Needham-Schroeder
This assignment is extra credit and to be completed individually.
Needham-Schroeder (NS) is a session key agreement protocol that was adapted for the Kerberos network authentication protocol. It is a classic example of a protocol that was proven to be secure, only to later be found to be vulnerable to an attack due to flaws in the formal model used to verify its security. In particular, if an attacker steals a session key and corresponding ticket that was previously issued by the authentication server to a victim client, they can replay the last three steps of the NS protocol and authenticate as the victim.
For reference, the version of NS used here is the following. Let Alice \(A\) and Bob \(B\) be two parties that trust server \(S\) but not each other. Alice wants to prove her identity to Bob. Let \(K_{A,S}, K_{B,S}\) be shared secrets between \(A,S\) and \(B,S\) and \(N_A,N_B\) be nonces generated by \(A,B\). Finally, let \(T\) be a ticket expiration expressed as seconds since UNIX epoch that is enforced iff \(T \neq 0\). \[ \begin{align*} A \rightarrow S &: A,B,N_A \\ S \rightarrow A &: \left\{ N_A, K_{A,B}, B, \left\{ K_{A,B}, A, T \right\}_{K_{B,S}} \right\}_{K_{A,S}} \\ A \rightarrow B &: \left\{ K_{A,B}, A, T \right\}_{K_{B,S}} \\ B \rightarrow A &: \left\{ N_B \right\}_{K_{A,B}} \\ A \rightarrow B &: \left\{ N_B - 1 \right\}_{K_{A,B}} \\ \end{align*} \]
In this assignment, you are given two pairs of “stolen” tickets and session keys. Your goal is to authenticate to a service using each of these. The “eternal” ticket does not expire (i.e., \(T = 0\)). The other, however, is only valid for a short time window.
The authentication server runs on
class.diverge.dev:1401/tcp
. This NS implementation uses protobuf
v3. Messages are defined as follows:
syntax = "proto3";
package wire;
// Network messages.
//
// Each message sent over the network can be an encrypted message or a plaintext error message.
message WireMessage {
oneof m {
Encrypted encrypted = 1;
string error = 2;
}
}
// Encrypted messages.
//
// The ciphertext decrypts to one of the messages below.
message Encrypted {
bytes ciphertext = 1;
bytes nonce = 2;
}
message Ticket {
bytes session_key = 1;
string client_principal = 2;
uint64 timestamp = 3;
}
message Challenge {
bytes nonce = 1;
}
message ChallengeResponse {
bytes nonce_sub_1 = 1;
}
message Authenticated {}
message Request {
string challenge = 1;
}
message Response {
bytes response = 1;
}
All messages sent over the network are WireMessage
s,
which are in turn either a plaintext error message or an
Encrypted
message. Message encryption is performed using libsodium; a compatible
python implementation is provided by pysodium.
Encrypted
messages are a combination of a nonce and
ciphertext produced using libsodium’s secretbox
API.
As the attacker \(M\), you should
use your stolen ticket and session key to engage in the following
protocol which consists of the last three steps of NS followed by an
authenticated request-response pair. Each message should be prepended by
its two-byte, big-endian length as usual. Also, the tickets you are
given are serialized WireMessage
s. Finally, the NS
challenge nonce (which is different from the libsodium
encryption nonce) should be treated as a little-endian
integer.
\[ \begin{align*} M \rightarrow S &: \mathsf{u16}(|\mathsf{Ticket}|) \cdot \mathsf{Ticket} \\ S \rightarrow M &: \mathsf{u16}(|\mathsf{Challenge}|) \cdot \mathsf{Challenge} \\ M \rightarrow S &: \mathsf{u16}(|\mathsf{ChallengeResponse}|) \cdot \mathsf{ChallengeResponse} \\ S \rightarrow M &: \mathsf{u16}(|\mathsf{Authenticated}|) \cdot \mathsf{Authenticated} \\ M \rightarrow S &: \mathsf{u16}(|\mathsf{Request}|) \cdot \mathsf{Request} \\ S \rightarrow M &: \mathsf{u16}(|\mathsf{Response}|) \cdot \mathsf{Response} \\ \end{align*} \]
Your attack should use your @northeastern.edu
email
address as the client principal. Having obtained a Response
message, it should output a base64-encoded response in the following
JSON object:
{
"id": "{{client_principal}}",
"response": "{{response}}"
}
Submission Instructions
Submit to Canvas a TAR archive containing your code and the JSON objects output by your code for each ticket you successfully replay.