Full Code of artkond/rpivot for AI

master 4963487d1923 cached
23 files
189.6 KB
51.8k tokens
260 symbols
1 requests
Download .txt
Repository: artkond/rpivot
Branch: master
Commit: 4963487d1923
Files: 23
Total size: 189.6 KB

Directory structure:
gitextract_pp1v33z2/

├── .gitignore
├── README.md
├── __main__.py
├── client.py
├── ntlm_auth/
│   ├── U32.py
│   ├── __init__.py
│   ├── compute_hash.py
│   ├── compute_keys.py
│   ├── compute_response.py
│   ├── constants.py
│   ├── des.py
│   ├── des_c.py
│   ├── des_data.py
│   ├── gss_channel_bindings.py
│   ├── messages.py
│   ├── ntlm.py
│   ├── rc4.py
│   ├── session_security.py
│   └── target_info.py
├── ordereddict.py
├── relay.py
├── server.py
└── six.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
venv
build


================================================
FILE: README.md
================================================
RPIVOT - reverse socks 4 proxy for penetration tests
===================


RPIVOT allows to tunnel traffic into internal network via socks 4. It works like ssh dynamic port forwarding but in the opposite direction. 


----------


Description
-------------

This tool is Python 2.6-2.7 compatible and has no dependencies beyond the standard library. It has client-server architecture. Just run the client on the machine you want to tunnel the traffic through. Server should be started on pentester's machine and listen to incoming connections from the client.

Works on Kali Linux, Solaris 10, Windows, Mac OS.


Usage example
-------------

Start server listener on port 9999, which creates a socks 4 proxy on 127.0.0.1:1080 upon connection from client:

`python server.py --server-port 9999 --server-ip 0.0.0.0 --proxy-ip 127.0.0.1 --proxy-port 1080`

Connect to the server:

`python client.py --server-ip <rpivot_server_ip> --server-port 9999`

To pivot through an NTLM proxy:

`python client.py --server-ip <rpivot_server_ip> --server-port 9999 --ntlm-proxy-ip <proxy_ip> --ntlm-proxy-port 8080 --domain CONTOSO.COM --username Alice --password P@ssw0rd`

Pass-the-hash is supported:

`python client.py --server-ip <rpivot_server_ip> --server-port 9999 --ntlm-proxy-ip <proxy_ip> --ntlm-proxy-port 8080 --domain CONTOSO.COM --username Alice --hashes 9b9850751be2515c8231e5189015bbe6:49ef7638d69a01f26d96ed673bf50c45`

You can use `proxychains` to tunnel traffic through socks proxy.

Edit /etc/proxychains.conf:

```
[ProxyList]
# add proxy here ...
# meanwile
# defaults set to "tor"
socks4 127.0.0.1 1080
```

Using single zip file mode:

```
zip rpivot.zip -r *.py ./ntlm_auth/
python rpivot.zip server <server_options>
python rpivot.zip client <client_options> 
```

Pivot and have fun:

`proxychains <tool_name>`

Pre-built Windows client binary available in release section.

Author
------

Artem Kondratenko https://twitter.com/artkond


================================================
FILE: __main__.py
================================================
#!/usr/bin/env python

import sys

try:
    rpivot_type = sys.argv.pop(1).lower()
    if rpivot_type not in ('client', 'server'):
        raise IndexError('Bad rpivot type')
except IndexError:
    print('{} <server|client> ...'.format(sys.argv[0]))
    sys.exit(1)

if rpivot_type == 'client':
    import client
    client.main()
elif rpivot_type == 'server':
    import server
    server.main()


================================================
FILE: client.py
================================================
#!/usr/bin/env python

import logging
import logging.handlers
import socket
import sys
import time
from struct import pack, unpack
import select
import optparse
import errno
import relay
import threading

from ntlm_auth.ntlm import Ntlm
import re

logger = None


def key_by_value(my_dict, value):
    for k, v in my_dict.iteritems():
        if v == value:
            return k
    return None


