1

I've tried to search through stackoverflow for a similar question but most people are asking about the client-side of the NTLMv2 protocol. I'm implementing a proxy that is performing the server-side of the protocol to authenticate users connecting to the proxy. I've coded a lot of the protocol but I'm now stuck because the documentation that should take me further is difficult to understand.

This is the best documentation I've found so far: http://www.innovation.ch/personal/ronald/ntlm.html, but how to deal with the LM and NT responses is oblivious to me.

The proxy is located on an application server. The domain server is a different machine.

Example code for the node proxy:

var http = require('http')
    , request = require('request')
    , ProxyAuth = require('./proxyAuth');

function handlerProxy(req, res) {
    ProxyAuth.authorize(req, res);
    var options = {
        url: req.url,
        method: req.method,
        headers: req.headers
    }
    req.pipe(request(options)).pipe(res)
}

var server = http.createServer(handlerProxy);


server.listen(3000, function(){
    console.log('Express server listening on port ' + 3000);
});

ProxyAuth.js code:

ProxyAuth = {
    parseType3Msg: function(buf) {
        var lmlen = buf.readUInt16LE(12);
        var lmoff = buf.readUInt16LE(16);
        var ntlen = buf.readUInt16LE(20);
        var ntoff = buf.readUInt16LE(24);
        var dlen = buf.readUInt16LE(28);
        var doff = buf.readUInt16LE(32);
        var ulen = buf.readUInt16LE(36);
        var uoff = buf.readUInt16LE(40);
        var hlen = buf.readUInt16LE(44);
        var hoff = buf.readUInt16LE(48);
        var domain = buf.slice(doff, doff+dlen).toString('utf8');
        var user = buf.slice(uoff, uoff+ulen).toString('utf8');
        var host = buf.slice(hoff, hoff+hlen).toString('utf8');
        var lmresp = buf.slice(lmoff, lmoff+lmlen).toString('utf8');
        var ntresp = buf.slice(ntoff, ntoff+ntlen).toString('utf8');
        console.log(user, lmresp, ntresp);
        /* NOW WHAT DO I DO? */
    },
    authorize: function(req, res) {
        var auth = req.headers['authorization'];
        if (!auth) {
            res.writeHead(401, {
                'WWW-Authenticate': 'NTLM',
            });
            res.end('<html><body>Proxy Authentication Required</body></html>');
        }
        else if(auth) {
            var header = auth.split(' ');
            var buf = new Buffer(header[1], 'base64');
            var msg = buf.toString('utf8');
            console.log("Decoded", msg);
            if (header[0] == "NTLM") {
                if (msg.substring(0,8) != "NTLMSSP\x00") {
                    res.writeHead(401, {
                        'WWW-Authenticate': 'NTLM',
                    });
                    res.end('<html><body>Header not recognized</body></html>');
                }
                // Type 1 message
                if (msg[8] == "\x01") {
                    console.log(buf.toString('hex'));
                    var challenge = require('crypto').randomBytes(8);
                    var type2msg = "NTLMSSP\x00"+
                        "\x02\x00\x00\x00"+ // 8 message type
                        "\x00\x00\x00\x00"+ // 12 target name len/alloc
                        "\x00\x00\x00\x00"+ // 16 target name offset
                        "\x01\x82\x00\x00"+ // 20 flags
                        challenge.toString('utf8')+ // 24 challenge
                        "\x00\x00\x00\x00\x00\x00\x00\x00"+ // 32 context
                        "\x00\x00\x00\x00\x00\x00\x00\x00"; // 40 target info len/alloc/offset

                    type2msg = new Buffer(type2msg).toString('base64');

                    res.writeHead(401, {
                        'WWW-Authenticate': 'NTLM '+type2msg.trim(),
                    });
                    res.end();
                }
                else if (msg[8] == "\x03") {
                    console.log(buf.toString('hex'));
                    ProxyAuth.parseType3Msg(buf);
                    /* NOW WHAT DO I DO? */
                }
            }
            else if (header[0] == "Basic") {
            }
        }
    }
};

module.exports = ProxyAuth;

The /* NOW WHAT DO I DO? */ comment specifies where I am stuck.

I hope I put enough information there, but let me know if anything else is needed.

AKwhat
  • 11
  • 4
  • Dealing with the NTLM protocol is not a good idea. The next step would be to validate the `LmChallengeResponse` and `NtChallengeResponse` which is not an easy thing since you would have to ask the corresponding Active Directory wether the user is authenticated or not. The easiest solution is to proxy the NTLM Authentication directly to the Active Directory and let it do the authentication for you as I did in [express-ntlm](https://www.npmjs.com/package/express-ntlm). – Fabio Poloni Jan 07 '15 at 07:35

0 Answers0