Kerberos
The goals of this assignment are to:
- Gain experience with key agreement protocols for symmetric key exchange over untrusted networks
- Implement the classic “stolen ticket” attack against Needham-Schroeder
The original version of Needham-Schroeder (NS) is known to be vulnerable to replay attacks. In particular, if an attacker steals a session key and corresponding ticket, they can replay the last three steps of the NS protocol and authenticate as the victim. In this lab, you are given a “stolen” ticket and session key. Your goal is to authenticate to a service using these before the ticket expires.
The server for this lab runs on
netsec.cyberops.institute
on port 1400/tcp
.
The stolen session keys and tickets are located in
/tmp
.
This NS implementation uses Google Protocol Buffers, documented here. Messages are defined as follows:
syntax = "proto3";
package wire;
// Network messages.
//
// The ciphertext decrypts to one of the messages below.
message WireMessage {
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_add_1 = 1;
}
message Authenticated {}
message Request {
string command = 1;
}
message Response {
bytes output = 1;
}
All messages sent over the network are WireMessage
s.
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
Needham-Schroeder 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}(|\left\{\mathsf{WireMessage(Challenge)}\right\}_{K}|) \cdot \left\{\mathsf{WireMessage(Challenge)}\right\}_{K} \\ M \rightarrow S &: \mathsf{u16}(|\left\{\mathsf{WireMessage(ChallengeResponse)}\right\}_{K}|) \cdot \left\{\mathsf{WireMessage(ChallengeResponse)}\right\}_{K} \\ S \rightarrow M &: \mathsf{u16}(|\left\{\mathsf{WireMessage(Authenticated)}\right\}_{K}|) \cdot \left\{\mathsf{WireMessage(Authenticated)}\right\}_{K} \\ M \rightarrow S &: \mathsf{u16}(|\left\{\mathsf{WireMessage(Request)}\right\}_{K}|) \cdot \left\{\mathsf{WireMessage(Request)}\right\}_{K} \\ S \rightarrow M &: \mathsf{u16}(|\left\{\mathsf{WireMessage(Response)}\right\}_{K}|) \cdot \left\{\mathsf{WireMessage(Response)}\right\}_{K} \\ \end{align*} \]
Once you are able to successfully replay the ticket, issue a command
using a Request
message to exfiltrate a flag located on the
server.
Submission Instructions
Submit your code and the flag (if obtained) to Canvas.