class SocksRelay:
    STATUS_SUCCESS = 0
    STATUS_REFUSED = 1
    STATUS_TIMEOUT = 2

    def __init__(self, bc_sock):
        self.channel = {}
        self.id_by_socket = {}
        self.bc_sock = bc_sock
        self.input_list = [self.bc_sock]
        self.establishing_dict = {}
        self.forward_socket = None
        self.data = None
        self.last_ping_time = time.time()

        logger.debug('Starting ping thread')


        self.ping_thread = threading.Thread(target=self.ping_worker)

        self.ping_thread.start()
        self.remote_side_down = False

    def ping_worker(self):
        while True:
            time.sleep(10)
            current_time = time.time()
            logger.debug('In ping worker')
            if self.remote_side_down:
                logger.debug('Remote side down. Exiting ping worker')
                return
            if current_time - self.last_ping_time > relay.relay_timeout:
                logger.info('No response from remote side for {0} seconds. Restarting relay'.format(relay.relay_timeout))
                self.bc_sock.close()
                return

    def shutdown(self):
        self.remote_side_down = True
        relay.close_sockets(self.input_list)
        sys.exit(1)

    def run(self):
        inputready = None
        outputready = None
        exceptready = None
        while True:

            try:
                time.sleep(relay.delay)
                logger.debug("Active channels: {0}. Pending Channels {1}".format(self.channel.keys(), self.establishing_dict.values()))
                inputready, outputready, exceptready = select.select(self.input_list, self.establishing_dict.keys(), [], 15)
            except KeyboardInterrupt:
                logger.info('SIGINT received. Closing relay and exiting')
                self.send_remote_cmd(self.bc_sock, relay.CLOSE_RELAY)
                self.shutdown()
            except select.error as (code, msg):
                logger.debug('Select error on select. Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))
                self.shutdown()
            except socket.error as (code, msg):
                logger.debug('Socket error on select. Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))
                self.shutdown()

            for sock in outputready:
                channel_id = self.establishing_dict[sock]
                logger.debug('Establishing connection with channel id {0}'.format(channel_id))
                try:
                    sock.recv(0)
                except socket.error as (code, err_msg):
                    if code == errno.ECONNREFUSED or code == errno.ETIMEDOUT:
                        logger.debug('Connection {0}'.format(errno.errorcode[code]))

                        if sock in inputready:
                            inputready.remove(sock)

                        del self.establishing_dict[sock]

                        self.send_remote_cmd(self.bc_sock, relay.FORWARD_CONNECTION_FAILURE, channel_id)
                        sock.close()
                        continue
                    elif code == errno.EAGAIN:
                        logger.debug('Recv(0) return errno.EAGAIN for socket {0} on channel {1}. Connection established.'.format(sock, channel_id))
                    elif code == 10035:
                        logger.debug('Recv(0) raised windows-specific exception 10035. Connection established.')
                    else:
                        raise

                logger.debug('Connection established on channel {0}'.format(channel_id))
                sock.setblocking(1)

                self.send_remote_cmd(self.bc_sock, relay.FORWARD_CONNECTION_SUCCESS, self.establishing_dict[sock])
                del self.establishing_dict[sock]
                self.input_list.append(sock)
                self.set_channel(sock, channel_id)

            for self.selected_input_socket in inputready:
                if self.selected_input_socket == self.bc_sock:
                    try:
                        self.manage_remote_socket(self.bc_sock)
                    except relay.RelayError:
                        logger.debug('Remote side closed socket')
                        relay.close_sockets(self.input_list)
                        return
                else:
                    self.manage_forward_socket(self.selected_input_socket)

    def handle_remote_cmd(self, data):
        cmd = data[0]
        logger.debug('Received cmd data from remote side. Cmd: {0}'.format(relay.cmd_names[cmd]))
        if cmd == relay.CHANNEL_CLOSE_CMD:
            channel_id = unpack('<H', data[1:3])[0]
            logger.debug('Channel close request with id: {0}'.format(channel_id))
            establishing_sock = key_by_value(self.establishing_dict, channel_id)
            if establishing_sock is not None:
                logger.debug('Closing establishing socket with id: {0}'.format(channel_id))
                del self.establishing_dict[establishing_sock]
            elif channel_id not in self.channel:
                logger.debug('Channel {0} non existent'.format(channel_id))
                return
            else:
                sock_to_close = self.channel[channel_id]
                self.unset_channel(channel_id)
                logger.debug('Closing socket with id: {0}'.format(channel_id))
                sock_to_close.close()
                self.input_list.remove(sock_to_close)
        elif cmd == relay.CHANNEL_OPEN_CMD:
            channel_id, packed_ip, port = unpack('<HIH', data[1:9])
            ip = socket.inet_ntoa(data[3:7])
            logger.debug('Got new channel request with id {0} . Opening new forward connection to host {1} port {2}'.format(channel_id, ip, port))
            self.establish_forward_socket(channel_id, ip, port)
        elif cmd == relay.CLOSE_RELAY:
            logger.info('Got command to close relay. Closing socket and exiting.')
            self.shutdown()
        elif cmd == relay.PING_CMD:
            self.last_ping_time = time.time()
            self.send_remote_cmd(self.bc_sock, relay.PING_CMD)
        else:
            logger.debug('Received unknown cmd: {0}'.format(cmd))

    def get_channel_data(self, sock):
        try:
            tlv_header = relay.recvall(sock, 4)
            channel_id, tlv_data_len = unpack('<HH', tlv_header)
            data = relay.recvall(sock, tlv_data_len)
        except socket.error as (code, msg):
            logger.debug('Exception on receiving tlv message from remote side. Exiting')
            logger.debug('Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))
            raise relay.RelayError

        return channel_id, data

    def manage_remote_socket(self, sock):
        try:
            (channel_id, data) = self.get_channel_data(sock)
        except relay.RelayError:
            logger.debug('Exiting!')
            self.close_remote_connection(sock)
            raise relay.RelayError

        if channel_id == relay.COMMAND_CHANNEL:
            self.handle_remote_cmd(data)
        elif channel_id in self.channel:
            relay_to_sock = self.channel[channel_id]
            logger.debug('Got data to relay from remote side. Channel id {0}. Data length: {1}'.format(channel_id, len(data)))
            logger.debug('Data contents: {0}'.format(data.encode('hex')))
            self.relay(data, relay_to_sock)
        else:
                logger.debug('Relay from socket {0} with channel {1} not possible. Channel does not exist'.format(sock, channel_id))
                return

    def close_remote_connection(self, sock):
        sock.close()
        self.input_list.remove(sock)

    def manage_forward_socket(self, sock):
        if sock not in self.id_by_socket:
            logger.debug('Channel corresponding to remote socket {0} already closed. Closing forward socket'.format(sock))
            return
        channel_id = self.id_by_socket[sock]
        #logger.debug('Readable socket {0} with channel id {1}'.format(sock, channel_id))
        try:
            data = sock.recv(relay.buffer_size)
        except socket.error as (code, msg):
            logger.debug('Exception on receiving data from socket {0} with channel id {1}'.format(sock, channel_id))
            logger.debug('Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))
            logger.debug('Closing socket {0} with channel id {1}'.format(sock, channel_id))
            self.close_forward_connection(sock)
            return
        data_len = len(data)
        if data_len == 0:
            self.close_forward_connection(sock)
            return
        else:
            channel_id = self.id_by_socket[sock]
            tlv_header = pack('<HH', channel_id, len(data))
            logger.debug('Got data to relay from app side. Channel id {0}. Data length: {1}'.format(channel_id, len(data)))
            logger.debug('Preparing tlv header: {0}'.format(tlv_header.encode('hex')))
            logger.debug('Data contents: {0}'.format(data.encode('hex')))
            self.relay(tlv_header + data, self.bc_sock)

    def close_forward_connection(self, sock):
        channel_id = self.id_by_socket[sock]
        logger.debug('Closing forward socket {0} with id {1}'.format(sock, channel_id))
        logger.debug('Current remote side socket: {0}'.format(self.bc_sock))
        logger.debug('Notifying remote side')
        self.unset_channel(channel_id)
        self.input_list.remove(sock)
        sock.close()
        self.send_remote_cmd(self.bc_sock, relay.CHANNEL_CLOSE_CMD, channel_id)

    def send_remote_cmd(self, sock, cmd, *args):
        logger.debug('Sending cmd to remote side. Cmd: {0}'.format(relay.cmd_names[cmd]))
        if cmd == relay.CHANNEL_CLOSE_CMD:
            cmd_buffer = cmd + pack('<H', args[0])
            tlv_header = pack('<HH', relay.COMMAND_CHANNEL, len(cmd_buffer))
        elif cmd == relay.FORWARD_CONNECTION_SUCCESS:
            cmd_buffer = cmd + pack('<H', args[0])
            tlv_header = pack('<HH', relay.COMMAND_CHANNEL, len(cmd_buffer))
        elif cmd == relay.FORWARD_CONNECTION_FAILURE:
            cmd_buffer = cmd + pack('<H', args[0])
            tlv_header = pack('<HH', relay.COMMAND_CHANNEL, len(cmd_buffer))
        else:
            cmd_buffer = cmd
            tlv_header = pack('<HH', relay.COMMAND_CHANNEL, len(cmd_buffer))
        try:
            sock.send(tlv_header + cmd_buffer)
        except socket.error as (code, cmd):
            logger.error('Socket error on sending command to remote side. Code {0}. Msg {1}'.format(code, cmd))

    def set_channel(self, sock, channel_id):
        self.channel[channel_id] = sock
        self.id_by_socket[sock] = channel_id

    def unset_channel(self, channel_id):
        sock = self.channel[channel_id]
        del self.id_by_socket[sock]
        del self.channel[channel_id]

    def establish_forward_socket(self, channel_id, host, port):
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.setblocking(0)
            sock.connect_ex((host, port))
        except socket.error as (code, msg):
            logger.debug("Caught exception socket.error during establishing forward connection. Code {0}. Msg {1}".format(code, msg))
            self.send_remote_cmd(self.bc_sock, relay.FORWARD_CONNECTION_FAILURE, channel_id)
            return
        logger.debug('Adding new pending forward connection with channel id {0} and socket {1}'.format(channel_id, sock))
        self.establishing_dict[sock] = channel_id

    def relay(self, data, to_socket):
        if to_socket is None:
            return
        try:
            to_socket.send(data)
        except socket.error as (code, msg):
            logger.debug('Exception on relaying data to socket {0}'.format(to_socket))
            logger.debug('Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))
            if to_socket == self.bc_sock:
                raise relay.RelayError
            else:
                logger.debug('Closing socket')
                to_socket.close()
                self.input_list.remove(to_socket)
                channel_id = self.id_by_socket[to_socket]
                self.unset_channel(channel_id)
                self.send_remote_cmd(self.socket_with_server, relay.CHANNEL_CLOSE_CMD, channel_id)


class NtlmProxyContext(object):

    negotiate_request = '''CONNECT {0}:{1} HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0
Proxy-Connection: keep-alive
Connection: keep-alive
Proxy-Authorization: NTLM {2}

'''
    authenticate_request = '''CONNECT {0}:{1} HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0
Proxy-Connection: keep-alive
Connection: keep-alive
Proxy-Authorization: NTLM {2}

'''

    def __init__(self, sock, proxy_ip, proxy_port, username, domain=None, password=None, nthash=None, lmhash=None):
        self._sock = sock
        self._proxy_ip = proxy_ip
        self._proxy_port = proxy_port
        self._username = username
        self._password = password
        self._nthash = nthash
        self._lmhash = lmhash
        self._domain = domain
        self._workstation = socket.gethostname().upper()

    def connect(self, host_port):
        (host, port) = host_port
        ntlm_context = Ntlm(ntlm_compatibility=5)
        negotiate_message = ntlm_context.create_negotiate_message(self._domain, self._workstation).decode()
        resp = None
        try:
            self._sock.connect((self._proxy_ip, self._proxy_port))
            self._sock.send(NtlmProxyContext.negotiate_request.format(host, str(port), negotiate_message))
            resp = self._sock.recv(4096)
        except socket.error as (code, msg):
            logger.error("Caught socket error trying to establish connection to proxy. Code {0}. Msg {1}".format(code, msg))
            raise

        try:
            chal_msg = NtlmProxyContext.get_challenge(resp)
            ntlm_context.parse_challenge_message(chal_msg)
        except TypeError:
            logger.error("Couldn't parse proxy challenge. Code {0}. Msg {1}".format(code, msg))
            if resp is not None:
                logger.error("Challenge contents: {0}".format(resp))
            else:
                logger.error("Challenge contents is 'None'")
            self._sock.close()



        authenticate_message = ntlm_context.create_authenticate_message(user_name=self._username,
                                                                        domain_name=self._domain,
                                                                        password=self._password,
                                                                        nthash=self._nthash,
                                                                        lmhash=self._lmhash).decode()
        resp = None
        try:
            self._sock.send(NtlmProxyContext.authenticate_request.format(host, str(port), authenticate_message))
            resp = self._sock.recv(4096)
        except socket.error as (code, msg):
            logger.error("Caught socket error trying to send challenge response connection to proxy. Code {0}. Msg {1}".format(code, msg))
            self._sock.close()
            raise

        if resp is None:
            logger.error("Received an empty response to the challenge response")
            self._sock.close()


        if 'HTTP/1.1 200 Connection established' in resp:
            logger.info('Ntlm proxy established connection')
            logger.debug(resp)
        elif 'HTTP/1.1 503 Service Unavailable' in resp:
            logger.error('Ntlm proxy response: Service Unavailable')
            logger.debug(resp)
            self._sock.close()
        elif 'HTTP/1.1 407 Proxy Authentication Required' in resp:
            logger.error('Ntlm proxy authentication failed')
            logger.debug(resp)
            self._sock.close()
            sys.exit(1)
        else:
            logger.error('Ntlm proxy unknown error')
            logger.debug(resp)
            self._sock.close()

    def __getattr__(self, attribute_name):
        """Defer unknown behaviour to the socket"""
        return getattr(self._sock, attribute_name)

    @staticmethod
    def get_challenge(raw_msg):
        if raw_msg is None:
            return None
        re_res = re.search(r'^Proxy-Authenticate: NTLM (.*)$', raw_msg, re.MULTILINE)
        if re_res is None:
            return None
        else:
            return re_res.group(1)


def main():
    global logger

    parser = optparse.OptionParser(description='Reverse socks client')
    parser.add_option('--server-ip', action="store", dest='server_ip')
    parser.add_option('--server-port', action="store", dest='server_port', default='9999')
    parser.add_option('--verbose', action="store_true", dest="verbose", default=False)
    parser.add_option('--logfile', action="store", dest="logfile", default=None)

    proxy_group = optparse.OptionGroup(parser, 'Ntlm Proxy authentication')

    proxy_group.add_option('--ntlm-proxy-ip', dest='ntlm_proxy_ip', default=None, action='store', help='IP address of NTLM proxy')
    proxy_group.add_option('--ntlm-proxy-port', dest='ntlm_proxy_port', default=None, action='store', help='Port of NTLM proxy')
    proxy_group.add_option('--username', dest='username', default='', action='store', help='Username to authenticate with NTLM proxy')
    proxy_group.add_option('--domain', dest='domain', default='', action='store', help='Domain to authenticate with NTLM proxy')
    proxy_group.add_option('--password', dest='password', default='', action='store', help='Password to authenticate with NTLM proxy')
    proxy_group.add_option('--hashes', dest='hashes', default=None, action='store', help='Hashes to authenticate with instead of password. Format - LMHASH:NTHASH')

    parser.add_option_group(proxy_group)


    cmd_options = parser.parse_args()[0]
    if cmd_options.server_ip is None:
        print 'Server IP required'
        sys.exit()
    logger = logging.getLogger('root')
    logger.setLevel(logging.DEBUG)

    if cmd_options.logfile is None:
        ch = logging.StreamHandler()
    else:
        ch = logging.FileHandler(cmd_options.logfile)

    if cmd_options.verbose:
        ch.setLevel(logging.DEBUG)
    else:
        ch.setLevel(logging.INFO)
    logger.addHandler(ch)
    logger.addHandler(ch)
    while True:
        logger.info('Backconnecting to server {0} port {1}'.format(cmd_options.server_ip, cmd_options.server_port))
        backconnect_host = cmd_options.server_ip
        backconnect_port = int(cmd_options.server_port)
        bc_sock = None
        while True:
            try:
                bc_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                if cmd_options.ntlm_proxy_ip is not None:
                    if cmd_options.ntlm_proxy_port is None:
                        logger.error('Error. Must specify ntlm proxy port')
                        sys.exit(1)
                    if cmd_options.hashes is not None:
                        if re.match('[a-zA-Z0-9]{32}:[a-zA-Z0-9]{32}', cmd_options.hashes) is None:
                            logger.error('Hash format error. Valid hash format - LMHASH:NTHASH')
                            sys.exit(1)

                    logger.info('Connecting via NTLM proxy at {0}:{1}'.format(cmd_options.ntlm_proxy_ip, cmd_options.ntlm_proxy_port))
                    ntlm_con = NtlmProxyContext(bc_sock, proxy_ip=cmd_options.ntlm_proxy_ip,
                                                proxy_port=int(cmd_options.ntlm_proxy_port),
                                                username=cmd_options.username,
                                                domain=cmd_options.domain,
                                                password=cmd_options.password,
                                                nthash=None if cmd_options.hashes is None else cmd_options.hashes.split(':')[1],
                                                lmhash=None if cmd_options.hashes is None else cmd_options.hashes.split(':')[0])

                    bc_sock = ntlm_con
                bc_sock.connect((backconnect_host, backconnect_port))
                break
            except socket.error as (code, msg):
                logger.info('Unable to connect to {0} port: {1}. Caught socket error trying to establish connection with RPIVOT server. Code {2}. Msg {3}'.format(cmd_options.server_ip, cmd_options.server_port, code, msg))
                logger.info('Retrying')
                time.sleep(5)

        try:
            bc_sock.send(relay.banner)
            banner_reponse_rcv = bc_sock.recv(4096)
            if banner_reponse_rcv != relay.banner_response:
                logger.error("Wrong banner response {0} from server. Retrying".format(repr(banner_reponse_rcv)))
                bc_sock.close()
                time.sleep(5)
                continue
        except socket.error as (code, msg):
            logger.error("Caught socket error trying to establish connection with RPIVOT server. Code {0}. Msg {1}".format(code, msg))
            bc_sock.close()
            time.sleep(5)
            continue

        socks_relayer = SocksRelay(bc_sock)
        try:
            socks_relayer.run()
        except socket.error as (code, msg):
            logger.debug('Exception in socks_relayer.run(). Restarting relay')
            logger.debug('Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))
            bc_sock.close()
            continue
        time.sleep(10)

if __name__ == '__main__':
    main()


================================================
FILE: ntlm_auth/U32.py
================================================
# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/
# Copyright 2001 Dmitry A. Rozmanov <dima@xenon.spb.ru>
#
# This library is free software: you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation, either
# version 3 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.

from __future__ import division
import six

C = 0x1000000000


def norm(n):
    return n & 0xFFFFFFFF


class U32:
    v = 0

    def __init__(self, value=0):
        if not isinstance(value, six.integer_types):
            value = six.byte2int(value)

        self.v = C + norm(abs(int(value)))

    def set(self, value=0):
        self.v = C + norm(abs(int(value)))

    def __repr__(self):
        return hex(norm(self.v))

    def __long__(self):
        return int(norm(self.v))

    def __int__(self):
        return int(norm(self.v))

    def __chr__(self):
        return chr(norm(self.v))

    def __add__(self, b):
        r = U32()
        r.v = C + norm(self.v + b.v)
        return r

    def __sub__(self, b):
        r = U32()
        if self.v < b.v:
            r.v = C + norm(0x100000000 - (b.v - self.v))
        else:
            r.v = C + norm(self.v - b.v)
        return r

    def __mul__(self, b):
        r = U32()
        r.v = C + norm(self.v * b.v)
        return r

    def __div__(self, b):
        r = U32()
        r.v = C + (norm(self.v) // norm(b.v))
        return r

    def __truediv__(self, b):
        r = U32()
        r.v = C + (norm(self.v) / norm(b.v))
        return r

    def __mod__(self, b):
        r = U32()
        r.v = C + (norm(self.v) % norm(b.v))
        return r

    def __neg__(self):
        return U32(self.v)

    def __pos__(self):
        return U32(self.v)

    def __abs__(self):
        return U32(self.v)

    def __invert__(self):
        r = U32()
        r.v = C + norm(~self.v)
        return r

    def __lshift__(self, b):
        r = U32()
        r.v = C + norm(self.v << b)
        return r

    def __rshift__(self, b):
        r = U32()
        r.v = C + (norm(self.v) >> b)
        return r

    def __and__(self, b):
        r = U32()
        r.v = C + norm(self.v & b.v)
        return r

    def __or__(self, b):
        r = U32()
        r.v = C + norm(self.v | b.v)
        return r

    def __xor__(self, b):
        r = U32()
        r.v = C + norm(self.v ^ b.v)
        return r

    def __not__(self):
        return U32(not norm(self.v))

    def truth(self):
        return norm(self.v)

    def __cmp__(self, b):
        if norm(self.v) > norm(b.v):
            return 1
        elif norm(self.v) < norm(b.v):
            return -1
        else:
            return 0

    def __lt__(self, other):
        return self.v < other.v

    def __gt__(self, other):
        return self.v > other.v

    def __eq__(self, other):
        return self.v == other.v

    def __le__(self, other):
        return self.v <= other.v

    def __ge__(self, other):
        return self.v >= other.v

    def __ne__(self, other):
        return self.v != other.v

    def __nonzero__(self):
        return norm(self.v)


================================================
FILE: ntlm_auth/__init__.py
================================================
from . import ntlm, session_security

__all__ = ('ntlm', 'session_security')

================================================
FILE: ntlm_auth/compute_hash.py
================================================
# This library is free software: you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation, either
# version 3 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.

import binascii
import hashlib
import hmac
import re
from ntlm_auth import des


def _lmowfv1(password, lmhash):
    """
    [MS-NLMP] v28.0 2016-07-14

    3.3.1 NTLM v1 Authentication
    Same function as LMOWFv1 in document to create a one way hash of the password. Only
    used in NTLMv1 auth without session security

    :param password: The password of the user we are trying to authenticate with
    :return res: A Lan Manager hash of the password supplied
    """

    # fix the password length to 14 bytes
    if lmhash is not None:
        return lmhash.decode('hex')

    password = password.upper()
    lm_pw = password[0:14]

    # do hash
    magic_str = b"KGS!@#$%"  # page 56 in [MS-NLMP v28.0]

    res = b''
    dobj = des.DES(lm_pw[0:7])
    res = res + dobj.encrypt(magic_str)

    dobj = des.DES(lm_pw[7:14])
    res = res + dobj.encrypt(magic_str)
    return res

def _ntowfv1(password, nthash):
    """
    [MS-NLMP] v28.0 2016-07-14

    3.3.1 NTLM v1 Authentication
    Same function as NTOWFv1 in document to create a one way hash of the password. Only
    used in NTLMv1 auth without session security

    :param password: The password of the user we are trying to authenticate with
    :return digest: An NT hash of the password supplied
    """
    if nthash is not None:
        return nthash.decode('hex')

    digest = hashlib.new('md4', password.encode('utf-16le')).digest()
    return digest

def _ntowfv2(user_name, password, nthash, domain_name):
    """
    [MS-NLMP] v28.0 2016-07-14

    3.3.2 NTLM v2 Authentication
    Same function as NTOWFv2 (and LMOWFv2) in document to create a one way hash of the password.
    This combines some extra security features over the v1 calculations used in NTLMv2 auth.

    :param user_name: The user name of the user we are trying to authenticate with
    :param password: The password of the user we are trying to authenticate with
    :param domain_name: The domain name of the user account we are authenticated with
    :return digest: An NT hash of the parameters supplied
    """
    digest = _ntowfv1(password, nthash)
    digest = hmac.new(digest, (user_name.upper() + domain_name).encode('utf-16le')).digest()


    return digest

================================================
FILE: ntlm_auth/compute_keys.py
================================================
# This library is free software: you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation, either
# version 3 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.

import binascii
import hashlib
import hmac
from ntlm_auth import des
from ntlm_auth.constants import NegotiateFlags

def _get_exchange_key_ntlm_v1(negotiate_flags, session_base_key, server_challenge, lm_challenge_response, lm_hash):
    """
    [MS-NLMP] v28.0 2016-07-14

    4.3.5.1 KXKEY
    Calculates the Key Exchange Key for NTLMv1 authentication. Used for signing and sealing messages

    @param negotiate_flags:
    @param session_base_key: A session key calculated from the user password challenge
    @param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE
    @param lm_challenge_response: The LmChallengeResponse value computed in ComputeResponse
    @param lm_hash: The LMOWF computed in Compute Response
    @return key_exchange_key: The Key Exchange Key (KXKEY) used to sign and seal messages and compute the ExportedSessionKey
    """
    if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
        key_exchange_key = hmac.new(session_base_key, server_challenge + lm_challenge_response[:8]).digest()
    elif negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_LM_KEY:
        des_handler = des.DES(lm_hash[:7])
        first_des = des_handler.encrypt(lm_challenge_response[:8])
        des_handler = des.DES(lm_hash[7:8] + binascii.unhexlify('bdbdbdbdbdbdbd'))
        second_des = des_handler.encrypt(lm_challenge_response[:8])

        key_exchange_key = first_des + second_des
    elif negotiate_flags & NegotiateFlags.NTLMSSP_REQUEST_NON_NT_SESSION_KEY:
        key_exchange_key = lm_hash[:8] + b'\0' * 8
    else:
        key_exchange_key = session_base_key

    return key_exchange_key

def _get_exchange_key_ntlm_v2(session_base_key):
    """
    [MS-NLMP] v28.0 2016-07-14

    4.3.5.1 KXKEY
    Calculates the Key Exchange Key for NTLMv2 authentication. Used for signing and sealing messages.
    According to docs, 'If NTLM v2 is used, KeyExchangeKey MUST be set to the given 128-bit SessionBaseKey

    @param session_base_key: A session key calculated from the user password challenge
    @return key_exchange_key: The Key Exchange Key (KXKEY) used to sign and seal messages
    """
    return session_base_key

def get_sign_key(exported_session_key, magic_constant):
    """
    3.4.5.2 SIGNKEY

    @param exported_session_key: A 128-bit session key used to derive signing and sealing keys
    @param magic_constant: A constant value set in the MS-NLMP documentation (constants.SignSealConstants)
    @return sign_key: Key used to sign messages
    """

    sign_key = hashlib.md5(exported_session_key + magic_constant).digest()

    return sign_key

def get_seal_key(negotiate_flags, exported_session_key, magic_constant):
    """
    3.4.5.3. SEALKEY
    Main method to use to calculate the seal_key used to seal (encrypt) messages. This will determine
    the correct method below to use based on the compatibility flags set and should be called instead
    of the others

    @param exported_session_key: A 128-bit session key used to derive signing and sealing keys
    @param negotiate_flags: The negotiate_flags structure sent by the server
    @param magic_constant: A constant value set in the MS-NLMP documentation (constants.SignSealConstants)
    @return seal_key: Key used to seal messages
    """

    if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
        seal_key = _get_seal_key_ntlm2(negotiate_flags, exported_session_key, magic_constant)
    elif negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_LM_KEY:
        seal_key = _get_seal_key_ntlm1(negotiate_flags, exported_session_key)
    else:
        seal_key = exported_session_key

    return seal_key

def _get_seal_key_ntlm1(negotiate_flags, exported_session_key):
    """
    3.4.5.3 SEALKEY
    Calculates the seal_key used to seal (encrypt) messages. This for authentication where
    NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY has not been negotiated. Will weaken the keys
    if NTLMSSP_NEGOTIATE_56 is not negotiated it will default to the 40-bit key

    @param negotiate_flags: The negotiate_flags structure sent by the server
    @param exported_session_key: A 128-bit session key used to derive signing and sealing keys
    @return seal_key: Key used to seal messages
    """
    if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_56:
        seal_key = exported_session_key[:7] + binascii.unhexlify('a0')
    else:
        seal_key = exported_session_key[:5] + binascii.unhexlify('e538b0')

    return seal_key

def _get_seal_key_ntlm2(negotiate_flags, exported_session_key, magic_constant):
    """
    3.4.5.3 SEALKEY
    Calculates the seal_key used to seal (encrypt) messages. This for authentication where
    NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY has been negotiated. Will weaken the keys
    if NTLMSSP_NEGOTIATE_128 is not negotiated, will try NEGOTIATE_56 and then will default
    to the 40-bit key

    @param negotiate_flags: The negotiate_flags structure sent by the server
    @param exported_session_key: A 128-bit session key used to derive signing and sealing keys
    @param magic_constant: A constant value set in the MS-NLMP documentation (constants.SignSealConstants)
    @return seal_key: Key used to seal messages
    """
    if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_128:
        seal_key = exported_session_key
    elif negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_56:
        seal_key = exported_session_key[:7]
    else:
        seal_key = exported_session_key[:5]

    seal_key = hashlib.md5(seal_key + magic_constant).digest()

    return seal_key

================================================
FILE: ntlm_auth/compute_response.py
================================================
# This library is free software: you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation, either
# version 3 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.

import base64
import calendar
import hashlib
import hmac
import os
import struct
import time
import ntlm_auth.compute_hash as comphash
import ntlm_auth.compute_keys as compkeys
from ntlm_auth import des
from ntlm_auth.constants import NegotiateFlags, AvFlags
from ntlm_auth.gss_channel_bindings import GssChannelBindingsStruct
from ntlm_auth.target_info import TargetInfo

class ComputeResponse():
    """
        Constructor for the response computations. This class will compute the various
        nt and lm challenge responses.

        :param user_name: The user name of the user we are trying to authenticate with
        :param password: The password of the user we are trying to authenticate with
        :param domain_name: The domain name of the user account we are authenticated with, default is None
        :param challenge_message: A ChallengeMessage object that was received from the server after the negotiate_message
        :param ntlm_compatibility: The Lan Manager Compatibility Level, used to determine what NTLM auth version to use, see Ntlm in ntlm.py for more details
    """
    def __init__(self, user_name, password, nthash, lmhash, domain_name, challenge_message, ntlm_compatibility):
        self._user_name = user_name
        self._password = password
        self._nthash = nthash
        self._lmhash = lmhash
        self._domain_name = domain_name
        self._challenge_message = challenge_message
        self._negotiate_flags = challenge_message.negotiate_flags
        self._server_challenge = challenge_message.server_challenge
        self._server_target_info = challenge_message.target_info
        self._ntlm_compatibility = ntlm_compatibility
        self._client_challenge = os.urandom(8)

    def get_lm_challenge_response(self):
        """
        [MS-NLMP] v28.0 2016-07-14

        3.3.1 - NTLM v1 Authentication
        3.3.2 - NTLM v2 Authentication

        This method returns the LmChallengeResponse key based on the ntlm_compatibility chosen
        and the target_info supplied by the CHALLENGE_MESSAGE. It is quite different from what
        is set in the document as it combines the NTLMv1, NTLM2 and NTLMv2 methods into one
        and calls separate methods based on the ntlm_compatibility flag chosen.

        :return: response (LmChallengeResponse) - The LM response to the server challenge. Computed by the client
        """
        if self._negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY and self._ntlm_compatibility < 3:
            response = ComputeResponse._get_LMv1_with_session_security_response(self._client_challenge)

        elif 0 <= self._ntlm_compatibility <= 1:
            response = ComputeResponse._get_LMv1_response(self._password, self._lmhash, self._server_challenge)
        elif self._ntlm_compatibility == 2:
            # Based on the compatibility level we don't want to use LM responses, ignore the session_base_key as it is returned in nt
            response, ignore_key = ComputeResponse._get_NTLMv1_response(self._password, self._nthash, self._server_challenge)
        else:
            """
            [MS-NLMP] v28.0 page 45 - 2016-07-14

            3.1.5.12 Client Received a CHALLENGE_MESSAGE from the Server
            If NTLMv2 authentication is used and the CHALLENGE_MESSAGE TargetInfo field has an MsvAvTimestamp present,
            the client SHOULD NOT send the LmChallengeResponse and SHOULD send Z(24) instead.
            """

            response = ComputeResponse._get_LMv2_response(self._user_name, self._password, self._nthash, self._domain_name,
                                                          self._server_challenge,
                                                          self._client_challenge)
            if self._server_target_info is not None:
                timestamp = self._server_target_info[TargetInfo.MSV_AV_TIMESTAMP]
                if timestamp is not None:
                    response = b'\0' * 24

        return response

    def get_nt_challenge_response(self, lm_challenge_response, server_certificate_hash):
        """
        [MS-NLMP] v28.0 2016-07-14

        3.3.1 - NTLM v1 Authentication
        3.3.2 - NTLM v2 Authentication

        This method returns the NtChallengeResponse key based on the ntlm_compatibility chosen
        and the target_info supplied by the CHALLENGE_MESSAGE. It is quite different from what
        is set in the document as it combines the NTLMv1, NTLM2 and NTLMv2 methods into one
        and calls separate methods based on the ntlm_compatibility value chosen.

        :param lm_challenge_response: The LmChallengeResponse calculated beforeand, used to get the key_exchange_key value
        :param server_certificate_hash: The SHA256 hash of the server certificate (DER encoded) NTLM is authenticated to.
                                        Used in Channel Binding Tokens if present, default value is None. See
                                        AuthenticateMessage in messages.py for more details
        :return response: (NtChallengeResponse) - The NT response to the server challenge. Computed by the client
        :return session_base_key: (SessionBaseKey) - A session key calculated from the user password challenge
        :return target_info: (AV_PAIR) - The AV_PAIR structure used in the nt_challenge calculations
        """
        if self._negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY and self._ntlm_compatibility < 3:
            # The compatibility level is less than 3 which means it doesn't support NTLMv2 but we want extended security so use NTLM2 which is different from NTLMv2
            # [MS-NLMP] - 3.3.1 NTLMv1 Authentication
            response, session_base_key = ComputeResponse._get_NTLM2_response(self._password, self._nthash, self._server_challenge, self._client_challenge)
            key_exchange_key = compkeys._get_exchange_key_ntlm_v1(self._negotiate_flags, session_base_key,
                                                                  self._server_challenge, lm_challenge_response,
                                                                  comphash._lmowfv1(self._password, self._lmhash))
            target_info = None

        elif 0 <= self._ntlm_compatibility < 3:
            response, session_base_key = ComputeResponse._get_NTLMv1_response(self._password, self._nthash, self._server_challenge)
            key_exchange_key = compkeys._get_exchange_key_ntlm_v1(self._negotiate_flags, session_base_key,
                                                                  self._server_challenge, lm_challenge_response,
                                                                  comphash._lmowfv1(self._password, self._lmhash))
            target_info = None
        else:
            if self._server_target_info is None:
                target_info = TargetInfo()
            else:
                target_info = self._server_target_info

            if target_info[TargetInfo.MSV_AV_TIMESTAMP] is None:
                timestamp = get_windows_timestamp()
            else:
                timestamp = target_info[TargetInfo.MSV_AV_TIMESTAMP][1]

                # [MS-NLMP] If the CHALLENGE_MESSAGE TargetInfo field has an MsvAvTimestamp present, the client SHOULD provide a MIC
                target_info[TargetInfo.MSV_AV_FLAGS] = struct.pack("<L", AvFlags.MIC_PROVIDED)

            if server_certificate_hash != None:
                channel_bindings_hash = ComputeResponse._get_channel_bindings_value(server_certificate_hash)
                target_info[TargetInfo.MSV_AV_CHANNEL_BINDINGS] = channel_bindings_hash

            response, session_base_key = ComputeResponse._get_NTLMv2_response(self._user_name, self._password, self._nthash, self._domain_name,
                                                 self._server_challenge, self._client_challenge, timestamp, target_info)

            key_exchange_key = compkeys._get_exchange_key_ntlm_v2(session_base_key)

        return response, key_exchange_key, target_info


    @staticmethod
    def _get_LMv1_response(password, lmhash, server_challenge):
        """
        [MS-NLMP] v28.0 2016-07-14

        2.2.2.3 LM_RESPONSE
        The LM_RESPONSE structure defines the NTLM v1 authentication LmChallengeResponse
        in the AUTHENTICATE_MESSAGE. This response is used only when NTLM v1
        authentication is configured.

        :param password: The password of the user we are trying to authenticate with
        :param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE
        :return response: LmChallengeResponse to the server challenge
        """
        lm_hash = comphash._lmowfv1(password, lmhash)
        response = ComputeResponse._calc_resp(lm_hash, server_challenge)

        return response

    @staticmethod
    def _get_LMv1_with_session_security_response(client_challenge):
        """
        [MS-NLMP] v28.0 2016-07-14

        2.2.2.3 LM_RESPONSE
        The LM_RESPONSE structure defines the NTLM v1 authentication LmChallengeResponse
        in the AUTHENTICATE_MESSAGE. This response is used only when NTLM v1
        authentication is configured and NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY is flages.

        :param client_challenge: A random 8-byte response generated by the client for the AUTHENTICATE_MESSAGE
        :return response: LmChallengeResponse to the server challenge
        """

        response = client_challenge + b'\0' * 16

        return response

    @staticmethod
    def _get_LMv2_response(user_name, password, nthash, domain_name, server_challenge, client_challenge):
        """
        [MS-NLMP] v28.0 2016-07-14

        2.2.2.4 LMv2_RESPONSE
        The LMv2_RESPONSE structure defines the NTLM v2 authentication LmChallengeResponse
        in the AUTHENTICATE_MESSAGE. This response is used only when NTLM v2
        authentication is configured.

        :param user_name: The user name of the user we are trying to authenticate with
        :param password: The password of the user we are trying to authenticate with
        :param domain_name: The domain name of the user account we are authenticated with
        :param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE
        :param client_challenge: A random 8-byte response generated by the client for the AUTHENTICATE_MESSAGE
        :return response: LmChallengeResponse to the server challenge
        """
        nt_hash = comphash._ntowfv2(user_name, password, nthash, domain_name)
        lm_hash = hmac.new(nt_hash, (server_challenge + client_challenge)).digest()
        response = lm_hash + client_challenge

        return response

    @staticmethod
    def _get_NTLMv1_response(password, nthash, server_challenge):
        """
        [MS-NLMP] v28.0 2016-07-14

        2.2.2.6 NTLM v1 Response: NTLM_RESPONSE
        The NTLM_RESPONSE strucutre defines the NTLM v1 authentication NtChallengeResponse
        in the AUTHENTICATE_MESSAGE. This response is only used when NTLM v1 authentication
        is configured.

        :param password: The password of the user we are trying to authenticate with
        :param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE
        :return response: NtChallengeResponse to the server_challenge
        :return session_base_key: A session key calculated from the user password challenge
        """
        ntlm_hash = comphash._ntowfv1(password, nthash)
        response = ComputeResponse._calc_resp(ntlm_hash, server_challenge)

        session_base_key = hashlib.new('md4', ntlm_hash).digest()

        return response, session_base_key

    @staticmethod
    def _get_NTLM2_response(password, nthash, server_challenge, client_challenge):
        """
        [MS-NLMP] v28.0 2016-07-14

        This name is really misleading as it isn't NTLM v2 authentication rather
        This authentication is only used when the ntlm_compatibility level is set
        to a value < 3 (No NTLMv2 auth) but the NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
        flag is set in the negotiate flags section. The documentation for computing this
        value is on page 56 under section 3.3.1 NTLM v1 Authentication

        :param password: The password of the user we are trying to authenticate with
        :param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE
        :param client_challenge: A random 8-byte response generated by the client for the AUTHENTICATE_MESSAGE
        :return response: NtChallengeResponse to the server_challenge
        :return session_base_key: A session key calculated from the user password challenge
        """
        ntlm_hash = comphash._ntowfv1(password, nthash)
        nt_session_hash = hashlib.md5(server_challenge + client_challenge).digest()[:8]
        response = ComputeResponse._calc_resp(ntlm_hash, nt_session_hash[0:8])

        session_base_key = hashlib.new('md4', ntlm_hash).digest()

        return response, session_base_key

    @staticmethod
    def _get_NTLMv2_response(user_name, password, nthash, domain_name, server_challenge, client_challenge, timestamp, target_info):
        """
        [MS-NLMP] v28.0 2016-07-14

        2.2.2.8 NTLM V2 Response: NTLMv2_RESPONSE
        The NTLMv2_RESPONSE strucutre defines the NTLMv2 authentication NtChallengeResponse
        in the AUTHENTICATE_MESSAGE. This response is used only when NTLMv2 authentication
        is configured.

        The guide on how this is computed is in 3.3.2 NTLM v2 Authentication.

        :param user_name: The user name of the user we are trying to authenticate with
        :param password: The password of the user we are trying to authenticate with
        :param domain_name: The domain name of the user account we are authenticated with
        :param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE
        :param client_challenge: A random 8-byte response generated by the client for the AUTHENTICATE_MESSAGE
        :param timestamp: An 8-byte timestamp in windows format, 100 nanoseconds since 1601-01-01
        :param target_info: The target_info structure from the CHALLENGE_MESSAGE with the CBT attached if required
        :return response: NtChallengeResponse to the server_challenge
        :return session_base_key: A session key calculated from the user password challenge
        """

        nt_hash = comphash._ntowfv2(user_name, password, nthash, domain_name)
        temp = ComputeResponse._get_NTLMv2_temp(timestamp, client_challenge, target_info)
        nt_proof_str = hmac.new(nt_hash, (server_challenge + temp)).digest()
        response = nt_proof_str + temp

        session_base_key = hmac.new(nt_hash, nt_proof_str).digest()

        return response, session_base_key

    @staticmethod
    def _get_NTLMv2_temp(timestamp, client_challenge, target_info):
        """
        [MS-NLMP] v28.0 2016-07-14

        2.2.2.7 NTLMv2_CLIENT_CHALLENGE - variable length
        The NTLMv2_CLIENT_CHALLENGE structure defines the client challenge in
        the AUTHENTICATE_MESSAGE. This structure is used only when NTLM v2
        authentication is configured and is transported in the NTLMv2_RESPONSE
        structure.

        The method to create this structure is defined in 3.3.2 NTLMv2 Authentication.
        In this method this variable is known as the temp value. The target_info variable
        corresponds to the ServerName variable used in that documentation. This is in
        reality a lot more than just the ServerName and contains the AV_PAIRS structure
        we need to transport with the message like Channel Binding tokens and others.
        By default this will be the target_info returned from the CHALLENGE_MESSAGE plus
        MSV_AV_CHANNEL_BINDINGS if specified otherwise it is a new target_info set with
        MSV_AV_TIMESTAMP to the current time.

        :param timestamp: An 8-byte timestamp in windows format, 100 nanoseconds since 1601-01-01
        :param client_challenge: A random 8-byte response generated by the client for the AUTHENTICATE_MESSAGE
        :param target_info: The target_info structure from the CHALLENGE_MESSAGE with the CBT attached if required
        :return temp: The CLIENT_CHALLENGE structure that will be added to the NtChallengeResponse structure
        """
        resp_type = b'\1'
        hi_resp_type = b'\1'
        reserved1 = b'\0' * 2
        reserved2 = b'\0' * 4
        reserved3 = b'\0' * 4
        reserved4 = b'\0' * 4  # This byte is not in the structure defined in 2.2.2.7 but is in the computation guide, works with it present

        temp = resp_type + hi_resp_type + reserved1 + \
               reserved2 + \
               timestamp + \
               client_challenge + \
               reserved3 + \
               target_info.get_data() + reserved4

        return temp

    @staticmethod
    def _calc_resp(password_hash, server_challenge):
        """
        Generate the LM response given a 16-byte password hash and the challenge
        from the CHALLENGE_MESSAGE

        :param password_hash: A 16-byte password hash
        :param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE
        :return res: A 24-byte buffer to contain the LM response upon return
        """

        # padding with zeros to make the hash 21 bytes long
        password_hash += b'\0' * (21 - len(password_hash))

        res = b''
        dobj = des.DES(password_hash[0:7])
        res = res + dobj.encrypt(server_challenge[0:8])

        dobj = des.DES(password_hash[7:14])
        res = res + dobj.encrypt(server_challenge[0:8])

        dobj = des.DES(password_hash[14:21])
        res = res + dobj.encrypt(server_challenge[0:8])
        return res

    @staticmethod
    def _get_channel_bindings_value(server_certificate_hash):
        """
        https://msdn.microsoft.com/en-us/library/windows/desktop/dd919963%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
        https://blogs.msdn.microsoft.com/openspecification/2013/03/26/ntlm-and-channel-binding-hash-aka-extended-protection-for-authentication/

        Get's the MD5 hash of the gss_channel_bindings_struct to add to the AV_PAIR MSV_AV_CHANNEL_BINDINGS.
        This method takes in the SHA256 hash (Hash of the DER encoded certificate of the server we are connecting to)
        and add's it to the gss_channel_bindings_struct. It then gets the MD5 hash and converts this to a
        byte array in preparation of adding it to the AV_PAIR structure.

        :param server_certificate_hash: The SHA256 hash of the server certificate (DER encoded) NTLM is authenticated to
        :return channel_bindings: An MD5 hash of the gss_channel_bindings_struct to add to the AV_PAIR MsvChannelBindings
        """
        # Channel Binding Tokens support, used for NTLMv2
        # Decode the SHA256 certificate hash
        certificate_digest = base64.b16decode(server_certificate_hash)

        # Initialise the GssChannelBindingsStruct and add the certificate_digest to the application_data field
        gss_channel_bindings = GssChannelBindingsStruct()
        gss_channel_bindings[gss_channel_bindings.APPLICATION_DATA] = 'tls-server-end-point:'.encode() + certificate_digest

        # Get the gss_channel_bindings_struct and create an MD5 hash
        channel_bindings_struct_data = gss_channel_bindings.get_data()
        channel_bindings_hash = hashlib.md5(channel_bindings_struct_data).hexdigest()

        try:
            cbt_value = bytearray.fromhex(channel_bindings_hash)
        except TypeError:
            # Work-around for Python 2.6 bug
            cbt_value = bytearray.fromhex(unicode(channel_bindings_hash))

        channel_bindings = bytes(cbt_value)
        return channel_bindings


def get_windows_timestamp():
    # Get Windows Date time, 100 nanoseconds since 1601-01-01 in a 64 bit structure
    timestamp = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000))

    return timestamp

================================================
FILE: ntlm_auth/constants.py
================================================
# This library is free software: you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation, either
# version 3 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.

"""
    [MS-NLMP] v28.0 2016-07-14

    2.2 Message Syntax
    The signature field used in NTLM messages
"""
NTLM_SIGNATURE = b'NTLMSSP\0'

"""
    [MS-NLMP] v28.0 2016-07-14

    2.2 Message Syntax
    The 3 message type options you can have in a message.
"""
class MessageTypes(object):
    NTLM_NEGOTIATE      = 0x1
    NTLM_CHALLENGE      = 0x2
    NTLM_AUTHENTICATE   = 0x3

"""
    [MS-NLMP] v28.0 2016-07-14

    2.2.2.1 AV_PAIR (MsvAvFlags)
    A 32-bit value indicated server or client configuration
"""
class AvFlags(object):
    AUTHENTICATION_CONSTRAINED  = 0x1
    MIC_PROVIDED                = 0x2
    UNTRUSTED_SPN_SOURCE        = 0x4

"""
    [MS-NLMP] v28.0 2016-07-14

    2.2.2.5 NEGOTIATE
    During NTLM authentication, each of the following flags is a possible value of the
    NegotiateFlags field of the NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE and AUTHENTICATE_MESSAGE,
    unless otherwise noted. These flags define client or server NTLM capabilities
    supported by the sender.
"""
class NegotiateFlags(object):
    NTLMSSP_NEGOTIATE_56                            = 0x80000000
    NTLMSSP_NEGOTIATE_KEY_EXCH                      = 0x40000000
    NTLMSSP_NEGOTIATE_128                           = 0x20000000
    NTLMSSP_RESERVED_R1                             = 0x10000000
    NTLMSSP_RESERVED_R2                             = 0x08000000
    NTLMSSP_RESERVED_R3                             = 0x04000000
    NTLMSSP_NEGOTIATE_VERSION                       = 0x02000000
    NTLMSSP_RESERVED_R4                             = 0x01000000
    NTLMSSP_NEGOTIATE_TARGET_INFO                   = 0x00800000
    NTLMSSP_REQUEST_NON_NT_SESSION_KEY              = 0x00400000
    NTLMSSP_RESERVED_R5                             = 0x00200000
    NTLMSSP_NEGOTIATE_IDENTITY                      = 0x00100000
    NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY      = 0x00080000
    NTLMSSP_RESERVED_R6                             = 0x00040000
    NTLMSSP_TARGET_TYPE_SERVER                      = 0x00020000
    NTLMSSP_TARGET_TYPE_DOMAIN                      = 0x00010000
    NTLMSSP_NEGOTIATE_ALWAYS_SIGN                   = 0x00008000
    NTLMSSP_RESERVED_R7                             = 0x00004000
    NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED      = 0x00002000
    NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED           = 0x00001000
    NTLMSSP_ANOYNMOUS                               = 0x00000800
    NTLMSSP_RESERVED_R8                             = 0x00000400
    NTLMSSP_NEGOTIATE_NTLM                          = 0x00000200
    NTLMSSP_RESERVED_R9                             = 0x00000100
    NTLMSSP_NEGOTIATE_LM_KEY                        = 0x00000080
    NTLMSSP_NEGOTIATE_DATAGRAM                      = 0x00000040
    NTLMSSP_NEGOTIATE_SEAL                          = 0x00000020
    NTLMSSP_NEGOTIATE_SIGN                          = 0x00000010
    NTLMSSP_RESERVED_R10                            = 0x00000008
    NTLMSSP_REQUEST_TARGET                          = 0x00000004
    NTLMSSP_NEGOTIATE_OEM                           = 0x00000002
    NTLMSSP_NEGOTIATE_UNICODE                       = 0x00000001

class SignSealConstants(object):
    # Magic Contants used to get the signing and sealing key for Extended Session Security
    CLIENT_SIGNING = b"session key to client-to-server signing key magic constant\0"
    SERVER_SIGNING = b"session key to server-to-client signing key magic constant\0"
    CLIENT_SEALING = b"session key to client-to-server sealing key magic constant\0"
    SERVER_SEALING = b"session key to server-to-client sealing key magic constant\0"


================================================
FILE: ntlm_auth/des.py
================================================
# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/
# Copyright 2001 Dmitry A. Rozmanov <dima@xenon.spb.ru>
#
# This library is free software: you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation, either
# version 3 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.
import logging
import six
from ntlm_auth import des_c

log = logging.getLogger(__name__)


class DES:
    des_c_obj = None

    def __init__(self, key_str):
        k = str_to_key56(key_str)
        k = key56_to_key64(k)

        key_str = b''
        for i in k:
            key_str += six.int2byte(i & 0xFF)

        self.des_c_obj = des_c.DES(key_str)

    def encrypt(self, plain_text):
        return self.des_c_obj.encrypt(plain_text)

    def decrypt(self, crypted_text):
        return self.des_c_obj.decrypt(crypted_text)


DESException = 'DESException'


def str_to_key56(key_str):

    if not type(key_str) == six.binary_type:
        # TODO rsanders high - figure out how to make this not necessary
        key_str = key_str.encode('ascii')

    if len(key_str) < 7:
        key_str = key_str + b'\000\000\000\000\000\000\000'[:(7 - len(key_str))]
    key_56 = []
    for i in six.iterbytes(key_str[:7]):
        key_56.append(i)

    return key_56


def key56_to_key64(key_56):
    key = []
    for i in range(8):
        key.append(0)

    key[0] = key_56[0]
    key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1)
    key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2)
    key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3)
    key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4)
    key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5)
    key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6)
    key[7] = (key_56[6] << 1) & 0xFF

    key = set_key_odd_parity(key)

    return key


