Added mpsHighSecurity option in config.json, #3910

Ylian Saint-Hilaire committed Apr 23, 2022 at 13:17 UTC fc60faefba0f75b5919c6d37043cab8a4e33e2c1
5 files changed +268 -28
apprelays.js
+1 -1
@@ -36,6 +36,7 @@ const PROTOCOL_WEBVNC = 204;
36
37
38 // Construct a MSTSC Relay object, called upon connection
39 +// This implementation does not have TLS support
40 // This is a bit of a hack as we are going to run the RDP connection thru a loopback connection.
41 // If the "node-rdpjs-2" module supported passing a socket, we would do something different.
42 module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
@@ -282,7 +283,6 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
283 };
284
285
285 -
286 // Construct a SSH Relay object, called upon connection
287 module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
288 const Net = require('net');
meshcentral-config-schema.json
+10 -9
@@ -156,16 +156,17 @@
156 },
157 "tlsOffload": { "type": [ "boolean", "string" ], "default": false, "description": "When true, indicates that a TLS offloader is in front of the MeshCentral server. More typically, set this to the IP address of the reverse proxy or TLS offloader so that IP forwarding headers will be trusted. For example: \"127.0.0.1,192.168.1.100\"." },
158 "trustedProxy": { "type": "string", "default": null, "description": "Trust forwarded headers from these IPs or domains. Providing the magic string \"CloudFlare\" will cause the server to download the IP address list of trusted CloudFlare proxies directly from CloudFlare on each server start. For example: \"127.0.0.1,proxy.example.com,CloudFlare\"." },
159 - "mpsPort": { "type": "integer", "minimum": 1, "maximum": 65535 },
160 - "mpsPortBind": { "type": "string" },
161 - "mpsAliasPort": { "type": "integer", "minimum": 1, "maximum": 65535 },
162 - "mpsAliasHost": { "type": "string" },
163 - "mpsTlsOffload": { "type": "boolean", "default": false },
159 + "mpsPort": { "type": "integer", "minimum": 0, "maximum": 65535, "default": 4433, "description": "The Management Presence Server (MPS), this is the server that received Intel AMT Client Initiated Remote Access (CIRA) connections." },
160 + "mpsPortBind": { "type": "string", "default": null },
161 + "mpsAliasPort": { "type": "integer", "minimum": 1, "maximum": 65535, "default": null },
162 + "mpsAliasHost": { "type": "string", "default": null },
163 + "mpsTlsOffload": { "type": "boolean", "default": false, "description": "When set to true, indicate that TLS is being performed by a device in front of MeshCentral." },
164 + "mpsHighSecurity": { "type": "boolean", "default": false, "description": "When set to true, the MPS server will only accept TLS 1.2 and 1.3 connections. Older Intel AMT devices will not be able to connect." },
165 "no2FactorAuth": { "type": "boolean", "default": false },
165 - "log": { "type": "string" },
166 - "syslog": { "type": "string" },
167 - "syslogauth": { "type": "string" },
168 - "syslogjson": { "type": "string" },
166 + "log": { "type": "string", "default": null },
167 + "syslog": { "type": "string", "default": null },
168 + "syslogauth": { "type": "string", "default": null },
169 + "syslogjson": { "type": "string", "default": null },
170 "syslogtcp": { "type": "string", "default": null, "description": "Send syslog events over the network (RFC3164) to a target hostname:port. For example: localhost:514" },
171 "webrtcConfig": {
172 "type": "object",
mpsserver.js
+7 -2
@@ -43,8 +43,13 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
43 if (obj.args.mpstlsoffload) {
44 obj.server = net.createServer(onConnection);
45 } else {
46 - // Note that in order to support older Intel AMT CIRA connections, we have to turn on TLSv1.
47 - obj.server = tls.createServer({ key: certificates.mps.key, cert: certificates.mps.cert, minVersion: 'TLSv1', requestCert: true, rejectUnauthorized: false, ciphers: "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA", secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION }, onConnection);
46 + if (obj.args.mpshighsecurity) {
47 + // Higher security TLS 1.2 and 1.3 only, some older Intel AMT CIRA connections will fail.
48 + obj.server = tls.createServer({ key: certificates.mps.key, cert: certificates.mps.cert, requestCert: true, rejectUnauthorized: false, ciphers: "HIGH:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:TLS_CHACHA20_POLY1305_SHA256", secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE | constants.SSL_OP_NO_TLSv1 | constants.SSL_OP_NO_TLSv1_1 }, onConnection)
49 + } else {
50 + // Lower security MPS in order to support older Intel AMT CIRA connections, we have to turn on TLSv1.
51 + obj.server = tls.createServer({ key: certificates.mps.key, cert: certificates.mps.cert, minVersion: 'TLSv1', requestCert: true, rejectUnauthorized: false, ciphers: "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA", secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION }, onConnection)
52 + }
53 //obj.server.on('error', function () { console.log('MPS tls server error'); });
54 obj.server.on('newSession', function (id, data, cb) { if (tlsSessionStoreCount > 1000) { tlsSessionStoreCount = 0; tlsSessionStore = {}; } tlsSessionStore[id.toString('hex')] = data; tlsSessionStoreCount++; cb(); });
55 obj.server.on('resumeSession', function (id, cb) { cb(null, tlsSessionStore[id.toString('hex')] || null); });
package.json
+2 -16
@@ -36,8 +36,6 @@
36 "sample-config-advanced.json"
37 ],
38 "dependencies": {
39 - "@yetzt/nedb": "^1.8.0",
40 - "archiver": "^4.0.2",
39 "body-parser": "^1.19.0",
40 "cbor": "~5.2.0",
41 "compression": "^1.7.4",
@@ -45,25 +43,13 @@
43 "express": "^4.17.0",
44 "express-handlebars": "^5.3.5",
45 "express-ws": "^4.0.0",
48 - "html-minifier": "^4.0.0",
49 - "image-size": "^1.0.1",
46 "ipcheck": "^0.1.0",
51 - "jsdom": "^19.0.0",
52 - "loadavg-windows": "^1.1.1",
53 - "minify-js": "^0.0.4",
47 "minimist": "^1.2.5",
48 "multiparty": "^4.2.1",
49 + "@yetzt/nedb": "^1.8.0",
50 "node-forge": "^1.0.0",
57 - "node-rdpjs-2": "^0.3.5",
58 - "node-windows": "^0.1.4",
59 - "otplib": "^10.2.3",
60 - "pg": "^8.7.1",
61 - "pgtools": "^0.3.2",
62 - "ssh2": "^1.9.0",
63 - "web-push": "^3.4.5",
51 "ws": "^5.2.3",
65 - "yauzl": "^2.10.0",
66 - "yubikeyotp": "^0.2.0"
52 + "yauzl": "^2.10.0"
53 },
54 "engines": {
55 "node": ">=10.0.0"
test.js new
+248
@@ -0,0 +1,248 @@
1 +/*
2 +YST: create_negotiate_message: 4e544c4d53535000010000003582086000000000000000000000000000000000
3 +WRITE: negotiate_message 302fa003020102a12830263024a02204204e544c4d53535000010000003582086000000000000000000000000000000000
4 +READ: read_ts_server_challenge 3081b2a003020106a181aa3081a73081a4a081a104819e4e544c4d53535000020000000e000e003800000035828a62f2290572b3cac375000000000000000058005800460000000a00614a0000000f430045004e005400520041004c0002000e00430045004e005400520041004c0001000e00430045004e005400520041004c0004000e00430065006e007400720061006c0003000e00430065006e007400720061006c0007000800afbc2c2a9256d80100000000
5 +YST: read_challenge_message1: 4e544c4d53535000020000000e000e003800000035828a62f2290572b3cac375000000000000000058005800460000000a00614a0000000f430045004e005400520041004c0002000e00430045004e005400520041004c0001000e00430045004e005400520041004c0004000e00430065006e007400720061006c0003000e00430065006e007400720061006c0007000800afbc2c2a9256d80100000000
6 +YST: target_name: 02000e00430045004e005400520041004c0001000e00430045004e005400520041004c0004000e00430065006e007400720061006c0003000e00430065006e007400720061006c0007000800afbc2c2a9256d80100000000
7 +YST: timestamp: afbc2c2a9256d801
8 +YST: client_challenge: f8d1e2057b9c7169
9 +YST: nt_challenge_response: 32e87ea049485920fca6695ae9daee820101000000000000afbc2c2a9256d801f8d1e2057b9c71690000000002000e00430045004e005400520041004c0001000e00430045004e005400520041004c0004000e00430065006e007400720061006c0003000e00430065006e007400720061006c0007000800afbc2c2a9256d80100000000
10 +YST: lm_challenge_response: 2b0f863797a00d4446a1c9f49de124a5f8d1e2057b9c7169
11 +YST: session_base_key: 52f86f741e92e2e9d8013c1afcecfa13
12 +YST: key_exchange_key: 52f86f741e92e2e9d8013c1afcecfa13
13 +YST: encrypted_random_session_key: d9b2353a7f7ba9569ece01e96686cdef
14 +YST: self.is_unicode: true
15 +YST: domain:
16 +YST: user: 640065006600610075006c007400
17 +YST: tmp_final_auth_message: 4e544c4d53535000030000001800180058000000840084007000000000000000f40000000e000e00f40000000000000002010000100010000201000035828a62060072170000000f000000000000000000000000000000002b0f863797a00d4446a1c9f49de124a5f8d1e2057b9c716932e87ea049485920fca6695ae9daee820101000000000000afbc2c2a9256d801f8d1e2057b9c71690000000002000e00430045004e005400520041004c0001000e00430045004e005400520041004c0004000e00430065006e007400720061006c0003000e00430065006e007400720061006c0007000800afbc2c2a9256d80100000000640065006600610075006c007400d9b2353a7f7ba9569ece01e96686cdef
18 +YST: signature: 4cbff4ee21ce4114c7657d7aa427ca3f
19 +YST: read_challenge_message2: 4e544c4d53535000030000001800180058000000840084007000000000000000f40000000e000e00f40000000000000002010000100010000201000035828a62060072170000000f4cbff4ee21ce4114c7657d7aa427ca3f2b0f863797a00d4446a1c9f49de124a5f8d1e2057b9c716932e87ea049485920fca6695ae9daee820101000000000000afbc2c2a9256d801f8d1e2057b9c71690000000002000e00430045004e005400520041004c0001000e00430045004e005400520041004c0004000e00430065006e007400720061006c0003000e00430065006e007400720061006c0007000800afbc2c2a9256d80100000000640065006600610075006c007400d9b2353a7f7ba9569ece01e96686cdef
20 +WRITE challenge: 30820251a003020102a18201223082011e3082011aa0820116048201124e544c4d53535000030000001800180058000000840084007000000000000000f40000000e000e00f40000000000000002010000100010000201000035828a62060072170000000f4cbff4ee21ce4114c7657d7aa427ca3f2b0f863797a00d4446a1c9f49de124a5f8d1e2057b9c716932e87ea049485920fca6695ae9daee820101000000000000afbc2c2a9256d801f8d1e2057b9c71690000000002000e00430045004e005400520041004c0001000e00430045004e005400520041004c0004000e00430065006e007400720061006c0003000e00430065006e007400720061006c0007000800afbc2c2a9256d80100000000640065006600610075006c007400d9b2353a7f7ba9569ece01e96686cdefa38201220482011e0100000095fb7df84ffcd81d00000000a0588a3354258442e2997c79a4005e91ac49759b3c362228f42aefa5daad071a8eb905d7bc16611df35a50c0c577acf4543609e3ade8ff8289d371d8baed9eb2bd738de6c208f6a9885f1b0ee8aee2b26be87aa189bb41989c79716d938eb68e2f1e4bdc74c25e995c438aa5e5e30c2784214f4763c6737417edac43371f65f22aab68619f022b2f46b4cb9d00d0befe6d7e83d0d2c4ae69b544b1e90b1d5198459722eff903e8550864a46c552d75c83fb8ca8491b573fcd59d17cdc34e2505995fa6922554fdf03016161b430e476875a3752907087e993388f56675957a75b42b062f1f66ef8597a69deb466337396747ec8e46c573344b24fc8fba9305207eb10462ce355299063bab4cf105
21 +READ: read_ts_validate 3081b2a003020106a181aa3081a73081a4a081a104819e4e544c4d53535000020000000e000e003800000035828a62f2290572b3cac375000000000000000058005800460000000a00614a0000000f430045004e005400520041004c0002000e00430045004e005400520041004c0001000e00430045004e005400520041004c0004000e00430065006e007400720061006c0003000e00430065006e007400720061006c0007000800afbc2c2a9256d80100000000
22 +WRITE credentials: 302fa003020102a12830263024a02204204e544c4d53535000010000003582086000000000000000000000000000000000
23 +*/
24 +
25 +/*
26 + "Signature" => Check::new(b"NTLMSSP\x00".to_vec()),
27 + "MessageType" => Check::new(U32::LE(2)),
28 + "TargetNameLen" => U16::LE(0),
29 + "TargetNameLenMax" => U16::LE(0),
30 + "TargetNameBufferOffset" => U32::LE(0),
31 + "NegotiateFlags" => DynOption::new(U32::LE(0), |node| {
32 + if node.inner() & (Negotiate::NtlmsspNegociateVersion as u32) == 0 {
33 + return MessageOption::SkipField("Version".to_string())
34 + }
35 + return MessageOption::None
36 + }),
37 + "ServerChallenge" => vec![0; 8],
38 + "Reserved" => vec![0; 8],
39 + "TargetInfoLen" => U16::LE(0),
40 + "TargetInfoMaxLen" => U16::LE(0),
41 + "TargetInfoBufferOffset" => U32::LE(0),
42 + "Version" => version(),
43 + "Payload" => Vec::<u8>::new()
44 +*/
45 +
46 +const NegotiateFlags = {
47 + NtlmsspNegociate56: 0x80000000,
48 + NtlmsspNegociateKeyExch: 0x40000000,
49 + NtlmsspNegociate128: 0x20000000,
50 + NtlmsspNegociateVersion: 0x02000000,
51 + NtlmsspNegociateTargetInfo: 0x00800000,
52 + NtlmsspRequestNonNTSessionKey: 0x00400000,
53 + NtlmsspNegociateIdentify: 0x00100000,
54 + NtlmsspNegociateExtendedSessionSecurity: 0x00080000,
55 + NtlmsspTargetTypeServer: 0x00020000,
56 + NtlmsspTargetTypeDomain: 0x00010000,
57 + NtlmsspNegociateAlwaysSign: 0x00008000,
58 + NtlmsspNegociateOEMWorkstationSupplied: 0x00002000,
59 + NtlmsspNegociateOEMDomainSupplied: 0x00001000,
60 + NtlmsspNegociateNTLM: 0x00000200,
61 + NtlmsspNegociateLMKey: 0x00000080,
62 + NtlmsspNegociateDatagram: 0x00000040,
63 + NtlmsspNegociateSeal: 0x00000020,
64 + NtlmsspNegociateSign: 0x00000010,
65 + NtlmsspRequestTarget: 0x00000004,
66 + NtlmNegotiateOEM: 0x00000002,
67 + NtlmsspNegociateUnicode: 0x00000001
68 +}
69 +
70 +const MajorVersion = {
71 + WindowsMajorVersion5: 0x05,
72 + WindowsMajorVersion6: 0x06
73 +}
74 +
75 +const MinorVersion = {
76 + WindowsMinorVersion0: 0x00,
77 + WindowsMinorVersion1: 0x01,
78 + WindowsMinorVersion2: 0x02,
79 + WindowsMinorVersion3: 0x03
80 +}
81 +
82 +const NTLMRevision = {
83 + NtlmSspRevisionW2K3: 0x0F
84 +}
85 +
86 +function decodeTargetInfo(targetInfoBuf) {
87 + var r = {}, type, len, data, ptr = 0;
88 + while (true) {
89 + type = targetInfoBuf.readInt16LE(ptr);
90 + if (type == 0) break;
91 + len = targetInfoBuf.readInt16LE(ptr + 2);
92 + r[type] = targetInfoBuf.slice(ptr + 4, ptr + 4 + len);
93 + ptr += (4 + len);
94 + }
95 + return r;
96 +}
97 +
98 +function bufToArr(b) { var r = []; for (var i = 0; i < b.length; i++) { r.push(b.readUInt8(i)); } return r; } // For unit testing
99 +function toUnicode(str) { return Buffer.from(str, 'ucs2'); }
100 +function md4(str) { return crypto.createHash('md4').update(str).digest(); }
101 +function md5(str) { return crypto.createHash('md5').update(str).digest(); }
102 +function hmacmd5(key, data) { return crypto.createHmac('md5', key).update(data).digest(); }
103 +function ntowfv2(password, user, domain) { return hmacmd5(md4(toUnicode(password)), toUnicode(user.toUpperCase() + domain)); }
104 +function lmowfv2(password, user, domain) { return ntowfv2(password, user, domain); }
105 +function zeroBuffer(len) { return Buffer.alloc(len); }
106 +function compute_response_v2(response_key_nt, response_key_lm, server_challenge, client_challenge, time, server_name) {
107 + const response_version = Buffer.from('01', 'hex');
108 + const hi_response_version = Buffer.from('01', 'hex');
109 + const temp = Buffer.concat([response_version, hi_response_version, zeroBuffer(6), time, client_challenge, zeroBuffer(4), server_name]);
110 + const nt_proof_str = hmacmd5(response_key_nt, Buffer.concat([server_challenge, temp]));
111 + const nt_challenge_response = Buffer.concat([nt_proof_str, temp]);
112 + const lm_challenge_response = Buffer.concat([hmacmd5(response_key_lm, Buffer.concat([server_challenge, client_challenge])), client_challenge]);
113 + const session_base_key = hmacmd5(response_key_nt, nt_proof_str);
114 + return [nt_challenge_response, lm_challenge_response, session_base_key];
115 +}
116 +function kx_key_v2(session_base_key, _lm_challenge_response, _server_challenge) { return session_base_key; }
117 +function rc4k(key, data) { return crypto.createCipheriv('rc4', key, null).update(data); }
118 +
119 +/// Compute a signature of all data exchange during NTLMv2 handshake
120 +function mic(exported_session_key, negotiate_message, challenge_message, authenticate_message) { return hmacmd5(exported_session_key, Buffer.concat([negotiate_message, challenge_message, authenticate_message])); }
121 +
122 +/// NTLMv2 security interface generate a sign key
123 +/// By using MD5 of the session key + a static member (sentense)
124 +function sign_key(exported_session_key, is_client) {
125 + if (is_client) {
126 + return md5(Buffer.concat([exported_session_key, Buffer.from("session key to client-to-server signing key magic constant\0")]));
127 + } else {
128 + return md5(Buffer.concat([exported_session_key, Buffer.from("session key to server-to-client signing key magic constant\0")]));
129 + }
130 +}
131 +
132 +/// NTLMv2 security interface generate a seal key
133 +/// By using MD5 of the session key + a static member (sentense)
134 +function seal_key(exported_session_key, is_client) {
135 + if (is_client) {
136 + return md5(Buffer.concat([exported_session_key, Buffer.from("session key to client-to-server sealing key magic constant\0")]));
137 + } else {
138 + return md5(Buffer.concat([exported_session_key, Buffer.from("session key to server-to-client sealing key magic constant\0")]));
139 + }
140 +}
141 +
142 +function authenticate_message(lm_challenge_response, nt_challenge_response, domain, user, workstation, encrypted_random_session_key, flags) {
143 + const payload = Buffer.concat([lm_challenge_response, nt_challenge_response, domain, user, workstation, encrypted_random_session_key]);
144 + const offset = ((flags & NegotiateFlags.NtlmsspNegociateVersion) == 0) ? 80 : 88;
145 + const buf = Buffer.alloc(offset - 16);
146 + buf.write('4e544c4d53535000', 0, 8, 'hex'); // Signature
147 + buf.writeInt32LE(3, 8); // MessageType
148 + buf.writeInt16LE(lm_challenge_response.length, 12); // LmChallengeResponseLen
149 + buf.writeInt16LE(lm_challenge_response.length, 14); // LmChallengeResponseMaxLen
150 + buf.writeInt32LE(offset, 16); // LmChallengeResponseBufferOffset
151 + buf.writeInt16LE(nt_challenge_response.length, 20); // NtChallengeResponseLen
152 + buf.writeInt16LE(nt_challenge_response.length, 22); // NtChallengeResponseMaxLen
153 + buf.writeInt32LE(offset + lm_challenge_response.length, 24); // NtChallengeResponseBufferOffset
154 + buf.writeInt16LE(domain.length, 28); // DomainNameLen
155 + buf.writeInt16LE(domain.length, 30); // DomainNameMaxLen
156 + buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length, 32); // DomainNameBufferOffset
157 + buf.writeInt16LE(user.length, 36); // UserNameLen
158 + buf.writeInt16LE(user.length, 38); // UserNameMaxLen
159 + buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length + domain.length, 40); // UserNameBufferOffset
160 + buf.writeInt16LE(workstation.length, 44); // WorkstationLen
161 + buf.writeInt16LE(workstation.length, 46); // WorkstationMaxLen
162 + buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length + domain.length + user.length, 48); // WorkstationBufferOffset
163 + buf.writeInt16LE(encrypted_random_session_key.length, 52); // EncryptedRandomSessionLen
164 + buf.writeInt16LE(encrypted_random_session_key.length, 54); // EncryptedRandomSessionMaxLen
165 + buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length + domain.length + user.length + workstation.length, 56); // EncryptedRandomSessionBufferOffset
166 + buf.writeInt32LE(flags, 60); // NegotiateFlags
167 + if ((flags & NegotiateFlags.NtlmsspNegociateVersion) != 0) {
168 + buf.writeUInt8(MajorVersion.WindowsMajorVersion6, 64); // ProductMajorVersion
169 + buf.writeUInt8(MinorVersion.WindowsMinorVersion0, 65); // ProductMinorVersion
170 + buf.writeInt16LE(6002, 66); // ProductBuild
171 + //buf.writeInt16LE(0, 68); // Reserved
172 + //buf.writeUInt8(0, 70); // Reserved
173 + buf.writeUInt8(NTLMRevision.NtlmSspRevisionW2K3, 71); // NTLMRevisionCurrent
174 + }
175 + return [buf, payload];
176 +}
177 +
178 +function read_challenge_message(derBuffer, user, pass, domain, negotiate_message) {
179 + const headerSignature = derBuffer.slice(0, 8);
180 + if (headerSignature.toString('hex') != '4e544c4d53535000') { console.log('BAD SIGNATURE'); }
181 + const messageType = derBuffer.readInt32LE(8);
182 + if (messageType != 2) { console.log('BAD MESSAGE TYPE'); }
183 + const targetNameLen = derBuffer.readInt16LE(12);
184 + const targetNameLenMax = derBuffer.readInt16LE(14);
185 + const targetNameBufferOffset = derBuffer.readInt32LE(16);
186 + const negotiateFlags = derBuffer.readInt32LE(20);
187 + const serverChallenge = derBuffer.slice(24, 32);
188 + const reserved = derBuffer.slice(32, 40);
189 + if (reserved.toString('hex') != '0000000000000000') { console.log('BAD RESERVED'); }
190 + const targetInfoLen = derBuffer.readInt16LE(40);
191 + const targetInfoLenMax = derBuffer.readInt16LE(42);
192 + const targetInfoBufferOffset = derBuffer.readInt32LE(44);
193 + const targetName = derBuffer.slice(targetNameBufferOffset, targetNameBufferOffset + targetNameLen);
194 + const targetInfo = decodeTargetInfo(derBuffer.slice(targetInfoBufferOffset, targetInfoBufferOffset + targetInfoLen));
195 + const timestamp = targetInfo[7];
196 + if (timestamp == null) { console.log('NO TIMESTAMP'); }
197 + const clientChallenge = crypto.randomBytes(8);
198 + const response_key_nt = ntowfv2(pass, user, domain); // Password, Username, Domain
199 + const response_key_lm = lmowfv2(pass, user, domain); // Password, Username, Domain
200 +
201 + var resp = compute_response_v2(response_key_nt, response_key_lm, serverChallenge, clientChallenge, timestamp, targetName);
202 + const nt_challenge_response = resp[0];
203 + const lm_challenge_response = resp[1];
204 + const session_base_key = resp[2];
205 +
206 + const key_exchange_key = kx_key_v2(session_base_key, lm_challenge_response, serverChallenge);
207 + const exported_session_key = crypto.randomBytes(16);
208 + const encrypted_random_session_key = rc4k(key_exchange_key, exported_session_key);
209 +
210 + const is_unicode = ((negotiateFlags & 1) != 0)
211 + var xdomain = null;
212 + var xuser = null;
213 + if (is_unicode) {
214 + xdomain = toUnicode(domain);
215 + xuser = toUnicode(user);
216 + } else {
217 + xdomain = Buffer.from(domain, 'utf8');
218 + xuser = Buffer.from(domain, 'utf8');
219 + }
220 +
221 + const auth_message_compute = authenticate_message(lm_challenge_response, nt_challenge_response, xdomain, xuser, zeroBuffer(0), encrypted_random_session_key, negotiateFlags);
222 +
223 + // Write a tmp message to compute MIC and then include it into final message
224 + const tmp_final_auth_message = Buffer.concat([auth_message_compute[0], zeroBuffer(16), auth_message_compute[1]]);
225 +
226 + const signature = mic(exported_session_key, negotiate_message, derBuffer, tmp_final_auth_message);
227 + return Buffer.concat([auth_message_compute[0], signature, auth_message_compute[1]]);
228 +}
229 +
230 +
231 +
232 +// Create create_ts_request
233 +const crypto = require('crypto');
234 +const forge = require('node-forge');
235 +const asn1 = forge.asn1;
236 +const pki = forge.pki;
237 +const entireBuffer = Buffer.from('3081b2a003020106a181aa3081a73081a4a081a104819e4e544c4d53535000020000000e000e003800000035828a62f2290572b3cac375000000000000000058005800460000000a00614a0000000f430045004e005400520041004c0002000e00430045004e005400520041004c0001000e00430045004e005400520041004c0004000e00430065006e007400720061006c0003000e00430065006e007400720061006c0007000800afbc2c2a9256d80100000000', 'hex').toString('binary');
238 +
239 +// We have a full ASN1 data block, decode it now
240 +const der = asn1.fromDer(entireBuffer.toString('binary'));
241 +const derNum = der.value[0].value[0].value.charCodeAt(0);
242 +const derBuffer = Buffer.from(der.value[1].value[0].value[0].value[0].value[0].value, 'binary');
243 +const negotiate_message = Buffer.from('4e544c4d53535000010000003582086000000000000000000000000000000000', 'hex');
244 +const client_challenge = read_challenge_message(derBuffer, "default", "", "", negotiate_message);
245 +
246 +console.log('client_challenge', client_challenge.toString('hex'));
247 +
248 +