You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
220 lines
8.5 KiB
220 lines
8.5 KiB
5 months ago
|
'use strict';
|
||
|
// Original file https://raw.githubusercontent.com/elasticio/node-ntlm-client/master/lib/ntlm.js
|
||
|
var os = require('os'), flags = require('./flags'), hash = require('./hash');
|
||
|
var NTLMSIGNATURE = "NTLMSSP\0";
|
||
|
function createType1Message(workstation, target) {
|
||
|
var dataPos = 32, pos = 0, buf = new Buffer.alloc(1024);
|
||
|
workstation = workstation === undefined ? os.hostname() : workstation;
|
||
|
target = target === undefined ? '' : target;
|
||
|
//signature
|
||
|
buf.write(NTLMSIGNATURE, pos, NTLMSIGNATURE.length, 'ascii');
|
||
|
pos += NTLMSIGNATURE.length;
|
||
|
//message type
|
||
|
buf.writeUInt32LE(1, pos);
|
||
|
pos += 4;
|
||
|
//flags
|
||
|
buf.writeUInt32LE(flags.NTLMFLAG_NEGOTIATE_OEM |
|
||
|
flags.NTLMFLAG_REQUEST_TARGET |
|
||
|
flags.NTLMFLAG_NEGOTIATE_NTLM_KEY |
|
||
|
flags.NTLMFLAG_NEGOTIATE_NTLM2_KEY |
|
||
|
flags.NTLMFLAG_NEGOTIATE_ALWAYS_SIGN, pos);
|
||
|
pos += 4;
|
||
|
//domain security buffer
|
||
|
buf.writeUInt16LE(target.length, pos);
|
||
|
pos += 2;
|
||
|
buf.writeUInt16LE(target.length, pos);
|
||
|
pos += 2;
|
||
|
buf.writeUInt32LE(target.length === 0 ? 0 : dataPos, pos);
|
||
|
pos += 4;
|
||
|
if (target.length > 0) {
|
||
|
dataPos += buf.write(target, dataPos, 'ascii');
|
||
|
}
|
||
|
//workstation security buffer
|
||
|
buf.writeUInt16LE(workstation.length, pos);
|
||
|
pos += 2;
|
||
|
buf.writeUInt16LE(workstation.length, pos);
|
||
|
pos += 2;
|
||
|
buf.writeUInt32LE(workstation.length === 0 ? 0 : dataPos, pos);
|
||
|
pos += 4;
|
||
|
if (workstation.length > 0) {
|
||
|
dataPos += buf.write(workstation, dataPos, 'ascii');
|
||
|
}
|
||
|
return 'NTLM ' + buf.toString('base64', 0, dataPos);
|
||
|
}
|
||
|
function decodeType2Message(str) {
|
||
|
if (str === undefined) {
|
||
|
throw new Error('Invalid argument');
|
||
|
}
|
||
|
//convenience
|
||
|
if (Object.prototype.toString.call(str) !== '[object String]') {
|
||
|
if (str.hasOwnProperty('headers') && str.headers.hasOwnProperty('www-authenticate')) {
|
||
|
str = str.headers['www-authenticate'];
|
||
|
}
|
||
|
else {
|
||
|
throw new Error('Invalid argument');
|
||
|
}
|
||
|
}
|
||
|
var ntlmMatch = /^NTLM ([^,\s]+)/.exec(str);
|
||
|
if (ntlmMatch) {
|
||
|
str = ntlmMatch[1];
|
||
|
}
|
||
|
var buf = new Buffer.from(str, 'base64'), obj = {};
|
||
|
//check signature
|
||
|
if (buf.toString('ascii', 0, NTLMSIGNATURE.length) !== NTLMSIGNATURE) {
|
||
|
throw new Error('Invalid message signature: ' + str);
|
||
|
}
|
||
|
//check message type
|
||
|
if (buf.readUInt32LE(NTLMSIGNATURE.length) !== 2) {
|
||
|
throw new Error('Invalid message type (no type 2)');
|
||
|
}
|
||
|
//read flags
|
||
|
obj.flags = buf.readUInt32LE(20);
|
||
|
obj.encoding = (obj.flags & flags.NTLMFLAG_NEGOTIATE_OEM) ? 'ascii' : 'ucs2';
|
||
|
obj.version = (obj.flags & flags.NTLMFLAG_NEGOTIATE_NTLM2_KEY) ? 2 : 1;
|
||
|
obj.challenge = buf.slice(24, 32);
|
||
|
//read target name
|
||
|
obj.targetName = (function () {
|
||
|
var length = buf.readUInt16LE(12);
|
||
|
//skipping allocated space
|
||
|
var offset = buf.readUInt32LE(16);
|
||
|
if (length === 0) {
|
||
|
return '';
|
||
|
}
|
||
|
if ((offset + length) > buf.length || offset < 32) {
|
||
|
throw new Error('Bad type 2 message');
|
||
|
}
|
||
|
return buf.toString(obj.encoding, offset, offset + length);
|
||
|
})();
|
||
|
//read target info
|
||
|
if (obj.flags & flags.NTLMFLAG_NEGOTIATE_TARGET_INFO) {
|
||
|
obj.targetInfo = (function () {
|
||
|
var info = {};
|
||
|
var length = buf.readUInt16LE(40);
|
||
|
//skipping allocated space
|
||
|
var offset = buf.readUInt32LE(44);
|
||
|
var targetInfoBuffer = new Buffer.alloc(length);
|
||
|
buf.copy(targetInfoBuffer, 0, offset, offset + length);
|
||
|
if (length === 0) {
|
||
|
return info;
|
||
|
}
|
||
|
if ((offset + length) > buf.length || offset < 32) {
|
||
|
throw new Error('Bad type 2 message');
|
||
|
}
|
||
|
var pos = offset;
|
||
|
while (pos < (offset + length)) {
|
||
|
var blockType = buf.readUInt16LE(pos);
|
||
|
pos += 2;
|
||
|
var blockLength = buf.readUInt16LE(pos);
|
||
|
pos += 2;
|
||
|
if (blockType === 0) {
|
||
|
//reached the terminator subblock
|
||
|
break;
|
||
|
}
|
||
|
var blockTypeStr = void 0;
|
||
|
switch (blockType) {
|
||
|
case 1:
|
||
|
blockTypeStr = 'SERVER';
|
||
|
break;
|
||
|
case 2:
|
||
|
blockTypeStr = 'DOMAIN';
|
||
|
break;
|
||
|
case 3:
|
||
|
blockTypeStr = 'FQDN';
|
||
|
break;
|
||
|
case 4:
|
||
|
blockTypeStr = 'DNS';
|
||
|
break;
|
||
|
case 5:
|
||
|
blockTypeStr = 'PARENT_DNS';
|
||
|
break;
|
||
|
default:
|
||
|
blockTypeStr = '';
|
||
|
break;
|
||
|
}
|
||
|
if (blockTypeStr) {
|
||
|
info[blockTypeStr] = buf.toString('ucs2', pos, pos + blockLength);
|
||
|
}
|
||
|
pos += blockLength;
|
||
|
}
|
||
|
return {
|
||
|
parsed: info,
|
||
|
buffer: targetInfoBuffer
|
||
|
};
|
||
|
})();
|
||
|
}
|
||
|
return obj;
|
||
|
}
|
||
|
function createType3Message(type2Message, username, password, workstation, target) {
|
||
|
var dataPos = 52, buf = new Buffer.alloc(1024);
|
||
|
if (workstation === undefined) {
|
||
|
workstation = os.hostname();
|
||
|
}
|
||
|
if (target === undefined) {
|
||
|
target = type2Message.targetName;
|
||
|
}
|
||
|
//signature
|
||
|
buf.write(NTLMSIGNATURE, 0, NTLMSIGNATURE.length, 'ascii');
|
||
|
//message type
|
||
|
buf.writeUInt32LE(3, 8);
|
||
|
if (type2Message.version === 2) {
|
||
|
dataPos = 64;
|
||
|
var ntlmHash = hash.createNTLMHash(password), nonce = hash.createPseudoRandomValue(16), lmv2 = hash.createLMv2Response(type2Message, username, ntlmHash, nonce, target), ntlmv2 = hash.createNTLMv2Response(type2Message, username, ntlmHash, nonce, target);
|
||
|
//lmv2 security buffer
|
||
|
buf.writeUInt16LE(lmv2.length, 12);
|
||
|
buf.writeUInt16LE(lmv2.length, 14);
|
||
|
buf.writeUInt32LE(dataPos, 16);
|
||
|
lmv2.copy(buf, dataPos);
|
||
|
dataPos += lmv2.length;
|
||
|
//ntlmv2 security buffer
|
||
|
buf.writeUInt16LE(ntlmv2.length, 20);
|
||
|
buf.writeUInt16LE(ntlmv2.length, 22);
|
||
|
buf.writeUInt32LE(dataPos, 24);
|
||
|
ntlmv2.copy(buf, dataPos);
|
||
|
dataPos += ntlmv2.length;
|
||
|
}
|
||
|
else {
|
||
|
var lmHash = hash.createLMHash(password), ntlmHash = hash.createNTLMHash(password), lm = hash.createLMResponse(type2Message.challenge, lmHash), ntlm = hash.createNTLMResponse(type2Message.challenge, ntlmHash);
|
||
|
//lm security buffer
|
||
|
buf.writeUInt16LE(lm.length, 12);
|
||
|
buf.writeUInt16LE(lm.length, 14);
|
||
|
buf.writeUInt32LE(dataPos, 16);
|
||
|
lm.copy(buf, dataPos);
|
||
|
dataPos += lm.length;
|
||
|
//ntlm security buffer
|
||
|
buf.writeUInt16LE(ntlm.length, 20);
|
||
|
buf.writeUInt16LE(ntlm.length, 22);
|
||
|
buf.writeUInt32LE(dataPos, 24);
|
||
|
ntlm.copy(buf, dataPos);
|
||
|
dataPos += ntlm.length;
|
||
|
}
|
||
|
//target name security buffer
|
||
|
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? target.length : target.length * 2, 28);
|
||
|
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? target.length : target.length * 2, 30);
|
||
|
buf.writeUInt32LE(dataPos, 32);
|
||
|
dataPos += buf.write(target, dataPos, type2Message.encoding);
|
||
|
//user name security buffer
|
||
|
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? username.length : username.length * 2, 36);
|
||
|
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? username.length : username.length * 2, 38);
|
||
|
buf.writeUInt32LE(dataPos, 40);
|
||
|
dataPos += buf.write(username, dataPos, type2Message.encoding);
|
||
|
//workstation name security buffer
|
||
|
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? workstation.length : workstation.length * 2, 44);
|
||
|
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? workstation.length : workstation.length * 2, 46);
|
||
|
buf.writeUInt32LE(dataPos, 48);
|
||
|
dataPos += buf.write(workstation, dataPos, type2Message.encoding);
|
||
|
if (type2Message.version === 2) {
|
||
|
//session key security buffer
|
||
|
buf.writeUInt16LE(0, 52);
|
||
|
buf.writeUInt16LE(0, 54);
|
||
|
buf.writeUInt32LE(0, 56);
|
||
|
//flags
|
||
|
buf.writeUInt32LE(type2Message.flags, 60);
|
||
|
}
|
||
|
return 'NTLM ' + buf.toString('base64', 0, dataPos);
|
||
|
}
|
||
|
module.exports = {
|
||
|
createType1Message: createType1Message,
|
||
|
decodeType2Message: decodeType2Message,
|
||
|
createType3Message: createType3Message
|
||
|
};
|
||
|
//# sourceMappingURL=ntlm.js.map
|