def set_key_odd_parity(key):
    for i in range(len(key)):
        for k in range(7):
            bit = 0
            t = key[i] >> k
            bit = (t ^ bit) & 0x1
        key[i] = (key[i] & 0xFE) | bit

    return key


================================================
FILE: ntlm_auth/des_c.py
================================================
# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/
# Copyright 2001 Dmitry A. Rozmanov <dima@xenon.spb.ru>
#
# This library is free software: you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation, either
# version 3 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.
import six

from ntlm_auth.U32 import U32
from ntlm_auth.des_data import des_SPtrans, des_skb

def c2l(c):
    "char[4] to unsigned long"
    l = U32(c[0])
    l = l | (U32(c[1]) << 8)
    l = l | (U32(c[2]) << 16)
    l = l | (U32(c[3]) << 24)
    return l


def l2c(l):
    "unsigned long to char[4]"
    c = []
    c.append(int(l & U32(0xFF)))
    c.append(int((l >> 8) & U32(0xFF)))
    c.append(int((l >> 16) & U32(0xFF)))
    c.append(int((l >> 24) & U32(0xFF)))
    return c


def D_ENCRYPT(tup, u, t, s):
    L, R, S = tup
    # print 'LRS1', L, R, S, u, t, '-->',
    u = (R ^ s[S])
    t = R ^ s[S + 1]
    t = ((t >> 4) + (t << 28))
    L = L ^ (des_SPtrans[1][int((t) & U32(0x3f))] |
             des_SPtrans[3][int((t >> 8) & U32(0x3f))] |
             des_SPtrans[5][int((t >> 16) & U32(0x3f))] |
             des_SPtrans[7][int((t >> 24) & U32(0x3f))] |
             des_SPtrans[0][int((u) & U32(0x3f))] |
             des_SPtrans[2][int((u >> 8) & U32(0x3f))] |
             des_SPtrans[4][int((u >> 16) & U32(0x3f))] |
             des_SPtrans[6][int((u >> 24) & U32(0x3f))])
    # print 'LRS:', L, R, S, u, t
    return (L, R, S), u, t, s


def PERM_OP(tup, n, m):
    "tup - (a, b, t)"
    a, b, t = tup
    t = ((a >> n) ^ b) & m
    b = b ^ t
    a = a ^ (t << n)
    return (a, b, t)


def HPERM_OP(tup, n, m):
    "tup - (a, t)"
    a, t = tup
    t = ((a << (16 - n)) ^ a) & m
    a = a ^ t ^ (t >> (16 - n))
    return a, t


shifts2 = [0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0]


class DES:
    KeySched = None  # des_key_schedule

    def __init__(self, key_str):
        self.KeySched = des_set_key(key_str)

    def decrypt(self, str):
        # block - UChar[]
        block = []

        for i in six.iterbytes(str):
            block.append(i)

        # print block
        block = des_ecb_encrypt(block, self.KeySched, 0)

        res = b''
        for i in block:
            res = res + six.int2byte(i)

        return res

    def encrypt(self, plaintext):
        # block - UChar[]

        block = []
        for i in plaintext:
            block.append(i)

        block = des_ecb_encrypt(block, self.KeySched, 1)

        res = b''

        for i in block:
            res += six.int2byte(i)

        return res


def des_encript(input, ks, encrypt):
    # input - U32[]
    # output - U32[]
    # ks - des_key_shedule - U32[2][16]
    # encrypt - int
    # l, r, t, u - U32
    # i - int
    # s - U32[]

    l = input[0]
    r = input[1]
    t = U32(0)
    u = U32(0)

    r, l, t = PERM_OP((r, l, t), 4, U32(0x0f0f0f0f))
    l, r, t = PERM_OP((l, r, t), 16, U32(0x0000ffff))
    r, l, t = PERM_OP((r, l, t), 2, U32(0x33333333))
    l, r, t = PERM_OP((l, r, t), 8, U32(0x00ff00ff))
    r, l, t = PERM_OP((r, l, t), 1, U32(0x55555555))

    t = (r << 1) | (r >> 31)
    r = (l << 1) | (l >> 31)
    l = t

    s = ks  # ???????????????
    # print l, r
    if encrypt:
        for i in range(0, 32, 4):
            rtup, u, t, s = D_ENCRYPT((l, r, i + 0), u, t, s)
            l = rtup[0]
            r = rtup[1]
            rtup, u, t, s = D_ENCRYPT((r, l, i + 2), u, t, s)
            r = rtup[0]
            l = rtup[1]
    else:
        for i in range(30, 0, -4):
            rtup, u, t, s = D_ENCRYPT((l, r, i - 0), u, t, s)
            l = rtup[0]
            r = rtup[1]
            rtup, u, t, s = D_ENCRYPT((r, l, i - 2), u, t, s)
            r = rtup[0]
            l = rtup[1]
        # print l, r
    l = (l >> 1) | (l << 31)
    r = (r >> 1) | (r << 31)

    r, l, t = PERM_OP((r, l, t), 1, U32(0x55555555))
    l, r, t = PERM_OP((l, r, t), 8, U32(0x00ff00ff))
    r, l, t = PERM_OP((r, l, t), 2, U32(0x33333333))
    l, r, t = PERM_OP((l, r, t), 16, U32(0x0000ffff))
    r, l, t = PERM_OP((r, l, t), 4, U32(0x0f0f0f0f))

    output = [l]
    output.append(r)
    l, r, t, u = U32(0), U32(0), U32(0), U32(0)
    return output


def des_ecb_encrypt(input, ks, encrypt):
    # input - des_cblock - UChar[8]
    # output - des_cblock - UChar[8]
    # ks - des_key_shedule - U32[2][16]
    # encrypt - int

    # print input
    l0 = c2l(input[0:4])
    l1 = c2l(input[4:8])
    ll = [l0]
    ll.append(l1)
    # print ll
    ll = des_encript(ll, ks, encrypt)
    # print ll
    l0 = ll[0]
    l1 = ll[1]
    output = l2c(l0)
    output = output + l2c(l1)
    # print output
    l0, l1, ll[0], ll[1] = U32(0), U32(0), U32(0), U32(0)
    return output


def des_set_key(key):
    # key - des_cblock - UChar[8]
    # schedule - des_key_schedule

    # register unsigned long c,d,t,s;
    # register unsigned char *in;
    # register unsigned long *k;
    # register int i;

    # k = schedule
    # in = key

    k = []
    c = c2l(key[0:4])
    d = c2l(key[4:8])
    t = U32(0)

    d, c, t = PERM_OP((d, c, t), 4, U32(0x0f0f0f0f))
    c, t = HPERM_OP((c, t), -2, U32(0xcccc0000))
    d, t = HPERM_OP((d, t), -2, U32(0xcccc0000))
    d, c, t = PERM_OP((d, c, t), 1, U32(0x55555555))
    c, d, t = PERM_OP((c, d, t), 8, U32(0x00ff00ff))
    d, c, t = PERM_OP((d, c, t), 1, U32(0x55555555))

    d = (((d & U32(0x000000ff)) << 16) | (d & U32(0x0000ff00)) | ((d & U32(0x00ff0000)) >> 16) | (
        (c & U32(0xf0000000)) >> 4))
    c = c & U32(0x0fffffff)

    for i in range(16):
        if (shifts2[i]):
            c = ((c >> 2) | (c << 26))
            d = ((d >> 2) | (d << 26))
        else:
            c = ((c >> 1) | (c << 27))
            d = ((d >> 1) | (d << 27))
        c = c & U32(0x0fffffff)
        d = d & U32(0x0fffffff)

        s = des_skb[0][int((c) & U32(0x3f))] | \
            des_skb[1][int(((c >> 6) & U32(0x03)) | ((c >> 7) & U32(0x3c)))] | \
            des_skb[2][int(((c >> 13) & U32(0x0f)) | ((c >> 14) & U32(0x30)))] | \
            des_skb[3][int(((c >> 20) & U32(0x01)) | ((c >> 21) & U32(0x06)) | ((c >> 22) & U32(0x38)))]

        t = des_skb[4][int((d) & U32(0x3f))] | \
            des_skb[5][int(((d >> 7) & U32(0x03)) | ((d >> 8) & U32(0x3c)))] | \
            des_skb[6][int((d >> 15) & U32(0x3f))] | \
            des_skb[7][int(((d >> 21) & U32(0x0f)) | ((d >> 22) & U32(0x30)))]
        # print s, t

        k.append(((t << 16) | (s & U32(0x0000ffff))) & U32(0xffffffff))
        s = ((s >> 16) | (t & U32(0xffff0000)))
        s = (s << 4) | (s >> 28)
        k.append(s & U32(0xffffffff))

    schedule = k

    return schedule


================================================
FILE: ntlm_auth/des_data.py
================================================
# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/
# Copyright 2001 Dmitry A. Rozmanov <dima@xenon.spb.ru>
#
# This library is free software: you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation, either
# version 3 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.

from ntlm_auth.U32 import U32

# static unsigned long des_SPtrans[8][64]={

des_SPtrans = \
    [
        # nibble 0
        [
            U32(0x00820200), U32(0x00020000), U32(0x80800000), U32(0x80820200),
            U32(0x00800000), U32(0x80020200), U32(0x80020000), U32(0x80800000),
            U32(0x80020200), U32(0x00820200), U32(0x00820000), U32(0x80000200),
            U32(0x80800200), U32(0x00800000), U32(0x00000000), U32(0x80020000),
            U32(0x00020000), U32(0x80000000), U32(0x00800200), U32(0x00020200),
            U32(0x80820200), U32(0x00820000), U32(0x80000200), U32(0x00800200),
            U32(0x80000000), U32(0x00000200), U32(0x00020200), U32(0x80820000),
            U32(0x00000200), U32(0x80800200), U32(0x80820000), U32(0x00000000),
            U32(0x00000000), U32(0x80820200), U32(0x00800200), U32(0x80020000),
            U32(0x00820200), U32(0x00020000), U32(0x80000200), U32(0x00800200),
            U32(0x80820000), U32(0x00000200), U32(0x00020200), U32(0x80800000),
            U32(0x80020200), U32(0x80000000), U32(0x80800000), U32(0x00820000),
            U32(0x80820200), U32(0x00020200), U32(0x00820000), U32(0x80800200),
            U32(0x00800000), U32(0x80000200), U32(0x80020000), U32(0x00000000),
            U32(0x00020000), U32(0x00800000), U32(0x80800200), U32(0x00820200),
            U32(0x80000000), U32(0x80820000), U32(0x00000200), U32(0x80020200),
        ],

        # nibble 1
        [
            U32(0x10042004), U32(0x00000000), U32(0x00042000), U32(0x10040000),
            U32(0x10000004), U32(0x00002004), U32(0x10002000), U32(0x00042000),
            U32(0x00002000), U32(0x10040004), U32(0x00000004), U32(0x10002000),
            U32(0x00040004), U32(0x10042000), U32(0x10040000), U32(0x00000004),
            U32(0x00040000), U32(0x10002004), U32(0x10040004), U32(0x00002000),
            U32(0x00042004), U32(0x10000000), U32(0x00000000), U32(0x00040004),
            U32(0x10002004), U32(0x00042004), U32(0x10042000), U32(0x10000004),
            U32(0x10000000), U32(0x00040000), U32(0x00002004), U32(0x10042004),
            U32(0x00040004), U32(0x10042000), U32(0x10002000), U32(0x00042004),
            U32(0x10042004), U32(0x00040004), U32(0x10000004), U32(0x00000000),
            U32(0x10000000), U32(0x00002004), U32(0x00040000), U32(0x10040004),
            U32(0x00002000), U32(0x10000000), U32(0x00042004), U32(0x10002004),
            U32(0x10042000), U32(0x00002000), U32(0x00000000), U32(0x10000004),
            U32(0x00000004), U32(0x10042004), U32(0x00042000), U32(0x10040000),
            U32(0x10040004), U32(0x00040000), U32(0x00002004), U32(0x10002000),
            U32(0x10002004), U32(0x00000004), U32(0x10040000), U32(0x00042000),
        ],

        # nibble 2
        [
            U32(0x41000000), U32(0x01010040), U32(0x00000040), U32(0x41000040),
            U32(0x40010000), U32(0x01000000), U32(0x41000040), U32(0x00010040),
            U32(0x01000040), U32(0x00010000), U32(0x01010000), U32(0x40000000),
            U32(0x41010040), U32(0x40000040), U32(0x40000000), U32(0x41010000),
            U32(0x00000000), U32(0x40010000), U32(0x01010040), U32(0x00000040),
            U32(0x40000040), U32(0x41010040), U32(0x00010000), U32(0x41000000),
            U32(0x41010000), U32(0x01000040), U32(0x40010040), U32(0x01010000),
            U32(0x00010040), U32(0x00000000), U32(0x01000000), U32(0x40010040),
            U32(0x01010040), U32(0x00000040), U32(0x40000000), U32(0x00010000),
            U32(0x40000040), U32(0x40010000), U32(0x01010000), U32(0x41000040),
            U32(0x00000000), U32(0x01010040), U32(0x00010040), U32(0x41010000),
            U32(0x40010000), U32(0x01000000), U32(0x41010040), U32(0x40000000),
            U32(0x40010040), U32(0x41000000), U32(0x01000000), U32(0x41010040),
            U32(0x00010000), U32(0x01000040), U32(0x41000040), U32(0x00010040),
            U32(0x01000040), U32(0x00000000), U32(0x41010000), U32(0x40000040),
            U32(0x41000000), U32(0x40010040), U32(0x00000040), U32(0x01010000),
        ],

        # nibble 3
        [
            U32(0x00100402), U32(0x04000400), U32(0x00000002), U32(0x04100402),
            U32(0x00000000), U32(0x04100000), U32(0x04000402), U32(0x00100002),
            U32(0x04100400), U32(0x04000002), U32(0x04000000), U32(0x00000402),
            U32(0x04000002), U32(0x00100402), U32(0x00100000), U32(0x04000000),
            U32(0x04100002), U32(0x00100400), U32(0x00000400), U32(0x00000002),
            U32(0x00100400), U32(0x04000402), U32(0x04100000), U32(0x00000400),
            U32(0x00000402), U32(0x00000000), U32(0x00100002), U32(0x04100400),
            U32(0x04000400), U32(0x04100002), U32(0x04100402), U32(0x00100000),
            U32(0x04100002), U32(0x00000402), U32(0x00100000), U32(0x04000002),
            U32(0x00100400), U32(0x04000400), U32(0x00000002), U32(0x04100000),
            U32(0x04000402), U32(0x00000000), U32(0x00000400), U32(0x00100002),
            U32(0x00000000), U32(0x04100002), U32(0x04100400), U32(0x00000400),
            U32(0x04000000), U32(0x04100402), U32(0x00100402), U32(0x00100000),
            U32(0x04100402), U32(0x00000002), U32(0x04000400), U32(0x00100402),
            U32(0x00100002), U32(0x00100400), U32(0x04100000), U32(0x04000402),
            U32(0x00000402), U32(0x04000000), U32(0x04000002), U32(0x04100400),
        ],

        # nibble 4
        [
            U32(0x02000000), U32(0x00004000), U32(0x00000100), U32(0x02004108),
            U32(0x02004008), U32(0x02000100), U32(0x00004108), U32(0x02004000),
            U32(0x00004000), U32(0x00000008), U32(0x02000008), U32(0x00004100),
            U32(0x02000108), U32(0x02004008), U32(0x02004100), U32(0x00000000),
            U32(0x00004100), U32(0x02000000), U32(0x00004008), U32(0x00000108),
            U32(0x02000100), U32(0x00004108), U32(0x00000000), U32(0x02000008),
            U32(0x00000008), U32(0x02000108), U32(0x02004108), U32(0x00004008),
            U32(0x02004000), U32(0x00000100), U32(0x00000108), U32(0x02004100),
            U32(0x02004100), U32(0x02000108), U32(0x00004008), U32(0x02004000),
            U32(0x00004000), U32(0x00000008), U32(0x02000008), U32(0x02000100),
            U32(0x02000000), U32(0x00004100), U32(0x02004108), U32(0x00000000),
            U32(0x00004108), U32(0x02000000), U32(0x00000100), U32(0x00004008),
            U32(0x02000108), U32(0x00000100), U32(0x00000000), U32(0x02004108),
            U32(0x02004008), U32(0x02004100), U32(0x00000108), U32(0x00004000),
            U32(0x00004100), U32(0x02004008), U32(0x02000100), U32(0x00000108),
            U32(0x00000008), U32(0x00004108), U32(0x02004000), U32(0x02000008),
        ],

        # nibble 5
        [
            U32(0x20000010), U32(0x00080010), U32(0x00000000), U32(0x20080800),
            U32(0x00080010), U32(0x00000800), U32(0x20000810), U32(0x00080000),
            U32(0x00000810), U32(0x20080810), U32(0x00080800), U32(0x20000000),
            U32(0x20000800), U32(0x20000010), U32(0x20080000), U32(0x00080810),
            U32(0x00080000), U32(0x20000810), U32(0x20080010), U32(0x00000000),
            U32(0x00000800), U32(0x00000010), U32(0x20080800), U32(0x20080010),
            U32(0x20080810), U32(0x20080000), U32(0x20000000), U32(0x00000810),
            U32(0x00000010), U32(0x00080800), U32(0x00080810), U32(0x20000800),
            U32(0x00000810), U32(0x20000000), U32(0x20000800), U32(0x00080810),
            U32(0x20080800), U32(0x00080010), U32(0x00000000), U32(0x20000800),
            U32(0x20000000), U32(0x00000800), U32(0x20080010), U32(0x00080000),
            U32(0x00080010), U32(0x20080810), U32(0x00080800), U32(0x00000010),
            U32(0x20080810), U32(0x00080800), U32(0x00080000), U32(0x20000810),
            U32(0x20000010), U32(0x20080000), U32(0x00080810), U32(0x00000000),
            U32(0x00000800), U32(0x20000010), U32(0x20000810), U32(0x20080800),
            U32(0x20080000), U32(0x00000810), U32(0x00000010), U32(0x20080010),
        ],

        # nibble 6
        [
            U32(0x00001000), U32(0x00000080), U32(0x00400080), U32(0x00400001),
            U32(0x00401081), U32(0x00001001), U32(0x00001080), U32(0x00000000),
            U32(0x00400000), U32(0x00400081), U32(0x00000081), U32(0x00401000),
            U32(0x00000001), U32(0x00401080), U32(0x00401000), U32(0x00000081),
            U32(0x00400081), U32(0x00001000), U32(0x00001001), U32(0x00401081),
            U32(0x00000000), U32(0x00400080), U32(0x00400001), U32(0x00001080),
            U32(0x00401001), U32(0x00001081), U32(0x00401080), U32(0x00000001),
            U32(0x00001081), U32(0x00401001), U32(0x00000080), U32(0x00400000),
            U32(0x00001081), U32(0x00401000), U32(0x00401001), U32(0x00000081),
            U32(0x00001000), U32(0x00000080), U32(0x00400000), U32(0x00401001),
            U32(0x00400081), U32(0x00001081), U32(0x00001080), U32(0x00000000),
            U32(0x00000080), U32(0x00400001), U32(0x00000001), U32(0x00400080),
            U32(0x00000000), U32(0x00400081), U32(0x00400080), U32(0x00001080),
            U32(0x00000081), U32(0x00001000), U32(0x00401081), U32(0x00400000),
            U32(0x00401080), U32(0x00000001), U32(0x00001001), U32(0x00401081),
            U32(0x00400001), U32(0x00401080), U32(0x00401000), U32(0x00001001),
        ],

        # nibble 7
        [
            U32(0x08200020), U32(0x08208000), U32(0x00008020), U32(0x00000000),
            U32(0x08008000), U32(0x00200020), U32(0x08200000), U32(0x08208020),
            U32(0x00000020), U32(0x08000000), U32(0x00208000), U32(0x00008020),
            U32(0x00208020), U32(0x08008020), U32(0x08000020), U32(0x08200000),
            U32(0x00008000), U32(0x00208020), U32(0x00200020), U32(0x08008000),
            U32(0x08208020), U32(0x08000020), U32(0x00000000), U32(0x00208000),
            U32(0x08000000), U32(0x00200000), U32(0x08008020), U32(0x08200020),
            U32(0x00200000), U32(0x00008000), U32(0x08208000), U32(0x00000020),
            U32(0x00200000), U32(0x00008000), U32(0x08000020), U32(0x08208020),
            U32(0x00008020), U32(0x08000000), U32(0x00000000), U32(0x00208000),
            U32(0x08200020), U32(0x08008020), U32(0x08008000), U32(0x00200020),
            U32(0x08208000), U32(0x00000020), U32(0x00200020), U32(0x08008000),
            U32(0x08208020), U32(0x00200000), U32(0x08200000), U32(0x08000020),
            U32(0x00208000), U32(0x00008020), U32(0x08008020), U32(0x08200000),
            U32(0x00000020), U32(0x08208000), U32(0x00208020), U32(0x00000000),
            U32(0x08000000), U32(0x08200020), U32(0x00008000), U32(0x00208020),
        ],
    ]

