From 0da4ad0963649da5505272eaed0eaf5296e289e9 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sat, 5 Oct 2013 23:47:12 +0200 Subject: [PATCH 1/1] Initial commit. --- ntlmssp.cpp | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 ntlmssp.cpp diff --git a/ntlmssp.cpp b/ntlmssp.cpp new file mode 100644 index 0000000..84381b2 --- /dev/null +++ b/ntlmssp.cpp @@ -0,0 +1,211 @@ +// Extracts NTMLSSP challenge/authentication pairs from a pcap file, +// into a format crackable by the “jumbo” edition of John the Ripper. +// Heavily inspired by https://github.com/psychomario/ntlmsspparse/blob/master/ntlmssp.py, +// but infinitely faster. +// +// The struct definitions were lifted from ChromeOS, who probably +// lifted them from some specification. They have been adapted a bit. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +enum ntlmssp_message_type +{ + NTLMSSP_NEGOTIATE = 1, + NTLMSSP_CHALLENGE = 2, + NTLMSSP_AUTH = 3, + NTLMSSP_UNKNOWN = 4, +}; + +#define NTLMSSP_SIGNATURE "NTLMSSP" +#define CIFS_CRYPTO_KEY_SIZE (8) + +typedef struct _SECURITY_BUFFER { + uint16_t Length; + uint16_t MaximumLength; + uint32_t BufferOffset; /* offset to buffer */ +} __attribute__((packed)) SECURITY_BUFFER; + +struct _NTLM_MESSAGE { + uint8_t Signature[sizeof(NTLMSSP_SIGNATURE)]; + uint32_t MessageType; +}; + +typedef struct _NEGOTIATE_MESSAGE { + uint8_t Signature[sizeof(NTLMSSP_SIGNATURE)]; + uint32_t MessageType; /* NtLmNegotiate = 1 */ + uint32_t NegotiateFlags; + SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */ + SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */ + /* SECURITY_BUFFER for version info not present since we + do not set the version is present flag */ + char DomainString[0]; + /* followed by WorkstationString */ +} __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; + +typedef struct _CHALLENGE_MESSAGE { + uint8_t Signature[sizeof(NTLMSSP_SIGNATURE)]; + uint32_t MessageType; /* NtLmChallenge = 2 */ + SECURITY_BUFFER TargetName; + uint32_t NegotiateFlags; + uint8_t Challenge[CIFS_CRYPTO_KEY_SIZE]; + uint8_t Reserved[8]; + SECURITY_BUFFER TargetInfoArray; + /* SECURITY_BUFFER for version info not present since we + do not set the version is present flag */ +} __attribute__((packed)) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; + +typedef struct _AUTHENTICATE_MESSAGE { + uint8_t Signature[sizeof(NTLMSSP_SIGNATURE)]; + uint32_t MessageType; /* NtLmsAuthenticate = 3 */ + SECURITY_BUFFER LmChallengeResponse; + SECURITY_BUFFER NtChallengeResponse; + SECURITY_BUFFER DomainName; + SECURITY_BUFFER UserName; + SECURITY_BUFFER WorkstationName; + SECURITY_BUFFER SessionKey; + uint32_t NegotiateFlags; + /* SECURITY_BUFFER for version info not present since we + do not set the version is present flag */ + char UserString[0]; +} __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; + +#define NTLMSSP_FEATURE_SESSION_KEY 0x00000001 +#define NTLMSSP_FEATURE_SIGN 0x00000002 +#define NTLMSSP_FEATURE_SEAL 0x00000004 +#define NTLMSSP_FEATURE_CCACHE 0x00000008 + +struct quintuple { + uint32_t saddr, daddr; + uint16_t sport, dport; + + bool operator< (const quintuple &o) const { + if (saddr != o.saddr) + return saddr < o.saddr; + if (daddr != o.daddr) + return daddr < o.daddr; + if (sport != o.sport) + return sport < o.sport; + return dport < o.dport; + } +}; + +map prev_packets; + +string to_ascii(const SECURITY_BUFFER &buf, const void *base) { + const char *str = (char *)base + buf.BufferOffset; + + string ret; + for (int i = 0; i < buf.Length; ++i) { + if (str[i] == 0) { + // poor man's UTF-16 conversion :-) + continue; + } + ret.push_back(str[i]); + } + return ret; +} + +string to_hex(const SECURITY_BUFFER &buf, const void *base) { + const uint8_t *str = (uint8_t *)base + buf.BufferOffset; + + string ret; + char tmp[256]; + for (int i = 0; i < buf.Length; ++i) { + sprintf(tmp, "%02x", str[i]); + ret += tmp; + } + return ret; +} + +string to_hex(const uint8_t *start, const uint8_t *end) { + string ret; + char tmp[256]; + for (const uint8_t *ptr = start; ptr != end; ++ptr) { + sprintf(tmp, "%02x", *ptr); + ret += tmp; + } + return ret; +} + +void my_callback(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) +{ + int len = h->caplen; + if (len < 40) { + //printf("skipped short packet\n"); + return; + } + if (bytes[12] != 0x08 || bytes[13] != 0x00) { + //printf("skipped non-IPv4 packet\n"); + return; + } + const struct iphdr *ip = (const struct iphdr *)(bytes + 14); + const struct tcphdr *tcp = (const struct tcphdr *)(bytes + 14 + sizeof(*ip)); + const u_char *data = bytes + 14 + sizeof(*ip) + sizeof(*tcp); + if (data > bytes + len) { + return; + } + const u_char *ntlmssp = (const u_char *)memmem(data, (bytes + len) - data, "NTLMSSP", 7); + if (ntlmssp == NULL) { + return; + } + + quintuple invq; + invq.saddr = ip->daddr; + invq.daddr = ip->saddr; + invq.sport = tcp->dest; + invq.dport = tcp->source; + + auto it = prev_packets.find(invq); + if (it == prev_packets.end()) { + const _CHALLENGE_MESSAGE *challenge = reinterpret_cast(ntlmssp); + if (challenge->MessageType != NTLMSSP_CHALLENGE || ntlmssp + sizeof(_CHALLENGE_MESSAGE) > bytes + len) { + return; + } + quintuple q; + q.saddr = ip->saddr; + q.daddr = ip->daddr; + q.sport = tcp->source; + q.dport = tcp->dest; + prev_packets.insert(make_pair(q, string(ntlmssp, bytes + len))); + return; + } + + const _CHALLENGE_MESSAGE *challenge = reinterpret_cast(it->second.data()); + const _AUTHENTICATE_MESSAGE *auth = reinterpret_cast(ntlmssp); + + if (auth->MessageType != NTLMSSP_AUTH || ntlmssp + sizeof(_AUTHENTICATE_MESSAGE) > bytes + len) { + return; + } + + printf("%s::%s:%s:%s:%s\n", + to_ascii(auth->UserName, auth).c_str(), + to_ascii(auth->DomainName, auth).c_str(), + to_hex(auth->LmChallengeResponse, auth).c_str(), + to_hex(auth->NtChallengeResponse, auth).c_str(), + to_hex(challenge->Challenge, challenge->Challenge + CIFS_CRYPTO_KEY_SIZE).c_str()); + + prev_packets.erase(it); +} + +int main(int argc, char **argv) +{ + pcap_t *pcap = pcap_open_offline(argv[1], NULL); + pcap_activate(pcap); + pcap_loop(pcap, -1, my_callback, NULL); + return 0; +} + -- 2.39.2