# static unsigned long des_skb[8][64]={

des_skb = \
    [
        # for C bits (numbered as per FIPS 46) 1 2 3 4 5 6
        [
            U32(0x00000000), U32(0x00000010), U32(0x20000000), U32(0x20000010),
            U32(0x00010000), U32(0x00010010), U32(0x20010000), U32(0x20010010),
            U32(0x00000800), U32(0x00000810), U32(0x20000800), U32(0x20000810),
            U32(0x00010800), U32(0x00010810), U32(0x20010800), U32(0x20010810),
            U32(0x00000020), U32(0x00000030), U32(0x20000020), U32(0x20000030),
            U32(0x00010020), U32(0x00010030), U32(0x20010020), U32(0x20010030),
            U32(0x00000820), U32(0x00000830), U32(0x20000820), U32(0x20000830),
            U32(0x00010820), U32(0x00010830), U32(0x20010820), U32(0x20010830),
            U32(0x00080000), U32(0x00080010), U32(0x20080000), U32(0x20080010),
            U32(0x00090000), U32(0x00090010), U32(0x20090000), U32(0x20090010),
            U32(0x00080800), U32(0x00080810), U32(0x20080800), U32(0x20080810),
            U32(0x00090800), U32(0x00090810), U32(0x20090800), U32(0x20090810),
            U32(0x00080020), U32(0x00080030), U32(0x20080020), U32(0x20080030),
            U32(0x00090020), U32(0x00090030), U32(0x20090020), U32(0x20090030),
            U32(0x00080820), U32(0x00080830), U32(0x20080820), U32(0x20080830),
            U32(0x00090820), U32(0x00090830), U32(0x20090820), U32(0x20090830),
        ],

        # for C bits (numbered as per FIPS 46) 7 8 10 11 12 13
        [
            U32(0x00000000), U32(0x02000000), U32(0x00002000), U32(0x02002000),
            U32(0x00200000), U32(0x02200000), U32(0x00202000), U32(0x02202000),
            U32(0x00000004), U32(0x02000004), U32(0x00002004), U32(0x02002004),
            U32(0x00200004), U32(0x02200004), U32(0x00202004), U32(0x02202004),
            U32(0x00000400), U32(0x02000400), U32(0x00002400), U32(0x02002400),
            U32(0x00200400), U32(0x02200400), U32(0x00202400), U32(0x02202400),
            U32(0x00000404), U32(0x02000404), U32(0x00002404), U32(0x02002404),
            U32(0x00200404), U32(0x02200404), U32(0x00202404), U32(0x02202404),
            U32(0x10000000), U32(0x12000000), U32(0x10002000), U32(0x12002000),
            U32(0x10200000), U32(0x12200000), U32(0x10202000), U32(0x12202000),
            U32(0x10000004), U32(0x12000004), U32(0x10002004), U32(0x12002004),
            U32(0x10200004), U32(0x12200004), U32(0x10202004), U32(0x12202004),
            U32(0x10000400), U32(0x12000400), U32(0x10002400), U32(0x12002400),
            U32(0x10200400), U32(0x12200400), U32(0x10202400), U32(0x12202400),
            U32(0x10000404), U32(0x12000404), U32(0x10002404), U32(0x12002404),
            U32(0x10200404), U32(0x12200404), U32(0x10202404), U32(0x12202404),
        ],

        # for C bits (numbered as per FIPS 46) 14 15 16 17 19 20
        [
            U32(0x00000000), U32(0x00000001), U32(0x00040000), U32(0x00040001),
            U32(0x01000000), U32(0x01000001), U32(0x01040000), U32(0x01040001),
            U32(0x00000002), U32(0x00000003), U32(0x00040002), U32(0x00040003),
            U32(0x01000002), U32(0x01000003), U32(0x01040002), U32(0x01040003),
            U32(0x00000200), U32(0x00000201), U32(0x00040200), U32(0x00040201),
            U32(0x01000200), U32(0x01000201), U32(0x01040200), U32(0x01040201),
            U32(0x00000202), U32(0x00000203), U32(0x00040202), U32(0x00040203),
            U32(0x01000202), U32(0x01000203), U32(0x01040202), U32(0x01040203),
            U32(0x08000000), U32(0x08000001), U32(0x08040000), U32(0x08040001),
            U32(0x09000000), U32(0x09000001), U32(0x09040000), U32(0x09040001),
            U32(0x08000002), U32(0x08000003), U32(0x08040002), U32(0x08040003),
            U32(0x09000002), U32(0x09000003), U32(0x09040002), U32(0x09040003),
            U32(0x08000200), U32(0x08000201), U32(0x08040200), U32(0x08040201),
            U32(0x09000200), U32(0x09000201), U32(0x09040200), U32(0x09040201),
            U32(0x08000202), U32(0x08000203), U32(0x08040202), U32(0x08040203),
            U32(0x09000202), U32(0x09000203), U32(0x09040202), U32(0x09040203),
        ],

        # for C bits (numbered as per FIPS 46) 21 23 24 26 27 28
        [
            U32(0x00000000), U32(0x00100000), U32(0x00000100), U32(0x00100100),
            U32(0x00000008), U32(0x00100008), U32(0x00000108), U32(0x00100108),
            U32(0x00001000), U32(0x00101000), U32(0x00001100), U32(0x00101100),
            U32(0x00001008), U32(0x00101008), U32(0x00001108), U32(0x00101108),
            U32(0x04000000), U32(0x04100000), U32(0x04000100), U32(0x04100100),
            U32(0x04000008), U32(0x04100008), U32(0x04000108), U32(0x04100108),
            U32(0x04001000), U32(0x04101000), U32(0x04001100), U32(0x04101100),
            U32(0x04001008), U32(0x04101008), U32(0x04001108), U32(0x04101108),
            U32(0x00020000), U32(0x00120000), U32(0x00020100), U32(0x00120100),
            U32(0x00020008), U32(0x00120008), U32(0x00020108), U32(0x00120108),
            U32(0x00021000), U32(0x00121000), U32(0x00021100), U32(0x00121100),
            U32(0x00021008), U32(0x00121008), U32(0x00021108), U32(0x00121108),
            U32(0x04020000), U32(0x04120000), U32(0x04020100), U32(0x04120100),
            U32(0x04020008), U32(0x04120008), U32(0x04020108), U32(0x04120108),
            U32(0x04021000), U32(0x04121000), U32(0x04021100), U32(0x04121100),
            U32(0x04021008), U32(0x04121008), U32(0x04021108), U32(0x04121108),
        ],

        # for D bits (numbered as per FIPS 46) 1 2 3 4 5 6
        [
            U32(0x00000000), U32(0x10000000), U32(0x00010000), U32(0x10010000),
            U32(0x00000004), U32(0x10000004), U32(0x00010004), U32(0x10010004),
            U32(0x20000000), U32(0x30000000), U32(0x20010000), U32(0x30010000),
            U32(0x20000004), U32(0x30000004), U32(0x20010004), U32(0x30010004),
            U32(0x00100000), U32(0x10100000), U32(0x00110000), U32(0x10110000),
            U32(0x00100004), U32(0x10100004), U32(0x00110004), U32(0x10110004),
            U32(0x20100000), U32(0x30100000), U32(0x20110000), U32(0x30110000),
            U32(0x20100004), U32(0x30100004), U32(0x20110004), U32(0x30110004),
            U32(0x00001000), U32(0x10001000), U32(0x00011000), U32(0x10011000),
            U32(0x00001004), U32(0x10001004), U32(0x00011004), U32(0x10011004),
            U32(0x20001000), U32(0x30001000), U32(0x20011000), U32(0x30011000),
            U32(0x20001004), U32(0x30001004), U32(0x20011004), U32(0x30011004),
            U32(0x00101000), U32(0x10101000), U32(0x00111000), U32(0x10111000),
            U32(0x00101004), U32(0x10101004), U32(0x00111004), U32(0x10111004),
            U32(0x20101000), U32(0x30101000), U32(0x20111000), U32(0x30111000),
            U32(0x20101004), U32(0x30101004), U32(0x20111004), U32(0x30111004),
        ],

        # for D bits (numbered as per FIPS 46) 8 9 11 12 13 14
        [
            U32(0x00000000), U32(0x08000000), U32(0x00000008), U32(0x08000008),
            U32(0x00000400), U32(0x08000400), U32(0x00000408), U32(0x08000408),
            U32(0x00020000), U32(0x08020000), U32(0x00020008), U32(0x08020008),
            U32(0x00020400), U32(0x08020400), U32(0x00020408), U32(0x08020408),
            U32(0x00000001), U32(0x08000001), U32(0x00000009), U32(0x08000009),
            U32(0x00000401), U32(0x08000401), U32(0x00000409), U32(0x08000409),
            U32(0x00020001), U32(0x08020001), U32(0x00020009), U32(0x08020009),
            U32(0x00020401), U32(0x08020401), U32(0x00020409), U32(0x08020409),
            U32(0x02000000), U32(0x0A000000), U32(0x02000008), U32(0x0A000008),
            U32(0x02000400), U32(0x0A000400), U32(0x02000408), U32(0x0A000408),
            U32(0x02020000), U32(0x0A020000), U32(0x02020008), U32(0x0A020008),
            U32(0x02020400), U32(0x0A020400), U32(0x02020408), U32(0x0A020408),
            U32(0x02000001), U32(0x0A000001), U32(0x02000009), U32(0x0A000009),
            U32(0x02000401), U32(0x0A000401), U32(0x02000409), U32(0x0A000409),
            U32(0x02020001), U32(0x0A020001), U32(0x02020009), U32(0x0A020009),
            U32(0x02020401), U32(0x0A020401), U32(0x02020409), U32(0x0A020409),
        ],

        # for D bits (numbered as per FIPS 46) 16 17 18 19 20 21
        [
            U32(0x00000000), U32(0x00000100), U32(0x00080000), U32(0x00080100),
            U32(0x01000000), U32(0x01000100), U32(0x01080000), U32(0x01080100),
            U32(0x00000010), U32(0x00000110), U32(0x00080010), U32(0x00080110),
            U32(0x01000010), U32(0x01000110), U32(0x01080010), U32(0x01080110),
            U32(0x00200000), U32(0x00200100), U32(0x00280000), U32(0x00280100),
            U32(0x01200000), U32(0x01200100), U32(0x01280000), U32(0x01280100),
            U32(0x00200010), U32(0x00200110), U32(0x00280010), U32(0x00280110),
            U32(0x01200010), U32(0x01200110), U32(0x01280010), U32(0x01280110),
            U32(0x00000200), U32(0x00000300), U32(0x00080200), U32(0x00080300),
            U32(0x01000200), U32(0x01000300), U32(0x01080200), U32(0x01080300),
            U32(0x00000210), U32(0x00000310), U32(0x00080210), U32(0x00080310),
            U32(0x01000210), U32(0x01000310), U32(0x01080210), U32(0x01080310),
            U32(0x00200200), U32(0x00200300), U32(0x00280200), U32(0x00280300),
            U32(0x01200200), U32(0x01200300), U32(0x01280200), U32(0x01280300),
            U32(0x00200210), U32(0x00200310), U32(0x00280210), U32(0x00280310),
            U32(0x01200210), U32(0x01200310), U32(0x01280210), U32(0x01280310),
        ],

        # for D bits (numbered as per FIPS 46) 22 23 24 25 27 28
        [
            U32(0x00000000), U32(0x04000000), U32(0x00040000), U32(0x04040000),
            U32(0x00000002), U32(0x04000002), U32(0x00040002), U32(0x04040002),
            U32(0x00002000), U32(0x04002000), U32(0x00042000), U32(0x04042000),
            U32(0x00002002), U32(0x04002002), U32(0x00042002), U32(0x04042002),
            U32(0x00000020), U32(0x04000020), U32(0x00040020), U32(0x04040020),
            U32(0x00000022), U32(0x04000022), U32(0x00040022), U32(0x04040022),
            U32(0x00002020), U32(0x04002020), U32(0x00042020), U32(0x04042020),
            U32(0x00002022), U32(0x04002022), U32(0x00042022), U32(0x04042022),
            U32(0x00000800), U32(0x04000800), U32(0x00040800), U32(0x04040800),
            U32(0x00000802), U32(0x04000802), U32(0x00040802), U32(0x04040802),
            U32(0x00002800), U32(0x04002800), U32(0x00042800), U32(0x04042800),
            U32(0x00002802), U32(0x04002802), U32(0x00042802), U32(0x04042802),
            U32(0x00000820), U32(0x04000820), U32(0x00040820), U32(0x04040820),
            U32(0x00000822), U32(0x04000822), U32(0x00040822), U32(0x04040822),
            U32(0x00002820), U32(0x04002820), U32(0x00042820), U32(0x04042820),
            U32(0x00002822), U32(0x04002822), U32(0x00042822), U32(0x04042822),
        ]

    ]


================================================
FILE: ntlm_auth/gss_channel_bindings.py
================================================
# This library is free software: you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation, either
# version 3 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.

import struct

"""
    This is not the easiest structure to understand, ultimately this is a set structure
    as defined by Microsoft. Channel Binding Tokens set the SHA256 hash of the server
    certificate to the application_data field and then ultimately creates the MD5 hash
    to include in the NTLM auth from there. This class is just designed to create the
    bindings structure which is then used by compute_response.py to do the rest of the
    work.

    For more infor on how this works and how it is derived, this is a great link;
    https://blogs.msdn.microsoft.com/openspecification/2013/03/26/ntlm-and-channel-binding-hash-aka-extended-protection-for-authentication/
"""
class GssChannelBindingsStruct(object):
    INITIATOR_ADDTYPE = 'initiator_addtype'
    INITIATOR_ADDRESS_LENGTH = 'initiator_address_length'
    ACCEPTOR_ADDRTYPE = 'acceptor_addrtype'
    ACCEPTOR_ADDRESS_LENGTH = 'acceptor_address_length'
    APPLICATION_DATA_LENGTH = 'application_data_length'
    INITIATOR_ADDRESS = 'initiator_address'
    ACCEPTOR_ADDRESS = 'acceptor_address'
    APPLICATION_DATA = 'application_data'

    def __init__(self):
        self.fields = {}
        self.fields[self.INITIATOR_ADDTYPE] = 0
        self.fields[self.INITIATOR_ADDRESS_LENGTH] = 0
        self.fields[self.ACCEPTOR_ADDRTYPE] = 0
        self.fields[self.ACCEPTOR_ADDRESS_LENGTH] = 0
        self.fields[self.APPLICATION_DATA_LENGTH] = 0
        self.fields[self.INITIATOR_ADDRESS] = b''
        self.fields[self.ACCEPTOR_ADDRESS] = b''
        self.fields[self.APPLICATION_DATA] = b''

    def __setitem__(self, key, value):
        self.fields[key] = value

    def get_data(self):
        # Set the lengths of each len field in case they have changed
        self.fields[self.INITIATOR_ADDRESS_LENGTH] = len(self.fields[self.INITIATOR_ADDRESS])
        self.fields[self.ACCEPTOR_ADDRESS_LENGTH] = len(self.fields[self.ACCEPTOR_ADDRESS])
        self.fields[self.APPLICATION_DATA_LENGTH] = len(self.fields[self.APPLICATION_DATA])

        # Add all the values together to create the gss_channel_bindings_struct
        data = struct.pack('<L', self.fields[self.INITIATOR_ADDTYPE]) + \
               struct.pack('<L', self.fields[self.INITIATOR_ADDRESS_LENGTH]) + \
               self.fields[self.INITIATOR_ADDRESS] + \
               struct.pack('<L', self.fields[self.ACCEPTOR_ADDRTYPE]) + \
               struct.pack('<L', self.fields[self.ACCEPTOR_ADDRESS_LENGTH]) + \
               self.fields[self.ACCEPTOR_ADDRESS] + \
               struct.pack('<L', self.fields[self.APPLICATION_DATA_LENGTH]) + \
               self.fields[self.APPLICATION_DATA]

        return data

================================================
FILE: ntlm_auth/messages.py
================================================
# This library is free software: you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation, either
# version 3 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.

import hmac
import os
import struct
from ntlm_auth.compute_response import ComputeResponse
from ntlm_auth.constants import NegotiateFlags, MessageTypes, NTLM_SIGNATURE, AvFlags
from ntlm_auth.rc4 import ARC4
from ntlm_auth.target_info import TargetInfo

class NegotiateMessage(object):
    EXPECTED_BODY_LENGTH = 40

    """
        [MS-NLMP] v28.0 2016-07-14

        2.2.1.1 NEGOTIATE_MESSAGE
        The NEGOTIATE_MESSAGE defines an NTLM Negotiate message that is sent from the client to
        the server. This message allows the client to specify its supported NTLM options to
        the server.

        :param negotiate_flags: A NEGOTIATE structure that contains a set of bit flags. These flags are the options the client supports
        :param domain_name: The domain name of the user to authenticate with, default is None
        :param workstation: The worksation of the client machine, default is None

        Attributes:
            signature: An 8-byte character array that MUST contain the ASCII string 'NTLMSSP\0'
            message_type: A 32-bit unsigned integer that indicates the message type. This field must be set to 0x00000001
            negotiate_flags: A NEGOTIATE structure that contains a set of bit flags. These flags are the options the client supports
            version: Contains the windows version info of the client. It is used only debugging purposes and are only set when NTLMSSP_NEGOTIATE_VERSION flag is set
            domain_name: A byte-array that contains the name of the client authentication domain that MUST Be encoded in the negotiated character set
            workstation: A byte-array that contains the name of the client machine that MUST Be encoded in the negotiated character set
    """
    def __init__(self, negotiate_flags, domain_name, workstation):
        self.signature = NTLM_SIGNATURE
        self.message_type = struct.pack('<L', MessageTypes.NTLM_NEGOTIATE)

        # Check if the domain_name value is set, if it is, make sure the negotiate_flag is also set
        if domain_name is None:
            self.domain_name = ''
        else:
            self.domain_name = domain_name
            negotiate_flags |= NegotiateFlags.NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED

        # Check if the workstation value is set, if it is, make sure the negotiate_flag is also set
        if workstation is None:
            self.workstation = ''
        else:
            self.workstation = workstation
            negotiate_flags |= NegotiateFlags.NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED

        # Set the encoding flag to use OEM, remove UNICODE if set as it isn't support in this message
        negotiate_flags -= NegotiateFlags.NTLMSSP_NEGOTIATE_UNICODE
        negotiate_flags |= NegotiateFlags.NTLMSSP_NEGOTIATE_OEM
        self.domain_name = self.domain_name.encode('ascii')
        self.workstation = self.workstation.encode('ascii')

        self.version = get_version(negotiate_flags)

        self.negotiate_flags = struct.pack('<I', negotiate_flags)

    def get_data(self):
        payload_offset = self.EXPECTED_BODY_LENGTH

        # DomainNameFields - 8 bytes
        domain_name_len = struct.pack('<H', len(self.domain_name))
        domain_name_max_len = struct.pack('<H', len(self.domain_name))
        domain_name_buffer_offset = struct.pack('<I', payload_offset)
        payload_offset += len(self.domain_name)

        # WorkstationFields - 8 bytes
        workstation_len = struct.pack('<H', len(self.workstation))
        workstation_max_len = struct.pack('<H', len(self.workstation))
        workstation_buffer_offset = struct.pack('<I', payload_offset)
        payload_offset += len(self.workstation)

        # Payload - variable length
        payload = self.domain_name
        payload += self.workstation

        # Bring the header values together into 1 message
        msg1 = self.signature
        msg1 += self.message_type
        msg1 += self.negotiate_flags
        msg1 += domain_name_len
        msg1 += domain_name_max_len
        msg1 += domain_name_buffer_offset
        msg1 += workstation_len
        msg1 += workstation_max_len
        msg1 += workstation_buffer_offset
        msg1 += self.version

        assert self.EXPECTED_BODY_LENGTH == len(msg1), "BODY_LENGTH: %d != msg1: %d" % (self.EXPECTED_BODY_LENGTH, len(msg1))

        # Adding the payload data to the message
        msg1 += payload
        return msg1

class ChallengeMessage(object):
    """
        [MS-NLMP] v28.0 2016-07-14

        2.2.1.2 CHALLENGE_MESSAGE
        The CHALLENGE_MESSAGE defines an NTLM challenge message that is sent from the server to
        the client. The CHALLENGE_MESSAGE is used by the server to challenge the client to prove
        its identity, For connection-oriented requests, the CHALLENGE_MESSAGE generated by the
        server is in response to the NEGOTIATE_MESSAGE from the client.

        :param msg2: The CHALLENGE_MESSAGE received from the server after sending our NEGOTIATE_MESSAGE. This has
                        been decoded from a base64 string

        Attributes
            signature: An 8-byte character array that MUST contain the ASCII string 'NTLMSSP\0'
            message_type: A 32-bit unsigned integer that indicates the message type. This field must be set to 0x00000002
            negotiate_flags: A NEGOTIATE strucutre that contains a set of bit flags. The server sets flags to indicate options it supports
            server_challenge: A 64-bit value that contains the NTLM challenge. The challenge is a 64-bit nonce. Used in the AuthenticateMessage message
            reserved: An 8-byte array whose elements MUST be zero when sent and MUST be ignored on receipt
            version: When NTLMSSP_NEGOTIATE_VERSION flag is set in negotiate_flags field which contains the windows version info. Used only for debugging purposes
            target_name: When NTLMSSP_REQUEST_TARGET is set is a byte array that contains the name of the server authentication realm. In a domain environment this is the domain name not server name
            target_info: When NTLMSSP_NEGOTIATE_TARGET_INFO is set is a byte array that contains a sequence of AV_PAIR structures (target_info.py)
    """
    def __init__(self, msg2):
        self.data = msg2
        # Setting the object values from the raw_challenge_message
        self.signature = msg2[0:8]
        self.message_type = struct.unpack("<I", msg2[8:12])[0]
        self.negotiate_flags = struct.unpack("<I", msg2[20:24])[0]
        self.server_challenge = msg2[24:32]
        self.reserved = msg2[32:40]

        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_VERSION and self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
            size = len(msg2)
            self.version = struct.unpack("<q", msg2[48:56])[0]
        else:
            self.version = None

        if self.negotiate_flags & NegotiateFlags.NTLMSSP_REQUEST_TARGET:
            target_name_len = struct.unpack("<H", msg2[12:14])[0]
            target_name_max_len = struct.unpack("<H", msg2[14:16])[0]
            target_name_buffer_offset = struct.unpack("<I", msg2[16:20])[0]
            self.target_name = msg2[target_name_buffer_offset:target_name_buffer_offset + target_name_len]
        else:
            self.target_name = None

        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_TARGET_INFO:
            target_info_len = struct.unpack("<H", msg2[40:42])[0]
            target_info_max_len = struct.unpack("<H", msg2[42:44])[0]
            target_info_buffer_offset = struct.unpack("<I", msg2[44:48])[0]

            target_info_raw = msg2[target_info_buffer_offset:target_info_buffer_offset + target_info_len]
            self.target_info = TargetInfo(target_info_raw)
        else:
            self.target_info = None

        # Verify initial integrity of the message, it matches what should be there
        assert self.signature == NTLM_SIGNATURE
        assert self.message_type == MessageTypes.NTLM_CHALLENGE

    def get_data(self):
        return self.data

class AuthenticateMessage(object):
    EXPECTED_BODY_LENGTH = 72
    EXPECTED_BODY_LENGTH_WITH_MIC = 88

    """
        [MS-NLMP] v28.0 2016-07-14

        2.2.1.3 AUTHENTICATE_MESSAGE
        The AUTHENTICATE_MESSAGE defines an NTLM authenticate message that is sent from the
        client to the server after the CHALLENGE_MESSAGE is processed by the client.

        :param user_name: The user name of the user we are trying to authenticate with
        :param password: The password of the user we are trying to authenticate with
        :param domain_name: The domain name of the user account we are authenticated with, default is None
        :param workstation: The workstation we are using to authenticate with, default is None
        :param challenge_message: A ChallengeMessage object that was received from the server after the negotiate_message
        :param ntlm_compatibility: The Lan Manager Compatibility Level, used to determine what NTLM auth version to use, see Ntlm in ntlm.py for more details
        :param server_certificate_hash: The SHA256 hash string of the server certificate (DER encoded) NTLM is authenticating to. This is used to add
                                          to the gss_channel_bindings_struct for Channel Binding Tokens support. If none is passed through then ntlm-auth
                                          will not use Channel Binding Tokens when authenticating with the server which could cause issues if it is set to
                                          only authenticate when these are present. This is only used for NTLMv2 authentication.

        Message Attributes (Attributes not used to compute the message structure):
            signature: An 8-byte character array that MUST contain the ASCII string 'NTLMSSP\0'
            message_type: A 32-bit unsigned integer that indicates the message type. This field must be set to 0x00000003
            negotiate_flags: A NEGOTIATE strucutre that contains a set of bit flags. These flags are the choices the client has made from the CHALLENGE_MESSAGE options
            version: Contains the windows version info of the client. It is used only debugging purposes and are only set when NTLMSSP_NEGOTIATE_VERSION flag is set
            mic: The message integrity for the NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE and AUTHENTICATE_MESSAGE
            lm_challenge_response: An LM_RESPONSE of LMv2_RESPONSE structure that contains the computed LM response to the challenge
            nt_challenge_response: An NTLM_RESPONSE or NTLMv2_RESPONSE structure that contains the computed NT response to the challenge
            domain_name: The domain or computer name hosting the user account, MUST be encoded in the negotiated character set
            user_name: The name of the user to be authenticated, MUST be encoded in the negotiated character set
            workstation: The name of the computer to which the user is logged on, MUST Be encoded in the negotiated character set
            encrypted_random_session_key: The client's encrypted random session key

        Non-Message Attributes (Attributes not used to compute the message structure):
            exported_session_key: A randomly generated session key based on other keys, used to derive the SIGNKEY and SEALKEY
            target_info: The AV_PAIR structure used in the nt response calculation
    """
    def __init__(self, user_name, password, nthash, lmhash, domain_name, workstation, challenge_message, ntlm_compatibility, server_certificate_hash):
        self.signature = NTLM_SIGNATURE
        self.message_type = struct.pack('<L', MessageTypes.NTLM_AUTHENTICATE)
        self.negotiate_flags = challenge_message.negotiate_flags
        self.version = get_version(self.negotiate_flags)
        self.mic = None

        if domain_name is None:
            self.domain_name = ''
        else:
            self.domain_name = domain_name

        if workstation is None:
            self.workstation = ''
        else:
            self.workstation = workstation

        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_UNICODE:
            self.negotiate_flags -= NegotiateFlags.NTLMSSP_NEGOTIATE_OEM
            encoding_value = 'utf-16-le'
        else:
            encoding_value = 'ascii'

        self.domain_name = self.domain_name.encode(encoding_value)
        self.user_name = user_name.encode(encoding_value)
        self.workstation = self.workstation.encode(encoding_value)

        compute_response = ComputeResponse(user_name, password, nthash, lmhash, domain_name, challenge_message,
                                           ntlm_compatibility)

        self.lm_challenge_response = compute_response.get_lm_challenge_response()
        self.nt_challenge_response, key_exchange_key, target_info = compute_response.get_nt_challenge_response(
            self.lm_challenge_response, server_certificate_hash)
        self.target_info = target_info

        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_KEY_EXCH:
            self.exported_session_key = get_random_export_session_key()

            rc4_handle = ARC4(key_exchange_key)
            self.encrypted_random_session_key = rc4_handle.update(self.exported_session_key)
        else:
            self.exported_session_key = key_exchange_key
            self.encrypted_random_session_key = b''

        self.negotiate_flags = struct.pack('<I', self.negotiate_flags)

    def get_data(self):
        if self.mic is None:
            mic = b''
            expected_body_length = self.EXPECTED_BODY_LENGTH
        else:
            mic = self.mic
            expected_body_length = self.EXPECTED_BODY_LENGTH_WITH_MIC

        payload_offset = expected_body_length

        # DomainNameFields - 8 bytes
        domain_name_len = struct.pack('<H', len(self.domain_name))
        domain_name_max_len = struct.pack('<H', len(self.domain_name))
        domain_name_buffer_offset = struct.pack('<I', payload_offset)
        payload_offset += len(self.domain_name)

        # UserNameFields - 8 bytes
        user_name_len = struct.pack('<H', len(self.user_name))
        user_name_max_len = struct.pack('<H', len(self.user_name))
        user_name_buffer_offset = struct.pack('<I', payload_offset)
        payload_offset += len(self.user_name)

        # WorkstatonFields - 8 bytes
        workstation_len = struct.pack('<H', len(self.workstation))
        workstation_max_len = struct.pack('<H', len(self.workstation))
        workstation_buffer_offset = struct.pack('<I', payload_offset)
        payload_offset += len(self.workstation)

        # LmChallengeResponseFields - 8 bytes
        lm_challenge_response_len = struct.pack('<H', len(self.lm_challenge_response))
        lm_challenge_response_max_len = struct.pack('<H', len(self.lm_challenge_response))
        lm_challenge_response_buffer_offset = struct.pack('<I', payload_offset)
        payload_offset += len(self.lm_challenge_response)

        # NtChallengeResponseFields - 8 bytes
        nt_challenge_response_len = struct.pack('<H', len(self.nt_challenge_response))
        nt_challenge_response_max_len = struct.pack('<H', len(self.nt_challenge_response))
        nt_challenge_response_buffer_offset = struct.pack('<I', payload_offset)
        payload_offset += len(self.nt_challenge_response)

        # EncryptedRandomSessionKeyFields - 8 bytes
        encrypted_random_session_key_len = struct.pack('<H', len(self.encrypted_random_session_key))
        encrypted_random_session_key_max_len = struct.pack('<H', len(self.encrypted_random_session_key))
        encrypted_random_session_key_buffer_offset = struct.pack('<I', payload_offset)
        payload_offset += len(self.encrypted_random_session_key)

        # Payload - variable length
        payload = self.domain_name
        payload += self.user_name
        payload += self.workstation
        payload += self.lm_challenge_response
        payload += self.nt_challenge_response
        payload += self.encrypted_random_session_key

        msg3 = self.signature
        msg3 += self.message_type
        msg3 += lm_challenge_response_len + lm_challenge_response_max_len + lm_challenge_response_buffer_offset
        msg3 += nt_challenge_response_len + nt_challenge_response_max_len + nt_challenge_response_buffer_offset
        msg3 += domain_name_len + domain_name_max_len + domain_name_buffer_offset
        msg3 += user_name_len + user_name_max_len + user_name_buffer_offset
        msg3 += workstation_len + workstation_max_len + workstation_buffer_offset
        msg3 += encrypted_random_session_key_len + encrypted_random_session_key_max_len + encrypted_random_session_key_buffer_offset
        msg3 += self.negotiate_flags
        msg3 += self.version
        msg3 += mic

        # Adding the payload data to the message
        msg3 += payload

        return msg3

    def add_mic(self, negotiate_message, challenge_message):
        if self.target_info is not None:
            av_flags = self.target_info[TargetInfo.MSV_AV_FLAGS]

            if av_flags is not None and av_flags[1] == struct.pack("<L", AvFlags.MIC_PROVIDED):
                self.mic = struct.pack("<IIII", 0, 0, 0, 0)
                negotiate_data = negotiate_message.get_data()
                challenge_data = challenge_message.get_data()
                authenticate_data = self.get_data()

                mic = hmac.new(self.exported_session_key,
                               (negotiate_data + challenge_data + authenticate_data)).digest()
                self.mic = mic

def get_version(negotiate_flags):
    # Check the negotiate_flag version is set, if it is make sure the version info is added to the data
    if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_VERSION:
        # TODO: Get the major and minor version of Windows instead of using default values
        product_major_version = struct.pack('<B', 6)
        product_minor_version = struct.pack('<B', 1)
        product_build = struct.pack('<H', 7601)
        version_reserved = b'\0' * 3
        ntlm_revision_current = struct.pack('<B', 15)
        version = product_major_version + product_minor_version + product_build + version_reserved + ntlm_revision_current
    else:
        version = b'\0' * 8

    return version

def get_random_export_session_key():
    return os.urandom(16)


================================================
FILE: ntlm_auth/ntlm.py
================================================
# This library is free software: you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation, either
# version 3 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.

import base64
import socket
import struct
from ntlm_auth.constants import NegotiateFlags
from ntlm_auth.messages import NegotiateMessage, ChallengeMessage, AuthenticateMessage
from ntlm_auth.session_security import SessionSecurity


"""
utility functions for Microsoft NTLM authentication

References:
[MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol Specification
http://download.microsoft.com/download/a/e/6/ae6e4142-aa58-45c6-8dcf-a657e5900cd3/%5BMS-NLMP%5D.pdf

[MS-NTHT]: NTLM Over HTTP Protocol Specification
http://download.microsoft.com/download/a/e/6/ae6e4142-aa58-45c6-8dcf-a657e5900cd3/%5BMS-NTHT%5D.pdf

Cntlm Authentication Proxy
http://cntlm.awk.cz/

NTLM Authorization Proxy Server
http://sourceforge.net/projects/ntlmaps/

Optimized Attack for NTLM2 Session Response
http://www.blackhat.com/presentations/bh-asia-04/bh-jp-04-pdfs/bh-jp-04-seki.pdf
"""

class Ntlm(object):
    """
    Initialises the NTLM context to use when sending and receiving messages to and from the server. You should be
    using this object as it supports NTLMv2 authenticate and it easier to use than before. It also brings in the
    ability to use signing and sealing with session_security and generate a MIC structure.

    :param ntlm_compatibility: The Lan Manager Compatibility Level to use withe the auth message - Default 3
                                This is set by an Administrator in the registry key
                                'HKLM\SYSTEM\CurrentControlSet\Control\Lsa\LmCompatibilityLevel'
                                The values correspond to the following;
                                    0 : LM and NTLMv1
                                    1 : LM, NTLMv1 and NTLMv1 with Extended Session Security
                                    2 : NTLMv1 and NTLMv1 with Extended Session Security
                                    3-5 : NTLMv2 Only
                                Note: Values 3 to 5 are no different as the client supports the same types

    Attributes:
        negotiate_flags: A NEGOTIATE structure that contains a set of bit flags. These flags are the options the client supports and are sent in the negotiate_message
        ntlm_compatibility: The Lan Manager Compatibility Level, same as the input if supplied
        negotiate_message: A NegotiateMessage object that is sent to the server
        challenge_message: A ChallengeMessage object that has been created from the server response
        authenticate_message: An AuthenticateMessage object that is sent to the server based on the ChallengeMessage
        session_security: A SessionSecurity structure that can be used to sign and seal messages sent after the authentication challenge
    """
    def __init__(self, ntlm_compatibility=3):
        self.ntlm_compatibility = ntlm_compatibility

        # Setting up our flags so the challenge message returns the target info block if supported
        self.negotiate_flags = NegotiateFlags.NTLMSSP_NEGOTIATE_TARGET_INFO | \
                               NegotiateFlags.NTLMSSP_NEGOTIATE_128 | \
                               NegotiateFlags.NTLMSSP_NEGOTIATE_56 | \
                               NegotiateFlags.NTLMSSP_NEGOTIATE_UNICODE | \
                               NegotiateFlags.NTLMSSP_NEGOTIATE_VERSION | \
                               NegotiateFlags.NTLMSSP_NEGOTIATE_KEY_EXCH | \
                               NegotiateFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
                               NegotiateFlags.NTLMSSP_NEGOTIATE_SIGN | \
                               NegotiateFlags.NTLMSSP_NEGOTIATE_SEAL

        # Setting the message types based on the ntlm_compatibility level
        self._set_ntlm_compatibility_flags(self.ntlm_compatibility)

        self.negotiate_message = None
        self.challenge_message = None
        self.authenticate_message = None
        self.session_security = None


    def create_negotiate_message(self, domain_name=None, workstation=None):
        """
        Create an NTLM NEGOTIATE_MESSAGE

        :param domain_name: The domain name of the user account we are authenticating with, default is None
        :param worksation: The workstation we are using to authenticate with, default is None
        :return: A base64 encoded string of the NEGOTIATE_MESSAGE
        """
        self.negotiate_message = NegotiateMessage(self.negotiate_flags, domain_name, workstation)

        return base64.b64encode(self.negotiate_message.get_data())

    def parse_challenge_message(self, msg2):
        """
        Parse the NTLM CHALLENGE_MESSAGE from the server and add it to the Ntlm context fields

        :param msg2: A base64 encoded string of the CHALLENGE_MESSAGE
        """
        msg2 = base64.b64decode(msg2)
        self.challenge_message = ChallengeMessage(msg2)

    def create_authenticate_message(self, user_name, password=None, nthash=None, lmhash=None, domain_name=None, workstation=None, server_certificate_hash=None):
        """
        Create an NTLM AUTHENTICATE_MESSAGE based on the Ntlm context and the previous messages sent and received

        :param user_name: The user name of the user we are trying to authenticate with
        :param password: The password of the user we are trying to authenticate with
        :param domain_name: The domain name of the user account we are authenticated with, default is None
        :param workstation: The workstation we are using to authenticate with, default is None
        :param server_certificate_hash: The SHA256 hash string of the server certificate (DER encoded) NTLM is authenticating to. Used for Channel
                                        Binding Tokens. If nothing is supplied then the CBT hash will not be sent. See messages.py AuthenticateMessage
                                        for more details
        :return: A base64 encoded string of the AUTHENTICATE_MESSAGE
        """
        self.authenticate_message = AuthenticateMessage(user_name, password, nthash, lmhash, domain_name, workstation,
                                                        self.challenge_message, self.ntlm_compatibility,
                                                        server_certificate_hash)
        self.authenticate_message.add_mic(self.negotiate_message, self.challenge_message)

        # Setups up the session_security context used to sign and seal messages if wanted
        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SEAL or self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SIGN:
            self.session_security = SessionSecurity(struct.unpack("<I", self.authenticate_message.negotiate_flags)[0],
                                                    self.authenticate_message.exported_session_key)

        return base64.b64encode(self.authenticate_message.get_data())

    def _set_ntlm_compatibility_flags(self, ntlm_compatibility):
        if (ntlm_compatibility >= 0) and (ntlm_compatibility <= 5):
            if ntlm_compatibility == 0:
                self.negotiate_flags |= NegotiateFlags.NTLMSSP_NEGOTIATE_NTLM | \
                                        NegotiateFlags.NTLMSSP_NEGOTIATE_LM_KEY
            elif ntlm_compatibility == 1:
                self.negotiate_flags |= NegotiateFlags.NTLMSSP_NEGOTIATE_NTLM | \
                                        NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
            else:
                self.negotiate_flags |= NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
        else:
            raise Exception("Unknown ntlm_compatibility level - expecting value between 0 and 5")


================================================
FILE: ntlm_auth/rc4.py
================================================
# This library is free software: you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation, either
# version 3 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.

class ARC4(object):
    state = None
    i = 0
    j = 0

    def __init__(self, key):
        # Split up the key into a list
        if isinstance(key, str):
            key = [ord(c) for c in key]
        else:
            key = [c for c in key]

        #Key-scheduling algorithm (KSA)
        self.state = [n for n in range(256)]
        j = 0
        for i in range(256):
            j = (j + self.state[i] + key[i % len(key)]) % 256
            self.state[i], self.state[j] = self.state[j], self.state[i]

    def update(self, value):
        chars = []
        random_gen = self._random_generator()
        for char in value:
            if isinstance(value, str):
                byte = ord(char)
            else:
                byte = char
            updated_byte = byte ^ next(random_gen)
            chars.append(updated_byte)
        return bytes(bytearray(chars))

    def _random_generator(self):
        #Pseudo-Random Generation Algorithm (PRGA)
        while True:
            self.i = (self.i + 1) % 256
            self.j = (self.j + self.state[self.i]) % 256
            self.state[self.i], self.state[self.j] = self.state[self.j], self.state[self.i]
            yield self.state[(self.state[self.i] + self.state[self.j]) % 256]


================================================
FILE: ntlm_auth/session_security.py
================================================
# This library is free software: you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation, either
# version 3 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.

import binascii
import hmac
import struct
import ntlm_auth.compute_keys as compkeys
from ntlm_auth.constants import NegotiateFlags, SignSealConstants
from ntlm_auth.rc4 import ARC4


class _NtlmMessageSignature1(object):
    EXPECTED_BODY_LENGTH = 16

    """
        [MS-NLMP] v28.0 2016-07-14

        2.2.2.9.1 NTLMSSP_MESSAGE_SIGNATURE
        This version of the NTLMSSP_MESSAGE_SIGNATURE structure MUST be used when the
        NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is not negotiated.

        :param random_pad: A 4-byte array that contains the random pad for the emssage
        :param checksum: A 4-byte array that contains the checksum for the message
        :param seq_num: A 32-bit unsigned integer that contains the NTLM sequence number for this application message
    """
    def __init__(self, random_pad, checksum, seq_num):
        self.version = struct.pack("<I", 1)
        self.random_pad = random_pad
        self.checksum = checksum
        self.seq_num = seq_num

    def get_data(self):
        signature = self.version
        signature += self.random_pad
        signature += self.checksum
        signature += self.seq_num

        assert self.EXPECTED_BODY_LENGTH == len(signature), "BODY_LENGTH: %d != signature: %d" % (
        self.EXPECTED_BODY_LENGTH, len(signature))

        return signature

class _NtlmMessageSignature2(object):
    EXPECTED_BODY_LENGTH = 16

    """
        [MS-NLMP] v28.0 2016-07-14

        2.2.2.9.2 NTLMSSP_MESSAGE_SIGNATURE for Extended Session Security
        This version of the NTLMSSP_MESSAGE_SIGNATURE structure MUST be used when the
        NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is negotiated

        :param checksum: An 8-byte array that contains the checksum for the message
        :param seq_num: A 32-bit unsigned integer that contains the NTLM sequence number for this application message
    """

    def __init__(self, checksum, seq_num):
        self.version = struct.pack("<I", 1)
        self.checksum = checksum
        self.seq_num = seq_num

    def get_data(self):
        signature = self.version
        signature += self.checksum
        signature += self.seq_num

        assert self.EXPECTED_BODY_LENGTH == len(signature), "BODY_LENGTH: %d != signature: %d" % (
            self.EXPECTED_BODY_LENGTH, len(signature))

        return signature

class SessionSecurity(object):
    """
    Initialises a security session context that can be used by libraries that call ntlm-auth to sign and seal
    messages send to the server as well as verify and unseal messages that have been received from the server.
    This is similar to the GSS_Wrap functions specified in the MS-NLMP document which does the same task.

    :param negotiate_flags: The negotiate flag structure that has been negotiated with the server
    :param exported_session_key: A 128-bit session key used to derive signing and sealing keys
    :param source: The source of the message, only used in test scenarios when testing out a server sealing and unsealing
    """
    def __init__(self, negotiate_flags, exported_session_key, source="client"):
        self.negotiate_flags = negotiate_flags
        self.outgoing_seq_num = 0
        self.incoming_seq_num = 0

        client_sealing_key = compkeys.get_seal_key(self.negotiate_flags, exported_session_key, SignSealConstants.CLIENT_SEALING)
        server_sealing_key = compkeys.get_seal_key(self.negotiate_flags, exported_session_key, SignSealConstants.SERVER_SEALING)

        if source == "client":
            self.outgoing_signing_key = compkeys.get_sign_key(exported_session_key, SignSealConstants.CLIENT_SIGNING)
            self.incoming_signing_key = compkeys.get_sign_key(exported_session_key, SignSealConstants.SERVER_SIGNING)
            self.outgoing_handle = ARC4(client_sealing_key)
            self.incoming_handle = ARC4(server_sealing_key)
        elif source == "server":
            self.outgoing_signing_key = compkeys.get_sign_key(exported_session_key, SignSealConstants.SERVER_SIGNING)
            self.incoming_signing_key = compkeys.get_sign_key(exported_session_key, SignSealConstants.CLIENT_SIGNING)
            self.outgoing_handle = ARC4(server_sealing_key)
            self.incoming_handle = ARC4(client_sealing_key)
        else:
            raise Exception("Invalid source parameter %s, must be client or server" % source)

    def wrap(self, message):
        """
        [MS-NLMP] v28.0 2016-07-14

        3.4.6 GSS_WrapEx()
        Emulates the GSS_Wrap() implementation to sign and seal messages if the correct flags
        are set.

        @param message: The message data that will be wrapped
        @return message: The message that has been sealed if flags are set
        @return signature: The signature of the message, None if flags are not set
        """
        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SEAL:
            encrypted_message = self._seal_message(message)
            signature = self._get_signature(message)
            message = encrypted_message

        elif self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SIGN:
            signature = self._get_signature(message)
        else:
            signature = None

        return message, signature

    def unwrap(self, message, signature):
        """
        [MS-NLMP] v28.0 2016-07-14

        3.4.7 GSS_UnwrapEx()
        Emulates the GSS_Unwrap() implementation to unseal messages and verify the signature
        sent matches what has been computed locally. Will throw an Exception if the signature
        doesn't match

        @param message: The message data received from the server
        @param signature: The signature of the message
        @return message: The message that has been unsealed if flags are set
        """
        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SEAL:
            message = self._unseal_message(message)
            self._verify_signature(message, signature)

        elif self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SIGN:
            self._verify_signature(message, signature)

        return message

    def _seal_message(self, message):
        """
        [MS-NLMP] v28.0 2016-07-14

        3.4.3 Message Confidentiality
        Will generate an encrypted message using RC4 based on the ClientSealingKey

        @param message: The message to be sealed (encrypted)
        @return encrypted_message: The encrypted message
        """
        encrypted_message = self.outgoing_handle.update(message)
        return encrypted_message

    def _unseal_message(self, message):
        """
        [MS-NLMP] v28.0 2016-07-14

        3.4.3 Message Confidentiality
        Will generate a dencrypted message using RC4 based on the ServerSealingKey

        @param message: The message to be unsealed (dencrypted)
        @return decrypted_message: The decrypted message
        """
        decrypted_message = self.incoming_handle.update(message)
        return decrypted_message

    def _get_signature(self, message):
        """
        [MS-NLMP] v28.0 2016-07-14

        3.4.4 Message Signature Functions
        Will create the signature based on the message to send to the server. Depending on the negotiate_flags
        set this could either be an NTLMv1 signature or NTLMv2 with Extended Session Security signature.

        @param message: The message data that will be signed
        @return signature: Either _NtlmMessageSignature1 or _NtlmMessageSignature2 depending on the flags set
        """
        signature = calc_signature(message, self.negotiate_flags, self.outgoing_signing_key, self.outgoing_seq_num, self.outgoing_handle)
        self.outgoing_seq_num += 1

        return signature.get_data()

    def _verify_signature(self, message, signature):
        """
        Will verify that the signature received from the server matches up with the expected signature
        computed locally. Will throw an exception if they do not match

        @param message: The message data that is received from the server
        @param signature: The signature of the message received from the server
        """
        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
            actual_checksum = signature[4:12]
            actual_seq_num = struct.unpack("<I", signature[12:16])[0]
        else:
            actual_checksum = signature[8:12]
            actual_seq_num = struct.unpack("<I", signature[12:16])[0]

        expected_signature = calc_signature(message, self.negotiate_flags, self.incoming_signing_key, self.incoming_seq_num, self.incoming_handle)
        expected_checksum = expected_signature.checksum
        expected_seq_num = struct.unpack("<I", expected_signature.seq_num)[0]

        if actual_checksum != expected_checksum:
            raise Exception("The signature checksum does not match, message has been altered")

        if actual_seq_num != expected_seq_num:
            raise Exception("The signature sequence number does not match up, message not received in the correct sequence")

        self.incoming_seq_num += 1


def calc_signature(message, negotiate_flags, signing_key, seq_num, handle):
    seq_num = struct.pack("<I", seq_num)
    if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
        checksum_hmac = hmac.new(signing_key, seq_num + message)
        if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_KEY_EXCH:
            checksum = handle.update(checksum_hmac.digest()[:8])
        else:
            checksum = checksum_hmac.digest()[:8]

        signature = _NtlmMessageSignature2(checksum, seq_num)

    else:
        message_crc = binascii.crc32(message) % (1 << 32)
        checksum = struct.pack("<I", message_crc)
        random_pad = handle.update(struct.pack("<I", 0))
        checksum = handle.update(checksum)
        seq_num = handle.update(seq_num)
        random_pad = struct.pack("<I", 0)

        signature = _NtlmMessageSignature1(random_pad, checksum, seq_num)

    return signature


================================================
FILE: ntlm_auth/target_info.py
================================================
"""
    Original Author: Ian Clegg
    Project: ntlmlib
    URL: https://github.com/ianclegg/ntlmlib
    License: Apache 2.0 License
    Notes: Most of this code has been copied from the messages.py in the ntlmlib repo.
    Some minor changes such as the name of the AV Pairs and extra comments have been added.
"""

import struct
try:
    from collections import OrderedDict
except ImportError:
    from ordereddict import OrderedDict

class TargetInfo(object):
    MSV_AV_EOL                  = 0x00
    MSV_AV_NB_COMPUTER_NAME     = 0x01
    MSV_AV_NB_DOMAIN_NAME       = 0x02
    MSV_AV_DNS_COMPUTER_NAME    = 0x03
    MSV_AV_DNS_DOMAIN_NAME      = 0x04
    MSV_AV_DNS_TREE_NAME        = 0x05
    MSV_AV_FLAGS                = 0x06
    MSV_AV_TIMESTAMP            = 0x07
    MSV_AV_SINGLE_HOST          = 0x08
    MSV_AV_TARGET_NAME          = 0x09
    MSV_AV_CHANNEL_BINDINGS     = 0x0a

    def __init__(self, data=None):
        self.fields = OrderedDict()
        if data is not None:
            self.from_string(data)

    def __setitem__(self, key, value):
        self.fields[key] = (len(value), value)

    def __getitem__(self, key):
        if key in self.fields:
           return self.fields[key]
        return None

    def __delitem__(self, key):
        del self.fields[key]

    def from_string(self, data):
        attribute_type = 0xff
        while attribute_type is not TargetInfo.MSV_AV_EOL:
            # Parse the Attribute Value pair from the structure
            attribute_type = struct.unpack('<H', data[:struct.calcsize('<H')])[0]
            data = data[struct.calcsize('<H'):]
            length = struct.unpack('<H', data[:struct.calcsize('<H')])[0]
            data = data[struct.calcsize('<H'):]
            # Add a new field to the object for the parse attribute value
            self.fields[attribute_type] = (length, data[:length])
            data = data[length:]

    def get_data(self):
        if TargetInfo.MSV_AV_EOL in self.fields:
            del self.fields[TargetInfo.MSV_AV_EOL]

        data = b''
        for i in self.fields.keys():
            data += struct.pack('<HH', i, self[i][0])
            data += self[i][1]

        # end with a NTLMSSP_AV_EOL
        data += struct.pack('<HH', TargetInfo.MSV_AV_EOL, 0)
        return data

================================================
FILE: ordereddict.py
================================================
# Copyright (c) 2009 Raymond Hettinger
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
#     The above copyright notice and this permission notice shall be
#     included in all copies or substantial portions of the Software.
#
#     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
#     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
#     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
#     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
#     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
#     OTHER DEALINGS IN THE SOFTWARE.

from UserDict import DictMixin

class OrderedDict(dict, DictMixin):

    def __init__(self, *args, **kwds):
        if len(args) > 1:
            raise TypeError('expected at most 1 arguments, got %d' % len(args))
        try:
            self.__end
        except AttributeError:
            self.clear()
        self.update(*args, **kwds)

    def clear(self):
        self.__end = end = []
        end += [None, end, end]         # sentinel node for doubly linked list
        self.__map = {}                 # key --> [key, prev, next]
        dict.clear(self)

    def __setitem__(self, key, value):
        if key not in self:
            end = self.__end
            curr = end[1]
            curr[2] = end[1] = self.__map[key] = [key, curr, end]
        dict.__setitem__(self, key, value)

    def __delitem__(self, key):
        dict.__delitem__(self, key)
        key, prev, next = self.__map.pop(key)
        prev[2] = next
        next[1] = prev

    def __iter__(self):
        end = self.__end
        curr = end[2]
        while curr is not end:
            yield curr[0]
            curr = curr[2]

    def __reversed__(self):
        end = self.__end
        curr = end[1]
        while curr is not end:
            yield curr[0]
            curr = curr[1]

    def popitem(self, last=True):
        if not self:
            raise KeyError('dictionary is empty')
        if last:
            key = reversed(self).next()
        else:
            key = iter(self).next()
        value = self.pop(key)
        return key, value

    def __reduce__(self):
        items = [[k, self[k]] for k in self]
        tmp = self.__map, self.__end
        del self.__map, self.__end
        inst_dict = vars(self).copy()
        self.__map, self.__end = tmp
        if inst_dict:
            return (self.__class__, (items,), inst_dict)
        return self.__class__, (items,)

    def keys(self):
        return list(self)

    setdefault = DictMixin.setdefault
    update = DictMixin.update
    pop = DictMixin.pop
    values = DictMixin.values
    items = DictMixin.items
    iterkeys = DictMixin.iterkeys
    itervalues = DictMixin.itervalues
    iteritems = DictMixin.iteritems

    def __repr__(self):
        if not self:
            return '%s()' % (self.__class__.__name__,)
        return '%s(%r)' % (self.__class__.__name__, self.items())

    def copy(self):
        return self.__class__(self)

    @classmethod
    def fromkeys(cls, iterable, value=None):
        d = cls()
        for key in iterable:
            d[key] = value
        return d

    def __eq__(self, other):
        if isinstance(other, OrderedDict):
            if len(self) != len(other):
                return False
            for p, q in  zip(self.items(), other.items()):
                if p != q:
                    return False
            return True
        return dict.__eq__(self, other)

    def __ne__(self, other):
        return not self == other


================================================
FILE: relay.py
================================================
import time
import socket


buffer_size = 4096
delay = 0.0001
socks_server_reply_success = '\x00\x5a\xff\xff\xff\xff\xff\xff'
socks_server_reply_fail = '\x00\x5b\xff\xff\xff\xff\xff\xff'
relay_timeout = 60
banner = 'RPIVOT'
banner_response = 'TUNNELRDY'

COMMAND_CHANNEL = 0

CHANNEL_CLOSE_CMD = '\xcc'
CHANNEL_OPEN_CMD = '\xdd'
FORWARD_CONNECTION_SUCCESS = '\xee'
FORWARD_CONNECTION_FAILURE = '\xff'
CLOSE_RELAY = '\xc4'
PING_CMD = '\x70'

cmd_names = {
    '\xcc': 'CHANNEL_CLOSE_CMD',
    '\xdd': 'CHANNEL_OPEN_CMD',
    '\xee': 'FORWARD_CONNECTION_SUCCESS',
    '\xff': 'FORWARD_CONNECTION_FAILURE',
    '\xc4': 'CLOSE_RELAY',
    '\x70': 'PING_CMD'
}


class ClosedSocket(Exception):
    pass


class RelayError(Exception):
    pass


def recvall(sock, data_len):
    buf = ''
    while True:
        buf += sock.recv(data_len - len(buf))
        if len(buf) == data_len:
            break
        time.sleep(delay)
    assert(data_len == len(buf))
    return buf


def close_sockets(sockets):
    for s in sockets:
        try:
            s.close()
        except socket.error:
            pass


================================================
FILE: server.py
================================================
#!/usr/bin/env python

import logging
import logging.handlers
import socket
import select
import sys
import time
from struct import pack, unpack
import struct
import random
import errno
import relay
import threading
import optparse

class RelayServer:
    def __init__(self, host, port, socket_with_server):
        self.input_list = []
        self.channel = {}
        self.last_ping_time = time.time()
        self.id_by_socket = {}
        self.pending_socks_clients = []
        self.socket_with_server = socket_with_server
        self.input_list.append(self.socket_with_server)
        self.remote_side_down = False

        logger.debug('Starting ping thread')

        self.ping_thread = threading.Thread(target=self.ping_worker)
        self.ping_thread.start()

        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        try:
            self.server.bind((host, port))
            self.server.listen(2000)
        except socket.error as (code, msg):
            logger.error('Error binding socks proxy. {0}'.format(msg))
            logger.error('Closing relay')
            socket_with_server.close()
            raise
        self.socks_client_socket = None

    def ping_worker(self):
        while True:
            time.sleep(10)
            current_time = time.time()
            if self.remote_side_down:
                logger.debug('Remote side down. Ping worker exiting')
                return
            if current_time - self.last_ping_time > relay.relay_timeout:
                logger.info('No response from remote side for {0} seconds. Restarting relay'.format(relay.relay_timeout))
                self.socket_with_server.close()
                return
            logger.debug('Sending ping')
            try:
                self.send_remote_cmd(self.socket_with_server, relay.PING_CMD)
            except socket.error as (code, msg):
                logger.debug('Ping thread got socket exception {0} {1}. Closing socket with remote side'.format(code, msg))
                self.socket_with_server.close()
                return
            except relay.RelayError:
                logger.debug('Ping worker caught RelayError. Exiting')
                self.shutdown()
                return

    def shutdown(self):
        relay.close_sockets(self.input_list)
        self.remote_side_down = True


    def main_loop(self):
        self.input_list.append(self.server)
        while True:
            time.sleep(relay.delay)

            try:
                logger.debug("Active channels: {0}".format(self.channel.keys()))
                inputready, outputready, exceptready = select.select(self.input_list, [], [])
            except socket.error as (code, msg):
                logger.debug('Socket error on select. Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))
                return
            except KeyboardInterrupt:
                logger.info('SIGINT received. Closing relay and exiting')
                self.shutdown()
                sys.exit(1)
            for self.selected_input_socket in inputready:
                if self.selected_input_socket == self.server:
                    self.on_accept()
                    break

                if self.selected_input_socket == self.socket_with_server:
                    try:
                        self.manage_remote_socket(self.selected_input_socket)
                    except relay.RelayError:
                        logger.debug('Main loop: got RelayError. Closing connection with remote side and exiting loop')
                        self.shutdown()
                        return
                elif self.selected_input_socket in self.pending_socks_clients:
                    self.pending_socks_clients.remove(self.selected_input_socket)
                    try:
                        ip, port = self.handle_new_socks_connection(self.selected_input_socket)
                    except relay.RelayError:
                        logger.debug("Closing socks client socket {0}".format(self.selected_input_socket))
                        self.input_list.remove(self.selected_input_socket)
                        self.selected_input_socket.close()
                        continue
                    #self.input_list.append(self.selected_input_socket)
                    new_channel_id = self.set_channel(self.selected_input_socket)
                    logger.debug("Sending command to open channel {0}".format(new_channel_id))
                    self.send_remote_cmd(self.socket_with_server, relay.CHANNEL_OPEN_CMD, new_channel_id, ip, port)


                elif self.selected_input_socket in self.id_by_socket:
                    self.manage_socks_client_socket(self.selected_input_socket)
                else:
                    logger.debug("Active socket {0} does not belong to channel. Closing it".format(self.selected_input_socket))
                    self.selected_input_socket.close()


    def parse_socks_header(self, data):
        try:
            (vn, cd, dstport, dstip) = unpack('>BBHI', data[:8])
        except struct.error:
            logger.debug('Invalid socks header! Got data: {0}'.format(repr(data)))
            raise relay.RelayError
        if vn != 4:
            logger.debug('Invalid socks header! Got data: {0}'.format(repr(data)))
            raise relay.RelayError
        str_ip = socket.inet_ntoa(pack(">L", dstip))
        logger.debug('Parsing socks header. Socks version: {0} Socks command: {1} Dstport: {2} Dstip: {3}'.format(vn, cd, dstport, str_ip))
        return str_ip, dstport

    def get_channel_data(self, sock):
        try:
            tlv_header = relay.recvall(sock, 4)
            channel_id, tlv_data_len = unpack('<HH', tlv_header)
            data = relay.recvall(sock, tlv_data_len)
        except socket.error as (code, msg):
            logger.debug('Exception on receiving tlv message from remote side. Exiting')
            logger.debug('Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))
            raise relay.RelayError
        return channel_id, data

    def manage_remote_socket(self, sock):
        channel_id, data = self.get_channel_data(sock)
        if channel_id == relay.COMMAND_CHANNEL:
            self.handle_remote_cmd(data)
        elif channel_id in self.channel:
            relay_to_sock = self.channel[channel_id]
            logger.debug('Got data to relay from remote side. Channel id {0}. Data length: {1}'.format(channel_id, len(data)))
            logger.debug('Data contents: {0}'.format(data.encode('hex')))
            self.relay(data, relay_to_sock)
        else:
            logger.debug('Relay from socket {0} with channel {1} not possible. Channel does not exist'.format(sock, channel_id))
            return

    def manage_socks_client_socket(self, sock):
        try:
            data = sock.recv(relay.buffer_size)
        except socket.error as (code, msg):
            logger.debug('Exception on reading socket {0} with channel id {1}'.format(sock, self.id_by_socket[sock]))
            logger.debug('Details: {0}, {1}'.format(errno.errorcode[code], msg))
            self.close_socks_connection(sock)
            return
        data_len = len(data)
        if data_len == 0:
            self.close_socks_connection(sock)
            return
        else:
            channel_id = self.id_by_socket[sock]
            tlv_header = pack('<HH', channel_id, len(data))
            logger.debug('Got data to relay from app side. Channel id {0}. Data length: {1}'.format(channel_id, len(data)))
            logger.debug('Preparint tlv header: {0}'.format(tlv_header.encode('hex')))
            logger.debug('Data contents: {0}'.format(data.encode('hex')))
            self.relay(tlv_header + data, self.socket_with_server)

    def handle_remote_cmd(self, data):
        cmd = data[0]
        logger.debug('Received cmd from remote side. Cmd: {0}'.format(relay.cmd_names[cmd]))
        if cmd == relay.CHANNEL_CLOSE_CMD:
            channel_id = unpack('<H', data[1:3])[0]
            logger.debug('Channel close request with id: {0}'.format(channel_id))
            if channel_id not in self.channel:
                logger.debug('Channel {0} already closed'.format(channel_id))
                return
            else:
                sock_to_close = self.channel[channel_id]
                self.input_list.remove(sock_to_close)
                self.unset_channel(channel_id)
                logger.debug('Closing socket {0}  with id: {1}'.format(sock_to_close, channel_id))
                sock_to_close.close()
        elif cmd == relay.FORWARD_CONNECTION_SUCCESS:
            channel_id = unpack('<H', data[1:3])[0]
            if channel_id in self.channel:
                logger.debug('Forward connection successful with id: {0}'.format(channel_id))
                sock = self.channel[channel_id]
                try:
                    sock.send(relay.socks_server_reply_success)
                except socket.error as (code, msg):
                    logger.error('Socket error on replying SUCCESS to socks client. Code {0}. Msg {1}'.format(code, cmd))
                    logger.debug('Closing client socket and sending channel close cmd to remote side')
                    sock = self.channel[channel_id]
                    self.input_list.remove(sock)
                    self.unset_channel(channel_id)
                    try:
                        sock.close()
                    except socket.error:
                        logger.debug('Error on closing socket')

                    self.send_remote_cmd(self.socket_with_server, relay.CHANNEL_CLOSE_CMD, channel_id)
            else:
                logger.debug('Forward connection successful with id: {0}. But channel already closed here'.format(channel_id))
        elif cmd == relay.FORWARD_CONNECTION_FAILURE:
            channel_id = unpack('<H', data[1:3])[0]
            logger.debug('Forward connection failed with id: {0}'.format(channel_id))
            if channel_id in self.channel:
                sock = self.channel[channel_id]
                try:
                    sock.send(relay.socks_server_reply_fail)
                except socket.error as (code, msg):
                    logger.error('Socket error on replying  FAILURE to socks client. Code {0}. Msg {0}'.format(code, cmd))
                self.input_list.remove(sock)
                self.unset_channel(channel_id)
                try:
                    sock.close()
                except socket.error:
                    logger.debug('Error on closing socket')
            else:
                logger.debug('Tried to close channel {0} that is already closed'.format(channel_id))

        elif cmd == relay.CLOSE_RELAY:
            logger.info('Got command to close relay. Closing connection with client.')
            raise relay.RelayError
        elif cmd == relay.PING_CMD:
            #logger.debug('Got ping response from remote side. Good.')
            self.last_ping_time = time.time()
        else:
            logger.error('Unknown cmd received! Exiting')
            raise relay.RelayError

    def send_remote_cmd(self, sock, cmd, *args):
        logger.debug('Sending cmd to remote side. Cmd: {0}'.format(relay.cmd_names[cmd]))
        if cmd == relay.CHANNEL_CLOSE_CMD:
            cmd_buffer = cmd + pack('<H', args[0])
            tlv_header = pack('<HH', relay.COMMAND_CHANNEL, len(cmd_buffer))
        elif cmd == relay.CHANNEL_OPEN_CMD:
            channel_id, ip, port = args
            cmd_buffer = cmd + pack('<H',  channel_id) + socket.inet_aton(ip) + pack('<H', port)
            tlv_header = pack('<HH', relay.COMMAND_CHANNEL, len(cmd_buffer))
        else:
            cmd_buffer = cmd
            tlv_header = pack('<HH', relay.COMMAND_CHANNEL, len(cmd_buffer))
        try:
            sock.send(tlv_header + cmd_buffer)
        except socket.error as (code, cmd):
            logger.error('Socket error on sending command to remote side. Code {0}. Msg {1}'.format(code, cmd))
            raise relay.RelayError

    def on_accept(self):
        socks_client_socket, clientaddr = self.server.accept()
        logger.debug("Socks client {0} has connected".format(clientaddr))
        self.input_list.append(socks_client_socket)
        self.pending_socks_clients.append(socks_client_socket)




    def handle_new_socks_connection(self, sock):
        try:
            logger.debug('Trying to recieve socks header from socks client')
            #data = relay.recvall(sock, 9)
            data = sock.recv(9)
            logger.debug('Got header data from socks client')
            if len(data) != 9:
                logger.debug('Error receiving socks header: corrupted header')
                raise relay.RelayError
            if data[-1] != '\x00':
                logger.debug('Error receiving socks header: corrupted header')
                raise relay.RelayError
        except socket.error as (code, msg):
            logger.debug('Error receiving socks header {0} {1}'.format(errno.errorcode[code], msg))
            raise relay.RelayError
        if len(data) == 0:
            logger.debug('Socks client prematurely ended connection')
            raise relay.RelayError
        return self.parse_socks_header(data)

    def set_channel(self, sock):
        new_channel_id = self.generate_new_channel_id()
        self.channel[new_channel_id] = sock
        self.id_by_socket[sock] = new_channel_id
        return new_channel_id

    def unset_channel(self, channel_id):
        sock = self.channel[channel_id]
        del self.id_by_socket[sock]
        del self.channel[channel_id]

    def generate_new_channel_id(self):
        channel_ids = self.channel.keys()
        while True:
            rint = random.randint(1, 65535)
            if rint not in channel_ids:
                return rint

    def close_socks_connection(self, sock):
        channel_id = self.id_by_socket[sock]
        logger.debug('Closing socks client socket {0} with id {1}'.format(sock, channel_id))
        logger.debug('Notifying remote side')
        self.unset_channel(channel_id)
        self.input_list.remove(sock)
        sock.close()
        self.send_remote_cmd(self.socket_with_server, relay.CHANNEL_CLOSE_CMD, channel_id)

    def relay(self, data, to_socket):
        if to_socket is None:
            return
        try:
            to_socket.send(data)
        except socket.error as (code, msg):
            logger.debug('Exception on relaying data to socket {0}'.format(to_socket))
            logger.debug('Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))
            if to_socket == self.socket_with_server:
                raise relay.RelayError
            else:
                logger.debug('Closing socket')
                to_socket.close()
                self.input_list.remove(to_socket)
                channel_id = self.id_by_socket[to_socket]
                self.unset_channel(channel_id)
                self.send_remote_cmd(self.socket_with_server, relay.CHANNEL_CLOSE_CMD, channel_id)


def run_server(host, port):
    while True:
        serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        try:
            serversock.bind((host, port))
            serversock.listen(5)
        except socket.error:
            logger.error('Exception binding server at {0} port {1}'.format(host, port))
            time.sleep(1)
            break

        try:
            (socket_with_remote_side, address) = serversock.accept()
        except KeyboardInterrupt:
            logger.info('SIGINT received. Shutting down')
            sys.exit(1)
        logger.info('New connection from host {0}, source port {1}'.format(address[0], address[1]))
        serversock.close()

        try:
            banner_rcv = socket_with_remote_side.recv(4096)
            if banner_rcv != relay.banner:
                logger.error("Wrong banner {0} from client. Closing connection".format(repr(banner_rcv)))
                socket_with_remote_side.close()
                continue
            socket_with_remote_side.send(relay.banner_response)
        except socket.error as (code, msg):
            logger.error("Caught socket error trying to establish connection with RPIVOT client. Code {0}. Msg {1}".format(code, msg))
            continue

        try:
            server = RelayServer(cmd_options.proxy_ip, int(cmd_options.proxy_port), socket_with_remote_side)

        except socket.error as (code, msg):
            logger.info('Error on running relay server. Restarting')
            continue
        try:
            server.main_loop()
        except relay.RelayError:
            logger.info('Got RelayError in server.main_loop(). Restarting relay')
            server.server.close()
            continue

        except KeyboardInterrupt:
            print "Ctrl C - Stopping server"
            sys.exit(1)


def main():
    global logger
    global cmd_options

    parser = optparse.OptionParser(description='Reverse socks server')
    parser.add_option('--server-ip', action="store", dest='server_ip', default='0.0.0.0')
    parser.add_option('--server-port', action="store", dest='server_port', default='9999')
    parser.add_option('--proxy-ip', action="store", dest='proxy_ip', default='127.0.0.1')
    parser.add_option('--proxy-port', action="store", dest='proxy_port', default='1080')
    parser.add_option('--verbose', action="store_true", dest="verbose", default=False)
    parser.add_option('--logfile', action="store", dest="logfile", default=None)



    cmd_options = parser.parse_args()[0]



    logger = logging.getLogger('root')
    logger.setLevel(logging.DEBUG)
    ch = None

    if cmd_options.logfile is None:
        ch = logging.StreamHandler()
    else:
        ch = logging.FileHandler(cmd_options.logfile)

    if cmd_options.verbose:
        ch.setLevel(logging.DEBUG)
    else:
        ch.setLevel(logging.INFO)

    logger.addHandler(ch)

    run_server(cmd_options.server_ip, int(cmd_options.server_port))


if __name__ == "__main__":
    main()





================================================
FILE: six.py
================================================
"""Utilities for writing code that runs on Python 2 and 3"""

# Copyright (c) 2010-2015 Benjamin Peterson
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

from __future__ import absolute_import

import functools
import itertools
import operator
import sys
import types

__author__ = "Benjamin Peterson <benjamin@python.org>"
__version__ = "1.10.0"


# Useful for very coarse version differentiation.
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3
PY34 = sys.version_info[0:2] >= (3, 4)

if PY3:
    string_types = str,
    integer_types = int,
    class_types = type,
    text_type = str
    binary_type = bytes

    MAXSIZE = sys.maxsize
else:
    string_types = basestring,
    integer_types = (int, long)
    class_types = (type, types.ClassType)
    text_type = unicode
    binary_type = str

    if sys.platform.startswith("java"):
        # Jython always uses 32 bits.
        MAXSIZE = int((1 << 31) - 1)
    else:
        # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
        class X(object):

            def __len__(self):
                return 1 << 31
        try:
            len(X())
        except OverflowError:
            # 32-bit
            MAXSIZE = int((1 << 31) - 1)
        else:
            # 64-bit
            MAXSIZE = int((1 << 63) - 1)
        del X


def _add_doc(func, doc):
    """Add documentation to a function."""
    func.__doc__ = doc


def _import_module(name):
    """Import module, returning the module after the last dot."""
    __import__(name)
    return sys.modules[name]


class _LazyDescr(object):

    def __init__(self, name):
        self.name = name

    def __get__(self, obj, tp):
        result = self._resolve()
        setattr(obj, self.name, result)  # Invokes __set__.
        try:
            # This is a bit ugly, but it avoids running this again by
            # removing this descriptor.
            delattr(obj.__class__, self.name)
        except AttributeError:
            pass
        return result


class MovedModule(_LazyDescr):

    def __init__(self, name, old, new=None):
        super(MovedModule, self).__init__(name)
        if PY3:
            if new is None:
                new = name
            self.mod = new
        else:
            self.mod = old

    def _resolve(self):
        return _import_module(self.mod)

    def __getattr__(self, attr):
        _module = self._resolve()
        value = getattr(_module, attr)
        setattr(self, attr, value)
        return value


class _LazyModule(types.ModuleType):

    def __init__(self, name):
        super(_LazyModule, self).__init__(name)
        self.__doc__ = self.__class__.__doc__

    def __dir__(self):
        attrs = ["__doc__", "__name__"]
        attrs += [attr.name for attr in self._moved_attributes]
        return attrs

    # Subclasses should override this
    _moved_attributes = []


class MovedAttribute(_LazyDescr):

    def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
        super(MovedAttribute, self).__init__(name)
        if PY3:
            if new_mod is None:
                new_mod = name
            self.mod = new_mod
            if new_attr is None:
                if old_attr is None:
                    new_attr = name
                else:
                    new_attr = old_attr
            self.attr = new_attr
        else:
            self.mod = old_mod
            if old_attr is None:
                old_attr = name
            self.attr = old_attr

    def _resolve(self):
        module = _import_module(self.mod)
        return getattr(module, self.attr)


class _SixMetaPathImporter(object):

    """
    A meta path importer to import six.moves and its submodules.

    This class implements a PEP302 finder and loader. It should be compatible
    with Python 2.5 and all existing versions of Python3
    """

    def __init__(self, six_module_name):
        self.name = six_module_name
        self.known_modules = {}

    def _add_module(self, mod, *fullnames):
        for fullname in fullnames:
            self.known_modules[self.name + "." + fullname] = mod

    def _get_module(self, fullname):
        return self.known_modules[self.name + "." + fullname]

    def find_module(self, fullname, path=None):
        if fullname in self.known_modules:
            return self
        return None

    def __get_module(self, fullname):
        try:
            return self.known_modules[fullname]
        except KeyError:
            raise ImportError("This loader does not know module " + fullname)

    def load_module(self, fullname):
        try:
            # in case of a reload
            return sys.modules[fullname]
        except KeyError:
            pass
        mod = self.__get_module(fullname)
        if isinstance(mod, MovedModule):
            mod = mod._resolve()
        else:
            mod.__loader__ = self
        sys.modules[fullname] = mod
        return mod

    def is_package(self, fullname):
        """
        Return true, if the named module is a package.

        We need this method to get correct spec objects with
        Python 3.4 (see PEP451)
        """
        return hasattr(self.__get_module(fullname), "__path__")

    def get_code(self, fullname):
        """Return None

        Required, if is_package is implemented"""
        self.__get_module(fullname)  # eventually raises ImportError
        return None
    get_source = get_code  # same as get_code

_importer = _SixMetaPathImporter(__name__)


class _MovedItems(_LazyModule):

    """Lazy loading of moved objects"""
    __path__ = []  # mark as package


_moved_attributes = [
    MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
    MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
    MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
    MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
    MovedAttribute("intern", "__builtin__", "sys"),
    MovedAttribute("map", "itertools", "builtins", "imap", "map"),
    MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
    MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
    MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
    MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
    MovedAttribute("reduce", "__builtin__", "functools"),
    MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
    MovedAttribute("StringIO", "StringIO", "io"),
    MovedAttribute("UserDict", "UserDict", "collections"),
    MovedAttribute("UserList", "UserList", "collections"),
    MovedAttribute("UserString", "UserString", "collections"),
    MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
    MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
    MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
    MovedModule("builtins", "__builtin__"),
    MovedModule("configparser", "ConfigParser"),
    MovedModule("copyreg", "copy_reg"),
    MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
    MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"),
    MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
    MovedModule("http_cookies", "Cookie", "http.cookies"),
    MovedModule("html_entities", "htmlentitydefs", "html.entities"),
    MovedModule("html_parser", "HTMLParser", "html.parser"),
    MovedModule("http_client", "httplib", "http.client"),
    MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
    MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"),
    MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
    MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
    MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
    MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
    MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
    MovedModule("cPickle", "cPickle", "pickle"),
    MovedModule("queue", "Queue"),
    MovedModule("reprlib", "repr"),
    MovedModule("socketserver", "SocketServer"),
    MovedModule("_thread", "thread", "_thread"),
    MovedModule("tkinter", "Tkinter"),
    MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
    MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
    MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
    MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
    MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
    MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
    MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
    MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
    MovedModule("tkinter_colorchooser", "tkColorChooser",
                "tkinter.colorchooser"),
    MovedModule("tkinter_commondialog", "tkCommonDialog",
                "tkinter.commondialog"),
    MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
    MovedModule("tkinter_font", "tkFont", "tkinter.font"),
    MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
    MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
                "tkinter.simpledialog"),
    MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
    MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
    MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
    MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
    MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
    MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
]
# Add windows specific modules.
if sys.platform == "win32":
    _moved_attributes += [
        MovedModule("winreg", "_winreg"),
    ]

for attr in _moved_attributes:
    setattr(_MovedItems, attr.name, attr)
    if isinstance(attr, MovedModule):
        _importer._add_module(attr, "moves." + attr.name)
del attr

_MovedItems._moved_attributes = _moved_attributes

moves = _MovedItems(__name__ + ".moves")
_importer._add_module(moves, "moves")


class Module_six_moves_urllib_parse(_LazyModule):

    """Lazy loading of moved objects in six.moves.urllib_parse"""


_urllib_parse_moved_attributes = [
    MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
    MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
    MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
    MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
    MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
    MovedAttribute("urljoin", "urlparse", "urllib.parse"),
    MovedAttribute("urlparse", "urlparse", "urllib.parse"),
    MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
    MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
    MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
    MovedAttribute("quote", "urllib", "urllib.parse"),
    MovedAttribute("quote_plus", "urllib", "urllib.parse"),
    MovedAttribute("unquote", "urllib", "urllib.parse"),
    MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
    MovedAttribute("urlencode", "urllib", "urllib.parse"),
    MovedAttribute("splitquery", "urllib", "urllib.parse"),
    MovedAttribute("splittag", "urllib", "urllib.parse"),
    MovedAttribute("splituser", "urllib", "urllib.parse"),
    MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
    MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
    MovedAttribute("uses_params", "urlparse", "urllib.parse"),
    MovedAttribute("uses_query", "urlparse", "urllib.parse"),
    MovedAttribute("uses_relative", "urlparse", "urllib.parse"),
]
for attr in _urllib_parse_moved_attributes:
    setattr(Module_six_moves_urllib_parse, attr.name, attr)
del attr

Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes

_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
                      "moves.urllib_parse", "moves.urllib.parse")


class Module_six_moves_urllib_error(_LazyModule):

    """Lazy loading of moved objects in six.moves.urllib_error"""


_urllib_error_moved_attributes = [
    MovedAttribute("URLError", "urllib2", "urllib.error"),
    MovedAttribute("HTTPError", "urllib2", "urllib.error"),
    MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
]
for attr in _urllib_error_moved_attributes:
    setattr(Module_six_moves_urllib_error, attr.name, attr)
del attr

Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes

_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
                      "moves.urllib_error", "moves.urllib.error")


class Module_six_moves_urllib_request(_LazyModule):

    """Lazy loading of moved objects in six.moves.urllib_request"""


_urllib_request_moved_attributes = [
    MovedAttribute("urlopen", "urllib2", "urllib.request"),
    MovedAttribute("install_opener", "urllib2", "urllib.request"),
    MovedAttribute("build_opener", "urllib2", "urllib.request"),
    MovedAttribute("pathname2url", "urllib", "urllib.request"),
    MovedAttribute("url2pathname", "urllib", "urllib.request"),
    MovedAttribute("getproxies", "urllib", "urllib.request"),
    MovedAttribute("Request", "urllib2", "urllib.request"),
    MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
    MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
    MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
    MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
    MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
    MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
    MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
    MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
    MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
    MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
    MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
    MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
    MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
    MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
    MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
    MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
    MovedAttribute("FileHandler", "urllib2", "urllib.request"),
    MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
    MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
    MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
    MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
    MovedAttribute("urlretrieve", "urllib", "urllib.request"),
    MovedAttribute("urlcleanup", "urllib", "urllib.request"),
    MovedAttribute("URLopener", "urllib", "urllib.request"),
    MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
    MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
]
for attr in _urllib_request_moved_attributes:
    setattr(Module_six_moves_urllib_request, attr.name, attr)
del attr

Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes

_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
                      "moves.urllib_request", "moves.urllib.request")


class Module_six_moves_urllib_response(_LazyModule):

    """Lazy loading of moved objects in six.moves.urllib_response"""


_urllib_response_moved_attributes = [
    MovedAttribute("addbase", "urllib", "urllib.response"),
    MovedAttribute("addclosehook", "urllib", "urllib.response"),
    MovedAttribute("addinfo", "urllib", "urllib.response"),
    MovedAttribute("addinfourl", "urllib", "urllib.response"),
]
for attr in _urllib_response_moved_attributes:
    setattr(Module_six_moves_urllib_response, attr.name, attr)
del attr

Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes

_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
                      "moves.urllib_response", "moves.urllib.response")


class Module_six_moves_urllib_robotparser(_LazyModule):

    """Lazy loading of moved objects in six.moves.urllib_robotparser"""


_urllib_robotparser_moved_attributes = [
    MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
]
for attr in _urllib_robotparser_moved_attributes:
    setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
del attr

Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes

_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
                      "moves.urllib_robotparser", "moves.urllib.robotparser")


class Module_six_moves_urllib(types.ModuleType):

    """Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
    __path__ = []  # mark as package
    parse = _importer._get_module("moves.urllib_parse")
    error = _importer._get_module("moves.urllib_error")
    request = _importer._get_module("moves.urllib_request")
    response = _importer._get_module("moves.urllib_response")
    robotparser = _importer._get_module("moves.urllib_robotparser")

    def __dir__(self):
        return ['parse', 'error', 'request', 'response', 'robotparser']

_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
                      "moves.urllib")


def add_move(move):
    """Add an item to six.moves."""
    setattr(_MovedItems, move.name, move)


def remove_move(name):
    """Remove item from six.moves."""
    try:
        delattr(_MovedItems, name)
    except AttributeError:
        try:
            del moves.__dict__[name]
        except KeyError:
            raise AttributeError("no such move, %r" % (name,))


if PY3:
    _meth_func = "__func__"
    _meth_self = "__self__"

    _func_closure = "__closure__"
    _func_code = "__code__"
    _func_defaults = "__defaults__"
    _func_globals = "__globals__"
else:
    _meth_func = "im_func"
    _meth_self = "im_self"

    _func_closure = "func_closure"
    _func_code = "func_code"
    _func_defaults = "func_defaults"
    _func_globals = "func_globals"


try:
    advance_iterator = next
except NameError:
    def advance_iterator(it):
        return it.next()
next = advance_iterator


try:
    callable = callable
except NameError:
    def callable(obj):
        return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)


if PY3:
    def get_unbound_function(unbound):
        return unbound

    create_bound_method = types.MethodType

    def create_unbound_method(func, cls):
        return func

    Iterator = object
else:
    def get_unbound_function(unbound):
        return unbound.im_func

    def create_bound_method(func, obj):
        return types.MethodType(func, obj, obj.__class__)

    def create_unbound_method(func, cls):
        return types.MethodType(func, None, cls)

    class Iterator(object):

        def next(self):
            return type(self).__next__(self)

    callable = callable
_add_doc(get_unbound_function,
         """Get the function out of a possibly unbound function""")


get_method_function = operator.attrgetter(_meth_func)
get_method_self = operator.attrgetter(_meth_self)
get_function_closure = operator.attrgetter(_func_closure)
get_function_code = operator.attrgetter(_func_code)
get_function_defaults = operator.attrgetter(_func_defaults)
get_function_globals = operator.attrgetter(_func_globals)


if PY3:
    def iterkeys(d, **kw):
        return iter(d.keys(**kw))

    def itervalues(d, **kw):
        return iter(d.values(**kw))

    def iteritems(d, **kw):
        return iter(d.items(**kw))

    def iterlists(d, **kw):
        return iter(d.lists(**kw))

    viewkeys = operator.methodcaller("keys")

    viewvalues = operator.methodcaller("values")

    viewitems = operator.methodcaller("items")
else:
    def iterkeys(d, **kw):
        return d.iterkeys(**kw)

    def itervalues(d, **kw):
        return d.itervalues(**kw)

    def iteritems(d, **kw):
        return d.iteritems(**kw)

    def iterlists(d, **kw):
        return d.iterlists(**kw)

    viewkeys = operator.methodcaller("viewkeys")

    viewvalues = operator.methodcaller("viewvalues")

    viewitems = operator.methodcaller("viewitems")

_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
_add_doc(iteritems,
         "Return an iterator over the (key, value) pairs of a dictionary.")
_add_doc(iterlists,
         "Return an iterator over the (key, [values]) pairs of a dictionary.")


if PY3:
    def b(s):
        return s.encode("latin-1")

    def u(s):
        return s
    unichr = chr
    import struct
    int2byte = struct.Struct(">B").pack
    del struct
    byte2int = operator.itemgetter(0)
    indexbytes = operator.getitem
    iterbytes = iter
    import io
    StringIO = io.StringIO
    BytesIO = io.BytesIO
    _assertCountEqual = "assertCountEqual"
    if sys.version_info[1] <= 1:
        _assertRaisesRegex = "assertRaisesRegexp"
        _assertRegex = "assertRegexpMatches"
    else:
        _assertRaisesRegex = "assertRaisesRegex"
        _assertRegex = "assertRegex"
else:
    def b(s):
        return s
    # Workaround for standalone backslash

    def u(s):
        return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
    unichr = unichr
    int2byte = chr

    def byte2int(bs):
        return ord(bs[0])

    def indexbytes(buf, i):
        return ord(buf[i])
    iterbytes = functools.partial(itertools.imap, ord)
    import StringIO
    StringIO = BytesIO = StringIO.StringIO
    _assertCountEqual = "assertItemsEqual"
    _assertRaisesRegex = "assertRaisesRegexp"
    _assertRegex = "assertRegexpMatches"
_add_doc(b, """Byte literal""")
_add_doc(u, """Text literal""")


def assertCountEqual(self, *args, **kwargs):
    return getattr(self, _assertCountEqual)(*args, **kwargs)


def assertRaisesRegex(self, *args, **kwargs):
    return getattr(self, _assertRaisesRegex)(*args, **kwargs)


def assertRegex(self, *args, **kwargs):
    return getattr(self, _assertRegex)(*args, **kwargs)


if PY3:
    exec_ = getattr(moves.builtins, "exec")

    def reraise(tp, value, tb=None):
        if value is None:
            value = tp()
        if value.__traceback__ is not tb:
            raise value.with_traceback(tb)
        raise value

else:
    def exec_(_code_, _globs_=None, _locs_=None):
        """Execute code in a namespace."""
        if _globs_ is None:
            frame = sys._getframe(1)
            _globs_ = frame.f_globals
            if _locs_ is None:
                _locs_ = frame.f_locals
            del frame
        elif _locs_ is None:
            _locs_ = _globs_
        exec("""exec _code_ in _globs_, _locs_""")

    exec_("""def reraise(tp, value, tb=None):
    raise tp, value, tb
""")


if sys.version_info[:2] == (3, 2):
    exec_("""def raise_from(value, from_value):
    if from_value is None:
        raise value
    raise value from from_value
""")
elif sys.version_info[:2] > (3, 2):
    exec_("""def raise_from(value, from_value):
    raise value from from_value
""")
else:
    def raise_from(value, from_value):
        raise value


print_ = getattr(moves.builtins, "print", None)
if print_ is None:
    def print_(*args, **kwargs):
        """The new-style print function for Python 2.4 and 2.5."""
        fp = kwargs.pop("file", sys.stdout)
        if fp is None:
            return

        def write(data):
            if not isinstance(data, basestring):
                data = str(data)
            # If the file has an encoding, encode unicode with it.
            if (isinstance(fp, file) and
                    isinstance(data, unicode) and
                    fp.encoding is not None):
                errors = getattr(fp, "errors", None)
                if errors is None:
                    errors = "strict"
                data = data.encode(fp.encoding, errors)
            fp.write(data)
        want_unicode = False
        sep = kwargs.pop("sep", None)
        if sep is not None:
            if isinstance(sep, unicode):
                want_unicode = True
            elif not isinstance(sep, str):
                raise TypeError("sep must be None or a string")
        end = kwargs.pop("end", None)
        if end is not None:
            if isinstance(end, unicode):
                want_unicode = True
            elif not isinstance(end, str):
                raise TypeError("end must be None or a string")
        if kwargs:
            raise TypeError("invalid keyword arguments to print()")
        if not want_unicode:
            for arg in args:
                if isinstance(arg, unicode):
                    want_unicode = True
                    break
        if want_unicode:
            newline = unicode("\n")
            space = unicode(" ")
        else:
            newline = "\n"
            space = " "
        if sep is None:
            sep = space
        if end is None:
            end = newline
        for i, arg in enumerate(args):
            if i:
                write(sep)
            write(arg)
        write(end)
if sys.version_info[:2] < (3, 3):
    _print = print_

    def print_(*args, **kwargs):
        fp = kwargs.get("file", sys.stdout)
        flush = kwargs.pop("flush", False)
        _print(*args, **kwargs)
        if flush and fp is not None:
            fp.flush()

_add_doc(reraise, """Reraise an exception.""")

if sys.version_info[0:2] < (3, 4):
    def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
              updated=functools.WRAPPER_UPDATES):
        def wrapper(f):
            f = functools.wraps(wrapped, assigned, updated)(f)
            f.__wrapped__ = wrapped
            return f
        return wrapper
else:
    wraps = functools.wraps


def with_metaclass(meta, *bases):
    """Create a base class with a metaclass."""
    # This requires a bit of explanation: the basic idea is to make a dummy
    # metaclass for one level of class instantiation that replaces itself with
    # the actual metaclass.
    class metaclass(meta):

        def __new__(cls, name, this_bases, d):
            return meta(name, bases, d)
    return type.__new__(metaclass, 'temporary_class', (), {})


def add_metaclass(metaclass):
    """Class decorator for creating a class with a metaclass."""
    def wrapper(cls):
        orig_vars = cls.__dict__.copy()
        slots = orig_vars.get('__slots__')
        if slots is not None:
            if isinstance(slots, str):
                slots = [slots]
            for slots_var in slots:
                orig_vars.pop(slots_var)
        orig_vars.pop('__dict__', None)
        orig_vars.pop('__weakref__', None)
        return metaclass(cls.__name__, cls.__bases__, orig_vars)
    return wrapper


def python_2_unicode_compatible(klass):
    """
    A decorator that defines __unicode__ and __str__ methods under Python 2.
    Under Python 3 it does nothing.

    To support Python 2 and 3 with a single code base, define a __str__ method
    returning text and apply this decorator to the class.
    """
    if PY2:
        if '__str__' not in klass.__dict__:
            raise ValueError("@python_2_unicode_compatible cannot be applied "
                             "to %s because it doesn't define __str__()." %
                             klass.__name__)
        klass.__unicode__ = klass.__str__
        klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
    return klass


# Complete the moves implementation.
# This code is at the end of this module to speed up module loading.
# Turn this module into a package.
__path__ = []  # required for PEP 302 and PEP 451
__package__ = __name__  # see PEP 366 @ReservedAssignment
if globals().get("__spec__") is not None:
    __spec__.submodule_search_locations = []  # PEP 451 @UndefinedVariable
# Remove other six meta path importers, since they cause problems. This can
# happen if six is removed from sys.modules and then reloaded. (Setuptools does
# this for some reason.)
if sys.meta_path:
    for i, importer in enumerate(sys.meta_path):
        # Here's some real nastiness: Another "instance" of the six module might
        # be floating around. Therefore, we can't use isinstance() to check for
        # the six meta path importer, since the other six instance will have
        # inserted an importer with different class.
        if (type(importer).__name__ == "_SixMetaPathImporter" and
                importer.name == __name__):
            del sys.meta_path[i]
            break
    del i, importer
# Finally, add the importer to the meta path import hook.
sys.meta_path.append(_importer)
Download .txt
gitextract_pp1v33z2/

├── .gitignore
├── README.md
├── __main__.py
├── client.py
├── ntlm_auth/
│   ├── U32.py
│   ├── __init__.py
│   ├── compute_hash.py
│   ├── compute_keys.py
│   ├── compute_response.py
│   ├── constants.py
│   ├── des.py
│   ├── des_c.py
│   ├── des_data.py
│   ├── gss_channel_bindings.py
│   ├── messages.py
│   ├── ntlm.py
│   ├── rc4.py
│   ├── session_security.py
│   └── target_info.py
├── ordereddict.py
├── relay.py
├── server.py
└── six.py
Download .txt
SYMBOL INDEX (260 symbols across 18 files)

FILE: client.py
  function key_by_value (line 21) | def key_by_value(my_dict, value):
  class SocksRelay (line 28) | class SocksRelay:
    method __init__ (line 33) | def __init__(self, bc_sock):
    method ping_worker (line 51) | def ping_worker(self):
    method shutdown (line 64) | def shutdown(self):
    method run (line 69) | def run(self):
    method handle_remote_cmd (line 133) | def handle_remote_cmd(self, data):
    method get_channel_data (line 166) | def get_channel_data(self, sock):
    method manage_remote_socket (line 178) | def manage_remote_socket(self, sock):
    method close_remote_connection (line 197) | def close_remote_connection(self, sock):
    method manage_forward_socket (line 201) | def manage_forward_socket(self, sock):
    method close_forward_connection (line 227) | def close_forward_connection(self, sock):
    method send_remote_cmd (line 237) | def send_remote_cmd(self, sock, cmd, *args):
    method set_channel (line 256) | def set_channel(self, sock, channel_id):
    method unset_channel (line 260) | def unset_channel(self, channel_id):
    method establish_forward_socket (line 265) | def establish_forward_socket(self, channel_id, host, port):
    method relay (line 277) | def relay(self, data, to_socket):
  class NtlmProxyContext (line 296) | class NtlmProxyContext(object):
    method __init__ (line 313) | def __init__(self, sock, proxy_ip, proxy_port, username, domain=None, ...
    method connect (line 324) | def connect(self, host_port):
    method __getattr__ (line 386) | def __getattr__(self, attribute_name):
    method get_challenge (line 391) | def get_challenge(raw_msg):
  function main (line 401) | def main():

FILE: ntlm_auth/U32.py
  function norm (line 23) | def norm(n):
  class U32 (line 27) | class U32:
    method __init__ (line 30) | def __init__(self, value=0):
    method set (line 36) | def set(self, value=0):
    method __repr__ (line 39) | def __repr__(self):
    method __long__ (line 42) | def __long__(self):
    method __int__ (line 45) | def __int__(self):
    method __chr__ (line 48) | def __chr__(self):
    method __add__ (line 51) | def __add__(self, b):
    method __sub__ (line 56) | def __sub__(self, b):
    method __mul__ (line 64) | def __mul__(self, b):
    method __div__ (line 69) | def __div__(self, b):
    method __truediv__ (line 74) | def __truediv__(self, b):
    method __mod__ (line 79) | def __mod__(self, b):
    method __neg__ (line 84) | def __neg__(self):
    method __pos__ (line 87) | def __pos__(self):
    method __abs__ (line 90) | def __abs__(self):
    method __invert__ (line 93) | def __invert__(self):
    method __lshift__ (line 98) | def __lshift__(self, b):
    method __rshift__ (line 103) | def __rshift__(self, b):
    method __and__ (line 108) | def __and__(self, b):
    method __or__ (line 113) | def __or__(self, b):
    method __xor__ (line 118) | def __xor__(self, b):
    method __not__ (line 123) | def __not__(self):
    method truth (line 126) | def truth(self):
    method __cmp__ (line 129) | def __cmp__(self, b):
    method __lt__ (line 137) | def __lt__(self, other):
    method __gt__ (line 140) | def __gt__(self, other):
    method __eq__ (line 143) | def __eq__(self, other):
    method __le__ (line 146) | def __le__(self, other):
    method __ge__ (line 149) | def __ge__(self, other):
    method __ne__ (line 152) | def __ne__(self, other):
    method __nonzero__ (line 155) | def __nonzero__(self):

FILE: ntlm_auth/compute_hash.py
  function _lmowfv1 (line 21) | def _lmowfv1(password, lmhash):
  function _ntowfv1 (line 51) | def _ntowfv1(password, nthash):
  function _ntowfv2 (line 68) | def _ntowfv2(user_name, password, nthash, domain_name):

FILE: ntlm_auth/compute_keys.py
  function _get_exchange_key_ntlm_v1 (line 20) | def _get_exchange_key_ntlm_v1(negotiate_flags, session_base_key, server_...
  function _get_exchange_key_ntlm_v2 (line 50) | def _get_exchange_key_ntlm_v2(session_base_key):
  function get_sign_key (line 63) | def get_sign_key(exported_session_key, magic_constant):
  function get_seal_key (line 76) | def get_seal_key(negotiate_flags, exported_session_key, magic_constant):
  function _get_seal_key_ntlm1 (line 98) | def _get_seal_key_ntlm1(negotiate_flags, exported_session_key):
  function _get_seal_key_ntlm2 (line 116) | def _get_seal_key_ntlm2(negotiate_flags, exported_session_key, magic_con...

FILE: ntlm_auth/compute_response.py
  class ComputeResponse (line 28) | class ComputeResponse():
    method __init__ (line 39) | def __init__(self, user_name, password, nthash, lmhash, domain_name, c...
    method get_lm_challenge_response (line 52) | def get_lm_challenge_response(self):
    method get_nt_challenge_response (line 93) | def get_nt_challenge_response(self, lm_challenge_response, server_cert...
    method _get_LMv1_response (line 155) | def _get_LMv1_response(password, lmhash, server_challenge):
    method _get_LMv1_with_session_security_response (line 174) | def _get_LMv1_with_session_security_response(client_challenge):
    method _get_LMv2_response (line 192) | def _get_LMv2_response(user_name, password, nthash, domain_name, serve...
    method _get_NTLMv1_response (line 215) | def _get_NTLMv1_response(password, nthash, server_challenge):
    method _get_NTLM2_response (line 237) | def _get_NTLM2_response(password, nthash, server_challenge, client_cha...
    method _get_NTLMv2_response (line 262) | def _get_NTLMv2_response(user_name, password, nthash, domain_name, ser...
    method _get_NTLMv2_temp (line 294) | def _get_NTLMv2_temp(timestamp, client_challenge, target_info):
    method _calc_resp (line 335) | def _calc_resp(password_hash, server_challenge):
    method _get_channel_bindings_value (line 360) | def _get_channel_bindings_value(server_certificate_hash):
  function get_windows_timestamp (line 395) | def get_windows_timestamp():

FILE: ntlm_auth/constants.py
  class MessageTypes (line 28) | class MessageTypes(object):
  class AvFlags (line 39) | class AvFlags(object):
  class NegotiateFlags (line 53) | class NegotiateFlags(object):
  class SignSealConstants (line 87) | class SignSealConstants(object):

FILE: ntlm_auth/des.py
  class DES (line 23) | class DES:
    method __init__ (line 26) | def __init__(self, key_str):
    method encrypt (line 36) | def encrypt(self, plain_text):
    method decrypt (line 39) | def decrypt(self, crypted_text):
  function str_to_key56 (line 46) | def str_to_key56(key_str):
  function key56_to_key64 (line 61) | def key56_to_key64(key_56):
  function set_key_odd_parity (line 80) | def set_key_odd_parity(key):

FILE: ntlm_auth/des_c.py
  function c2l (line 21) | def c2l(c):
  function l2c (line 30) | def l2c(l):
  function D_ENCRYPT (line 40) | def D_ENCRYPT(tup, u, t, s):
  function PERM_OP (line 58) | def PERM_OP(tup, n, m):
  function HPERM_OP (line 67) | def HPERM_OP(tup, n, m):
  class DES (line 78) | class DES:
    method __init__ (line 81) | def __init__(self, key_str):
    method decrypt (line 84) | def decrypt(self, str):
    method encrypt (line 100) | def encrypt(self, plaintext):
  function des_encript (line 117) | def des_encript(input, ks, encrypt):
  function des_ecb_encrypt (line 175) | def des_ecb_encrypt(input, ks, encrypt):
  function des_set_key (line 198) | def des_set_key(key):

FILE: ntlm_auth/gss_channel_bindings.py
  class GssChannelBindingsStruct (line 27) | class GssChannelBindingsStruct(object):
    method __init__ (line 37) | def __init__(self):
    method __setitem__ (line 48) | def __setitem__(self, key, value):
    method get_data (line 51) | def get_data(self):

FILE: ntlm_auth/messages.py
  class NegotiateMessage (line 22) | class NegotiateMessage(object):
    method __init__ (line 45) | def __init__(self, negotiate_flags, domain_name, workstation):
    method get_data (line 73) | def get_data(self):
  class ChallengeMessage (line 110) | class ChallengeMessage(object):
    method __init__ (line 133) | def __init__(self, msg2):
    method get_data (line 170) | def get_data(self):
  class AuthenticateMessage (line 173) | class AuthenticateMessage(object):
    method __init__ (line 212) | def __init__(self, user_name, password, nthash, lmhash, domain_name, w...
    method get_data (line 258) | def get_data(self):
    method add_mic (line 329) | def add_mic(self, negotiate_message, challenge_message):
  function get_version (line 343) | def get_version(negotiate_flags):
  function get_random_export_session_key (line 358) | def get_random_export_session_key():

FILE: ntlm_auth/ntlm.py
  class Ntlm (line 42) | class Ntlm(object):
    method __init__ (line 66) | def __init__(self, ntlm_compatibility=3):
    method create_negotiate_message (line 89) | def create_negotiate_message(self, domain_name=None, workstation=None):
    method parse_challenge_message (line 101) | def parse_challenge_message(self, msg2):
    method create_authenticate_message (line 110) | def create_authenticate_message(self, user_name, password=None, nthash...
    method _set_ntlm_compatibility_flags (line 135) | def _set_ntlm_compatibility_flags(self, ntlm_compatibility):

FILE: ntlm_auth/rc4.py
  class ARC4 (line 14) | class ARC4(object):
    method __init__ (line 19) | def __init__(self, key):
    method update (line 33) | def update(self, value):
    method _random_generator (line 45) | def _random_generator(self):

FILE: ntlm_auth/session_security.py
  class _NtlmMessageSignature1 (line 22) | class _NtlmMessageSignature1(object):
    method __init__ (line 36) | def __init__(self, random_pad, checksum, seq_num):
    method get_data (line 42) | def get_data(self):
  class _NtlmMessageSignature2 (line 53) | class _NtlmMessageSignature2(object):
    method __init__ (line 67) | def __init__(self, checksum, seq_num):
    method get_data (line 72) | def get_data(self):
  class SessionSecurity (line 82) | class SessionSecurity(object):
    method __init__ (line 92) | def __init__(self, negotiate_flags, exported_session_key, source="clie...
    method wrap (line 113) | def wrap(self, message):
    method unwrap (line 137) | def unwrap(self, message, signature):
    method _seal_message (line 159) | def _seal_message(self, message):
    method _unseal_message (line 172) | def _unseal_message(self, message):
    method _get_signature (line 185) | def _get_signature(self, message):
    method _verify_signature (line 201) | def _verify_signature(self, message, signature):
  function calc_signature (line 229) | def calc_signature(message, negotiate_flags, signing_key, seq_num, handle):

FILE: ntlm_auth/target_info.py
  class TargetInfo (line 16) | class TargetInfo(object):
    method __init__ (line 29) | def __init__(self, data=None):
    method __setitem__ (line 34) | def __setitem__(self, key, value):
    method __getitem__ (line 37) | def __getitem__(self, key):
    method __delitem__ (line 42) | def __delitem__(self, key):
    method from_string (line 45) | def from_string(self, data):
    method get_data (line 57) | def get_data(self):

FILE: ordereddict.py
  class OrderedDict (line 25) | class OrderedDict(dict, DictMixin):
    method __init__ (line 27) | def __init__(self, *args, **kwds):
    method clear (line 36) | def clear(self):
    method __setitem__ (line 42) | def __setitem__(self, key, value):
    method __delitem__ (line 49) | def __delitem__(self, key):
    method __iter__ (line 55) | def __iter__(self):
    method __reversed__ (line 62) | def __reversed__(self):
    method popitem (line 69) | def popitem(self, last=True):
    method __reduce__ (line 79) | def __reduce__(self):
    method keys (line 89) | def keys(self):
    method __repr__ (line 101) | def __repr__(self):
    method copy (line 106) | def copy(self):
    method fromkeys (line 110) | def fromkeys(cls, iterable, value=None):
    method __eq__ (line 116) | def __eq__(self, other):
    method __ne__ (line 126) | def __ne__(self, other):

FILE: relay.py
  class ClosedSocket (line 32) | class ClosedSocket(Exception):
  class RelayError (line 36) | class RelayError(Exception):
  function recvall (line 40) | def recvall(sock, data_len):
  function close_sockets (line 51) | def close_sockets(sockets):

FILE: server.py
  class RelayServer (line 17) | class RelayServer:
    method __init__ (line 18) | def __init__(self, host, port, socket_with_server):
    method ping_worker (line 46) | def ping_worker(self):
    method shutdown (line 69) | def shutdown(self):
    method main_loop (line 74) | def main_loop(self):
    method parse_socks_header (line 123) | def parse_socks_header(self, data):
    method get_channel_data (line 136) | def get_channel_data(self, sock):
    method manage_remote_socket (line 147) | def manage_remote_socket(self, sock):
    method manage_socks_client_socket (line 160) | def manage_socks_client_socket(self, sock):
    method handle_remote_cmd (line 180) | def handle_remote_cmd(self, data):
    method send_remote_cmd (line 244) | def send_remote_cmd(self, sock, cmd, *args):
    method on_accept (line 262) | def on_accept(self):
    method handle_new_socks_connection (line 271) | def handle_new_socks_connection(self, sock):
    method set_channel (line 291) | def set_channel(self, sock):
    method unset_channel (line 297) | def unset_channel(self, channel_id):
    method generate_new_channel_id (line 302) | def generate_new_channel_id(self):
    method close_socks_connection (line 309) | def close_socks_connection(self, sock):
    method relay (line 318) | def relay(self, data, to_socket):
  function run_server (line 337) | def run_server(host, port):
  function main (line 386) | def main():

FILE: six.py
  class X (line 60) | class X(object):
    method __len__ (line 62) | def __len__(self):
  function _add_doc (line 75) | def _add_doc(func, doc):
  function _import_module (line 80) | def _import_module(name):
  class _LazyDescr (line 86) | class _LazyDescr(object):
    method __init__ (line 88) | def __init__(self, name):
    method __get__ (line 91) | def __get__(self, obj, tp):
  class MovedModule (line 103) | class MovedModule(_LazyDescr):
    method __init__ (line 105) | def __init__(self, name, old, new=None):
    method _resolve (line 114) | def _resolve(self):
    method __getattr__ (line 117) | def __getattr__(self, attr):
  class _LazyModule (line 124) | class _LazyModule(types.ModuleType):
    method __init__ (line 126) | def __init__(self, name):
    method __dir__ (line 130) | def __dir__(self):
  class MovedAttribute (line 139) | class MovedAttribute(_LazyDescr):
    method __init__ (line 141) | def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
    method _resolve (line 159) | def _resolve(self):
  class _SixMetaPathImporter (line 164) | class _SixMetaPathImporter(object):
    method __init__ (line 173) | def __init__(self, six_module_name):
    method _add_module (line 177) | def _add_module(self, mod, *fullnames):
    method _get_module (line 181) | def _get_module(self, fullname):
    method find_module (line 184) | def find_module(self, fullname, path=None):
    method __get_module (line 189) | def __get_module(self, fullname):
    method load_module (line 195) | def load_module(self, fullname):
    method is_package (line 209) | def is_package(self, fullname):
    method get_code (line 218) | def get_code(self, fullname):
  class _MovedItems (line 229) | class _MovedItems(_LazyModule):
  class Module_six_moves_urllib_parse (line 320) | class Module_six_moves_urllib_parse(_LazyModule):
  class Module_six_moves_urllib_error (line 360) | class Module_six_moves_urllib_error(_LazyModule):
  class Module_six_moves_urllib_request (line 380) | class Module_six_moves_urllib_request(_LazyModule):
  class Module_six_moves_urllib_response (line 430) | class Module_six_moves_urllib_response(_LazyModule):
  class Module_six_moves_urllib_robotparser (line 451) | class Module_six_moves_urllib_robotparser(_LazyModule):
  class Module_six_moves_urllib (line 469) | class Module_six_moves_urllib(types.ModuleType):
    method __dir__ (line 479) | def __dir__(self):
  function add_move (line 486) | def add_move(move):
  function remove_move (line 491) | def remove_move(name):
  function advance_iterator (line 523) | def advance_iterator(it):
  function callable (line 531) | def callable(obj):
  function get_unbound_function (line 536) | def get_unbound_function(unbound):
  function create_unbound_method (line 541) | def create_unbound_method(func, cls):
  function get_unbound_function (line 546) | def get_unbound_function(unbound):
  function create_bound_method (line 549) | def create_bound_method(func, obj):
  function create_unbound_method (line 552) | def create_unbound_method(func, cls):
  class Iterator (line 555) | class Iterator(object):
    method next (line 557) | def next(self):
  function iterkeys (line 574) | def iterkeys(d, **kw):
  function itervalues (line 577) | def itervalues(d, **kw):
  function iteritems (line 580) | def iteritems(d, **kw):
  function iterlists (line 583) | def iterlists(d, **kw):
  function iterkeys (line 592) | def iterkeys(d, **kw):
  function itervalues (line 595) | def itervalues(d, **kw):
  function iteritems (line 598) | def iteritems(d, **kw):
  function iterlists (line 601) | def iterlists(d, **kw):
  function b (line 619) | def b(s):
  function u (line 622) | def u(s):
  function b (line 642) | def b(s):
  function u (line 646) | def u(s):
  function byte2int (line 651) | def byte2int(bs):
  function indexbytes (line 654) | def indexbytes(buf, i):
  function assertCountEqual (line 666) | def assertCountEqual(self, *args, **kwargs):
  function assertRaisesRegex (line 670) | def assertRaisesRegex(self, *args, **kwargs):
  function assertRegex (line 674) | def assertRegex(self, *args, **kwargs):
  function reraise (line 681) | def reraise(tp, value, tb=None):
  function exec_ (line 689) | def exec_(_code_, _globs_=None, _locs_=None):
  function raise_from (line 717) | def raise_from(value, from_value):
  function print_ (line 723) | def print_(*args, **kwargs):
  function print_ (line 779) | def print_(*args, **kwargs):
  function wraps (line 789) | def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
  function with_metaclass (line 800) | def with_metaclass(meta, *bases):
  function add_metaclass (line 812) | def add_metaclass(metaclass):
  function python_2_unicode_compatible (line 828) | def python_2_unicode_compatible(klass):
Condensed preview — 23 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (202K chars).
[
  {
    "path": ".gitignore",
    "chars": 11,
    "preview": "venv\nbuild\n"
  },
  {
    "path": "README.md",
    "chars": 1946,
    "preview": "RPIVOT - reverse socks 4 proxy for penetration tests\n===================\n\n\nRPIVOT allows to tunnel traffic into internal"
  },
  {
    "path": "__main__.py",
    "chars": 396,
    "preview": "#!/usr/bin/env python\n\nimport sys\n\ntry:\n    rpivot_type = sys.argv.pop(1).lower()\n    if rpivot_type not in ('client', '"
  },
  {
    "path": "client.py",
    "chars": 22003,
    "preview": "#!/usr/bin/env python\n\nimport logging\nimport logging.handlers\nimport socket\nimport sys\nimport time\nfrom struct import pa"
  },
  {
    "path": "ntlm_auth/U32.py",
    "chars": 3644,
    "preview": "# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/\n# Copyright 2001 Dmitr"
  },
  {
    "path": "ntlm_auth/__init__.py",
    "chars": 76,
    "preview": "from . import ntlm, session_security\n\n__all__ = ('ntlm', 'session_security')"
  },
  {
    "path": "ntlm_auth/compute_hash.py",
    "chars": 2913,
    "preview": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Pu"
  },
  {
    "path": "ntlm_auth/compute_keys.py",
    "chars": 6318,
    "preview": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Pu"
  },
  {
    "path": "ntlm_auth/compute_response.py",
    "chars": 20859,
    "preview": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Pu"
  },
  {
    "path": "ntlm_auth/constants.py",
    "chars": 4277,
    "preview": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Pu"
  },
  {
    "path": "ntlm_auth/des.py",
    "chars": 2586,
    "preview": "# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/\n# Copyright 2001 Dmitr"
  },
  {
    "path": "ntlm_auth/des_c.py",
    "chars": 7181,
    "preview": "# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/\n# Copyright 2001 Dmitr"
  },
  {
    "path": "ntlm_auth/des_data.py",
    "chars": 22508,
    "preview": "# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/\n# Copyright 2001 Dmitr"
  },
  {
    "path": "ntlm_auth/gss_channel_bindings.py",
    "chars": 3364,
    "preview": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Pu"
  },
  {
    "path": "ntlm_auth/messages.py",
    "chars": 19130,
    "preview": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Pu"
  },
  {
    "path": "ntlm_auth/ntlm.py",
    "chars": 8277,
    "preview": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Pu"
  },
  {
    "path": "ntlm_auth/rc4.py",
    "chars": 1948,
    "preview": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Pu"
  },
  {
    "path": "ntlm_auth/session_security.py",
    "chars": 10769,
    "preview": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Pu"
  },
  {
    "path": "ntlm_auth/target_info.py",
    "chars": 2292,
    "preview": "\"\"\"\n    Original Author: Ian Clegg\n    Project: ntlmlib\n    URL: https://github.com/ianclegg/ntlmlib\n    License: Apache"
  },
  {
    "path": "ordereddict.py",
    "chars": 4221,
    "preview": "# Copyright (c) 2009 Raymond Hettinger\r\n#\r\n# Permission is hereby granted, free of charge, to any person\r\n# obtaining a "
  },
  {
    "path": "relay.py",
    "chars": 1102,
    "preview": "import time\nimport socket\n\n\nbuffer_size = 4096\ndelay = 0.0001\nsocks_server_reply_success = '\\x00\\x5a\\xff\\xff\\xff\\xff\\xff"
  },
  {
    "path": "server.py",
    "chars": 18214,
    "preview": "#!/usr/bin/env python\n\nimport logging\nimport logging.handlers\nimport socket\nimport select\nimport sys\nimport time\nfrom st"
  },
  {
    "path": "six.py",
    "chars": 30098,
    "preview": "\"\"\"Utilities for writing code that runs on Python 2 and 3\"\"\"\n\n# Copyright (c) 2010-2015 Benjamin Peterson\n#\n# Permission"
  }
]

About this extraction

This page contains the full source code of the artkond/rpivot GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 23 files (189.6 KB), approximately 51.8k tokens, and a symbol index with 260 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!