[
  {
    "path": ".gitignore",
    "content": "venv\nbuild\n"
  },
  {
    "path": "README.md",
    "content": "RPIVOT - reverse socks 4 proxy for penetration tests\n===================\n\n\nRPIVOT allows to tunnel traffic into internal network via socks 4. It works like ssh dynamic port forwarding but in the opposite direction. \n\n\n----------\n\n\nDescription\n-------------\n\nThis 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.\n\nWorks on Kali Linux, Solaris 10, Windows, Mac OS.\n\n\nUsage example\n-------------\n\nStart server listener on port 9999, which creates a socks 4 proxy on 127.0.0.1:1080 upon connection from client:\n\n`python server.py --server-port 9999 --server-ip 0.0.0.0 --proxy-ip 127.0.0.1 --proxy-port 1080`\n\nConnect to the server:\n\n`python client.py --server-ip <rpivot_server_ip> --server-port 9999`\n\nTo pivot through an NTLM proxy:\n\n`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`\n\nPass-the-hash is supported:\n\n`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`\n\nYou can use `proxychains` to tunnel traffic through socks proxy.\n\nEdit /etc/proxychains.conf:\n\n```\n[ProxyList]\n# add proxy here ...\n# meanwile\n# defaults set to \"tor\"\nsocks4 127.0.0.1 1080\n```\n\nUsing single zip file mode:\n\n```\nzip rpivot.zip -r *.py ./ntlm_auth/\npython rpivot.zip server <server_options>\npython rpivot.zip client <client_options> \n```\n\nPivot and have fun:\n\n`proxychains <tool_name>`\n\nPre-built Windows client binary available in release section.\n\nAuthor\n------\n\nArtem Kondratenko https://twitter.com/artkond\n"
  },
  {
    "path": "__main__.py",
    "content": "#!/usr/bin/env python\n\nimport sys\n\ntry:\n    rpivot_type = sys.argv.pop(1).lower()\n    if rpivot_type not in ('client', 'server'):\n        raise IndexError('Bad rpivot type')\nexcept IndexError:\n    print('{} <server|client> ...'.format(sys.argv[0]))\n    sys.exit(1)\n\nif rpivot_type == 'client':\n    import client\n    client.main()\nelif rpivot_type == 'server':\n    import server\n    server.main()\n"
  },
  {
    "path": "client.py",
    "content": "#!/usr/bin/env python\n\nimport logging\nimport logging.handlers\nimport socket\nimport sys\nimport time\nfrom struct import pack, unpack\nimport select\nimport optparse\nimport errno\nimport relay\nimport threading\n\nfrom ntlm_auth.ntlm import Ntlm\nimport re\n\nlogger = None\n\n\ndef key_by_value(my_dict, value):\n    for k, v in my_dict.iteritems():\n        if v == value:\n            return k\n    return None\n\n\nclass SocksRelay:\n    STATUS_SUCCESS = 0\n    STATUS_REFUSED = 1\n    STATUS_TIMEOUT = 2\n\n    def __init__(self, bc_sock):\n        self.channel = {}\n        self.id_by_socket = {}\n        self.bc_sock = bc_sock\n        self.input_list = [self.bc_sock]\n        self.establishing_dict = {}\n        self.forward_socket = None\n        self.data = None\n        self.last_ping_time = time.time()\n\n        logger.debug('Starting ping thread')\n\n\n        self.ping_thread = threading.Thread(target=self.ping_worker)\n\n        self.ping_thread.start()\n        self.remote_side_down = False\n\n    def ping_worker(self):\n        while True:\n            time.sleep(10)\n            current_time = time.time()\n            logger.debug('In ping worker')\n            if self.remote_side_down:\n                logger.debug('Remote side down. Exiting ping worker')\n                return\n            if current_time - self.last_ping_time > relay.relay_timeout:\n                logger.info('No response from remote side for {0} seconds. Restarting relay'.format(relay.relay_timeout))\n                self.bc_sock.close()\n                return\n\n    def shutdown(self):\n        self.remote_side_down = True\n        relay.close_sockets(self.input_list)\n        sys.exit(1)\n\n    def run(self):\n        inputready = None\n        outputready = None\n        exceptready = None\n        while True:\n\n            try:\n                time.sleep(relay.delay)\n                logger.debug(\"Active channels: {0}. Pending Channels {1}\".format(self.channel.keys(), self.establishing_dict.values()))\n                inputready, outputready, exceptready = select.select(self.input_list, self.establishing_dict.keys(), [], 15)\n            except KeyboardInterrupt:\n                logger.info('SIGINT received. Closing relay and exiting')\n                self.send_remote_cmd(self.bc_sock, relay.CLOSE_RELAY)\n                self.shutdown()\n            except select.error as (code, msg):\n                logger.debug('Select error on select. Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))\n                self.shutdown()\n            except socket.error as (code, msg):\n                logger.debug('Socket error on select. Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))\n                self.shutdown()\n\n            for sock in outputready:\n                channel_id = self.establishing_dict[sock]\n                logger.debug('Establishing connection with channel id {0}'.format(channel_id))\n                try:\n                    sock.recv(0)\n                except socket.error as (code, err_msg):\n                    if code == errno.ECONNREFUSED or code == errno.ETIMEDOUT:\n                        logger.debug('Connection {0}'.format(errno.errorcode[code]))\n\n                        if sock in inputready:\n                            inputready.remove(sock)\n\n                        del self.establishing_dict[sock]\n\n                        self.send_remote_cmd(self.bc_sock, relay.FORWARD_CONNECTION_FAILURE, channel_id)\n                        sock.close()\n                        continue\n                    elif code == errno.EAGAIN:\n                        logger.debug('Recv(0) return errno.EAGAIN for socket {0} on channel {1}. Connection established.'.format(sock, channel_id))\n                    elif code == 10035:\n                        logger.debug('Recv(0) raised windows-specific exception 10035. Connection established.')\n                    else:\n                        raise\n\n                logger.debug('Connection established on channel {0}'.format(channel_id))\n                sock.setblocking(1)\n\n                self.send_remote_cmd(self.bc_sock, relay.FORWARD_CONNECTION_SUCCESS, self.establishing_dict[sock])\n                del self.establishing_dict[sock]\n                self.input_list.append(sock)\n                self.set_channel(sock, channel_id)\n\n            for self.selected_input_socket in inputready:\n                if self.selected_input_socket == self.bc_sock:\n                    try:\n                        self.manage_remote_socket(self.bc_sock)\n                    except relay.RelayError:\n                        logger.debug('Remote side closed socket')\n                        relay.close_sockets(self.input_list)\n                        return\n                else:\n                    self.manage_forward_socket(self.selected_input_socket)\n\n    def handle_remote_cmd(self, data):\n        cmd = data[0]\n        logger.debug('Received cmd data from remote side. Cmd: {0}'.format(relay.cmd_names[cmd]))\n        if cmd == relay.CHANNEL_CLOSE_CMD:\n            channel_id = unpack('<H', data[1:3])[0]\n            logger.debug('Channel close request with id: {0}'.format(channel_id))\n            establishing_sock = key_by_value(self.establishing_dict, channel_id)\n            if establishing_sock is not None:\n                logger.debug('Closing establishing socket with id: {0}'.format(channel_id))\n                del self.establishing_dict[establishing_sock]\n            elif channel_id not in self.channel:\n                logger.debug('Channel {0} non existent'.format(channel_id))\n                return\n            else:\n                sock_to_close = self.channel[channel_id]\n                self.unset_channel(channel_id)\n                logger.debug('Closing socket with id: {0}'.format(channel_id))\n                sock_to_close.close()\n                self.input_list.remove(sock_to_close)\n        elif cmd == relay.CHANNEL_OPEN_CMD:\n            channel_id, packed_ip, port = unpack('<HIH', data[1:9])\n            ip = socket.inet_ntoa(data[3:7])\n            logger.debug('Got new channel request with id {0} . Opening new forward connection to host {1} port {2}'.format(channel_id, ip, port))\n            self.establish_forward_socket(channel_id, ip, port)\n        elif cmd == relay.CLOSE_RELAY:\n            logger.info('Got command to close relay. Closing socket and exiting.')\n            self.shutdown()\n        elif cmd == relay.PING_CMD:\n            self.last_ping_time = time.time()\n            self.send_remote_cmd(self.bc_sock, relay.PING_CMD)\n        else:\n            logger.debug('Received unknown cmd: {0}'.format(cmd))\n\n    def get_channel_data(self, sock):\n        try:\n            tlv_header = relay.recvall(sock, 4)\n            channel_id, tlv_data_len = unpack('<HH', tlv_header)\n            data = relay.recvall(sock, tlv_data_len)\n        except socket.error as (code, msg):\n            logger.debug('Exception on receiving tlv message from remote side. Exiting')\n            logger.debug('Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))\n            raise relay.RelayError\n\n        return channel_id, data\n\n    def manage_remote_socket(self, sock):\n        try:\n            (channel_id, data) = self.get_channel_data(sock)\n        except relay.RelayError:\n            logger.debug('Exiting!')\n            self.close_remote_connection(sock)\n            raise relay.RelayError\n\n        if channel_id == relay.COMMAND_CHANNEL:\n            self.handle_remote_cmd(data)\n        elif channel_id in self.channel:\n            relay_to_sock = self.channel[channel_id]\n            logger.debug('Got data to relay from remote side. Channel id {0}. Data length: {1}'.format(channel_id, len(data)))\n            logger.debug('Data contents: {0}'.format(data.encode('hex')))\n            self.relay(data, relay_to_sock)\n        else:\n                logger.debug('Relay from socket {0} with channel {1} not possible. Channel does not exist'.format(sock, channel_id))\n                return\n\n    def close_remote_connection(self, sock):\n        sock.close()\n        self.input_list.remove(sock)\n\n    def manage_forward_socket(self, sock):\n        if sock not in self.id_by_socket:\n            logger.debug('Channel corresponding to remote socket {0} already closed. Closing forward socket'.format(sock))\n            return\n        channel_id = self.id_by_socket[sock]\n        #logger.debug('Readable socket {0} with channel id {1}'.format(sock, channel_id))\n        try:\n            data = sock.recv(relay.buffer_size)\n        except socket.error as (code, msg):\n            logger.debug('Exception on receiving data from socket {0} with channel id {1}'.format(sock, channel_id))\n            logger.debug('Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))\n            logger.debug('Closing socket {0} with channel id {1}'.format(sock, channel_id))\n            self.close_forward_connection(sock)\n            return\n        data_len = len(data)\n        if data_len == 0:\n            self.close_forward_connection(sock)\n            return\n        else:\n            channel_id = self.id_by_socket[sock]\n            tlv_header = pack('<HH', channel_id, len(data))\n            logger.debug('Got data to relay from app side. Channel id {0}. Data length: {1}'.format(channel_id, len(data)))\n            logger.debug('Preparing tlv header: {0}'.format(tlv_header.encode('hex')))\n            logger.debug('Data contents: {0}'.format(data.encode('hex')))\n            self.relay(tlv_header + data, self.bc_sock)\n\n    def close_forward_connection(self, sock):\n        channel_id = self.id_by_socket[sock]\n        logger.debug('Closing forward socket {0} with id {1}'.format(sock, channel_id))\n        logger.debug('Current remote side socket: {0}'.format(self.bc_sock))\n        logger.debug('Notifying remote side')\n        self.unset_channel(channel_id)\n        self.input_list.remove(sock)\n        sock.close()\n        self.send_remote_cmd(self.bc_sock, relay.CHANNEL_CLOSE_CMD, channel_id)\n\n    def send_remote_cmd(self, sock, cmd, *args):\n        logger.debug('Sending cmd to remote side. Cmd: {0}'.format(relay.cmd_names[cmd]))\n        if cmd == relay.CHANNEL_CLOSE_CMD:\n            cmd_buffer = cmd + pack('<H', args[0])\n            tlv_header = pack('<HH', relay.COMMAND_CHANNEL, len(cmd_buffer))\n        elif cmd == relay.FORWARD_CONNECTION_SUCCESS:\n            cmd_buffer = cmd + pack('<H', args[0])\n            tlv_header = pack('<HH', relay.COMMAND_CHANNEL, len(cmd_buffer))\n        elif cmd == relay.FORWARD_CONNECTION_FAILURE:\n            cmd_buffer = cmd + pack('<H', args[0])\n            tlv_header = pack('<HH', relay.COMMAND_CHANNEL, len(cmd_buffer))\n        else:\n            cmd_buffer = cmd\n            tlv_header = pack('<HH', relay.COMMAND_CHANNEL, len(cmd_buffer))\n        try:\n            sock.send(tlv_header + cmd_buffer)\n        except socket.error as (code, cmd):\n            logger.error('Socket error on sending command to remote side. Code {0}. Msg {1}'.format(code, cmd))\n\n    def set_channel(self, sock, channel_id):\n        self.channel[channel_id] = sock\n        self.id_by_socket[sock] = channel_id\n\n    def unset_channel(self, channel_id):\n        sock = self.channel[channel_id]\n        del self.id_by_socket[sock]\n        del self.channel[channel_id]\n\n    def establish_forward_socket(self, channel_id, host, port):\n        try:\n            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n            sock.setblocking(0)\n            sock.connect_ex((host, port))\n        except socket.error as (code, msg):\n            logger.debug(\"Caught exception socket.error during establishing forward connection. Code {0}. Msg {1}\".format(code, msg))\n            self.send_remote_cmd(self.bc_sock, relay.FORWARD_CONNECTION_FAILURE, channel_id)\n            return\n        logger.debug('Adding new pending forward connection with channel id {0} and socket {1}'.format(channel_id, sock))\n        self.establishing_dict[sock] = channel_id\n\n    def relay(self, data, to_socket):\n        if to_socket is None:\n            return\n        try:\n            to_socket.send(data)\n        except socket.error as (code, msg):\n            logger.debug('Exception on relaying data to socket {0}'.format(to_socket))\n            logger.debug('Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))\n            if to_socket == self.bc_sock:\n                raise relay.RelayError\n            else:\n                logger.debug('Closing socket')\n                to_socket.close()\n                self.input_list.remove(to_socket)\n                channel_id = self.id_by_socket[to_socket]\n                self.unset_channel(channel_id)\n                self.send_remote_cmd(self.socket_with_server, relay.CHANNEL_CLOSE_CMD, channel_id)\n\n\nclass NtlmProxyContext(object):\n\n    negotiate_request = '''CONNECT {0}:{1} HTTP/1.1\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0\nProxy-Connection: keep-alive\nConnection: keep-alive\nProxy-Authorization: NTLM {2}\n\n'''\n    authenticate_request = '''CONNECT {0}:{1} HTTP/1.1\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0\nProxy-Connection: keep-alive\nConnection: keep-alive\nProxy-Authorization: NTLM {2}\n\n'''\n\n    def __init__(self, sock, proxy_ip, proxy_port, username, domain=None, password=None, nthash=None, lmhash=None):\n        self._sock = sock\n        self._proxy_ip = proxy_ip\n        self._proxy_port = proxy_port\n        self._username = username\n        self._password = password\n        self._nthash = nthash\n        self._lmhash = lmhash\n        self._domain = domain\n        self._workstation = socket.gethostname().upper()\n\n    def connect(self, host_port):\n        (host, port) = host_port\n        ntlm_context = Ntlm(ntlm_compatibility=5)\n        negotiate_message = ntlm_context.create_negotiate_message(self._domain, self._workstation).decode()\n        resp = None\n        try:\n            self._sock.connect((self._proxy_ip, self._proxy_port))\n            self._sock.send(NtlmProxyContext.negotiate_request.format(host, str(port), negotiate_message))\n            resp = self._sock.recv(4096)\n        except socket.error as (code, msg):\n            logger.error(\"Caught socket error trying to establish connection to proxy. Code {0}. Msg {1}\".format(code, msg))\n            raise\n\n        try:\n            chal_msg = NtlmProxyContext.get_challenge(resp)\n            ntlm_context.parse_challenge_message(chal_msg)\n        except TypeError:\n            logger.error(\"Couldn't parse proxy challenge. Code {0}. Msg {1}\".format(code, msg))\n            if resp is not None:\n                logger.error(\"Challenge contents: {0}\".format(resp))\n            else:\n                logger.error(\"Challenge contents is 'None'\")\n            self._sock.close()\n\n\n\n        authenticate_message = ntlm_context.create_authenticate_message(user_name=self._username,\n                                                                        domain_name=self._domain,\n                                                                        password=self._password,\n                                                                        nthash=self._nthash,\n                                                                        lmhash=self._lmhash).decode()\n        resp = None\n        try:\n            self._sock.send(NtlmProxyContext.authenticate_request.format(host, str(port), authenticate_message))\n            resp = self._sock.recv(4096)\n        except socket.error as (code, msg):\n            logger.error(\"Caught socket error trying to send challenge response connection to proxy. Code {0}. Msg {1}\".format(code, msg))\n            self._sock.close()\n            raise\n\n        if resp is None:\n            logger.error(\"Received an empty response to the challenge response\")\n            self._sock.close()\n\n\n        if 'HTTP/1.1 200 Connection established' in resp:\n            logger.info('Ntlm proxy established connection')\n            logger.debug(resp)\n        elif 'HTTP/1.1 503 Service Unavailable' in resp:\n            logger.error('Ntlm proxy response: Service Unavailable')\n            logger.debug(resp)\n            self._sock.close()\n        elif 'HTTP/1.1 407 Proxy Authentication Required' in resp:\n            logger.error('Ntlm proxy authentication failed')\n            logger.debug(resp)\n            self._sock.close()\n            sys.exit(1)\n        else:\n            logger.error('Ntlm proxy unknown error')\n            logger.debug(resp)\n            self._sock.close()\n\n    def __getattr__(self, attribute_name):\n        \"\"\"Defer unknown behaviour to the socket\"\"\"\n        return getattr(self._sock, attribute_name)\n\n    @staticmethod\n    def get_challenge(raw_msg):\n        if raw_msg is None:\n            return None\n        re_res = re.search(r'^Proxy-Authenticate: NTLM (.*)$', raw_msg, re.MULTILINE)\n        if re_res is None:\n            return None\n        else:\n            return re_res.group(1)\n\n\ndef main():\n    global logger\n\n    parser = optparse.OptionParser(description='Reverse socks client')\n    parser.add_option('--server-ip', action=\"store\", dest='server_ip')\n    parser.add_option('--server-port', action=\"store\", dest='server_port', default='9999')\n    parser.add_option('--verbose', action=\"store_true\", dest=\"verbose\", default=False)\n    parser.add_option('--logfile', action=\"store\", dest=\"logfile\", default=None)\n\n    proxy_group = optparse.OptionGroup(parser, 'Ntlm Proxy authentication')\n\n    proxy_group.add_option('--ntlm-proxy-ip', dest='ntlm_proxy_ip', default=None, action='store', help='IP address of NTLM proxy')\n    proxy_group.add_option('--ntlm-proxy-port', dest='ntlm_proxy_port', default=None, action='store', help='Port of NTLM proxy')\n    proxy_group.add_option('--username', dest='username', default='', action='store', help='Username to authenticate with NTLM proxy')\n    proxy_group.add_option('--domain', dest='domain', default='', action='store', help='Domain to authenticate with NTLM proxy')\n    proxy_group.add_option('--password', dest='password', default='', action='store', help='Password to authenticate with NTLM proxy')\n    proxy_group.add_option('--hashes', dest='hashes', default=None, action='store', help='Hashes to authenticate with instead of password. Format - LMHASH:NTHASH')\n\n    parser.add_option_group(proxy_group)\n\n\n    cmd_options = parser.parse_args()[0]\n    if cmd_options.server_ip is None:\n        print 'Server IP required'\n        sys.exit()\n    logger = logging.getLogger('root')\n    logger.setLevel(logging.DEBUG)\n\n    if cmd_options.logfile is None:\n        ch = logging.StreamHandler()\n    else:\n        ch = logging.FileHandler(cmd_options.logfile)\n\n    if cmd_options.verbose:\n        ch.setLevel(logging.DEBUG)\n    else:\n        ch.setLevel(logging.INFO)\n    logger.addHandler(ch)\n    logger.addHandler(ch)\n    while True:\n        logger.info('Backconnecting to server {0} port {1}'.format(cmd_options.server_ip, cmd_options.server_port))\n        backconnect_host = cmd_options.server_ip\n        backconnect_port = int(cmd_options.server_port)\n        bc_sock = None\n        while True:\n            try:\n                bc_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n                if cmd_options.ntlm_proxy_ip is not None:\n                    if cmd_options.ntlm_proxy_port is None:\n                        logger.error('Error. Must specify ntlm proxy port')\n                        sys.exit(1)\n                    if cmd_options.hashes is not None:\n                        if re.match('[a-zA-Z0-9]{32}:[a-zA-Z0-9]{32}', cmd_options.hashes) is None:\n                            logger.error('Hash format error. Valid hash format - LMHASH:NTHASH')\n                            sys.exit(1)\n\n                    logger.info('Connecting via NTLM proxy at {0}:{1}'.format(cmd_options.ntlm_proxy_ip, cmd_options.ntlm_proxy_port))\n                    ntlm_con = NtlmProxyContext(bc_sock, proxy_ip=cmd_options.ntlm_proxy_ip,\n                                                proxy_port=int(cmd_options.ntlm_proxy_port),\n                                                username=cmd_options.username,\n                                                domain=cmd_options.domain,\n                                                password=cmd_options.password,\n                                                nthash=None if cmd_options.hashes is None else cmd_options.hashes.split(':')[1],\n                                                lmhash=None if cmd_options.hashes is None else cmd_options.hashes.split(':')[0])\n\n                    bc_sock = ntlm_con\n                bc_sock.connect((backconnect_host, backconnect_port))\n                break\n            except socket.error as (code, msg):\n                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))\n                logger.info('Retrying')\n                time.sleep(5)\n\n        try:\n            bc_sock.send(relay.banner)\n            banner_reponse_rcv = bc_sock.recv(4096)\n            if banner_reponse_rcv != relay.banner_response:\n                logger.error(\"Wrong banner response {0} from server. Retrying\".format(repr(banner_reponse_rcv)))\n                bc_sock.close()\n                time.sleep(5)\n                continue\n        except socket.error as (code, msg):\n            logger.error(\"Caught socket error trying to establish connection with RPIVOT server. Code {0}. Msg {1}\".format(code, msg))\n            bc_sock.close()\n            time.sleep(5)\n            continue\n\n        socks_relayer = SocksRelay(bc_sock)\n        try:\n            socks_relayer.run()\n        except socket.error as (code, msg):\n            logger.debug('Exception in socks_relayer.run(). Restarting relay')\n            logger.debug('Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))\n            bc_sock.close()\n            continue\n        time.sleep(10)\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "ntlm_auth/U32.py",
    "content": "# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/\n# Copyright 2001 Dmitry A. Rozmanov <dima@xenon.spb.ru>\n#\n# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation, either\n# version 3 of the License, or (at your option) any later version.\n\n# This library is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n\n# You should have received a copy of the GNU Lesser General Public\n# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.\n\nfrom __future__ import division\nimport six\n\nC = 0x1000000000\n\n\ndef norm(n):\n    return n & 0xFFFFFFFF\n\n\nclass U32:\n    v = 0\n\n    def __init__(self, value=0):\n        if not isinstance(value, six.integer_types):\n            value = six.byte2int(value)\n\n        self.v = C + norm(abs(int(value)))\n\n    def set(self, value=0):\n        self.v = C + norm(abs(int(value)))\n\n    def __repr__(self):\n        return hex(norm(self.v))\n\n    def __long__(self):\n        return int(norm(self.v))\n\n    def __int__(self):\n        return int(norm(self.v))\n\n    def __chr__(self):\n        return chr(norm(self.v))\n\n    def __add__(self, b):\n        r = U32()\n        r.v = C + norm(self.v + b.v)\n        return r\n\n    def __sub__(self, b):\n        r = U32()\n        if self.v < b.v:\n            r.v = C + norm(0x100000000 - (b.v - self.v))\n        else:\n            r.v = C + norm(self.v - b.v)\n        return r\n\n    def __mul__(self, b):\n        r = U32()\n        r.v = C + norm(self.v * b.v)\n        return r\n\n    def __div__(self, b):\n        r = U32()\n        r.v = C + (norm(self.v) // norm(b.v))\n        return r\n\n    def __truediv__(self, b):\n        r = U32()\n        r.v = C + (norm(self.v) / norm(b.v))\n        return r\n\n    def __mod__(self, b):\n        r = U32()\n        r.v = C + (norm(self.v) % norm(b.v))\n        return r\n\n    def __neg__(self):\n        return U32(self.v)\n\n    def __pos__(self):\n        return U32(self.v)\n\n    def __abs__(self):\n        return U32(self.v)\n\n    def __invert__(self):\n        r = U32()\n        r.v = C + norm(~self.v)\n        return r\n\n    def __lshift__(self, b):\n        r = U32()\n        r.v = C + norm(self.v << b)\n        return r\n\n    def __rshift__(self, b):\n        r = U32()\n        r.v = C + (norm(self.v) >> b)\n        return r\n\n    def __and__(self, b):\n        r = U32()\n        r.v = C + norm(self.v & b.v)\n        return r\n\n    def __or__(self, b):\n        r = U32()\n        r.v = C + norm(self.v | b.v)\n        return r\n\n    def __xor__(self, b):\n        r = U32()\n        r.v = C + norm(self.v ^ b.v)\n        return r\n\n    def __not__(self):\n        return U32(not norm(self.v))\n\n    def truth(self):\n        return norm(self.v)\n\n    def __cmp__(self, b):\n        if norm(self.v) > norm(b.v):\n            return 1\n        elif norm(self.v) < norm(b.v):\n            return -1\n        else:\n            return 0\n\n    def __lt__(self, other):\n        return self.v < other.v\n\n    def __gt__(self, other):\n        return self.v > other.v\n\n    def __eq__(self, other):\n        return self.v == other.v\n\n    def __le__(self, other):\n        return self.v <= other.v\n\n    def __ge__(self, other):\n        return self.v >= other.v\n\n    def __ne__(self, other):\n        return self.v != other.v\n\n    def __nonzero__(self):\n        return norm(self.v)\n"
  },
  {
    "path": "ntlm_auth/__init__.py",
    "content": "from . import ntlm, session_security\n\n__all__ = ('ntlm', 'session_security')"
  },
  {
    "path": "ntlm_auth/compute_hash.py",
    "content": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation, either\n# version 3 of the License, or (at your option) any later version.\n\n# This library is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n\n# You should have received a copy of the GNU Lesser General Public\n# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.\n\nimport binascii\nimport hashlib\nimport hmac\nimport re\nfrom ntlm_auth import des\n\n\ndef _lmowfv1(password, lmhash):\n    \"\"\"\n    [MS-NLMP] v28.0 2016-07-14\n\n    3.3.1 NTLM v1 Authentication\n    Same function as LMOWFv1 in document to create a one way hash of the password. Only\n    used in NTLMv1 auth without session security\n\n    :param password: The password of the user we are trying to authenticate with\n    :return res: A Lan Manager hash of the password supplied\n    \"\"\"\n\n    # fix the password length to 14 bytes\n    if lmhash is not None:\n        return lmhash.decode('hex')\n\n    password = password.upper()\n    lm_pw = password[0:14]\n\n    # do hash\n    magic_str = b\"KGS!@#$%\"  # page 56 in [MS-NLMP v28.0]\n\n    res = b''\n    dobj = des.DES(lm_pw[0:7])\n    res = res + dobj.encrypt(magic_str)\n\n    dobj = des.DES(lm_pw[7:14])\n    res = res + dobj.encrypt(magic_str)\n    return res\n\ndef _ntowfv1(password, nthash):\n    \"\"\"\n    [MS-NLMP] v28.0 2016-07-14\n\n    3.3.1 NTLM v1 Authentication\n    Same function as NTOWFv1 in document to create a one way hash of the password. Only\n    used in NTLMv1 auth without session security\n\n    :param password: The password of the user we are trying to authenticate with\n    :return digest: An NT hash of the password supplied\n    \"\"\"\n    if nthash is not None:\n        return nthash.decode('hex')\n\n    digest = hashlib.new('md4', password.encode('utf-16le')).digest()\n    return digest\n\ndef _ntowfv2(user_name, password, nthash, domain_name):\n    \"\"\"\n    [MS-NLMP] v28.0 2016-07-14\n\n    3.3.2 NTLM v2 Authentication\n    Same function as NTOWFv2 (and LMOWFv2) in document to create a one way hash of the password.\n    This combines some extra security features over the v1 calculations used in NTLMv2 auth.\n\n    :param user_name: The user name of the user we are trying to authenticate with\n    :param password: The password of the user we are trying to authenticate with\n    :param domain_name: The domain name of the user account we are authenticated with\n    :return digest: An NT hash of the parameters supplied\n    \"\"\"\n    digest = _ntowfv1(password, nthash)\n    digest = hmac.new(digest, (user_name.upper() + domain_name).encode('utf-16le')).digest()\n\n\n    return digest"
  },
  {
    "path": "ntlm_auth/compute_keys.py",
    "content": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation, either\n# version 3 of the License, or (at your option) any later version.\n\n# This library is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n\n# You should have received a copy of the GNU Lesser General Public\n# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.\n\nimport binascii\nimport hashlib\nimport hmac\nfrom ntlm_auth import des\nfrom ntlm_auth.constants import NegotiateFlags\n\ndef _get_exchange_key_ntlm_v1(negotiate_flags, session_base_key, server_challenge, lm_challenge_response, lm_hash):\n    \"\"\"\n    [MS-NLMP] v28.0 2016-07-14\n\n    4.3.5.1 KXKEY\n    Calculates the Key Exchange Key for NTLMv1 authentication. Used for signing and sealing messages\n\n    @param negotiate_flags:\n    @param session_base_key: A session key calculated from the user password challenge\n    @param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE\n    @param lm_challenge_response: The LmChallengeResponse value computed in ComputeResponse\n    @param lm_hash: The LMOWF computed in Compute Response\n    @return key_exchange_key: The Key Exchange Key (KXKEY) used to sign and seal messages and compute the ExportedSessionKey\n    \"\"\"\n    if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:\n        key_exchange_key = hmac.new(session_base_key, server_challenge + lm_challenge_response[:8]).digest()\n    elif negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_LM_KEY:\n        des_handler = des.DES(lm_hash[:7])\n        first_des = des_handler.encrypt(lm_challenge_response[:8])\n        des_handler = des.DES(lm_hash[7:8] + binascii.unhexlify('bdbdbdbdbdbdbd'))\n        second_des = des_handler.encrypt(lm_challenge_response[:8])\n\n        key_exchange_key = first_des + second_des\n    elif negotiate_flags & NegotiateFlags.NTLMSSP_REQUEST_NON_NT_SESSION_KEY:\n        key_exchange_key = lm_hash[:8] + b'\\0' * 8\n    else:\n        key_exchange_key = session_base_key\n\n    return key_exchange_key\n\ndef _get_exchange_key_ntlm_v2(session_base_key):\n    \"\"\"\n    [MS-NLMP] v28.0 2016-07-14\n\n    4.3.5.1 KXKEY\n    Calculates the Key Exchange Key for NTLMv2 authentication. Used for signing and sealing messages.\n    According to docs, 'If NTLM v2 is used, KeyExchangeKey MUST be set to the given 128-bit SessionBaseKey\n\n    @param session_base_key: A session key calculated from the user password challenge\n    @return key_exchange_key: The Key Exchange Key (KXKEY) used to sign and seal messages\n    \"\"\"\n    return session_base_key\n\ndef get_sign_key(exported_session_key, magic_constant):\n    \"\"\"\n    3.4.5.2 SIGNKEY\n\n    @param exported_session_key: A 128-bit session key used to derive signing and sealing keys\n    @param magic_constant: A constant value set in the MS-NLMP documentation (constants.SignSealConstants)\n    @return sign_key: Key used to sign messages\n    \"\"\"\n\n    sign_key = hashlib.md5(exported_session_key + magic_constant).digest()\n\n    return sign_key\n\ndef get_seal_key(negotiate_flags, exported_session_key, magic_constant):\n    \"\"\"\n    3.4.5.3. SEALKEY\n    Main method to use to calculate the seal_key used to seal (encrypt) messages. This will determine\n    the correct method below to use based on the compatibility flags set and should be called instead\n    of the others\n\n    @param exported_session_key: A 128-bit session key used to derive signing and sealing keys\n    @param negotiate_flags: The negotiate_flags structure sent by the server\n    @param magic_constant: A constant value set in the MS-NLMP documentation (constants.SignSealConstants)\n    @return seal_key: Key used to seal messages\n    \"\"\"\n\n    if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:\n        seal_key = _get_seal_key_ntlm2(negotiate_flags, exported_session_key, magic_constant)\n    elif negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_LM_KEY:\n        seal_key = _get_seal_key_ntlm1(negotiate_flags, exported_session_key)\n    else:\n        seal_key = exported_session_key\n\n    return seal_key\n\ndef _get_seal_key_ntlm1(negotiate_flags, exported_session_key):\n    \"\"\"\n    3.4.5.3 SEALKEY\n    Calculates the seal_key used to seal (encrypt) messages. This for authentication where\n    NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY has not been negotiated. Will weaken the keys\n    if NTLMSSP_NEGOTIATE_56 is not negotiated it will default to the 40-bit key\n\n    @param negotiate_flags: The negotiate_flags structure sent by the server\n    @param exported_session_key: A 128-bit session key used to derive signing and sealing keys\n    @return seal_key: Key used to seal messages\n    \"\"\"\n    if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_56:\n        seal_key = exported_session_key[:7] + binascii.unhexlify('a0')\n    else:\n        seal_key = exported_session_key[:5] + binascii.unhexlify('e538b0')\n\n    return seal_key\n\ndef _get_seal_key_ntlm2(negotiate_flags, exported_session_key, magic_constant):\n    \"\"\"\n    3.4.5.3 SEALKEY\n    Calculates the seal_key used to seal (encrypt) messages. This for authentication where\n    NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY has been negotiated. Will weaken the keys\n    if NTLMSSP_NEGOTIATE_128 is not negotiated, will try NEGOTIATE_56 and then will default\n    to the 40-bit key\n\n    @param negotiate_flags: The negotiate_flags structure sent by the server\n    @param exported_session_key: A 128-bit session key used to derive signing and sealing keys\n    @param magic_constant: A constant value set in the MS-NLMP documentation (constants.SignSealConstants)\n    @return seal_key: Key used to seal messages\n    \"\"\"\n    if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_128:\n        seal_key = exported_session_key\n    elif negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_56:\n        seal_key = exported_session_key[:7]\n    else:\n        seal_key = exported_session_key[:5]\n\n    seal_key = hashlib.md5(seal_key + magic_constant).digest()\n\n    return seal_key"
  },
  {
    "path": "ntlm_auth/compute_response.py",
    "content": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation, either\n# version 3 of the License, or (at your option) any later version.\n\n# This library is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n\n# You should have received a copy of the GNU Lesser General Public\n# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.\n\nimport base64\nimport calendar\nimport hashlib\nimport hmac\nimport os\nimport struct\nimport time\nimport ntlm_auth.compute_hash as comphash\nimport ntlm_auth.compute_keys as compkeys\nfrom ntlm_auth import des\nfrom ntlm_auth.constants import NegotiateFlags, AvFlags\nfrom ntlm_auth.gss_channel_bindings import GssChannelBindingsStruct\nfrom ntlm_auth.target_info import TargetInfo\n\nclass ComputeResponse():\n    \"\"\"\n        Constructor for the response computations. This class will compute the various\n        nt and lm challenge responses.\n\n        :param user_name: The user name of the user we are trying to authenticate with\n        :param password: The password of the user we are trying to authenticate with\n        :param domain_name: The domain name of the user account we are authenticated with, default is None\n        :param challenge_message: A ChallengeMessage object that was received from the server after the negotiate_message\n        :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\n    \"\"\"\n    def __init__(self, user_name, password, nthash, lmhash, domain_name, challenge_message, ntlm_compatibility):\n        self._user_name = user_name\n        self._password = password\n        self._nthash = nthash\n        self._lmhash = lmhash\n        self._domain_name = domain_name\n        self._challenge_message = challenge_message\n        self._negotiate_flags = challenge_message.negotiate_flags\n        self._server_challenge = challenge_message.server_challenge\n        self._server_target_info = challenge_message.target_info\n        self._ntlm_compatibility = ntlm_compatibility\n        self._client_challenge = os.urandom(8)\n\n    def get_lm_challenge_response(self):\n        \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        3.3.1 - NTLM v1 Authentication\n        3.3.2 - NTLM v2 Authentication\n\n        This method returns the LmChallengeResponse key based on the ntlm_compatibility chosen\n        and the target_info supplied by the CHALLENGE_MESSAGE. It is quite different from what\n        is set in the document as it combines the NTLMv1, NTLM2 and NTLMv2 methods into one\n        and calls separate methods based on the ntlm_compatibility flag chosen.\n\n        :return: response (LmChallengeResponse) - The LM response to the server challenge. Computed by the client\n        \"\"\"\n        if self._negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY and self._ntlm_compatibility < 3:\n            response = ComputeResponse._get_LMv1_with_session_security_response(self._client_challenge)\n\n        elif 0 <= self._ntlm_compatibility <= 1:\n            response = ComputeResponse._get_LMv1_response(self._password, self._lmhash, self._server_challenge)\n        elif self._ntlm_compatibility == 2:\n            # Based on the compatibility level we don't want to use LM responses, ignore the session_base_key as it is returned in nt\n            response, ignore_key = ComputeResponse._get_NTLMv1_response(self._password, self._nthash, self._server_challenge)\n        else:\n            \"\"\"\n            [MS-NLMP] v28.0 page 45 - 2016-07-14\n\n            3.1.5.12 Client Received a CHALLENGE_MESSAGE from the Server\n            If NTLMv2 authentication is used and the CHALLENGE_MESSAGE TargetInfo field has an MsvAvTimestamp present,\n            the client SHOULD NOT send the LmChallengeResponse and SHOULD send Z(24) instead.\n            \"\"\"\n\n            response = ComputeResponse._get_LMv2_response(self._user_name, self._password, self._nthash, self._domain_name,\n                                                          self._server_challenge,\n                                                          self._client_challenge)\n            if self._server_target_info is not None:\n                timestamp = self._server_target_info[TargetInfo.MSV_AV_TIMESTAMP]\n                if timestamp is not None:\n                    response = b'\\0' * 24\n\n        return response\n\n    def get_nt_challenge_response(self, lm_challenge_response, server_certificate_hash):\n        \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        3.3.1 - NTLM v1 Authentication\n        3.3.2 - NTLM v2 Authentication\n\n        This method returns the NtChallengeResponse key based on the ntlm_compatibility chosen\n        and the target_info supplied by the CHALLENGE_MESSAGE. It is quite different from what\n        is set in the document as it combines the NTLMv1, NTLM2 and NTLMv2 methods into one\n        and calls separate methods based on the ntlm_compatibility value chosen.\n\n        :param lm_challenge_response: The LmChallengeResponse calculated beforeand, used to get the key_exchange_key value\n        :param server_certificate_hash: The SHA256 hash of the server certificate (DER encoded) NTLM is authenticated to.\n                                        Used in Channel Binding Tokens if present, default value is None. See\n                                        AuthenticateMessage in messages.py for more details\n        :return response: (NtChallengeResponse) - The NT response to the server challenge. Computed by the client\n        :return session_base_key: (SessionBaseKey) - A session key calculated from the user password challenge\n        :return target_info: (AV_PAIR) - The AV_PAIR structure used in the nt_challenge calculations\n        \"\"\"\n        if self._negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY and self._ntlm_compatibility < 3:\n            # 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\n            # [MS-NLMP] - 3.3.1 NTLMv1 Authentication\n            response, session_base_key = ComputeResponse._get_NTLM2_response(self._password, self._nthash, self._server_challenge, self._client_challenge)\n            key_exchange_key = compkeys._get_exchange_key_ntlm_v1(self._negotiate_flags, session_base_key,\n                                                                  self._server_challenge, lm_challenge_response,\n                                                                  comphash._lmowfv1(self._password, self._lmhash))\n            target_info = None\n\n        elif 0 <= self._ntlm_compatibility < 3:\n            response, session_base_key = ComputeResponse._get_NTLMv1_response(self._password, self._nthash, self._server_challenge)\n            key_exchange_key = compkeys._get_exchange_key_ntlm_v1(self._negotiate_flags, session_base_key,\n                                                                  self._server_challenge, lm_challenge_response,\n                                                                  comphash._lmowfv1(self._password, self._lmhash))\n            target_info = None\n        else:\n            if self._server_target_info is None:\n                target_info = TargetInfo()\n            else:\n                target_info = self._server_target_info\n\n            if target_info[TargetInfo.MSV_AV_TIMESTAMP] is None:\n                timestamp = get_windows_timestamp()\n            else:\n                timestamp = target_info[TargetInfo.MSV_AV_TIMESTAMP][1]\n\n                # [MS-NLMP] If the CHALLENGE_MESSAGE TargetInfo field has an MsvAvTimestamp present, the client SHOULD provide a MIC\n                target_info[TargetInfo.MSV_AV_FLAGS] = struct.pack(\"<L\", AvFlags.MIC_PROVIDED)\n\n            if server_certificate_hash != None:\n                channel_bindings_hash = ComputeResponse._get_channel_bindings_value(server_certificate_hash)\n                target_info[TargetInfo.MSV_AV_CHANNEL_BINDINGS] = channel_bindings_hash\n\n            response, session_base_key = ComputeResponse._get_NTLMv2_response(self._user_name, self._password, self._nthash, self._domain_name,\n                                                 self._server_challenge, self._client_challenge, timestamp, target_info)\n\n            key_exchange_key = compkeys._get_exchange_key_ntlm_v2(session_base_key)\n\n        return response, key_exchange_key, target_info\n\n\n    @staticmethod\n    def _get_LMv1_response(password, lmhash, server_challenge):\n        \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        2.2.2.3 LM_RESPONSE\n        The LM_RESPONSE structure defines the NTLM v1 authentication LmChallengeResponse\n        in the AUTHENTICATE_MESSAGE. This response is used only when NTLM v1\n        authentication is configured.\n\n        :param password: The password of the user we are trying to authenticate with\n        :param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE\n        :return response: LmChallengeResponse to the server challenge\n        \"\"\"\n        lm_hash = comphash._lmowfv1(password, lmhash)\n        response = ComputeResponse._calc_resp(lm_hash, server_challenge)\n\n        return response\n\n    @staticmethod\n    def _get_LMv1_with_session_security_response(client_challenge):\n        \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        2.2.2.3 LM_RESPONSE\n        The LM_RESPONSE structure defines the NTLM v1 authentication LmChallengeResponse\n        in the AUTHENTICATE_MESSAGE. This response is used only when NTLM v1\n        authentication is configured and NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY is flages.\n\n        :param client_challenge: A random 8-byte response generated by the client for the AUTHENTICATE_MESSAGE\n        :return response: LmChallengeResponse to the server challenge\n        \"\"\"\n\n        response = client_challenge + b'\\0' * 16\n\n        return response\n\n    @staticmethod\n    def _get_LMv2_response(user_name, password, nthash, domain_name, server_challenge, client_challenge):\n        \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        2.2.2.4 LMv2_RESPONSE\n        The LMv2_RESPONSE structure defines the NTLM v2 authentication LmChallengeResponse\n        in the AUTHENTICATE_MESSAGE. This response is used only when NTLM v2\n        authentication is configured.\n\n        :param user_name: The user name of the user we are trying to authenticate with\n        :param password: The password of the user we are trying to authenticate with\n        :param domain_name: The domain name of the user account we are authenticated with\n        :param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE\n        :param client_challenge: A random 8-byte response generated by the client for the AUTHENTICATE_MESSAGE\n        :return response: LmChallengeResponse to the server challenge\n        \"\"\"\n        nt_hash = comphash._ntowfv2(user_name, password, nthash, domain_name)\n        lm_hash = hmac.new(nt_hash, (server_challenge + client_challenge)).digest()\n        response = lm_hash + client_challenge\n\n        return response\n\n    @staticmethod\n    def _get_NTLMv1_response(password, nthash, server_challenge):\n        \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        2.2.2.6 NTLM v1 Response: NTLM_RESPONSE\n        The NTLM_RESPONSE strucutre defines the NTLM v1 authentication NtChallengeResponse\n        in the AUTHENTICATE_MESSAGE. This response is only used when NTLM v1 authentication\n        is configured.\n\n        :param password: The password of the user we are trying to authenticate with\n        :param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE\n        :return response: NtChallengeResponse to the server_challenge\n        :return session_base_key: A session key calculated from the user password challenge\n        \"\"\"\n        ntlm_hash = comphash._ntowfv1(password, nthash)\n        response = ComputeResponse._calc_resp(ntlm_hash, server_challenge)\n\n        session_base_key = hashlib.new('md4', ntlm_hash).digest()\n\n        return response, session_base_key\n\n    @staticmethod\n    def _get_NTLM2_response(password, nthash, server_challenge, client_challenge):\n        \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        This name is really misleading as it isn't NTLM v2 authentication rather\n        This authentication is only used when the ntlm_compatibility level is set\n        to a value < 3 (No NTLMv2 auth) but the NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY\n        flag is set in the negotiate flags section. The documentation for computing this\n        value is on page 56 under section 3.3.1 NTLM v1 Authentication\n\n        :param password: The password of the user we are trying to authenticate with\n        :param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE\n        :param client_challenge: A random 8-byte response generated by the client for the AUTHENTICATE_MESSAGE\n        :return response: NtChallengeResponse to the server_challenge\n        :return session_base_key: A session key calculated from the user password challenge\n        \"\"\"\n        ntlm_hash = comphash._ntowfv1(password, nthash)\n        nt_session_hash = hashlib.md5(server_challenge + client_challenge).digest()[:8]\n        response = ComputeResponse._calc_resp(ntlm_hash, nt_session_hash[0:8])\n\n        session_base_key = hashlib.new('md4', ntlm_hash).digest()\n\n        return response, session_base_key\n\n    @staticmethod\n    def _get_NTLMv2_response(user_name, password, nthash, domain_name, server_challenge, client_challenge, timestamp, target_info):\n        \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        2.2.2.8 NTLM V2 Response: NTLMv2_RESPONSE\n        The NTLMv2_RESPONSE strucutre defines the NTLMv2 authentication NtChallengeResponse\n        in the AUTHENTICATE_MESSAGE. This response is used only when NTLMv2 authentication\n        is configured.\n\n        The guide on how this is computed is in 3.3.2 NTLM v2 Authentication.\n\n        :param user_name: The user name of the user we are trying to authenticate with\n        :param password: The password of the user we are trying to authenticate with\n        :param domain_name: The domain name of the user account we are authenticated with\n        :param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE\n        :param client_challenge: A random 8-byte response generated by the client for the AUTHENTICATE_MESSAGE\n        :param timestamp: An 8-byte timestamp in windows format, 100 nanoseconds since 1601-01-01\n        :param target_info: The target_info structure from the CHALLENGE_MESSAGE with the CBT attached if required\n        :return response: NtChallengeResponse to the server_challenge\n        :return session_base_key: A session key calculated from the user password challenge\n        \"\"\"\n\n        nt_hash = comphash._ntowfv2(user_name, password, nthash, domain_name)\n        temp = ComputeResponse._get_NTLMv2_temp(timestamp, client_challenge, target_info)\n        nt_proof_str = hmac.new(nt_hash, (server_challenge + temp)).digest()\n        response = nt_proof_str + temp\n\n        session_base_key = hmac.new(nt_hash, nt_proof_str).digest()\n\n        return response, session_base_key\n\n    @staticmethod\n    def _get_NTLMv2_temp(timestamp, client_challenge, target_info):\n        \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        2.2.2.7 NTLMv2_CLIENT_CHALLENGE - variable length\n        The NTLMv2_CLIENT_CHALLENGE structure defines the client challenge in\n        the AUTHENTICATE_MESSAGE. This structure is used only when NTLM v2\n        authentication is configured and is transported in the NTLMv2_RESPONSE\n        structure.\n\n        The method to create this structure is defined in 3.3.2 NTLMv2 Authentication.\n        In this method this variable is known as the temp value. The target_info variable\n        corresponds to the ServerName variable used in that documentation. This is in\n        reality a lot more than just the ServerName and contains the AV_PAIRS structure\n        we need to transport with the message like Channel Binding tokens and others.\n        By default this will be the target_info returned from the CHALLENGE_MESSAGE plus\n        MSV_AV_CHANNEL_BINDINGS if specified otherwise it is a new target_info set with\n        MSV_AV_TIMESTAMP to the current time.\n\n        :param timestamp: An 8-byte timestamp in windows format, 100 nanoseconds since 1601-01-01\n        :param client_challenge: A random 8-byte response generated by the client for the AUTHENTICATE_MESSAGE\n        :param target_info: The target_info structure from the CHALLENGE_MESSAGE with the CBT attached if required\n        :return temp: The CLIENT_CHALLENGE structure that will be added to the NtChallengeResponse structure\n        \"\"\"\n        resp_type = b'\\1'\n        hi_resp_type = b'\\1'\n        reserved1 = b'\\0' * 2\n        reserved2 = b'\\0' * 4\n        reserved3 = b'\\0' * 4\n        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\n\n        temp = resp_type + hi_resp_type + reserved1 + \\\n               reserved2 + \\\n               timestamp + \\\n               client_challenge + \\\n               reserved3 + \\\n               target_info.get_data() + reserved4\n\n        return temp\n\n    @staticmethod\n    def _calc_resp(password_hash, server_challenge):\n        \"\"\"\n        Generate the LM response given a 16-byte password hash and the challenge\n        from the CHALLENGE_MESSAGE\n\n        :param password_hash: A 16-byte password hash\n        :param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE\n        :return res: A 24-byte buffer to contain the LM response upon return\n        \"\"\"\n\n        # padding with zeros to make the hash 21 bytes long\n        password_hash += b'\\0' * (21 - len(password_hash))\n\n        res = b''\n        dobj = des.DES(password_hash[0:7])\n        res = res + dobj.encrypt(server_challenge[0:8])\n\n        dobj = des.DES(password_hash[7:14])\n        res = res + dobj.encrypt(server_challenge[0:8])\n\n        dobj = des.DES(password_hash[14:21])\n        res = res + dobj.encrypt(server_challenge[0:8])\n        return res\n\n    @staticmethod\n    def _get_channel_bindings_value(server_certificate_hash):\n        \"\"\"\n        https://msdn.microsoft.com/en-us/library/windows/desktop/dd919963%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396\n        https://blogs.msdn.microsoft.com/openspecification/2013/03/26/ntlm-and-channel-binding-hash-aka-extended-protection-for-authentication/\n\n        Get's the MD5 hash of the gss_channel_bindings_struct to add to the AV_PAIR MSV_AV_CHANNEL_BINDINGS.\n        This method takes in the SHA256 hash (Hash of the DER encoded certificate of the server we are connecting to)\n        and add's it to the gss_channel_bindings_struct. It then gets the MD5 hash and converts this to a\n        byte array in preparation of adding it to the AV_PAIR structure.\n\n        :param server_certificate_hash: The SHA256 hash of the server certificate (DER encoded) NTLM is authenticated to\n        :return channel_bindings: An MD5 hash of the gss_channel_bindings_struct to add to the AV_PAIR MsvChannelBindings\n        \"\"\"\n        # Channel Binding Tokens support, used for NTLMv2\n        # Decode the SHA256 certificate hash\n        certificate_digest = base64.b16decode(server_certificate_hash)\n\n        # Initialise the GssChannelBindingsStruct and add the certificate_digest to the application_data field\n        gss_channel_bindings = GssChannelBindingsStruct()\n        gss_channel_bindings[gss_channel_bindings.APPLICATION_DATA] = 'tls-server-end-point:'.encode() + certificate_digest\n\n        # Get the gss_channel_bindings_struct and create an MD5 hash\n        channel_bindings_struct_data = gss_channel_bindings.get_data()\n        channel_bindings_hash = hashlib.md5(channel_bindings_struct_data).hexdigest()\n\n        try:\n            cbt_value = bytearray.fromhex(channel_bindings_hash)\n        except TypeError:\n            # Work-around for Python 2.6 bug\n            cbt_value = bytearray.fromhex(unicode(channel_bindings_hash))\n\n        channel_bindings = bytes(cbt_value)\n        return channel_bindings\n\n\ndef get_windows_timestamp():\n    # Get Windows Date time, 100 nanoseconds since 1601-01-01 in a 64 bit structure\n    timestamp = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000))\n\n    return timestamp"
  },
  {
    "path": "ntlm_auth/constants.py",
    "content": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation, either\n# version 3 of the License, or (at your option) any later version.\n\n# This library is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n\n# You should have received a copy of the GNU Lesser General Public\n# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.\n\n\"\"\"\n    [MS-NLMP] v28.0 2016-07-14\n\n    2.2 Message Syntax\n    The signature field used in NTLM messages\n\"\"\"\nNTLM_SIGNATURE = b'NTLMSSP\\0'\n\n\"\"\"\n    [MS-NLMP] v28.0 2016-07-14\n\n    2.2 Message Syntax\n    The 3 message type options you can have in a message.\n\"\"\"\nclass MessageTypes(object):\n    NTLM_NEGOTIATE      = 0x1\n    NTLM_CHALLENGE      = 0x2\n    NTLM_AUTHENTICATE   = 0x3\n\n\"\"\"\n    [MS-NLMP] v28.0 2016-07-14\n\n    2.2.2.1 AV_PAIR (MsvAvFlags)\n    A 32-bit value indicated server or client configuration\n\"\"\"\nclass AvFlags(object):\n    AUTHENTICATION_CONSTRAINED  = 0x1\n    MIC_PROVIDED                = 0x2\n    UNTRUSTED_SPN_SOURCE        = 0x4\n\n\"\"\"\n    [MS-NLMP] v28.0 2016-07-14\n\n    2.2.2.5 NEGOTIATE\n    During NTLM authentication, each of the following flags is a possible value of the\n    NegotiateFlags field of the NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE and AUTHENTICATE_MESSAGE,\n    unless otherwise noted. These flags define client or server NTLM capabilities\n    supported by the sender.\n\"\"\"\nclass NegotiateFlags(object):\n    NTLMSSP_NEGOTIATE_56                            = 0x80000000\n    NTLMSSP_NEGOTIATE_KEY_EXCH                      = 0x40000000\n    NTLMSSP_NEGOTIATE_128                           = 0x20000000\n    NTLMSSP_RESERVED_R1                             = 0x10000000\n    NTLMSSP_RESERVED_R2                             = 0x08000000\n    NTLMSSP_RESERVED_R3                             = 0x04000000\n    NTLMSSP_NEGOTIATE_VERSION                       = 0x02000000\n    NTLMSSP_RESERVED_R4                             = 0x01000000\n    NTLMSSP_NEGOTIATE_TARGET_INFO                   = 0x00800000\n    NTLMSSP_REQUEST_NON_NT_SESSION_KEY              = 0x00400000\n    NTLMSSP_RESERVED_R5                             = 0x00200000\n    NTLMSSP_NEGOTIATE_IDENTITY                      = 0x00100000\n    NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY      = 0x00080000\n    NTLMSSP_RESERVED_R6                             = 0x00040000\n    NTLMSSP_TARGET_TYPE_SERVER                      = 0x00020000\n    NTLMSSP_TARGET_TYPE_DOMAIN                      = 0x00010000\n    NTLMSSP_NEGOTIATE_ALWAYS_SIGN                   = 0x00008000\n    NTLMSSP_RESERVED_R7                             = 0x00004000\n    NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED      = 0x00002000\n    NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED           = 0x00001000\n    NTLMSSP_ANOYNMOUS                               = 0x00000800\n    NTLMSSP_RESERVED_R8                             = 0x00000400\n    NTLMSSP_NEGOTIATE_NTLM                          = 0x00000200\n    NTLMSSP_RESERVED_R9                             = 0x00000100\n    NTLMSSP_NEGOTIATE_LM_KEY                        = 0x00000080\n    NTLMSSP_NEGOTIATE_DATAGRAM                      = 0x00000040\n    NTLMSSP_NEGOTIATE_SEAL                          = 0x00000020\n    NTLMSSP_NEGOTIATE_SIGN                          = 0x00000010\n    NTLMSSP_RESERVED_R10                            = 0x00000008\n    NTLMSSP_REQUEST_TARGET                          = 0x00000004\n    NTLMSSP_NEGOTIATE_OEM                           = 0x00000002\n    NTLMSSP_NEGOTIATE_UNICODE                       = 0x00000001\n\nclass SignSealConstants(object):\n    # Magic Contants used to get the signing and sealing key for Extended Session Security\n    CLIENT_SIGNING = b\"session key to client-to-server signing key magic constant\\0\"\n    SERVER_SIGNING = b\"session key to server-to-client signing key magic constant\\0\"\n    CLIENT_SEALING = b\"session key to client-to-server sealing key magic constant\\0\"\n    SERVER_SEALING = b\"session key to server-to-client sealing key magic constant\\0\"\n"
  },
  {
    "path": "ntlm_auth/des.py",
    "content": "# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/\n# Copyright 2001 Dmitry A. Rozmanov <dima@xenon.spb.ru>\n#\n# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation, either\n# version 3 of the License, or (at your option) any later version.\n\n# This library is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.\nimport logging\nimport six\nfrom ntlm_auth import des_c\n\nlog = logging.getLogger(__name__)\n\n\nclass DES:\n    des_c_obj = None\n\n    def __init__(self, key_str):\n        k = str_to_key56(key_str)\n        k = key56_to_key64(k)\n\n        key_str = b''\n        for i in k:\n            key_str += six.int2byte(i & 0xFF)\n\n        self.des_c_obj = des_c.DES(key_str)\n\n    def encrypt(self, plain_text):\n        return self.des_c_obj.encrypt(plain_text)\n\n    def decrypt(self, crypted_text):\n        return self.des_c_obj.decrypt(crypted_text)\n\n\nDESException = 'DESException'\n\n\ndef str_to_key56(key_str):\n\n    if not type(key_str) == six.binary_type:\n        # TODO rsanders high - figure out how to make this not necessary\n        key_str = key_str.encode('ascii')\n\n    if len(key_str) < 7:\n        key_str = key_str + b'\\000\\000\\000\\000\\000\\000\\000'[:(7 - len(key_str))]\n    key_56 = []\n    for i in six.iterbytes(key_str[:7]):\n        key_56.append(i)\n\n    return key_56\n\n\ndef key56_to_key64(key_56):\n    key = []\n    for i in range(8):\n        key.append(0)\n\n    key[0] = key_56[0]\n    key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1)\n    key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2)\n    key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3)\n    key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4)\n    key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5)\n    key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6)\n    key[7] = (key_56[6] << 1) & 0xFF\n\n    key = set_key_odd_parity(key)\n\n    return key\n\n\ndef set_key_odd_parity(key):\n    for i in range(len(key)):\n        for k in range(7):\n            bit = 0\n            t = key[i] >> k\n            bit = (t ^ bit) & 0x1\n        key[i] = (key[i] & 0xFE) | bit\n\n    return key\n"
  },
  {
    "path": "ntlm_auth/des_c.py",
    "content": "# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/\n# Copyright 2001 Dmitry A. Rozmanov <dima@xenon.spb.ru>\n#\n# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation, either\n# version 3 of the License, or (at your option) any later version.\n\n# This library is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n\n# You should have received a copy of the GNU Lesser General Public\n# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.\nimport six\n\nfrom ntlm_auth.U32 import U32\nfrom ntlm_auth.des_data import des_SPtrans, des_skb\n\ndef c2l(c):\n    \"char[4] to unsigned long\"\n    l = U32(c[0])\n    l = l | (U32(c[1]) << 8)\n    l = l | (U32(c[2]) << 16)\n    l = l | (U32(c[3]) << 24)\n    return l\n\n\ndef l2c(l):\n    \"unsigned long to char[4]\"\n    c = []\n    c.append(int(l & U32(0xFF)))\n    c.append(int((l >> 8) & U32(0xFF)))\n    c.append(int((l >> 16) & U32(0xFF)))\n    c.append(int((l >> 24) & U32(0xFF)))\n    return c\n\n\ndef D_ENCRYPT(tup, u, t, s):\n    L, R, S = tup\n    # print 'LRS1', L, R, S, u, t, '-->',\n    u = (R ^ s[S])\n    t = R ^ s[S + 1]\n    t = ((t >> 4) + (t << 28))\n    L = L ^ (des_SPtrans[1][int((t) & U32(0x3f))] |\n             des_SPtrans[3][int((t >> 8) & U32(0x3f))] |\n             des_SPtrans[5][int((t >> 16) & U32(0x3f))] |\n             des_SPtrans[7][int((t >> 24) & U32(0x3f))] |\n             des_SPtrans[0][int((u) & U32(0x3f))] |\n             des_SPtrans[2][int((u >> 8) & U32(0x3f))] |\n             des_SPtrans[4][int((u >> 16) & U32(0x3f))] |\n             des_SPtrans[6][int((u >> 24) & U32(0x3f))])\n    # print 'LRS:', L, R, S, u, t\n    return (L, R, S), u, t, s\n\n\ndef PERM_OP(tup, n, m):\n    \"tup - (a, b, t)\"\n    a, b, t = tup\n    t = ((a >> n) ^ b) & m\n    b = b ^ t\n    a = a ^ (t << n)\n    return (a, b, t)\n\n\ndef HPERM_OP(tup, n, m):\n    \"tup - (a, t)\"\n    a, t = tup\n    t = ((a << (16 - n)) ^ a) & m\n    a = a ^ t ^ (t >> (16 - n))\n    return a, t\n\n\nshifts2 = [0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0]\n\n\nclass DES:\n    KeySched = None  # des_key_schedule\n\n    def __init__(self, key_str):\n        self.KeySched = des_set_key(key_str)\n\n    def decrypt(self, str):\n        # block - UChar[]\n        block = []\n\n        for i in six.iterbytes(str):\n            block.append(i)\n\n        # print block\n        block = des_ecb_encrypt(block, self.KeySched, 0)\n\n        res = b''\n        for i in block:\n            res = res + six.int2byte(i)\n\n        return res\n\n    def encrypt(self, plaintext):\n        # block - UChar[]\n\n        block = []\n        for i in plaintext:\n            block.append(i)\n\n        block = des_ecb_encrypt(block, self.KeySched, 1)\n\n        res = b''\n\n        for i in block:\n            res += six.int2byte(i)\n\n        return res\n\n\ndef des_encript(input, ks, encrypt):\n    # input - U32[]\n    # output - U32[]\n    # ks - des_key_shedule - U32[2][16]\n    # encrypt - int\n    # l, r, t, u - U32\n    # i - int\n    # s - U32[]\n\n    l = input[0]\n    r = input[1]\n    t = U32(0)\n    u = U32(0)\n\n    r, l, t = PERM_OP((r, l, t), 4, U32(0x0f0f0f0f))\n    l, r, t = PERM_OP((l, r, t), 16, U32(0x0000ffff))\n    r, l, t = PERM_OP((r, l, t), 2, U32(0x33333333))\n    l, r, t = PERM_OP((l, r, t), 8, U32(0x00ff00ff))\n    r, l, t = PERM_OP((r, l, t), 1, U32(0x55555555))\n\n    t = (r << 1) | (r >> 31)\n    r = (l << 1) | (l >> 31)\n    l = t\n\n    s = ks  # ???????????????\n    # print l, r\n    if encrypt:\n        for i in range(0, 32, 4):\n            rtup, u, t, s = D_ENCRYPT((l, r, i + 0), u, t, s)\n            l = rtup[0]\n            r = rtup[1]\n            rtup, u, t, s = D_ENCRYPT((r, l, i + 2), u, t, s)\n            r = rtup[0]\n            l = rtup[1]\n    else:\n        for i in range(30, 0, -4):\n            rtup, u, t, s = D_ENCRYPT((l, r, i - 0), u, t, s)\n            l = rtup[0]\n            r = rtup[1]\n            rtup, u, t, s = D_ENCRYPT((r, l, i - 2), u, t, s)\n            r = rtup[0]\n            l = rtup[1]\n        # print l, r\n    l = (l >> 1) | (l << 31)\n    r = (r >> 1) | (r << 31)\n\n    r, l, t = PERM_OP((r, l, t), 1, U32(0x55555555))\n    l, r, t = PERM_OP((l, r, t), 8, U32(0x00ff00ff))\n    r, l, t = PERM_OP((r, l, t), 2, U32(0x33333333))\n    l, r, t = PERM_OP((l, r, t), 16, U32(0x0000ffff))\n    r, l, t = PERM_OP((r, l, t), 4, U32(0x0f0f0f0f))\n\n    output = [l]\n    output.append(r)\n    l, r, t, u = U32(0), U32(0), U32(0), U32(0)\n    return output\n\n\ndef des_ecb_encrypt(input, ks, encrypt):\n    # input - des_cblock - UChar[8]\n    # output - des_cblock - UChar[8]\n    # ks - des_key_shedule - U32[2][16]\n    # encrypt - int\n\n    # print input\n    l0 = c2l(input[0:4])\n    l1 = c2l(input[4:8])\n    ll = [l0]\n    ll.append(l1)\n    # print ll\n    ll = des_encript(ll, ks, encrypt)\n    # print ll\n    l0 = ll[0]\n    l1 = ll[1]\n    output = l2c(l0)\n    output = output + l2c(l1)\n    # print output\n    l0, l1, ll[0], ll[1] = U32(0), U32(0), U32(0), U32(0)\n    return output\n\n\ndef des_set_key(key):\n    # key - des_cblock - UChar[8]\n    # schedule - des_key_schedule\n\n    # register unsigned long c,d,t,s;\n    # register unsigned char *in;\n    # register unsigned long *k;\n    # register int i;\n\n    # k = schedule\n    # in = key\n\n    k = []\n    c = c2l(key[0:4])\n    d = c2l(key[4:8])\n    t = U32(0)\n\n    d, c, t = PERM_OP((d, c, t), 4, U32(0x0f0f0f0f))\n    c, t = HPERM_OP((c, t), -2, U32(0xcccc0000))\n    d, t = HPERM_OP((d, t), -2, U32(0xcccc0000))\n    d, c, t = PERM_OP((d, c, t), 1, U32(0x55555555))\n    c, d, t = PERM_OP((c, d, t), 8, U32(0x00ff00ff))\n    d, c, t = PERM_OP((d, c, t), 1, U32(0x55555555))\n\n    d = (((d & U32(0x000000ff)) << 16) | (d & U32(0x0000ff00)) | ((d & U32(0x00ff0000)) >> 16) | (\n        (c & U32(0xf0000000)) >> 4))\n    c = c & U32(0x0fffffff)\n\n    for i in range(16):\n        if (shifts2[i]):\n            c = ((c >> 2) | (c << 26))\n            d = ((d >> 2) | (d << 26))\n        else:\n            c = ((c >> 1) | (c << 27))\n            d = ((d >> 1) | (d << 27))\n        c = c & U32(0x0fffffff)\n        d = d & U32(0x0fffffff)\n\n        s = des_skb[0][int((c) & U32(0x3f))] | \\\n            des_skb[1][int(((c >> 6) & U32(0x03)) | ((c >> 7) & U32(0x3c)))] | \\\n            des_skb[2][int(((c >> 13) & U32(0x0f)) | ((c >> 14) & U32(0x30)))] | \\\n            des_skb[3][int(((c >> 20) & U32(0x01)) | ((c >> 21) & U32(0x06)) | ((c >> 22) & U32(0x38)))]\n\n        t = des_skb[4][int((d) & U32(0x3f))] | \\\n            des_skb[5][int(((d >> 7) & U32(0x03)) | ((d >> 8) & U32(0x3c)))] | \\\n            des_skb[6][int((d >> 15) & U32(0x3f))] | \\\n            des_skb[7][int(((d >> 21) & U32(0x0f)) | ((d >> 22) & U32(0x30)))]\n        # print s, t\n\n        k.append(((t << 16) | (s & U32(0x0000ffff))) & U32(0xffffffff))\n        s = ((s >> 16) | (t & U32(0xffff0000)))\n        s = (s << 4) | (s >> 28)\n        k.append(s & U32(0xffffffff))\n\n    schedule = k\n\n    return schedule\n"
  },
  {
    "path": "ntlm_auth/des_data.py",
    "content": "# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/\n# Copyright 2001 Dmitry A. Rozmanov <dima@xenon.spb.ru>\n#\n# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation, either\n# version 3 of the License, or (at your option) any later version.\n\n# This library is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n\n# You should have received a copy of the GNU Lesser General Public\n# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.\n\nfrom ntlm_auth.U32 import U32\n\n# static unsigned long des_SPtrans[8][64]={\n\ndes_SPtrans = \\\n    [\n        # nibble 0\n        [\n            U32(0x00820200), U32(0x00020000), U32(0x80800000), U32(0x80820200),\n            U32(0x00800000), U32(0x80020200), U32(0x80020000), U32(0x80800000),\n            U32(0x80020200), U32(0x00820200), U32(0x00820000), U32(0x80000200),\n            U32(0x80800200), U32(0x00800000), U32(0x00000000), U32(0x80020000),\n            U32(0x00020000), U32(0x80000000), U32(0x00800200), U32(0x00020200),\n            U32(0x80820200), U32(0x00820000), U32(0x80000200), U32(0x00800200),\n            U32(0x80000000), U32(0x00000200), U32(0x00020200), U32(0x80820000),\n            U32(0x00000200), U32(0x80800200), U32(0x80820000), U32(0x00000000),\n            U32(0x00000000), U32(0x80820200), U32(0x00800200), U32(0x80020000),\n            U32(0x00820200), U32(0x00020000), U32(0x80000200), U32(0x00800200),\n            U32(0x80820000), U32(0x00000200), U32(0x00020200), U32(0x80800000),\n            U32(0x80020200), U32(0x80000000), U32(0x80800000), U32(0x00820000),\n            U32(0x80820200), U32(0x00020200), U32(0x00820000), U32(0x80800200),\n            U32(0x00800000), U32(0x80000200), U32(0x80020000), U32(0x00000000),\n            U32(0x00020000), U32(0x00800000), U32(0x80800200), U32(0x00820200),\n            U32(0x80000000), U32(0x80820000), U32(0x00000200), U32(0x80020200),\n        ],\n\n        # nibble 1\n        [\n            U32(0x10042004), U32(0x00000000), U32(0x00042000), U32(0x10040000),\n            U32(0x10000004), U32(0x00002004), U32(0x10002000), U32(0x00042000),\n            U32(0x00002000), U32(0x10040004), U32(0x00000004), U32(0x10002000),\n            U32(0x00040004), U32(0x10042000), U32(0x10040000), U32(0x00000004),\n            U32(0x00040000), U32(0x10002004), U32(0x10040004), U32(0x00002000),\n            U32(0x00042004), U32(0x10000000), U32(0x00000000), U32(0x00040004),\n            U32(0x10002004), U32(0x00042004), U32(0x10042000), U32(0x10000004),\n            U32(0x10000000), U32(0x00040000), U32(0x00002004), U32(0x10042004),\n            U32(0x00040004), U32(0x10042000), U32(0x10002000), U32(0x00042004),\n            U32(0x10042004), U32(0x00040004), U32(0x10000004), U32(0x00000000),\n            U32(0x10000000), U32(0x00002004), U32(0x00040000), U32(0x10040004),\n            U32(0x00002000), U32(0x10000000), U32(0x00042004), U32(0x10002004),\n            U32(0x10042000), U32(0x00002000), U32(0x00000000), U32(0x10000004),\n            U32(0x00000004), U32(0x10042004), U32(0x00042000), U32(0x10040000),\n            U32(0x10040004), U32(0x00040000), U32(0x00002004), U32(0x10002000),\n            U32(0x10002004), U32(0x00000004), U32(0x10040000), U32(0x00042000),\n        ],\n\n        # nibble 2\n        [\n            U32(0x41000000), U32(0x01010040), U32(0x00000040), U32(0x41000040),\n            U32(0x40010000), U32(0x01000000), U32(0x41000040), U32(0x00010040),\n            U32(0x01000040), U32(0x00010000), U32(0x01010000), U32(0x40000000),\n            U32(0x41010040), U32(0x40000040), U32(0x40000000), U32(0x41010000),\n            U32(0x00000000), U32(0x40010000), U32(0x01010040), U32(0x00000040),\n            U32(0x40000040), U32(0x41010040), U32(0x00010000), U32(0x41000000),\n            U32(0x41010000), U32(0x01000040), U32(0x40010040), U32(0x01010000),\n            U32(0x00010040), U32(0x00000000), U32(0x01000000), U32(0x40010040),\n            U32(0x01010040), U32(0x00000040), U32(0x40000000), U32(0x00010000),\n            U32(0x40000040), U32(0x40010000), U32(0x01010000), U32(0x41000040),\n            U32(0x00000000), U32(0x01010040), U32(0x00010040), U32(0x41010000),\n            U32(0x40010000), U32(0x01000000), U32(0x41010040), U32(0x40000000),\n            U32(0x40010040), U32(0x41000000), U32(0x01000000), U32(0x41010040),\n            U32(0x00010000), U32(0x01000040), U32(0x41000040), U32(0x00010040),\n            U32(0x01000040), U32(0x00000000), U32(0x41010000), U32(0x40000040),\n            U32(0x41000000), U32(0x40010040), U32(0x00000040), U32(0x01010000),\n        ],\n\n        # nibble 3\n        [\n            U32(0x00100402), U32(0x04000400), U32(0x00000002), U32(0x04100402),\n            U32(0x00000000), U32(0x04100000), U32(0x04000402), U32(0x00100002),\n            U32(0x04100400), U32(0x04000002), U32(0x04000000), U32(0x00000402),\n            U32(0x04000002), U32(0x00100402), U32(0x00100000), U32(0x04000000),\n            U32(0x04100002), U32(0x00100400), U32(0x00000400), U32(0x00000002),\n            U32(0x00100400), U32(0x04000402), U32(0x04100000), U32(0x00000400),\n            U32(0x00000402), U32(0x00000000), U32(0x00100002), U32(0x04100400),\n            U32(0x04000400), U32(0x04100002), U32(0x04100402), U32(0x00100000),\n            U32(0x04100002), U32(0x00000402), U32(0x00100000), U32(0x04000002),\n            U32(0x00100400), U32(0x04000400), U32(0x00000002), U32(0x04100000),\n            U32(0x04000402), U32(0x00000000), U32(0x00000400), U32(0x00100002),\n            U32(0x00000000), U32(0x04100002), U32(0x04100400), U32(0x00000400),\n            U32(0x04000000), U32(0x04100402), U32(0x00100402), U32(0x00100000),\n            U32(0x04100402), U32(0x00000002), U32(0x04000400), U32(0x00100402),\n            U32(0x00100002), U32(0x00100400), U32(0x04100000), U32(0x04000402),\n            U32(0x00000402), U32(0x04000000), U32(0x04000002), U32(0x04100400),\n        ],\n\n        # nibble 4\n        [\n            U32(0x02000000), U32(0x00004000), U32(0x00000100), U32(0x02004108),\n            U32(0x02004008), U32(0x02000100), U32(0x00004108), U32(0x02004000),\n            U32(0x00004000), U32(0x00000008), U32(0x02000008), U32(0x00004100),\n            U32(0x02000108), U32(0x02004008), U32(0x02004100), U32(0x00000000),\n            U32(0x00004100), U32(0x02000000), U32(0x00004008), U32(0x00000108),\n            U32(0x02000100), U32(0x00004108), U32(0x00000000), U32(0x02000008),\n            U32(0x00000008), U32(0x02000108), U32(0x02004108), U32(0x00004008),\n            U32(0x02004000), U32(0x00000100), U32(0x00000108), U32(0x02004100),\n            U32(0x02004100), U32(0x02000108), U32(0x00004008), U32(0x02004000),\n            U32(0x00004000), U32(0x00000008), U32(0x02000008), U32(0x02000100),\n            U32(0x02000000), U32(0x00004100), U32(0x02004108), U32(0x00000000),\n            U32(0x00004108), U32(0x02000000), U32(0x00000100), U32(0x00004008),\n            U32(0x02000108), U32(0x00000100), U32(0x00000000), U32(0x02004108),\n            U32(0x02004008), U32(0x02004100), U32(0x00000108), U32(0x00004000),\n            U32(0x00004100), U32(0x02004008), U32(0x02000100), U32(0x00000108),\n            U32(0x00000008), U32(0x00004108), U32(0x02004000), U32(0x02000008),\n        ],\n\n        # nibble 5\n        [\n            U32(0x20000010), U32(0x00080010), U32(0x00000000), U32(0x20080800),\n            U32(0x00080010), U32(0x00000800), U32(0x20000810), U32(0x00080000),\n            U32(0x00000810), U32(0x20080810), U32(0x00080800), U32(0x20000000),\n            U32(0x20000800), U32(0x20000010), U32(0x20080000), U32(0x00080810),\n            U32(0x00080000), U32(0x20000810), U32(0x20080010), U32(0x00000000),\n            U32(0x00000800), U32(0x00000010), U32(0x20080800), U32(0x20080010),\n            U32(0x20080810), U32(0x20080000), U32(0x20000000), U32(0x00000810),\n            U32(0x00000010), U32(0x00080800), U32(0x00080810), U32(0x20000800),\n            U32(0x00000810), U32(0x20000000), U32(0x20000800), U32(0x00080810),\n            U32(0x20080800), U32(0x00080010), U32(0x00000000), U32(0x20000800),\n            U32(0x20000000), U32(0x00000800), U32(0x20080010), U32(0x00080000),\n            U32(0x00080010), U32(0x20080810), U32(0x00080800), U32(0x00000010),\n            U32(0x20080810), U32(0x00080800), U32(0x00080000), U32(0x20000810),\n            U32(0x20000010), U32(0x20080000), U32(0x00080810), U32(0x00000000),\n            U32(0x00000800), U32(0x20000010), U32(0x20000810), U32(0x20080800),\n            U32(0x20080000), U32(0x00000810), U32(0x00000010), U32(0x20080010),\n        ],\n\n        # nibble 6\n        [\n            U32(0x00001000), U32(0x00000080), U32(0x00400080), U32(0x00400001),\n            U32(0x00401081), U32(0x00001001), U32(0x00001080), U32(0x00000000),\n            U32(0x00400000), U32(0x00400081), U32(0x00000081), U32(0x00401000),\n            U32(0x00000001), U32(0x00401080), U32(0x00401000), U32(0x00000081),\n            U32(0x00400081), U32(0x00001000), U32(0x00001001), U32(0x00401081),\n            U32(0x00000000), U32(0x00400080), U32(0x00400001), U32(0x00001080),\n            U32(0x00401001), U32(0x00001081), U32(0x00401080), U32(0x00000001),\n            U32(0x00001081), U32(0x00401001), U32(0x00000080), U32(0x00400000),\n            U32(0x00001081), U32(0x00401000), U32(0x00401001), U32(0x00000081),\n            U32(0x00001000), U32(0x00000080), U32(0x00400000), U32(0x00401001),\n            U32(0x00400081), U32(0x00001081), U32(0x00001080), U32(0x00000000),\n            U32(0x00000080), U32(0x00400001), U32(0x00000001), U32(0x00400080),\n            U32(0x00000000), U32(0x00400081), U32(0x00400080), U32(0x00001080),\n            U32(0x00000081), U32(0x00001000), U32(0x00401081), U32(0x00400000),\n            U32(0x00401080), U32(0x00000001), U32(0x00001001), U32(0x00401081),\n            U32(0x00400001), U32(0x00401080), U32(0x00401000), U32(0x00001001),\n        ],\n\n        # nibble 7\n        [\n            U32(0x08200020), U32(0x08208000), U32(0x00008020), U32(0x00000000),\n            U32(0x08008000), U32(0x00200020), U32(0x08200000), U32(0x08208020),\n            U32(0x00000020), U32(0x08000000), U32(0x00208000), U32(0x00008020),\n            U32(0x00208020), U32(0x08008020), U32(0x08000020), U32(0x08200000),\n            U32(0x00008000), U32(0x00208020), U32(0x00200020), U32(0x08008000),\n            U32(0x08208020), U32(0x08000020), U32(0x00000000), U32(0x00208000),\n            U32(0x08000000), U32(0x00200000), U32(0x08008020), U32(0x08200020),\n            U32(0x00200000), U32(0x00008000), U32(0x08208000), U32(0x00000020),\n            U32(0x00200000), U32(0x00008000), U32(0x08000020), U32(0x08208020),\n            U32(0x00008020), U32(0x08000000), U32(0x00000000), U32(0x00208000),\n            U32(0x08200020), U32(0x08008020), U32(0x08008000), U32(0x00200020),\n            U32(0x08208000), U32(0x00000020), U32(0x00200020), U32(0x08008000),\n            U32(0x08208020), U32(0x00200000), U32(0x08200000), U32(0x08000020),\n            U32(0x00208000), U32(0x00008020), U32(0x08008020), U32(0x08200000),\n            U32(0x00000020), U32(0x08208000), U32(0x00208020), U32(0x00000000),\n            U32(0x08000000), U32(0x08200020), U32(0x00008000), U32(0x00208020),\n        ],\n    ]\n\n# static unsigned long des_skb[8][64]={\n\ndes_skb = \\\n    [\n        # for C bits (numbered as per FIPS 46) 1 2 3 4 5 6\n        [\n            U32(0x00000000), U32(0x00000010), U32(0x20000000), U32(0x20000010),\n            U32(0x00010000), U32(0x00010010), U32(0x20010000), U32(0x20010010),\n            U32(0x00000800), U32(0x00000810), U32(0x20000800), U32(0x20000810),\n            U32(0x00010800), U32(0x00010810), U32(0x20010800), U32(0x20010810),\n            U32(0x00000020), U32(0x00000030), U32(0x20000020), U32(0x20000030),\n            U32(0x00010020), U32(0x00010030), U32(0x20010020), U32(0x20010030),\n            U32(0x00000820), U32(0x00000830), U32(0x20000820), U32(0x20000830),\n            U32(0x00010820), U32(0x00010830), U32(0x20010820), U32(0x20010830),\n            U32(0x00080000), U32(0x00080010), U32(0x20080000), U32(0x20080010),\n            U32(0x00090000), U32(0x00090010), U32(0x20090000), U32(0x20090010),\n            U32(0x00080800), U32(0x00080810), U32(0x20080800), U32(0x20080810),\n            U32(0x00090800), U32(0x00090810), U32(0x20090800), U32(0x20090810),\n            U32(0x00080020), U32(0x00080030), U32(0x20080020), U32(0x20080030),\n            U32(0x00090020), U32(0x00090030), U32(0x20090020), U32(0x20090030),\n            U32(0x00080820), U32(0x00080830), U32(0x20080820), U32(0x20080830),\n            U32(0x00090820), U32(0x00090830), U32(0x20090820), U32(0x20090830),\n        ],\n\n        # for C bits (numbered as per FIPS 46) 7 8 10 11 12 13\n        [\n            U32(0x00000000), U32(0x02000000), U32(0x00002000), U32(0x02002000),\n            U32(0x00200000), U32(0x02200000), U32(0x00202000), U32(0x02202000),\n            U32(0x00000004), U32(0x02000004), U32(0x00002004), U32(0x02002004),\n            U32(0x00200004), U32(0x02200004), U32(0x00202004), U32(0x02202004),\n            U32(0x00000400), U32(0x02000400), U32(0x00002400), U32(0x02002400),\n            U32(0x00200400), U32(0x02200400), U32(0x00202400), U32(0x02202400),\n            U32(0x00000404), U32(0x02000404), U32(0x00002404), U32(0x02002404),\n            U32(0x00200404), U32(0x02200404), U32(0x00202404), U32(0x02202404),\n            U32(0x10000000), U32(0x12000000), U32(0x10002000), U32(0x12002000),\n            U32(0x10200000), U32(0x12200000), U32(0x10202000), U32(0x12202000),\n            U32(0x10000004), U32(0x12000004), U32(0x10002004), U32(0x12002004),\n            U32(0x10200004), U32(0x12200004), U32(0x10202004), U32(0x12202004),\n            U32(0x10000400), U32(0x12000400), U32(0x10002400), U32(0x12002400),\n            U32(0x10200400), U32(0x12200400), U32(0x10202400), U32(0x12202400),\n            U32(0x10000404), U32(0x12000404), U32(0x10002404), U32(0x12002404),\n            U32(0x10200404), U32(0x12200404), U32(0x10202404), U32(0x12202404),\n        ],\n\n        # for C bits (numbered as per FIPS 46) 14 15 16 17 19 20\n        [\n            U32(0x00000000), U32(0x00000001), U32(0x00040000), U32(0x00040001),\n            U32(0x01000000), U32(0x01000001), U32(0x01040000), U32(0x01040001),\n            U32(0x00000002), U32(0x00000003), U32(0x00040002), U32(0x00040003),\n            U32(0x01000002), U32(0x01000003), U32(0x01040002), U32(0x01040003),\n            U32(0x00000200), U32(0x00000201), U32(0x00040200), U32(0x00040201),\n            U32(0x01000200), U32(0x01000201), U32(0x01040200), U32(0x01040201),\n            U32(0x00000202), U32(0x00000203), U32(0x00040202), U32(0x00040203),\n            U32(0x01000202), U32(0x01000203), U32(0x01040202), U32(0x01040203),\n            U32(0x08000000), U32(0x08000001), U32(0x08040000), U32(0x08040001),\n            U32(0x09000000), U32(0x09000001), U32(0x09040000), U32(0x09040001),\n            U32(0x08000002), U32(0x08000003), U32(0x08040002), U32(0x08040003),\n            U32(0x09000002), U32(0x09000003), U32(0x09040002), U32(0x09040003),\n            U32(0x08000200), U32(0x08000201), U32(0x08040200), U32(0x08040201),\n            U32(0x09000200), U32(0x09000201), U32(0x09040200), U32(0x09040201),\n            U32(0x08000202), U32(0x08000203), U32(0x08040202), U32(0x08040203),\n            U32(0x09000202), U32(0x09000203), U32(0x09040202), U32(0x09040203),\n        ],\n\n        # for C bits (numbered as per FIPS 46) 21 23 24 26 27 28\n        [\n            U32(0x00000000), U32(0x00100000), U32(0x00000100), U32(0x00100100),\n            U32(0x00000008), U32(0x00100008), U32(0x00000108), U32(0x00100108),\n            U32(0x00001000), U32(0x00101000), U32(0x00001100), U32(0x00101100),\n            U32(0x00001008), U32(0x00101008), U32(0x00001108), U32(0x00101108),\n            U32(0x04000000), U32(0x04100000), U32(0x04000100), U32(0x04100100),\n            U32(0x04000008), U32(0x04100008), U32(0x04000108), U32(0x04100108),\n            U32(0x04001000), U32(0x04101000), U32(0x04001100), U32(0x04101100),\n            U32(0x04001008), U32(0x04101008), U32(0x04001108), U32(0x04101108),\n            U32(0x00020000), U32(0x00120000), U32(0x00020100), U32(0x00120100),\n            U32(0x00020008), U32(0x00120008), U32(0x00020108), U32(0x00120108),\n            U32(0x00021000), U32(0x00121000), U32(0x00021100), U32(0x00121100),\n            U32(0x00021008), U32(0x00121008), U32(0x00021108), U32(0x00121108),\n            U32(0x04020000), U32(0x04120000), U32(0x04020100), U32(0x04120100),\n            U32(0x04020008), U32(0x04120008), U32(0x04020108), U32(0x04120108),\n            U32(0x04021000), U32(0x04121000), U32(0x04021100), U32(0x04121100),\n            U32(0x04021008), U32(0x04121008), U32(0x04021108), U32(0x04121108),\n        ],\n\n        # for D bits (numbered as per FIPS 46) 1 2 3 4 5 6\n        [\n            U32(0x00000000), U32(0x10000000), U32(0x00010000), U32(0x10010000),\n            U32(0x00000004), U32(0x10000004), U32(0x00010004), U32(0x10010004),\n            U32(0x20000000), U32(0x30000000), U32(0x20010000), U32(0x30010000),\n            U32(0x20000004), U32(0x30000004), U32(0x20010004), U32(0x30010004),\n            U32(0x00100000), U32(0x10100000), U32(0x00110000), U32(0x10110000),\n            U32(0x00100004), U32(0x10100004), U32(0x00110004), U32(0x10110004),\n            U32(0x20100000), U32(0x30100000), U32(0x20110000), U32(0x30110000),\n            U32(0x20100004), U32(0x30100004), U32(0x20110004), U32(0x30110004),\n            U32(0x00001000), U32(0x10001000), U32(0x00011000), U32(0x10011000),\n            U32(0x00001004), U32(0x10001004), U32(0x00011004), U32(0x10011004),\n            U32(0x20001000), U32(0x30001000), U32(0x20011000), U32(0x30011000),\n            U32(0x20001004), U32(0x30001004), U32(0x20011004), U32(0x30011004),\n            U32(0x00101000), U32(0x10101000), U32(0x00111000), U32(0x10111000),\n            U32(0x00101004), U32(0x10101004), U32(0x00111004), U32(0x10111004),\n            U32(0x20101000), U32(0x30101000), U32(0x20111000), U32(0x30111000),\n            U32(0x20101004), U32(0x30101004), U32(0x20111004), U32(0x30111004),\n        ],\n\n        # for D bits (numbered as per FIPS 46) 8 9 11 12 13 14\n        [\n            U32(0x00000000), U32(0x08000000), U32(0x00000008), U32(0x08000008),\n            U32(0x00000400), U32(0x08000400), U32(0x00000408), U32(0x08000408),\n            U32(0x00020000), U32(0x08020000), U32(0x00020008), U32(0x08020008),\n            U32(0x00020400), U32(0x08020400), U32(0x00020408), U32(0x08020408),\n            U32(0x00000001), U32(0x08000001), U32(0x00000009), U32(0x08000009),\n            U32(0x00000401), U32(0x08000401), U32(0x00000409), U32(0x08000409),\n            U32(0x00020001), U32(0x08020001), U32(0x00020009), U32(0x08020009),\n            U32(0x00020401), U32(0x08020401), U32(0x00020409), U32(0x08020409),\n            U32(0x02000000), U32(0x0A000000), U32(0x02000008), U32(0x0A000008),\n            U32(0x02000400), U32(0x0A000400), U32(0x02000408), U32(0x0A000408),\n            U32(0x02020000), U32(0x0A020000), U32(0x02020008), U32(0x0A020008),\n            U32(0x02020400), U32(0x0A020400), U32(0x02020408), U32(0x0A020408),\n            U32(0x02000001), U32(0x0A000001), U32(0x02000009), U32(0x0A000009),\n            U32(0x02000401), U32(0x0A000401), U32(0x02000409), U32(0x0A000409),\n            U32(0x02020001), U32(0x0A020001), U32(0x02020009), U32(0x0A020009),\n            U32(0x02020401), U32(0x0A020401), U32(0x02020409), U32(0x0A020409),\n        ],\n\n        # for D bits (numbered as per FIPS 46) 16 17 18 19 20 21\n        [\n            U32(0x00000000), U32(0x00000100), U32(0x00080000), U32(0x00080100),\n            U32(0x01000000), U32(0x01000100), U32(0x01080000), U32(0x01080100),\n            U32(0x00000010), U32(0x00000110), U32(0x00080010), U32(0x00080110),\n            U32(0x01000010), U32(0x01000110), U32(0x01080010), U32(0x01080110),\n            U32(0x00200000), U32(0x00200100), U32(0x00280000), U32(0x00280100),\n            U32(0x01200000), U32(0x01200100), U32(0x01280000), U32(0x01280100),\n            U32(0x00200010), U32(0x00200110), U32(0x00280010), U32(0x00280110),\n            U32(0x01200010), U32(0x01200110), U32(0x01280010), U32(0x01280110),\n            U32(0x00000200), U32(0x00000300), U32(0x00080200), U32(0x00080300),\n            U32(0x01000200), U32(0x01000300), U32(0x01080200), U32(0x01080300),\n            U32(0x00000210), U32(0x00000310), U32(0x00080210), U32(0x00080310),\n            U32(0x01000210), U32(0x01000310), U32(0x01080210), U32(0x01080310),\n            U32(0x00200200), U32(0x00200300), U32(0x00280200), U32(0x00280300),\n            U32(0x01200200), U32(0x01200300), U32(0x01280200), U32(0x01280300),\n            U32(0x00200210), U32(0x00200310), U32(0x00280210), U32(0x00280310),\n            U32(0x01200210), U32(0x01200310), U32(0x01280210), U32(0x01280310),\n        ],\n\n        # for D bits (numbered as per FIPS 46) 22 23 24 25 27 28\n        [\n            U32(0x00000000), U32(0x04000000), U32(0x00040000), U32(0x04040000),\n            U32(0x00000002), U32(0x04000002), U32(0x00040002), U32(0x04040002),\n            U32(0x00002000), U32(0x04002000), U32(0x00042000), U32(0x04042000),\n            U32(0x00002002), U32(0x04002002), U32(0x00042002), U32(0x04042002),\n            U32(0x00000020), U32(0x04000020), U32(0x00040020), U32(0x04040020),\n            U32(0x00000022), U32(0x04000022), U32(0x00040022), U32(0x04040022),\n            U32(0x00002020), U32(0x04002020), U32(0x00042020), U32(0x04042020),\n            U32(0x00002022), U32(0x04002022), U32(0x00042022), U32(0x04042022),\n            U32(0x00000800), U32(0x04000800), U32(0x00040800), U32(0x04040800),\n            U32(0x00000802), U32(0x04000802), U32(0x00040802), U32(0x04040802),\n            U32(0x00002800), U32(0x04002800), U32(0x00042800), U32(0x04042800),\n            U32(0x00002802), U32(0x04002802), U32(0x00042802), U32(0x04042802),\n            U32(0x00000820), U32(0x04000820), U32(0x00040820), U32(0x04040820),\n            U32(0x00000822), U32(0x04000822), U32(0x00040822), U32(0x04040822),\n            U32(0x00002820), U32(0x04002820), U32(0x00042820), U32(0x04042820),\n            U32(0x00002822), U32(0x04002822), U32(0x00042822), U32(0x04042822),\n        ]\n\n    ]\n"
  },
  {
    "path": "ntlm_auth/gss_channel_bindings.py",
    "content": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation, either\n# version 3 of the License, or (at your option) any later version.\n\n# This library is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n\n# You should have received a copy of the GNU Lesser General Public\n# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.\n\nimport struct\n\n\"\"\"\n    This is not the easiest structure to understand, ultimately this is a set structure\n    as defined by Microsoft. Channel Binding Tokens set the SHA256 hash of the server\n    certificate to the application_data field and then ultimately creates the MD5 hash\n    to include in the NTLM auth from there. This class is just designed to create the\n    bindings structure which is then used by compute_response.py to do the rest of the\n    work.\n\n    For more infor on how this works and how it is derived, this is a great link;\n    https://blogs.msdn.microsoft.com/openspecification/2013/03/26/ntlm-and-channel-binding-hash-aka-extended-protection-for-authentication/\n\"\"\"\nclass GssChannelBindingsStruct(object):\n    INITIATOR_ADDTYPE = 'initiator_addtype'\n    INITIATOR_ADDRESS_LENGTH = 'initiator_address_length'\n    ACCEPTOR_ADDRTYPE = 'acceptor_addrtype'\n    ACCEPTOR_ADDRESS_LENGTH = 'acceptor_address_length'\n    APPLICATION_DATA_LENGTH = 'application_data_length'\n    INITIATOR_ADDRESS = 'initiator_address'\n    ACCEPTOR_ADDRESS = 'acceptor_address'\n    APPLICATION_DATA = 'application_data'\n\n    def __init__(self):\n        self.fields = {}\n        self.fields[self.INITIATOR_ADDTYPE] = 0\n        self.fields[self.INITIATOR_ADDRESS_LENGTH] = 0\n        self.fields[self.ACCEPTOR_ADDRTYPE] = 0\n        self.fields[self.ACCEPTOR_ADDRESS_LENGTH] = 0\n        self.fields[self.APPLICATION_DATA_LENGTH] = 0\n        self.fields[self.INITIATOR_ADDRESS] = b''\n        self.fields[self.ACCEPTOR_ADDRESS] = b''\n        self.fields[self.APPLICATION_DATA] = b''\n\n    def __setitem__(self, key, value):\n        self.fields[key] = value\n\n    def get_data(self):\n        # Set the lengths of each len field in case they have changed\n        self.fields[self.INITIATOR_ADDRESS_LENGTH] = len(self.fields[self.INITIATOR_ADDRESS])\n        self.fields[self.ACCEPTOR_ADDRESS_LENGTH] = len(self.fields[self.ACCEPTOR_ADDRESS])\n        self.fields[self.APPLICATION_DATA_LENGTH] = len(self.fields[self.APPLICATION_DATA])\n\n        # Add all the values together to create the gss_channel_bindings_struct\n        data = struct.pack('<L', self.fields[self.INITIATOR_ADDTYPE]) + \\\n               struct.pack('<L', self.fields[self.INITIATOR_ADDRESS_LENGTH]) + \\\n               self.fields[self.INITIATOR_ADDRESS] + \\\n               struct.pack('<L', self.fields[self.ACCEPTOR_ADDRTYPE]) + \\\n               struct.pack('<L', self.fields[self.ACCEPTOR_ADDRESS_LENGTH]) + \\\n               self.fields[self.ACCEPTOR_ADDRESS] + \\\n               struct.pack('<L', self.fields[self.APPLICATION_DATA_LENGTH]) + \\\n               self.fields[self.APPLICATION_DATA]\n\n        return data"
  },
  {
    "path": "ntlm_auth/messages.py",
    "content": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation, either\n# version 3 of the License, or (at your option) any later version.\n\n# This library is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n\n# You should have received a copy of the GNU Lesser General Public\n# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.\n\nimport hmac\nimport os\nimport struct\nfrom ntlm_auth.compute_response import ComputeResponse\nfrom ntlm_auth.constants import NegotiateFlags, MessageTypes, NTLM_SIGNATURE, AvFlags\nfrom ntlm_auth.rc4 import ARC4\nfrom ntlm_auth.target_info import TargetInfo\n\nclass NegotiateMessage(object):\n    EXPECTED_BODY_LENGTH = 40\n\n    \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        2.2.1.1 NEGOTIATE_MESSAGE\n        The NEGOTIATE_MESSAGE defines an NTLM Negotiate message that is sent from the client to\n        the server. This message allows the client to specify its supported NTLM options to\n        the server.\n\n        :param negotiate_flags: A NEGOTIATE structure that contains a set of bit flags. These flags are the options the client supports\n        :param domain_name: The domain name of the user to authenticate with, default is None\n        :param workstation: The worksation of the client machine, default is None\n\n        Attributes:\n            signature: An 8-byte character array that MUST contain the ASCII string 'NTLMSSP\\0'\n            message_type: A 32-bit unsigned integer that indicates the message type. This field must be set to 0x00000001\n            negotiate_flags: A NEGOTIATE structure that contains a set of bit flags. These flags are the options the client supports\n            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\n            domain_name: A byte-array that contains the name of the client authentication domain that MUST Be encoded in the negotiated character set\n            workstation: A byte-array that contains the name of the client machine that MUST Be encoded in the negotiated character set\n    \"\"\"\n    def __init__(self, negotiate_flags, domain_name, workstation):\n        self.signature = NTLM_SIGNATURE\n        self.message_type = struct.pack('<L', MessageTypes.NTLM_NEGOTIATE)\n\n        # Check if the domain_name value is set, if it is, make sure the negotiate_flag is also set\n        if domain_name is None:\n            self.domain_name = ''\n        else:\n            self.domain_name = domain_name\n            negotiate_flags |= NegotiateFlags.NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED\n\n        # Check if the workstation value is set, if it is, make sure the negotiate_flag is also set\n        if workstation is None:\n            self.workstation = ''\n        else:\n            self.workstation = workstation\n            negotiate_flags |= NegotiateFlags.NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED\n\n        # Set the encoding flag to use OEM, remove UNICODE if set as it isn't support in this message\n        negotiate_flags -= NegotiateFlags.NTLMSSP_NEGOTIATE_UNICODE\n        negotiate_flags |= NegotiateFlags.NTLMSSP_NEGOTIATE_OEM\n        self.domain_name = self.domain_name.encode('ascii')\n        self.workstation = self.workstation.encode('ascii')\n\n        self.version = get_version(negotiate_flags)\n\n        self.negotiate_flags = struct.pack('<I', negotiate_flags)\n\n    def get_data(self):\n        payload_offset = self.EXPECTED_BODY_LENGTH\n\n        # DomainNameFields - 8 bytes\n        domain_name_len = struct.pack('<H', len(self.domain_name))\n        domain_name_max_len = struct.pack('<H', len(self.domain_name))\n        domain_name_buffer_offset = struct.pack('<I', payload_offset)\n        payload_offset += len(self.domain_name)\n\n        # WorkstationFields - 8 bytes\n        workstation_len = struct.pack('<H', len(self.workstation))\n        workstation_max_len = struct.pack('<H', len(self.workstation))\n        workstation_buffer_offset = struct.pack('<I', payload_offset)\n        payload_offset += len(self.workstation)\n\n        # Payload - variable length\n        payload = self.domain_name\n        payload += self.workstation\n\n        # Bring the header values together into 1 message\n        msg1 = self.signature\n        msg1 += self.message_type\n        msg1 += self.negotiate_flags\n        msg1 += domain_name_len\n        msg1 += domain_name_max_len\n        msg1 += domain_name_buffer_offset\n        msg1 += workstation_len\n        msg1 += workstation_max_len\n        msg1 += workstation_buffer_offset\n        msg1 += self.version\n\n        assert self.EXPECTED_BODY_LENGTH == len(msg1), \"BODY_LENGTH: %d != msg1: %d\" % (self.EXPECTED_BODY_LENGTH, len(msg1))\n\n        # Adding the payload data to the message\n        msg1 += payload\n        return msg1\n\nclass ChallengeMessage(object):\n    \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        2.2.1.2 CHALLENGE_MESSAGE\n        The CHALLENGE_MESSAGE defines an NTLM challenge message that is sent from the server to\n        the client. The CHALLENGE_MESSAGE is used by the server to challenge the client to prove\n        its identity, For connection-oriented requests, the CHALLENGE_MESSAGE generated by the\n        server is in response to the NEGOTIATE_MESSAGE from the client.\n\n        :param msg2: The CHALLENGE_MESSAGE received from the server after sending our NEGOTIATE_MESSAGE. This has\n                        been decoded from a base64 string\n\n        Attributes\n            signature: An 8-byte character array that MUST contain the ASCII string 'NTLMSSP\\0'\n            message_type: A 32-bit unsigned integer that indicates the message type. This field must be set to 0x00000002\n            negotiate_flags: A NEGOTIATE strucutre that contains a set of bit flags. The server sets flags to indicate options it supports\n            server_challenge: A 64-bit value that contains the NTLM challenge. The challenge is a 64-bit nonce. Used in the AuthenticateMessage message\n            reserved: An 8-byte array whose elements MUST be zero when sent and MUST be ignored on receipt\n            version: When NTLMSSP_NEGOTIATE_VERSION flag is set in negotiate_flags field which contains the windows version info. Used only for debugging purposes\n            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\n            target_info: When NTLMSSP_NEGOTIATE_TARGET_INFO is set is a byte array that contains a sequence of AV_PAIR structures (target_info.py)\n    \"\"\"\n    def __init__(self, msg2):\n        self.data = msg2\n        # Setting the object values from the raw_challenge_message\n        self.signature = msg2[0:8]\n        self.message_type = struct.unpack(\"<I\", msg2[8:12])[0]\n        self.negotiate_flags = struct.unpack(\"<I\", msg2[20:24])[0]\n        self.server_challenge = msg2[24:32]\n        self.reserved = msg2[32:40]\n\n        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_VERSION and self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:\n            size = len(msg2)\n            self.version = struct.unpack(\"<q\", msg2[48:56])[0]\n        else:\n            self.version = None\n\n        if self.negotiate_flags & NegotiateFlags.NTLMSSP_REQUEST_TARGET:\n            target_name_len = struct.unpack(\"<H\", msg2[12:14])[0]\n            target_name_max_len = struct.unpack(\"<H\", msg2[14:16])[0]\n            target_name_buffer_offset = struct.unpack(\"<I\", msg2[16:20])[0]\n            self.target_name = msg2[target_name_buffer_offset:target_name_buffer_offset + target_name_len]\n        else:\n            self.target_name = None\n\n        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_TARGET_INFO:\n            target_info_len = struct.unpack(\"<H\", msg2[40:42])[0]\n            target_info_max_len = struct.unpack(\"<H\", msg2[42:44])[0]\n            target_info_buffer_offset = struct.unpack(\"<I\", msg2[44:48])[0]\n\n            target_info_raw = msg2[target_info_buffer_offset:target_info_buffer_offset + target_info_len]\n            self.target_info = TargetInfo(target_info_raw)\n        else:\n            self.target_info = None\n\n        # Verify initial integrity of the message, it matches what should be there\n        assert self.signature == NTLM_SIGNATURE\n        assert self.message_type == MessageTypes.NTLM_CHALLENGE\n\n    def get_data(self):\n        return self.data\n\nclass AuthenticateMessage(object):\n    EXPECTED_BODY_LENGTH = 72\n    EXPECTED_BODY_LENGTH_WITH_MIC = 88\n\n    \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        2.2.1.3 AUTHENTICATE_MESSAGE\n        The AUTHENTICATE_MESSAGE defines an NTLM authenticate message that is sent from the\n        client to the server after the CHALLENGE_MESSAGE is processed by the client.\n\n        :param user_name: The user name of the user we are trying to authenticate with\n        :param password: The password of the user we are trying to authenticate with\n        :param domain_name: The domain name of the user account we are authenticated with, default is None\n        :param workstation: The workstation we are using to authenticate with, default is None\n        :param challenge_message: A ChallengeMessage object that was received from the server after the negotiate_message\n        :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\n        :param server_certificate_hash: The SHA256 hash string of the server certificate (DER encoded) NTLM is authenticating to. This is used to add\n                                          to the gss_channel_bindings_struct for Channel Binding Tokens support. If none is passed through then ntlm-auth\n                                          will not use Channel Binding Tokens when authenticating with the server which could cause issues if it is set to\n                                          only authenticate when these are present. This is only used for NTLMv2 authentication.\n\n        Message Attributes (Attributes not used to compute the message structure):\n            signature: An 8-byte character array that MUST contain the ASCII string 'NTLMSSP\\0'\n            message_type: A 32-bit unsigned integer that indicates the message type. This field must be set to 0x00000003\n            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\n            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\n            mic: The message integrity for the NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE and AUTHENTICATE_MESSAGE\n            lm_challenge_response: An LM_RESPONSE of LMv2_RESPONSE structure that contains the computed LM response to the challenge\n            nt_challenge_response: An NTLM_RESPONSE or NTLMv2_RESPONSE structure that contains the computed NT response to the challenge\n            domain_name: The domain or computer name hosting the user account, MUST be encoded in the negotiated character set\n            user_name: The name of the user to be authenticated, MUST be encoded in the negotiated character set\n            workstation: The name of the computer to which the user is logged on, MUST Be encoded in the negotiated character set\n            encrypted_random_session_key: The client's encrypted random session key\n\n        Non-Message Attributes (Attributes not used to compute the message structure):\n            exported_session_key: A randomly generated session key based on other keys, used to derive the SIGNKEY and SEALKEY\n            target_info: The AV_PAIR structure used in the nt response calculation\n    \"\"\"\n    def __init__(self, user_name, password, nthash, lmhash, domain_name, workstation, challenge_message, ntlm_compatibility, server_certificate_hash):\n        self.signature = NTLM_SIGNATURE\n        self.message_type = struct.pack('<L', MessageTypes.NTLM_AUTHENTICATE)\n        self.negotiate_flags = challenge_message.negotiate_flags\n        self.version = get_version(self.negotiate_flags)\n        self.mic = None\n\n        if domain_name is None:\n            self.domain_name = ''\n        else:\n            self.domain_name = domain_name\n\n        if workstation is None:\n            self.workstation = ''\n        else:\n            self.workstation = workstation\n\n        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_UNICODE:\n            self.negotiate_flags -= NegotiateFlags.NTLMSSP_NEGOTIATE_OEM\n            encoding_value = 'utf-16-le'\n        else:\n            encoding_value = 'ascii'\n\n        self.domain_name = self.domain_name.encode(encoding_value)\n        self.user_name = user_name.encode(encoding_value)\n        self.workstation = self.workstation.encode(encoding_value)\n\n        compute_response = ComputeResponse(user_name, password, nthash, lmhash, domain_name, challenge_message,\n                                           ntlm_compatibility)\n\n        self.lm_challenge_response = compute_response.get_lm_challenge_response()\n        self.nt_challenge_response, key_exchange_key, target_info = compute_response.get_nt_challenge_response(\n            self.lm_challenge_response, server_certificate_hash)\n        self.target_info = target_info\n\n        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_KEY_EXCH:\n            self.exported_session_key = get_random_export_session_key()\n\n            rc4_handle = ARC4(key_exchange_key)\n            self.encrypted_random_session_key = rc4_handle.update(self.exported_session_key)\n        else:\n            self.exported_session_key = key_exchange_key\n            self.encrypted_random_session_key = b''\n\n        self.negotiate_flags = struct.pack('<I', self.negotiate_flags)\n\n    def get_data(self):\n        if self.mic is None:\n            mic = b''\n            expected_body_length = self.EXPECTED_BODY_LENGTH\n        else:\n            mic = self.mic\n            expected_body_length = self.EXPECTED_BODY_LENGTH_WITH_MIC\n\n        payload_offset = expected_body_length\n\n        # DomainNameFields - 8 bytes\n        domain_name_len = struct.pack('<H', len(self.domain_name))\n        domain_name_max_len = struct.pack('<H', len(self.domain_name))\n        domain_name_buffer_offset = struct.pack('<I', payload_offset)\n        payload_offset += len(self.domain_name)\n\n        # UserNameFields - 8 bytes\n        user_name_len = struct.pack('<H', len(self.user_name))\n        user_name_max_len = struct.pack('<H', len(self.user_name))\n        user_name_buffer_offset = struct.pack('<I', payload_offset)\n        payload_offset += len(self.user_name)\n\n        # WorkstatonFields - 8 bytes\n        workstation_len = struct.pack('<H', len(self.workstation))\n        workstation_max_len = struct.pack('<H', len(self.workstation))\n        workstation_buffer_offset = struct.pack('<I', payload_offset)\n        payload_offset += len(self.workstation)\n\n        # LmChallengeResponseFields - 8 bytes\n        lm_challenge_response_len = struct.pack('<H', len(self.lm_challenge_response))\n        lm_challenge_response_max_len = struct.pack('<H', len(self.lm_challenge_response))\n        lm_challenge_response_buffer_offset = struct.pack('<I', payload_offset)\n        payload_offset += len(self.lm_challenge_response)\n\n        # NtChallengeResponseFields - 8 bytes\n        nt_challenge_response_len = struct.pack('<H', len(self.nt_challenge_response))\n        nt_challenge_response_max_len = struct.pack('<H', len(self.nt_challenge_response))\n        nt_challenge_response_buffer_offset = struct.pack('<I', payload_offset)\n        payload_offset += len(self.nt_challenge_response)\n\n        # EncryptedRandomSessionKeyFields - 8 bytes\n        encrypted_random_session_key_len = struct.pack('<H', len(self.encrypted_random_session_key))\n        encrypted_random_session_key_max_len = struct.pack('<H', len(self.encrypted_random_session_key))\n        encrypted_random_session_key_buffer_offset = struct.pack('<I', payload_offset)\n        payload_offset += len(self.encrypted_random_session_key)\n\n        # Payload - variable length\n        payload = self.domain_name\n        payload += self.user_name\n        payload += self.workstation\n        payload += self.lm_challenge_response\n        payload += self.nt_challenge_response\n        payload += self.encrypted_random_session_key\n\n        msg3 = self.signature\n        msg3 += self.message_type\n        msg3 += lm_challenge_response_len + lm_challenge_response_max_len + lm_challenge_response_buffer_offset\n        msg3 += nt_challenge_response_len + nt_challenge_response_max_len + nt_challenge_response_buffer_offset\n        msg3 += domain_name_len + domain_name_max_len + domain_name_buffer_offset\n        msg3 += user_name_len + user_name_max_len + user_name_buffer_offset\n        msg3 += workstation_len + workstation_max_len + workstation_buffer_offset\n        msg3 += encrypted_random_session_key_len + encrypted_random_session_key_max_len + encrypted_random_session_key_buffer_offset\n        msg3 += self.negotiate_flags\n        msg3 += self.version\n        msg3 += mic\n\n        # Adding the payload data to the message\n        msg3 += payload\n\n        return msg3\n\n    def add_mic(self, negotiate_message, challenge_message):\n        if self.target_info is not None:\n            av_flags = self.target_info[TargetInfo.MSV_AV_FLAGS]\n\n            if av_flags is not None and av_flags[1] == struct.pack(\"<L\", AvFlags.MIC_PROVIDED):\n                self.mic = struct.pack(\"<IIII\", 0, 0, 0, 0)\n                negotiate_data = negotiate_message.get_data()\n                challenge_data = challenge_message.get_data()\n                authenticate_data = self.get_data()\n\n                mic = hmac.new(self.exported_session_key,\n                               (negotiate_data + challenge_data + authenticate_data)).digest()\n                self.mic = mic\n\ndef get_version(negotiate_flags):\n    # Check the negotiate_flag version is set, if it is make sure the version info is added to the data\n    if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_VERSION:\n        # TODO: Get the major and minor version of Windows instead of using default values\n        product_major_version = struct.pack('<B', 6)\n        product_minor_version = struct.pack('<B', 1)\n        product_build = struct.pack('<H', 7601)\n        version_reserved = b'\\0' * 3\n        ntlm_revision_current = struct.pack('<B', 15)\n        version = product_major_version + product_minor_version + product_build + version_reserved + ntlm_revision_current\n    else:\n        version = b'\\0' * 8\n\n    return version\n\ndef get_random_export_session_key():\n    return os.urandom(16)\n"
  },
  {
    "path": "ntlm_auth/ntlm.py",
    "content": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation, either\n# version 3 of the License, or (at your option) any later version.\n\n# This library is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n\n# You should have received a copy of the GNU Lesser General Public\n# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.\n\nimport base64\nimport socket\nimport struct\nfrom ntlm_auth.constants import NegotiateFlags\nfrom ntlm_auth.messages import NegotiateMessage, ChallengeMessage, AuthenticateMessage\nfrom ntlm_auth.session_security import SessionSecurity\n\n\n\"\"\"\nutility functions for Microsoft NTLM authentication\n\nReferences:\n[MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol Specification\nhttp://download.microsoft.com/download/a/e/6/ae6e4142-aa58-45c6-8dcf-a657e5900cd3/%5BMS-NLMP%5D.pdf\n\n[MS-NTHT]: NTLM Over HTTP Protocol Specification\nhttp://download.microsoft.com/download/a/e/6/ae6e4142-aa58-45c6-8dcf-a657e5900cd3/%5BMS-NTHT%5D.pdf\n\nCntlm Authentication Proxy\nhttp://cntlm.awk.cz/\n\nNTLM Authorization Proxy Server\nhttp://sourceforge.net/projects/ntlmaps/\n\nOptimized Attack for NTLM2 Session Response\nhttp://www.blackhat.com/presentations/bh-asia-04/bh-jp-04-pdfs/bh-jp-04-seki.pdf\n\"\"\"\n\nclass Ntlm(object):\n    \"\"\"\n    Initialises the NTLM context to use when sending and receiving messages to and from the server. You should be\n    using this object as it supports NTLMv2 authenticate and it easier to use than before. It also brings in the\n    ability to use signing and sealing with session_security and generate a MIC structure.\n\n    :param ntlm_compatibility: The Lan Manager Compatibility Level to use withe the auth message - Default 3\n                                This is set by an Administrator in the registry key\n                                'HKLM\\SYSTEM\\CurrentControlSet\\Control\\Lsa\\LmCompatibilityLevel'\n                                The values correspond to the following;\n                                    0 : LM and NTLMv1\n                                    1 : LM, NTLMv1 and NTLMv1 with Extended Session Security\n                                    2 : NTLMv1 and NTLMv1 with Extended Session Security\n                                    3-5 : NTLMv2 Only\n                                Note: Values 3 to 5 are no different as the client supports the same types\n\n    Attributes:\n        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\n        ntlm_compatibility: The Lan Manager Compatibility Level, same as the input if supplied\n        negotiate_message: A NegotiateMessage object that is sent to the server\n        challenge_message: A ChallengeMessage object that has been created from the server response\n        authenticate_message: An AuthenticateMessage object that is sent to the server based on the ChallengeMessage\n        session_security: A SessionSecurity structure that can be used to sign and seal messages sent after the authentication challenge\n    \"\"\"\n    def __init__(self, ntlm_compatibility=3):\n        self.ntlm_compatibility = ntlm_compatibility\n\n        # Setting up our flags so the challenge message returns the target info block if supported\n        self.negotiate_flags = NegotiateFlags.NTLMSSP_NEGOTIATE_TARGET_INFO | \\\n                               NegotiateFlags.NTLMSSP_NEGOTIATE_128 | \\\n                               NegotiateFlags.NTLMSSP_NEGOTIATE_56 | \\\n                               NegotiateFlags.NTLMSSP_NEGOTIATE_UNICODE | \\\n                               NegotiateFlags.NTLMSSP_NEGOTIATE_VERSION | \\\n                               NegotiateFlags.NTLMSSP_NEGOTIATE_KEY_EXCH | \\\n                               NegotiateFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \\\n                               NegotiateFlags.NTLMSSP_NEGOTIATE_SIGN | \\\n                               NegotiateFlags.NTLMSSP_NEGOTIATE_SEAL\n\n        # Setting the message types based on the ntlm_compatibility level\n        self._set_ntlm_compatibility_flags(self.ntlm_compatibility)\n\n        self.negotiate_message = None\n        self.challenge_message = None\n        self.authenticate_message = None\n        self.session_security = None\n\n\n    def create_negotiate_message(self, domain_name=None, workstation=None):\n        \"\"\"\n        Create an NTLM NEGOTIATE_MESSAGE\n\n        :param domain_name: The domain name of the user account we are authenticating with, default is None\n        :param worksation: The workstation we are using to authenticate with, default is None\n        :return: A base64 encoded string of the NEGOTIATE_MESSAGE\n        \"\"\"\n        self.negotiate_message = NegotiateMessage(self.negotiate_flags, domain_name, workstation)\n\n        return base64.b64encode(self.negotiate_message.get_data())\n\n    def parse_challenge_message(self, msg2):\n        \"\"\"\n        Parse the NTLM CHALLENGE_MESSAGE from the server and add it to the Ntlm context fields\n\n        :param msg2: A base64 encoded string of the CHALLENGE_MESSAGE\n        \"\"\"\n        msg2 = base64.b64decode(msg2)\n        self.challenge_message = ChallengeMessage(msg2)\n\n    def create_authenticate_message(self, user_name, password=None, nthash=None, lmhash=None, domain_name=None, workstation=None, server_certificate_hash=None):\n        \"\"\"\n        Create an NTLM AUTHENTICATE_MESSAGE based on the Ntlm context and the previous messages sent and received\n\n        :param user_name: The user name of the user we are trying to authenticate with\n        :param password: The password of the user we are trying to authenticate with\n        :param domain_name: The domain name of the user account we are authenticated with, default is None\n        :param workstation: The workstation we are using to authenticate with, default is None\n        :param server_certificate_hash: The SHA256 hash string of the server certificate (DER encoded) NTLM is authenticating to. Used for Channel\n                                        Binding Tokens. If nothing is supplied then the CBT hash will not be sent. See messages.py AuthenticateMessage\n                                        for more details\n        :return: A base64 encoded string of the AUTHENTICATE_MESSAGE\n        \"\"\"\n        self.authenticate_message = AuthenticateMessage(user_name, password, nthash, lmhash, domain_name, workstation,\n                                                        self.challenge_message, self.ntlm_compatibility,\n                                                        server_certificate_hash)\n        self.authenticate_message.add_mic(self.negotiate_message, self.challenge_message)\n\n        # Setups up the session_security context used to sign and seal messages if wanted\n        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SEAL or self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SIGN:\n            self.session_security = SessionSecurity(struct.unpack(\"<I\", self.authenticate_message.negotiate_flags)[0],\n                                                    self.authenticate_message.exported_session_key)\n\n        return base64.b64encode(self.authenticate_message.get_data())\n\n    def _set_ntlm_compatibility_flags(self, ntlm_compatibility):\n        if (ntlm_compatibility >= 0) and (ntlm_compatibility <= 5):\n            if ntlm_compatibility == 0:\n                self.negotiate_flags |= NegotiateFlags.NTLMSSP_NEGOTIATE_NTLM | \\\n                                        NegotiateFlags.NTLMSSP_NEGOTIATE_LM_KEY\n            elif ntlm_compatibility == 1:\n                self.negotiate_flags |= NegotiateFlags.NTLMSSP_NEGOTIATE_NTLM | \\\n                                        NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY\n            else:\n                self.negotiate_flags |= NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY\n        else:\n            raise Exception(\"Unknown ntlm_compatibility level - expecting value between 0 and 5\")\n"
  },
  {
    "path": "ntlm_auth/rc4.py",
    "content": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation, either\n# version 3 of the License, or (at your option) any later version.\n\n# This library is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n\n# You should have received a copy of the GNU Lesser General Public\n# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.\n\nclass ARC4(object):\n    state = None\n    i = 0\n    j = 0\n\n    def __init__(self, key):\n        # Split up the key into a list\n        if isinstance(key, str):\n            key = [ord(c) for c in key]\n        else:\n            key = [c for c in key]\n\n        #Key-scheduling algorithm (KSA)\n        self.state = [n for n in range(256)]\n        j = 0\n        for i in range(256):\n            j = (j + self.state[i] + key[i % len(key)]) % 256\n            self.state[i], self.state[j] = self.state[j], self.state[i]\n\n    def update(self, value):\n        chars = []\n        random_gen = self._random_generator()\n        for char in value:\n            if isinstance(value, str):\n                byte = ord(char)\n            else:\n                byte = char\n            updated_byte = byte ^ next(random_gen)\n            chars.append(updated_byte)\n        return bytes(bytearray(chars))\n\n    def _random_generator(self):\n        #Pseudo-Random Generation Algorithm (PRGA)\n        while True:\n            self.i = (self.i + 1) % 256\n            self.j = (self.j + self.state[self.i]) % 256\n            self.state[self.i], self.state[self.j] = self.state[self.j], self.state[self.i]\n            yield self.state[(self.state[self.i] + self.state[self.j]) % 256]\n"
  },
  {
    "path": "ntlm_auth/session_security.py",
    "content": "# This library is free software: you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation, either\n# version 3 of the License, or (at your option) any later version.\n\n# This library is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n\n# You should have received a copy of the GNU Lesser General Public\n# License along with this library.  If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.\n\nimport binascii\nimport hmac\nimport struct\nimport ntlm_auth.compute_keys as compkeys\nfrom ntlm_auth.constants import NegotiateFlags, SignSealConstants\nfrom ntlm_auth.rc4 import ARC4\n\n\nclass _NtlmMessageSignature1(object):\n    EXPECTED_BODY_LENGTH = 16\n\n    \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        2.2.2.9.1 NTLMSSP_MESSAGE_SIGNATURE\n        This version of the NTLMSSP_MESSAGE_SIGNATURE structure MUST be used when the\n        NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is not negotiated.\n\n        :param random_pad: A 4-byte array that contains the random pad for the emssage\n        :param checksum: A 4-byte array that contains the checksum for the message\n        :param seq_num: A 32-bit unsigned integer that contains the NTLM sequence number for this application message\n    \"\"\"\n    def __init__(self, random_pad, checksum, seq_num):\n        self.version = struct.pack(\"<I\", 1)\n        self.random_pad = random_pad\n        self.checksum = checksum\n        self.seq_num = seq_num\n\n    def get_data(self):\n        signature = self.version\n        signature += self.random_pad\n        signature += self.checksum\n        signature += self.seq_num\n\n        assert self.EXPECTED_BODY_LENGTH == len(signature), \"BODY_LENGTH: %d != signature: %d\" % (\n        self.EXPECTED_BODY_LENGTH, len(signature))\n\n        return signature\n\nclass _NtlmMessageSignature2(object):\n    EXPECTED_BODY_LENGTH = 16\n\n    \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        2.2.2.9.2 NTLMSSP_MESSAGE_SIGNATURE for Extended Session Security\n        This version of the NTLMSSP_MESSAGE_SIGNATURE structure MUST be used when the\n        NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is negotiated\n\n        :param checksum: An 8-byte array that contains the checksum for the message\n        :param seq_num: A 32-bit unsigned integer that contains the NTLM sequence number for this application message\n    \"\"\"\n\n    def __init__(self, checksum, seq_num):\n        self.version = struct.pack(\"<I\", 1)\n        self.checksum = checksum\n        self.seq_num = seq_num\n\n    def get_data(self):\n        signature = self.version\n        signature += self.checksum\n        signature += self.seq_num\n\n        assert self.EXPECTED_BODY_LENGTH == len(signature), \"BODY_LENGTH: %d != signature: %d\" % (\n            self.EXPECTED_BODY_LENGTH, len(signature))\n\n        return signature\n\nclass SessionSecurity(object):\n    \"\"\"\n    Initialises a security session context that can be used by libraries that call ntlm-auth to sign and seal\n    messages send to the server as well as verify and unseal messages that have been received from the server.\n    This is similar to the GSS_Wrap functions specified in the MS-NLMP document which does the same task.\n\n    :param negotiate_flags: The negotiate flag structure that has been negotiated with the server\n    :param exported_session_key: A 128-bit session key used to derive signing and sealing keys\n    :param source: The source of the message, only used in test scenarios when testing out a server sealing and unsealing\n    \"\"\"\n    def __init__(self, negotiate_flags, exported_session_key, source=\"client\"):\n        self.negotiate_flags = negotiate_flags\n        self.outgoing_seq_num = 0\n        self.incoming_seq_num = 0\n\n        client_sealing_key = compkeys.get_seal_key(self.negotiate_flags, exported_session_key, SignSealConstants.CLIENT_SEALING)\n        server_sealing_key = compkeys.get_seal_key(self.negotiate_flags, exported_session_key, SignSealConstants.SERVER_SEALING)\n\n        if source == \"client\":\n            self.outgoing_signing_key = compkeys.get_sign_key(exported_session_key, SignSealConstants.CLIENT_SIGNING)\n            self.incoming_signing_key = compkeys.get_sign_key(exported_session_key, SignSealConstants.SERVER_SIGNING)\n            self.outgoing_handle = ARC4(client_sealing_key)\n            self.incoming_handle = ARC4(server_sealing_key)\n        elif source == \"server\":\n            self.outgoing_signing_key = compkeys.get_sign_key(exported_session_key, SignSealConstants.SERVER_SIGNING)\n            self.incoming_signing_key = compkeys.get_sign_key(exported_session_key, SignSealConstants.CLIENT_SIGNING)\n            self.outgoing_handle = ARC4(server_sealing_key)\n            self.incoming_handle = ARC4(client_sealing_key)\n        else:\n            raise Exception(\"Invalid source parameter %s, must be client or server\" % source)\n\n    def wrap(self, message):\n        \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        3.4.6 GSS_WrapEx()\n        Emulates the GSS_Wrap() implementation to sign and seal messages if the correct flags\n        are set.\n\n        @param message: The message data that will be wrapped\n        @return message: The message that has been sealed if flags are set\n        @return signature: The signature of the message, None if flags are not set\n        \"\"\"\n        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SEAL:\n            encrypted_message = self._seal_message(message)\n            signature = self._get_signature(message)\n            message = encrypted_message\n\n        elif self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SIGN:\n            signature = self._get_signature(message)\n        else:\n            signature = None\n\n        return message, signature\n\n    def unwrap(self, message, signature):\n        \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        3.4.7 GSS_UnwrapEx()\n        Emulates the GSS_Unwrap() implementation to unseal messages and verify the signature\n        sent matches what has been computed locally. Will throw an Exception if the signature\n        doesn't match\n\n        @param message: The message data received from the server\n        @param signature: The signature of the message\n        @return message: The message that has been unsealed if flags are set\n        \"\"\"\n        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SEAL:\n            message = self._unseal_message(message)\n            self._verify_signature(message, signature)\n\n        elif self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SIGN:\n            self._verify_signature(message, signature)\n\n        return message\n\n    def _seal_message(self, message):\n        \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        3.4.3 Message Confidentiality\n        Will generate an encrypted message using RC4 based on the ClientSealingKey\n\n        @param message: The message to be sealed (encrypted)\n        @return encrypted_message: The encrypted message\n        \"\"\"\n        encrypted_message = self.outgoing_handle.update(message)\n        return encrypted_message\n\n    def _unseal_message(self, message):\n        \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        3.4.3 Message Confidentiality\n        Will generate a dencrypted message using RC4 based on the ServerSealingKey\n\n        @param message: The message to be unsealed (dencrypted)\n        @return decrypted_message: The decrypted message\n        \"\"\"\n        decrypted_message = self.incoming_handle.update(message)\n        return decrypted_message\n\n    def _get_signature(self, message):\n        \"\"\"\n        [MS-NLMP] v28.0 2016-07-14\n\n        3.4.4 Message Signature Functions\n        Will create the signature based on the message to send to the server. Depending on the negotiate_flags\n        set this could either be an NTLMv1 signature or NTLMv2 with Extended Session Security signature.\n\n        @param message: The message data that will be signed\n        @return signature: Either _NtlmMessageSignature1 or _NtlmMessageSignature2 depending on the flags set\n        \"\"\"\n        signature = calc_signature(message, self.negotiate_flags, self.outgoing_signing_key, self.outgoing_seq_num, self.outgoing_handle)\n        self.outgoing_seq_num += 1\n\n        return signature.get_data()\n\n    def _verify_signature(self, message, signature):\n        \"\"\"\n        Will verify that the signature received from the server matches up with the expected signature\n        computed locally. Will throw an exception if they do not match\n\n        @param message: The message data that is received from the server\n        @param signature: The signature of the message received from the server\n        \"\"\"\n        if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:\n            actual_checksum = signature[4:12]\n            actual_seq_num = struct.unpack(\"<I\", signature[12:16])[0]\n        else:\n            actual_checksum = signature[8:12]\n            actual_seq_num = struct.unpack(\"<I\", signature[12:16])[0]\n\n        expected_signature = calc_signature(message, self.negotiate_flags, self.incoming_signing_key, self.incoming_seq_num, self.incoming_handle)\n        expected_checksum = expected_signature.checksum\n        expected_seq_num = struct.unpack(\"<I\", expected_signature.seq_num)[0]\n\n        if actual_checksum != expected_checksum:\n            raise Exception(\"The signature checksum does not match, message has been altered\")\n\n        if actual_seq_num != expected_seq_num:\n            raise Exception(\"The signature sequence number does not match up, message not received in the correct sequence\")\n\n        self.incoming_seq_num += 1\n\n\ndef calc_signature(message, negotiate_flags, signing_key, seq_num, handle):\n    seq_num = struct.pack(\"<I\", seq_num)\n    if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:\n        checksum_hmac = hmac.new(signing_key, seq_num + message)\n        if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_KEY_EXCH:\n            checksum = handle.update(checksum_hmac.digest()[:8])\n        else:\n            checksum = checksum_hmac.digest()[:8]\n\n        signature = _NtlmMessageSignature2(checksum, seq_num)\n\n    else:\n        message_crc = binascii.crc32(message) % (1 << 32)\n        checksum = struct.pack(\"<I\", message_crc)\n        random_pad = handle.update(struct.pack(\"<I\", 0))\n        checksum = handle.update(checksum)\n        seq_num = handle.update(seq_num)\n        random_pad = struct.pack(\"<I\", 0)\n\n        signature = _NtlmMessageSignature1(random_pad, checksum, seq_num)\n\n    return signature\n"
  },
  {
    "path": "ntlm_auth/target_info.py",
    "content": "\"\"\"\n    Original Author: Ian Clegg\n    Project: ntlmlib\n    URL: https://github.com/ianclegg/ntlmlib\n    License: Apache 2.0 License\n    Notes: Most of this code has been copied from the messages.py in the ntlmlib repo.\n    Some minor changes such as the name of the AV Pairs and extra comments have been added.\n\"\"\"\n\nimport struct\ntry:\n    from collections import OrderedDict\nexcept ImportError:\n    from ordereddict import OrderedDict\n\nclass TargetInfo(object):\n    MSV_AV_EOL                  = 0x00\n    MSV_AV_NB_COMPUTER_NAME     = 0x01\n    MSV_AV_NB_DOMAIN_NAME       = 0x02\n    MSV_AV_DNS_COMPUTER_NAME    = 0x03\n    MSV_AV_DNS_DOMAIN_NAME      = 0x04\n    MSV_AV_DNS_TREE_NAME        = 0x05\n    MSV_AV_FLAGS                = 0x06\n    MSV_AV_TIMESTAMP            = 0x07\n    MSV_AV_SINGLE_HOST          = 0x08\n    MSV_AV_TARGET_NAME          = 0x09\n    MSV_AV_CHANNEL_BINDINGS     = 0x0a\n\n    def __init__(self, data=None):\n        self.fields = OrderedDict()\n        if data is not None:\n            self.from_string(data)\n\n    def __setitem__(self, key, value):\n        self.fields[key] = (len(value), value)\n\n    def __getitem__(self, key):\n        if key in self.fields:\n           return self.fields[key]\n        return None\n\n    def __delitem__(self, key):\n        del self.fields[key]\n\n    def from_string(self, data):\n        attribute_type = 0xff\n        while attribute_type is not TargetInfo.MSV_AV_EOL:\n            # Parse the Attribute Value pair from the structure\n            attribute_type = struct.unpack('<H', data[:struct.calcsize('<H')])[0]\n            data = data[struct.calcsize('<H'):]\n            length = struct.unpack('<H', data[:struct.calcsize('<H')])[0]\n            data = data[struct.calcsize('<H'):]\n            # Add a new field to the object for the parse attribute value\n            self.fields[attribute_type] = (length, data[:length])\n            data = data[length:]\n\n    def get_data(self):\n        if TargetInfo.MSV_AV_EOL in self.fields:\n            del self.fields[TargetInfo.MSV_AV_EOL]\n\n        data = b''\n        for i in self.fields.keys():\n            data += struct.pack('<HH', i, self[i][0])\n            data += self[i][1]\n\n        # end with a NTLMSSP_AV_EOL\n        data += struct.pack('<HH', TargetInfo.MSV_AV_EOL, 0)\n        return data"
  },
  {
    "path": "ordereddict.py",
    "content": "# Copyright (c) 2009 Raymond Hettinger\r\n#\r\n# Permission is hereby granted, free of charge, to any person\r\n# obtaining a copy of this software and associated documentation files\r\n# (the \"Software\"), to deal in the Software without restriction,\r\n# including without limitation the rights to use, copy, modify, merge,\r\n# publish, distribute, sublicense, and/or sell copies of the Software,\r\n# and to permit persons to whom the Software is furnished to do so,\r\n# subject to the following conditions:\r\n#\r\n#     The above copyright notice and this permission notice shall be\r\n#     included in all copies or substantial portions of the Software.\r\n#\r\n#     THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n#     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\r\n#     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r\n#     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\r\n#     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r\n#     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r\n#     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\r\n#     OTHER DEALINGS IN THE SOFTWARE.\r\n\r\nfrom UserDict import DictMixin\r\n\r\nclass OrderedDict(dict, DictMixin):\r\n\r\n    def __init__(self, *args, **kwds):\r\n        if len(args) > 1:\r\n            raise TypeError('expected at most 1 arguments, got %d' % len(args))\r\n        try:\r\n            self.__end\r\n        except AttributeError:\r\n            self.clear()\r\n        self.update(*args, **kwds)\r\n\r\n    def clear(self):\r\n        self.__end = end = []\r\n        end += [None, end, end]         # sentinel node for doubly linked list\r\n        self.__map = {}                 # key --> [key, prev, next]\r\n        dict.clear(self)\r\n\r\n    def __setitem__(self, key, value):\r\n        if key not in self:\r\n            end = self.__end\r\n            curr = end[1]\r\n            curr[2] = end[1] = self.__map[key] = [key, curr, end]\r\n        dict.__setitem__(self, key, value)\r\n\r\n    def __delitem__(self, key):\r\n        dict.__delitem__(self, key)\r\n        key, prev, next = self.__map.pop(key)\r\n        prev[2] = next\r\n        next[1] = prev\r\n\r\n    def __iter__(self):\r\n        end = self.__end\r\n        curr = end[2]\r\n        while curr is not end:\r\n            yield curr[0]\r\n            curr = curr[2]\r\n\r\n    def __reversed__(self):\r\n        end = self.__end\r\n        curr = end[1]\r\n        while curr is not end:\r\n            yield curr[0]\r\n            curr = curr[1]\r\n\r\n    def popitem(self, last=True):\r\n        if not self:\r\n            raise KeyError('dictionary is empty')\r\n        if last:\r\n            key = reversed(self).next()\r\n        else:\r\n            key = iter(self).next()\r\n        value = self.pop(key)\r\n        return key, value\r\n\r\n    def __reduce__(self):\r\n        items = [[k, self[k]] for k in self]\r\n        tmp = self.__map, self.__end\r\n        del self.__map, self.__end\r\n        inst_dict = vars(self).copy()\r\n        self.__map, self.__end = tmp\r\n        if inst_dict:\r\n            return (self.__class__, (items,), inst_dict)\r\n        return self.__class__, (items,)\r\n\r\n    def keys(self):\r\n        return list(self)\r\n\r\n    setdefault = DictMixin.setdefault\r\n    update = DictMixin.update\r\n    pop = DictMixin.pop\r\n    values = DictMixin.values\r\n    items = DictMixin.items\r\n    iterkeys = DictMixin.iterkeys\r\n    itervalues = DictMixin.itervalues\r\n    iteritems = DictMixin.iteritems\r\n\r\n    def __repr__(self):\r\n        if not self:\r\n            return '%s()' % (self.__class__.__name__,)\r\n        return '%s(%r)' % (self.__class__.__name__, self.items())\r\n\r\n    def copy(self):\r\n        return self.__class__(self)\r\n\r\n    @classmethod\r\n    def fromkeys(cls, iterable, value=None):\r\n        d = cls()\r\n        for key in iterable:\r\n            d[key] = value\r\n        return d\r\n\r\n    def __eq__(self, other):\r\n        if isinstance(other, OrderedDict):\r\n            if len(self) != len(other):\r\n                return False\r\n            for p, q in  zip(self.items(), other.items()):\r\n                if p != q:\r\n                    return False\r\n            return True\r\n        return dict.__eq__(self, other)\r\n\r\n    def __ne__(self, other):\r\n        return not self == other\r\n"
  },
  {
    "path": "relay.py",
    "content": "import time\nimport socket\n\n\nbuffer_size = 4096\ndelay = 0.0001\nsocks_server_reply_success = '\\x00\\x5a\\xff\\xff\\xff\\xff\\xff\\xff'\nsocks_server_reply_fail = '\\x00\\x5b\\xff\\xff\\xff\\xff\\xff\\xff'\nrelay_timeout = 60\nbanner = 'RPIVOT'\nbanner_response = 'TUNNELRDY'\n\nCOMMAND_CHANNEL = 0\n\nCHANNEL_CLOSE_CMD = '\\xcc'\nCHANNEL_OPEN_CMD = '\\xdd'\nFORWARD_CONNECTION_SUCCESS = '\\xee'\nFORWARD_CONNECTION_FAILURE = '\\xff'\nCLOSE_RELAY = '\\xc4'\nPING_CMD = '\\x70'\n\ncmd_names = {\n    '\\xcc': 'CHANNEL_CLOSE_CMD',\n    '\\xdd': 'CHANNEL_OPEN_CMD',\n    '\\xee': 'FORWARD_CONNECTION_SUCCESS',\n    '\\xff': 'FORWARD_CONNECTION_FAILURE',\n    '\\xc4': 'CLOSE_RELAY',\n    '\\x70': 'PING_CMD'\n}\n\n\nclass ClosedSocket(Exception):\n    pass\n\n\nclass RelayError(Exception):\n    pass\n\n\ndef recvall(sock, data_len):\n    buf = ''\n    while True:\n        buf += sock.recv(data_len - len(buf))\n        if len(buf) == data_len:\n            break\n        time.sleep(delay)\n    assert(data_len == len(buf))\n    return buf\n\n\ndef close_sockets(sockets):\n    for s in sockets:\n        try:\n            s.close()\n        except socket.error:\n            pass\n"
  },
  {
    "path": "server.py",
    "content": "#!/usr/bin/env python\n\nimport logging\nimport logging.handlers\nimport socket\nimport select\nimport sys\nimport time\nfrom struct import pack, unpack\nimport struct\nimport random\nimport errno\nimport relay\nimport threading\nimport optparse\n\nclass RelayServer:\n    def __init__(self, host, port, socket_with_server):\n        self.input_list = []\n        self.channel = {}\n        self.last_ping_time = time.time()\n        self.id_by_socket = {}\n        self.pending_socks_clients = []\n        self.socket_with_server = socket_with_server\n        self.input_list.append(self.socket_with_server)\n        self.remote_side_down = False\n\n        logger.debug('Starting ping thread')\n\n        self.ping_thread = threading.Thread(target=self.ping_worker)\n        self.ping_thread.start()\n\n        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n        self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n\n        try:\n            self.server.bind((host, port))\n            self.server.listen(2000)\n        except socket.error as (code, msg):\n            logger.error('Error binding socks proxy. {0}'.format(msg))\n            logger.error('Closing relay')\n            socket_with_server.close()\n            raise\n        self.socks_client_socket = None\n\n    def ping_worker(self):\n        while True:\n            time.sleep(10)\n            current_time = time.time()\n            if self.remote_side_down:\n                logger.debug('Remote side down. Ping worker exiting')\n                return\n            if current_time - self.last_ping_time > relay.relay_timeout:\n                logger.info('No response from remote side for {0} seconds. Restarting relay'.format(relay.relay_timeout))\n                self.socket_with_server.close()\n                return\n            logger.debug('Sending ping')\n            try:\n                self.send_remote_cmd(self.socket_with_server, relay.PING_CMD)\n            except socket.error as (code, msg):\n                logger.debug('Ping thread got socket exception {0} {1}. Closing socket with remote side'.format(code, msg))\n                self.socket_with_server.close()\n                return\n            except relay.RelayError:\n                logger.debug('Ping worker caught RelayError. Exiting')\n                self.shutdown()\n                return\n\n    def shutdown(self):\n        relay.close_sockets(self.input_list)\n        self.remote_side_down = True\n\n\n    def main_loop(self):\n        self.input_list.append(self.server)\n        while True:\n            time.sleep(relay.delay)\n\n            try:\n                logger.debug(\"Active channels: {0}\".format(self.channel.keys()))\n                inputready, outputready, exceptready = select.select(self.input_list, [], [])\n            except socket.error as (code, msg):\n                logger.debug('Socket error on select. Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))\n                return\n            except KeyboardInterrupt:\n                logger.info('SIGINT received. Closing relay and exiting')\n                self.shutdown()\n                sys.exit(1)\n            for self.selected_input_socket in inputready:\n                if self.selected_input_socket == self.server:\n                    self.on_accept()\n                    break\n\n                if self.selected_input_socket == self.socket_with_server:\n                    try:\n                        self.manage_remote_socket(self.selected_input_socket)\n                    except relay.RelayError:\n                        logger.debug('Main loop: got RelayError. Closing connection with remote side and exiting loop')\n                        self.shutdown()\n                        return\n                elif self.selected_input_socket in self.pending_socks_clients:\n                    self.pending_socks_clients.remove(self.selected_input_socket)\n                    try:\n                        ip, port = self.handle_new_socks_connection(self.selected_input_socket)\n                    except relay.RelayError:\n                        logger.debug(\"Closing socks client socket {0}\".format(self.selected_input_socket))\n                        self.input_list.remove(self.selected_input_socket)\n                        self.selected_input_socket.close()\n                        continue\n                    #self.input_list.append(self.selected_input_socket)\n                    new_channel_id = self.set_channel(self.selected_input_socket)\n                    logger.debug(\"Sending command to open channel {0}\".format(new_channel_id))\n                    self.send_remote_cmd(self.socket_with_server, relay.CHANNEL_OPEN_CMD, new_channel_id, ip, port)\n\n\n                elif self.selected_input_socket in self.id_by_socket:\n                    self.manage_socks_client_socket(self.selected_input_socket)\n                else:\n                    logger.debug(\"Active socket {0} does not belong to channel. Closing it\".format(self.selected_input_socket))\n                    self.selected_input_socket.close()\n\n\n    def parse_socks_header(self, data):\n        try:\n            (vn, cd, dstport, dstip) = unpack('>BBHI', data[:8])\n        except struct.error:\n            logger.debug('Invalid socks header! Got data: {0}'.format(repr(data)))\n            raise relay.RelayError\n        if vn != 4:\n            logger.debug('Invalid socks header! Got data: {0}'.format(repr(data)))\n            raise relay.RelayError\n        str_ip = socket.inet_ntoa(pack(\">L\", dstip))\n        logger.debug('Parsing socks header. Socks version: {0} Socks command: {1} Dstport: {2} Dstip: {3}'.format(vn, cd, dstport, str_ip))\n        return str_ip, dstport\n\n    def get_channel_data(self, sock):\n        try:\n            tlv_header = relay.recvall(sock, 4)\n            channel_id, tlv_data_len = unpack('<HH', tlv_header)\n            data = relay.recvall(sock, tlv_data_len)\n        except socket.error as (code, msg):\n            logger.debug('Exception on receiving tlv message from remote side. Exiting')\n            logger.debug('Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))\n            raise relay.RelayError\n        return channel_id, data\n\n    def manage_remote_socket(self, sock):\n        channel_id, data = self.get_channel_data(sock)\n        if channel_id == relay.COMMAND_CHANNEL:\n            self.handle_remote_cmd(data)\n        elif channel_id in self.channel:\n            relay_to_sock = self.channel[channel_id]\n            logger.debug('Got data to relay from remote side. Channel id {0}. Data length: {1}'.format(channel_id, len(data)))\n            logger.debug('Data contents: {0}'.format(data.encode('hex')))\n            self.relay(data, relay_to_sock)\n        else:\n            logger.debug('Relay from socket {0} with channel {1} not possible. Channel does not exist'.format(sock, channel_id))\n            return\n\n    def manage_socks_client_socket(self, sock):\n        try:\n            data = sock.recv(relay.buffer_size)\n        except socket.error as (code, msg):\n            logger.debug('Exception on reading socket {0} with channel id {1}'.format(sock, self.id_by_socket[sock]))\n            logger.debug('Details: {0}, {1}'.format(errno.errorcode[code], msg))\n            self.close_socks_connection(sock)\n            return\n        data_len = len(data)\n        if data_len == 0:\n            self.close_socks_connection(sock)\n            return\n        else:\n            channel_id = self.id_by_socket[sock]\n            tlv_header = pack('<HH', channel_id, len(data))\n            logger.debug('Got data to relay from app side. Channel id {0}. Data length: {1}'.format(channel_id, len(data)))\n            logger.debug('Preparint tlv header: {0}'.format(tlv_header.encode('hex')))\n            logger.debug('Data contents: {0}'.format(data.encode('hex')))\n            self.relay(tlv_header + data, self.socket_with_server)\n\n    def handle_remote_cmd(self, data):\n        cmd = data[0]\n        logger.debug('Received cmd from remote side. Cmd: {0}'.format(relay.cmd_names[cmd]))\n        if cmd == relay.CHANNEL_CLOSE_CMD:\n            channel_id = unpack('<H', data[1:3])[0]\n            logger.debug('Channel close request with id: {0}'.format(channel_id))\n            if channel_id not in self.channel:\n                logger.debug('Channel {0} already closed'.format(channel_id))\n                return\n            else:\n                sock_to_close = self.channel[channel_id]\n                self.input_list.remove(sock_to_close)\n                self.unset_channel(channel_id)\n                logger.debug('Closing socket {0}  with id: {1}'.format(sock_to_close, channel_id))\n                sock_to_close.close()\n        elif cmd == relay.FORWARD_CONNECTION_SUCCESS:\n            channel_id = unpack('<H', data[1:3])[0]\n            if channel_id in self.channel:\n                logger.debug('Forward connection successful with id: {0}'.format(channel_id))\n                sock = self.channel[channel_id]\n                try:\n                    sock.send(relay.socks_server_reply_success)\n                except socket.error as (code, msg):\n                    logger.error('Socket error on replying SUCCESS to socks client. Code {0}. Msg {1}'.format(code, cmd))\n                    logger.debug('Closing client socket and sending channel close cmd to remote side')\n                    sock = self.channel[channel_id]\n                    self.input_list.remove(sock)\n                    self.unset_channel(channel_id)\n                    try:\n                        sock.close()\n                    except socket.error:\n                        logger.debug('Error on closing socket')\n\n                    self.send_remote_cmd(self.socket_with_server, relay.CHANNEL_CLOSE_CMD, channel_id)\n            else:\n                logger.debug('Forward connection successful with id: {0}. But channel already closed here'.format(channel_id))\n        elif cmd == relay.FORWARD_CONNECTION_FAILURE:\n            channel_id = unpack('<H', data[1:3])[0]\n            logger.debug('Forward connection failed with id: {0}'.format(channel_id))\n            if channel_id in self.channel:\n                sock = self.channel[channel_id]\n                try:\n                    sock.send(relay.socks_server_reply_fail)\n                except socket.error as (code, msg):\n                    logger.error('Socket error on replying  FAILURE to socks client. Code {0}. Msg {0}'.format(code, cmd))\n                self.input_list.remove(sock)\n                self.unset_channel(channel_id)\n                try:\n                    sock.close()\n                except socket.error:\n                    logger.debug('Error on closing socket')\n            else:\n                logger.debug('Tried to close channel {0} that is already closed'.format(channel_id))\n\n        elif cmd == relay.CLOSE_RELAY:\n            logger.info('Got command to close relay. Closing connection with client.')\n            raise relay.RelayError\n        elif cmd == relay.PING_CMD:\n            #logger.debug('Got ping response from remote side. Good.')\n            self.last_ping_time = time.time()\n        else:\n            logger.error('Unknown cmd received! Exiting')\n            raise relay.RelayError\n\n    def send_remote_cmd(self, sock, cmd, *args):\n        logger.debug('Sending cmd to remote side. Cmd: {0}'.format(relay.cmd_names[cmd]))\n        if cmd == relay.CHANNEL_CLOSE_CMD:\n            cmd_buffer = cmd + pack('<H', args[0])\n            tlv_header = pack('<HH', relay.COMMAND_CHANNEL, len(cmd_buffer))\n        elif cmd == relay.CHANNEL_OPEN_CMD:\n            channel_id, ip, port = args\n            cmd_buffer = cmd + pack('<H',  channel_id) + socket.inet_aton(ip) + pack('<H', port)\n            tlv_header = pack('<HH', relay.COMMAND_CHANNEL, len(cmd_buffer))\n        else:\n            cmd_buffer = cmd\n            tlv_header = pack('<HH', relay.COMMAND_CHANNEL, len(cmd_buffer))\n        try:\n            sock.send(tlv_header + cmd_buffer)\n        except socket.error as (code, cmd):\n            logger.error('Socket error on sending command to remote side. Code {0}. Msg {1}'.format(code, cmd))\n            raise relay.RelayError\n\n    def on_accept(self):\n        socks_client_socket, clientaddr = self.server.accept()\n        logger.debug(\"Socks client {0} has connected\".format(clientaddr))\n        self.input_list.append(socks_client_socket)\n        self.pending_socks_clients.append(socks_client_socket)\n\n\n\n\n    def handle_new_socks_connection(self, sock):\n        try:\n            logger.debug('Trying to recieve socks header from socks client')\n            #data = relay.recvall(sock, 9)\n            data = sock.recv(9)\n            logger.debug('Got header data from socks client')\n            if len(data) != 9:\n                logger.debug('Error receiving socks header: corrupted header')\n                raise relay.RelayError\n            if data[-1] != '\\x00':\n                logger.debug('Error receiving socks header: corrupted header')\n                raise relay.RelayError\n        except socket.error as (code, msg):\n            logger.debug('Error receiving socks header {0} {1}'.format(errno.errorcode[code], msg))\n            raise relay.RelayError\n        if len(data) == 0:\n            logger.debug('Socks client prematurely ended connection')\n            raise relay.RelayError\n        return self.parse_socks_header(data)\n\n    def set_channel(self, sock):\n        new_channel_id = self.generate_new_channel_id()\n        self.channel[new_channel_id] = sock\n        self.id_by_socket[sock] = new_channel_id\n        return new_channel_id\n\n    def unset_channel(self, channel_id):\n        sock = self.channel[channel_id]\n        del self.id_by_socket[sock]\n        del self.channel[channel_id]\n\n    def generate_new_channel_id(self):\n        channel_ids = self.channel.keys()\n        while True:\n            rint = random.randint(1, 65535)\n            if rint not in channel_ids:\n                return rint\n\n    def close_socks_connection(self, sock):\n        channel_id = self.id_by_socket[sock]\n        logger.debug('Closing socks client socket {0} with id {1}'.format(sock, channel_id))\n        logger.debug('Notifying remote side')\n        self.unset_channel(channel_id)\n        self.input_list.remove(sock)\n        sock.close()\n        self.send_remote_cmd(self.socket_with_server, relay.CHANNEL_CLOSE_CMD, channel_id)\n\n    def relay(self, data, to_socket):\n        if to_socket is None:\n            return\n        try:\n            to_socket.send(data)\n        except socket.error as (code, msg):\n            logger.debug('Exception on relaying data to socket {0}'.format(to_socket))\n            logger.debug('Errno: {0} Msg: {1}'.format(errno.errorcode[code], msg))\n            if to_socket == self.socket_with_server:\n                raise relay.RelayError\n            else:\n                logger.debug('Closing socket')\n                to_socket.close()\n                self.input_list.remove(to_socket)\n                channel_id = self.id_by_socket[to_socket]\n                self.unset_channel(channel_id)\n                self.send_remote_cmd(self.socket_with_server, relay.CHANNEL_CLOSE_CMD, channel_id)\n\n\ndef run_server(host, port):\n    while True:\n        serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n        serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n        try:\n            serversock.bind((host, port))\n            serversock.listen(5)\n        except socket.error:\n            logger.error('Exception binding server at {0} port {1}'.format(host, port))\n            time.sleep(1)\n            break\n\n        try:\n            (socket_with_remote_side, address) = serversock.accept()\n        except KeyboardInterrupt:\n            logger.info('SIGINT received. Shutting down')\n            sys.exit(1)\n        logger.info('New connection from host {0}, source port {1}'.format(address[0], address[1]))\n        serversock.close()\n\n        try:\n            banner_rcv = socket_with_remote_side.recv(4096)\n            if banner_rcv != relay.banner:\n                logger.error(\"Wrong banner {0} from client. Closing connection\".format(repr(banner_rcv)))\n                socket_with_remote_side.close()\n                continue\n            socket_with_remote_side.send(relay.banner_response)\n        except socket.error as (code, msg):\n            logger.error(\"Caught socket error trying to establish connection with RPIVOT client. Code {0}. Msg {1}\".format(code, msg))\n            continue\n\n        try:\n            server = RelayServer(cmd_options.proxy_ip, int(cmd_options.proxy_port), socket_with_remote_side)\n\n        except socket.error as (code, msg):\n            logger.info('Error on running relay server. Restarting')\n            continue\n        try:\n            server.main_loop()\n        except relay.RelayError:\n            logger.info('Got RelayError in server.main_loop(). Restarting relay')\n            server.server.close()\n            continue\n\n        except KeyboardInterrupt:\n            print \"Ctrl C - Stopping server\"\n            sys.exit(1)\n\n\ndef main():\n    global logger\n    global cmd_options\n\n    parser = optparse.OptionParser(description='Reverse socks server')\n    parser.add_option('--server-ip', action=\"store\", dest='server_ip', default='0.0.0.0')\n    parser.add_option('--server-port', action=\"store\", dest='server_port', default='9999')\n    parser.add_option('--proxy-ip', action=\"store\", dest='proxy_ip', default='127.0.0.1')\n    parser.add_option('--proxy-port', action=\"store\", dest='proxy_port', default='1080')\n    parser.add_option('--verbose', action=\"store_true\", dest=\"verbose\", default=False)\n    parser.add_option('--logfile', action=\"store\", dest=\"logfile\", default=None)\n\n\n\n    cmd_options = parser.parse_args()[0]\n\n\n\n    logger = logging.getLogger('root')\n    logger.setLevel(logging.DEBUG)\n    ch = None\n\n    if cmd_options.logfile is None:\n        ch = logging.StreamHandler()\n    else:\n        ch = logging.FileHandler(cmd_options.logfile)\n\n    if cmd_options.verbose:\n        ch.setLevel(logging.DEBUG)\n    else:\n        ch.setLevel(logging.INFO)\n\n    logger.addHandler(ch)\n\n    run_server(cmd_options.server_ip, int(cmd_options.server_port))\n\n\nif __name__ == \"__main__\":\n    main()\n\n\n\n"
  },
  {
    "path": "six.py",
    "content": "\"\"\"Utilities for writing code that runs on Python 2 and 3\"\"\"\n\n# Copyright (c) 2010-2015 Benjamin Peterson\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in all\n# copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\nfrom __future__ import absolute_import\n\nimport functools\nimport itertools\nimport operator\nimport sys\nimport types\n\n__author__ = \"Benjamin Peterson <benjamin@python.org>\"\n__version__ = \"1.10.0\"\n\n\n# Useful for very coarse version differentiation.\nPY2 = sys.version_info[0] == 2\nPY3 = sys.version_info[0] == 3\nPY34 = sys.version_info[0:2] >= (3, 4)\n\nif PY3:\n    string_types = str,\n    integer_types = int,\n    class_types = type,\n    text_type = str\n    binary_type = bytes\n\n    MAXSIZE = sys.maxsize\nelse:\n    string_types = basestring,\n    integer_types = (int, long)\n    class_types = (type, types.ClassType)\n    text_type = unicode\n    binary_type = str\n\n    if sys.platform.startswith(\"java\"):\n        # Jython always uses 32 bits.\n        MAXSIZE = int((1 << 31) - 1)\n    else:\n        # It's possible to have sizeof(long) != sizeof(Py_ssize_t).\n        class X(object):\n\n            def __len__(self):\n                return 1 << 31\n        try:\n            len(X())\n        except OverflowError:\n            # 32-bit\n            MAXSIZE = int((1 << 31) - 1)\n        else:\n            # 64-bit\n            MAXSIZE = int((1 << 63) - 1)\n        del X\n\n\ndef _add_doc(func, doc):\n    \"\"\"Add documentation to a function.\"\"\"\n    func.__doc__ = doc\n\n\ndef _import_module(name):\n    \"\"\"Import module, returning the module after the last dot.\"\"\"\n    __import__(name)\n    return sys.modules[name]\n\n\nclass _LazyDescr(object):\n\n    def __init__(self, name):\n        self.name = name\n\n    def __get__(self, obj, tp):\n        result = self._resolve()\n        setattr(obj, self.name, result)  # Invokes __set__.\n        try:\n            # This is a bit ugly, but it avoids running this again by\n            # removing this descriptor.\n            delattr(obj.__class__, self.name)\n        except AttributeError:\n            pass\n        return result\n\n\nclass MovedModule(_LazyDescr):\n\n    def __init__(self, name, old, new=None):\n        super(MovedModule, self).__init__(name)\n        if PY3:\n            if new is None:\n                new = name\n            self.mod = new\n        else:\n            self.mod = old\n\n    def _resolve(self):\n        return _import_module(self.mod)\n\n    def __getattr__(self, attr):\n        _module = self._resolve()\n        value = getattr(_module, attr)\n        setattr(self, attr, value)\n        return value\n\n\nclass _LazyModule(types.ModuleType):\n\n    def __init__(self, name):\n        super(_LazyModule, self).__init__(name)\n        self.__doc__ = self.__class__.__doc__\n\n    def __dir__(self):\n        attrs = [\"__doc__\", \"__name__\"]\n        attrs += [attr.name for attr in self._moved_attributes]\n        return attrs\n\n    # Subclasses should override this\n    _moved_attributes = []\n\n\nclass MovedAttribute(_LazyDescr):\n\n    def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):\n        super(MovedAttribute, self).__init__(name)\n        if PY3:\n            if new_mod is None:\n                new_mod = name\n            self.mod = new_mod\n            if new_attr is None:\n                if old_attr is None:\n                    new_attr = name\n                else:\n                    new_attr = old_attr\n            self.attr = new_attr\n        else:\n            self.mod = old_mod\n            if old_attr is None:\n                old_attr = name\n            self.attr = old_attr\n\n    def _resolve(self):\n        module = _import_module(self.mod)\n        return getattr(module, self.attr)\n\n\nclass _SixMetaPathImporter(object):\n\n    \"\"\"\n    A meta path importer to import six.moves and its submodules.\n\n    This class implements a PEP302 finder and loader. It should be compatible\n    with Python 2.5 and all existing versions of Python3\n    \"\"\"\n\n    def __init__(self, six_module_name):\n        self.name = six_module_name\n        self.known_modules = {}\n\n    def _add_module(self, mod, *fullnames):\n        for fullname in fullnames:\n            self.known_modules[self.name + \".\" + fullname] = mod\n\n    def _get_module(self, fullname):\n        return self.known_modules[self.name + \".\" + fullname]\n\n    def find_module(self, fullname, path=None):\n        if fullname in self.known_modules:\n            return self\n        return None\n\n    def __get_module(self, fullname):\n        try:\n            return self.known_modules[fullname]\n        except KeyError:\n            raise ImportError(\"This loader does not know module \" + fullname)\n\n    def load_module(self, fullname):\n        try:\n            # in case of a reload\n            return sys.modules[fullname]\n        except KeyError:\n            pass\n        mod = self.__get_module(fullname)\n        if isinstance(mod, MovedModule):\n            mod = mod._resolve()\n        else:\n            mod.__loader__ = self\n        sys.modules[fullname] = mod\n        return mod\n\n    def is_package(self, fullname):\n        \"\"\"\n        Return true, if the named module is a package.\n\n        We need this method to get correct spec objects with\n        Python 3.4 (see PEP451)\n        \"\"\"\n        return hasattr(self.__get_module(fullname), \"__path__\")\n\n    def get_code(self, fullname):\n        \"\"\"Return None\n\n        Required, if is_package is implemented\"\"\"\n        self.__get_module(fullname)  # eventually raises ImportError\n        return None\n    get_source = get_code  # same as get_code\n\n_importer = _SixMetaPathImporter(__name__)\n\n\nclass _MovedItems(_LazyModule):\n\n    \"\"\"Lazy loading of moved objects\"\"\"\n    __path__ = []  # mark as package\n\n\n_moved_attributes = [\n    MovedAttribute(\"cStringIO\", \"cStringIO\", \"io\", \"StringIO\"),\n    MovedAttribute(\"filter\", \"itertools\", \"builtins\", \"ifilter\", \"filter\"),\n    MovedAttribute(\"filterfalse\", \"itertools\", \"itertools\", \"ifilterfalse\", \"filterfalse\"),\n    MovedAttribute(\"input\", \"__builtin__\", \"builtins\", \"raw_input\", \"input\"),\n    MovedAttribute(\"intern\", \"__builtin__\", \"sys\"),\n    MovedAttribute(\"map\", \"itertools\", \"builtins\", \"imap\", \"map\"),\n    MovedAttribute(\"getcwd\", \"os\", \"os\", \"getcwdu\", \"getcwd\"),\n    MovedAttribute(\"getcwdb\", \"os\", \"os\", \"getcwd\", \"getcwdb\"),\n    MovedAttribute(\"range\", \"__builtin__\", \"builtins\", \"xrange\", \"range\"),\n    MovedAttribute(\"reload_module\", \"__builtin__\", \"importlib\" if PY34 else \"imp\", \"reload\"),\n    MovedAttribute(\"reduce\", \"__builtin__\", \"functools\"),\n    MovedAttribute(\"shlex_quote\", \"pipes\", \"shlex\", \"quote\"),\n    MovedAttribute(\"StringIO\", \"StringIO\", \"io\"),\n    MovedAttribute(\"UserDict\", \"UserDict\", \"collections\"),\n    MovedAttribute(\"UserList\", \"UserList\", \"collections\"),\n    MovedAttribute(\"UserString\", \"UserString\", \"collections\"),\n    MovedAttribute(\"xrange\", \"__builtin__\", \"builtins\", \"xrange\", \"range\"),\n    MovedAttribute(\"zip\", \"itertools\", \"builtins\", \"izip\", \"zip\"),\n    MovedAttribute(\"zip_longest\", \"itertools\", \"itertools\", \"izip_longest\", \"zip_longest\"),\n    MovedModule(\"builtins\", \"__builtin__\"),\n    MovedModule(\"configparser\", \"ConfigParser\"),\n    MovedModule(\"copyreg\", \"copy_reg\"),\n    MovedModule(\"dbm_gnu\", \"gdbm\", \"dbm.gnu\"),\n    MovedModule(\"_dummy_thread\", \"dummy_thread\", \"_dummy_thread\"),\n    MovedModule(\"http_cookiejar\", \"cookielib\", \"http.cookiejar\"),\n    MovedModule(\"http_cookies\", \"Cookie\", \"http.cookies\"),\n    MovedModule(\"html_entities\", \"htmlentitydefs\", \"html.entities\"),\n    MovedModule(\"html_parser\", \"HTMLParser\", \"html.parser\"),\n    MovedModule(\"http_client\", \"httplib\", \"http.client\"),\n    MovedModule(\"email_mime_multipart\", \"email.MIMEMultipart\", \"email.mime.multipart\"),\n    MovedModule(\"email_mime_nonmultipart\", \"email.MIMENonMultipart\", \"email.mime.nonmultipart\"),\n    MovedModule(\"email_mime_text\", \"email.MIMEText\", \"email.mime.text\"),\n    MovedModule(\"email_mime_base\", \"email.MIMEBase\", \"email.mime.base\"),\n    MovedModule(\"BaseHTTPServer\", \"BaseHTTPServer\", \"http.server\"),\n    MovedModule(\"CGIHTTPServer\", \"CGIHTTPServer\", \"http.server\"),\n    MovedModule(\"SimpleHTTPServer\", \"SimpleHTTPServer\", \"http.server\"),\n    MovedModule(\"cPickle\", \"cPickle\", \"pickle\"),\n    MovedModule(\"queue\", \"Queue\"),\n    MovedModule(\"reprlib\", \"repr\"),\n    MovedModule(\"socketserver\", \"SocketServer\"),\n    MovedModule(\"_thread\", \"thread\", \"_thread\"),\n    MovedModule(\"tkinter\", \"Tkinter\"),\n    MovedModule(\"tkinter_dialog\", \"Dialog\", \"tkinter.dialog\"),\n    MovedModule(\"tkinter_filedialog\", \"FileDialog\", \"tkinter.filedialog\"),\n    MovedModule(\"tkinter_scrolledtext\", \"ScrolledText\", \"tkinter.scrolledtext\"),\n    MovedModule(\"tkinter_simpledialog\", \"SimpleDialog\", \"tkinter.simpledialog\"),\n    MovedModule(\"tkinter_tix\", \"Tix\", \"tkinter.tix\"),\n    MovedModule(\"tkinter_ttk\", \"ttk\", \"tkinter.ttk\"),\n    MovedModule(\"tkinter_constants\", \"Tkconstants\", \"tkinter.constants\"),\n    MovedModule(\"tkinter_dnd\", \"Tkdnd\", \"tkinter.dnd\"),\n    MovedModule(\"tkinter_colorchooser\", \"tkColorChooser\",\n                \"tkinter.colorchooser\"),\n    MovedModule(\"tkinter_commondialog\", \"tkCommonDialog\",\n                \"tkinter.commondialog\"),\n    MovedModule(\"tkinter_tkfiledialog\", \"tkFileDialog\", \"tkinter.filedialog\"),\n    MovedModule(\"tkinter_font\", \"tkFont\", \"tkinter.font\"),\n    MovedModule(\"tkinter_messagebox\", \"tkMessageBox\", \"tkinter.messagebox\"),\n    MovedModule(\"tkinter_tksimpledialog\", \"tkSimpleDialog\",\n                \"tkinter.simpledialog\"),\n    MovedModule(\"urllib_parse\", __name__ + \".moves.urllib_parse\", \"urllib.parse\"),\n    MovedModule(\"urllib_error\", __name__ + \".moves.urllib_error\", \"urllib.error\"),\n    MovedModule(\"urllib\", __name__ + \".moves.urllib\", __name__ + \".moves.urllib\"),\n    MovedModule(\"urllib_robotparser\", \"robotparser\", \"urllib.robotparser\"),\n    MovedModule(\"xmlrpc_client\", \"xmlrpclib\", \"xmlrpc.client\"),\n    MovedModule(\"xmlrpc_server\", \"SimpleXMLRPCServer\", \"xmlrpc.server\"),\n]\n# Add windows specific modules.\nif sys.platform == \"win32\":\n    _moved_attributes += [\n        MovedModule(\"winreg\", \"_winreg\"),\n    ]\n\nfor attr in _moved_attributes:\n    setattr(_MovedItems, attr.name, attr)\n    if isinstance(attr, MovedModule):\n        _importer._add_module(attr, \"moves.\" + attr.name)\ndel attr\n\n_MovedItems._moved_attributes = _moved_attributes\n\nmoves = _MovedItems(__name__ + \".moves\")\n_importer._add_module(moves, \"moves\")\n\n\nclass Module_six_moves_urllib_parse(_LazyModule):\n\n    \"\"\"Lazy loading of moved objects in six.moves.urllib_parse\"\"\"\n\n\n_urllib_parse_moved_attributes = [\n    MovedAttribute(\"ParseResult\", \"urlparse\", \"urllib.parse\"),\n    MovedAttribute(\"SplitResult\", \"urlparse\", \"urllib.parse\"),\n    MovedAttribute(\"parse_qs\", \"urlparse\", \"urllib.parse\"),\n    MovedAttribute(\"parse_qsl\", \"urlparse\", \"urllib.parse\"),\n    MovedAttribute(\"urldefrag\", \"urlparse\", \"urllib.parse\"),\n    MovedAttribute(\"urljoin\", \"urlparse\", \"urllib.parse\"),\n    MovedAttribute(\"urlparse\", \"urlparse\", \"urllib.parse\"),\n    MovedAttribute(\"urlsplit\", \"urlparse\", \"urllib.parse\"),\n    MovedAttribute(\"urlunparse\", \"urlparse\", \"urllib.parse\"),\n    MovedAttribute(\"urlunsplit\", \"urlparse\", \"urllib.parse\"),\n    MovedAttribute(\"quote\", \"urllib\", \"urllib.parse\"),\n    MovedAttribute(\"quote_plus\", \"urllib\", \"urllib.parse\"),\n    MovedAttribute(\"unquote\", \"urllib\", \"urllib.parse\"),\n    MovedAttribute(\"unquote_plus\", \"urllib\", \"urllib.parse\"),\n    MovedAttribute(\"urlencode\", \"urllib\", \"urllib.parse\"),\n    MovedAttribute(\"splitquery\", \"urllib\", \"urllib.parse\"),\n    MovedAttribute(\"splittag\", \"urllib\", \"urllib.parse\"),\n    MovedAttribute(\"splituser\", \"urllib\", \"urllib.parse\"),\n    MovedAttribute(\"uses_fragment\", \"urlparse\", \"urllib.parse\"),\n    MovedAttribute(\"uses_netloc\", \"urlparse\", \"urllib.parse\"),\n    MovedAttribute(\"uses_params\", \"urlparse\", \"urllib.parse\"),\n    MovedAttribute(\"uses_query\", \"urlparse\", \"urllib.parse\"),\n    MovedAttribute(\"uses_relative\", \"urlparse\", \"urllib.parse\"),\n]\nfor attr in _urllib_parse_moved_attributes:\n    setattr(Module_six_moves_urllib_parse, attr.name, attr)\ndel attr\n\nModule_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes\n\n_importer._add_module(Module_six_moves_urllib_parse(__name__ + \".moves.urllib_parse\"),\n                      \"moves.urllib_parse\", \"moves.urllib.parse\")\n\n\nclass Module_six_moves_urllib_error(_LazyModule):\n\n    \"\"\"Lazy loading of moved objects in six.moves.urllib_error\"\"\"\n\n\n_urllib_error_moved_attributes = [\n    MovedAttribute(\"URLError\", \"urllib2\", \"urllib.error\"),\n    MovedAttribute(\"HTTPError\", \"urllib2\", \"urllib.error\"),\n    MovedAttribute(\"ContentTooShortError\", \"urllib\", \"urllib.error\"),\n]\nfor attr in _urllib_error_moved_attributes:\n    setattr(Module_six_moves_urllib_error, attr.name, attr)\ndel attr\n\nModule_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes\n\n_importer._add_module(Module_six_moves_urllib_error(__name__ + \".moves.urllib.error\"),\n                      \"moves.urllib_error\", \"moves.urllib.error\")\n\n\nclass Module_six_moves_urllib_request(_LazyModule):\n\n    \"\"\"Lazy loading of moved objects in six.moves.urllib_request\"\"\"\n\n\n_urllib_request_moved_attributes = [\n    MovedAttribute(\"urlopen\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"install_opener\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"build_opener\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"pathname2url\", \"urllib\", \"urllib.request\"),\n    MovedAttribute(\"url2pathname\", \"urllib\", \"urllib.request\"),\n    MovedAttribute(\"getproxies\", \"urllib\", \"urllib.request\"),\n    MovedAttribute(\"Request\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"OpenerDirector\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"HTTPDefaultErrorHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"HTTPRedirectHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"HTTPCookieProcessor\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"ProxyHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"BaseHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"HTTPPasswordMgr\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"HTTPPasswordMgrWithDefaultRealm\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"AbstractBasicAuthHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"HTTPBasicAuthHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"ProxyBasicAuthHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"AbstractDigestAuthHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"HTTPDigestAuthHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"ProxyDigestAuthHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"HTTPHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"HTTPSHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"FileHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"FTPHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"CacheFTPHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"UnknownHandler\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"HTTPErrorProcessor\", \"urllib2\", \"urllib.request\"),\n    MovedAttribute(\"urlretrieve\", \"urllib\", \"urllib.request\"),\n    MovedAttribute(\"urlcleanup\", \"urllib\", \"urllib.request\"),\n    MovedAttribute(\"URLopener\", \"urllib\", \"urllib.request\"),\n    MovedAttribute(\"FancyURLopener\", \"urllib\", \"urllib.request\"),\n    MovedAttribute(\"proxy_bypass\", \"urllib\", \"urllib.request\"),\n]\nfor attr in _urllib_request_moved_attributes:\n    setattr(Module_six_moves_urllib_request, attr.name, attr)\ndel attr\n\nModule_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes\n\n_importer._add_module(Module_six_moves_urllib_request(__name__ + \".moves.urllib.request\"),\n                      \"moves.urllib_request\", \"moves.urllib.request\")\n\n\nclass Module_six_moves_urllib_response(_LazyModule):\n\n    \"\"\"Lazy loading of moved objects in six.moves.urllib_response\"\"\"\n\n\n_urllib_response_moved_attributes = [\n    MovedAttribute(\"addbase\", \"urllib\", \"urllib.response\"),\n    MovedAttribute(\"addclosehook\", \"urllib\", \"urllib.response\"),\n    MovedAttribute(\"addinfo\", \"urllib\", \"urllib.response\"),\n    MovedAttribute(\"addinfourl\", \"urllib\", \"urllib.response\"),\n]\nfor attr in _urllib_response_moved_attributes:\n    setattr(Module_six_moves_urllib_response, attr.name, attr)\ndel attr\n\nModule_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes\n\n_importer._add_module(Module_six_moves_urllib_response(__name__ + \".moves.urllib.response\"),\n                      \"moves.urllib_response\", \"moves.urllib.response\")\n\n\nclass Module_six_moves_urllib_robotparser(_LazyModule):\n\n    \"\"\"Lazy loading of moved objects in six.moves.urllib_robotparser\"\"\"\n\n\n_urllib_robotparser_moved_attributes = [\n    MovedAttribute(\"RobotFileParser\", \"robotparser\", \"urllib.robotparser\"),\n]\nfor attr in _urllib_robotparser_moved_attributes:\n    setattr(Module_six_moves_urllib_robotparser, attr.name, attr)\ndel attr\n\nModule_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes\n\n_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + \".moves.urllib.robotparser\"),\n                      \"moves.urllib_robotparser\", \"moves.urllib.robotparser\")\n\n\nclass Module_six_moves_urllib(types.ModuleType):\n\n    \"\"\"Create a six.moves.urllib namespace that resembles the Python 3 namespace\"\"\"\n    __path__ = []  # mark as package\n    parse = _importer._get_module(\"moves.urllib_parse\")\n    error = _importer._get_module(\"moves.urllib_error\")\n    request = _importer._get_module(\"moves.urllib_request\")\n    response = _importer._get_module(\"moves.urllib_response\")\n    robotparser = _importer._get_module(\"moves.urllib_robotparser\")\n\n    def __dir__(self):\n        return ['parse', 'error', 'request', 'response', 'robotparser']\n\n_importer._add_module(Module_six_moves_urllib(__name__ + \".moves.urllib\"),\n                      \"moves.urllib\")\n\n\ndef add_move(move):\n    \"\"\"Add an item to six.moves.\"\"\"\n    setattr(_MovedItems, move.name, move)\n\n\ndef remove_move(name):\n    \"\"\"Remove item from six.moves.\"\"\"\n    try:\n        delattr(_MovedItems, name)\n    except AttributeError:\n        try:\n            del moves.__dict__[name]\n        except KeyError:\n            raise AttributeError(\"no such move, %r\" % (name,))\n\n\nif PY3:\n    _meth_func = \"__func__\"\n    _meth_self = \"__self__\"\n\n    _func_closure = \"__closure__\"\n    _func_code = \"__code__\"\n    _func_defaults = \"__defaults__\"\n    _func_globals = \"__globals__\"\nelse:\n    _meth_func = \"im_func\"\n    _meth_self = \"im_self\"\n\n    _func_closure = \"func_closure\"\n    _func_code = \"func_code\"\n    _func_defaults = \"func_defaults\"\n    _func_globals = \"func_globals\"\n\n\ntry:\n    advance_iterator = next\nexcept NameError:\n    def advance_iterator(it):\n        return it.next()\nnext = advance_iterator\n\n\ntry:\n    callable = callable\nexcept NameError:\n    def callable(obj):\n        return any(\"__call__\" in klass.__dict__ for klass in type(obj).__mro__)\n\n\nif PY3:\n    def get_unbound_function(unbound):\n        return unbound\n\n    create_bound_method = types.MethodType\n\n    def create_unbound_method(func, cls):\n        return func\n\n    Iterator = object\nelse:\n    def get_unbound_function(unbound):\n        return unbound.im_func\n\n    def create_bound_method(func, obj):\n        return types.MethodType(func, obj, obj.__class__)\n\n    def create_unbound_method(func, cls):\n        return types.MethodType(func, None, cls)\n\n    class Iterator(object):\n\n        def next(self):\n            return type(self).__next__(self)\n\n    callable = callable\n_add_doc(get_unbound_function,\n         \"\"\"Get the function out of a possibly unbound function\"\"\")\n\n\nget_method_function = operator.attrgetter(_meth_func)\nget_method_self = operator.attrgetter(_meth_self)\nget_function_closure = operator.attrgetter(_func_closure)\nget_function_code = operator.attrgetter(_func_code)\nget_function_defaults = operator.attrgetter(_func_defaults)\nget_function_globals = operator.attrgetter(_func_globals)\n\n\nif PY3:\n    def iterkeys(d, **kw):\n        return iter(d.keys(**kw))\n\n    def itervalues(d, **kw):\n        return iter(d.values(**kw))\n\n    def iteritems(d, **kw):\n        return iter(d.items(**kw))\n\n    def iterlists(d, **kw):\n        return iter(d.lists(**kw))\n\n    viewkeys = operator.methodcaller(\"keys\")\n\n    viewvalues = operator.methodcaller(\"values\")\n\n    viewitems = operator.methodcaller(\"items\")\nelse:\n    def iterkeys(d, **kw):\n        return d.iterkeys(**kw)\n\n    def itervalues(d, **kw):\n        return d.itervalues(**kw)\n\n    def iteritems(d, **kw):\n        return d.iteritems(**kw)\n\n    def iterlists(d, **kw):\n        return d.iterlists(**kw)\n\n    viewkeys = operator.methodcaller(\"viewkeys\")\n\n    viewvalues = operator.methodcaller(\"viewvalues\")\n\n    viewitems = operator.methodcaller(\"viewitems\")\n\n_add_doc(iterkeys, \"Return an iterator over the keys of a dictionary.\")\n_add_doc(itervalues, \"Return an iterator over the values of a dictionary.\")\n_add_doc(iteritems,\n         \"Return an iterator over the (key, value) pairs of a dictionary.\")\n_add_doc(iterlists,\n         \"Return an iterator over the (key, [values]) pairs of a dictionary.\")\n\n\nif PY3:\n    def b(s):\n        return s.encode(\"latin-1\")\n\n    def u(s):\n        return s\n    unichr = chr\n    import struct\n    int2byte = struct.Struct(\">B\").pack\n    del struct\n    byte2int = operator.itemgetter(0)\n    indexbytes = operator.getitem\n    iterbytes = iter\n    import io\n    StringIO = io.StringIO\n    BytesIO = io.BytesIO\n    _assertCountEqual = \"assertCountEqual\"\n    if sys.version_info[1] <= 1:\n        _assertRaisesRegex = \"assertRaisesRegexp\"\n        _assertRegex = \"assertRegexpMatches\"\n    else:\n        _assertRaisesRegex = \"assertRaisesRegex\"\n        _assertRegex = \"assertRegex\"\nelse:\n    def b(s):\n        return s\n    # Workaround for standalone backslash\n\n    def u(s):\n        return unicode(s.replace(r'\\\\', r'\\\\\\\\'), \"unicode_escape\")\n    unichr = unichr\n    int2byte = chr\n\n    def byte2int(bs):\n        return ord(bs[0])\n\n    def indexbytes(buf, i):\n        return ord(buf[i])\n    iterbytes = functools.partial(itertools.imap, ord)\n    import StringIO\n    StringIO = BytesIO = StringIO.StringIO\n    _assertCountEqual = \"assertItemsEqual\"\n    _assertRaisesRegex = \"assertRaisesRegexp\"\n    _assertRegex = \"assertRegexpMatches\"\n_add_doc(b, \"\"\"Byte literal\"\"\")\n_add_doc(u, \"\"\"Text literal\"\"\")\n\n\ndef assertCountEqual(self, *args, **kwargs):\n    return getattr(self, _assertCountEqual)(*args, **kwargs)\n\n\ndef assertRaisesRegex(self, *args, **kwargs):\n    return getattr(self, _assertRaisesRegex)(*args, **kwargs)\n\n\ndef assertRegex(self, *args, **kwargs):\n    return getattr(self, _assertRegex)(*args, **kwargs)\n\n\nif PY3:\n    exec_ = getattr(moves.builtins, \"exec\")\n\n    def reraise(tp, value, tb=None):\n        if value is None:\n            value = tp()\n        if value.__traceback__ is not tb:\n            raise value.with_traceback(tb)\n        raise value\n\nelse:\n    def exec_(_code_, _globs_=None, _locs_=None):\n        \"\"\"Execute code in a namespace.\"\"\"\n        if _globs_ is None:\n            frame = sys._getframe(1)\n            _globs_ = frame.f_globals\n            if _locs_ is None:\n                _locs_ = frame.f_locals\n            del frame\n        elif _locs_ is None:\n            _locs_ = _globs_\n        exec(\"\"\"exec _code_ in _globs_, _locs_\"\"\")\n\n    exec_(\"\"\"def reraise(tp, value, tb=None):\n    raise tp, value, tb\n\"\"\")\n\n\nif sys.version_info[:2] == (3, 2):\n    exec_(\"\"\"def raise_from(value, from_value):\n    if from_value is None:\n        raise value\n    raise value from from_value\n\"\"\")\nelif sys.version_info[:2] > (3, 2):\n    exec_(\"\"\"def raise_from(value, from_value):\n    raise value from from_value\n\"\"\")\nelse:\n    def raise_from(value, from_value):\n        raise value\n\n\nprint_ = getattr(moves.builtins, \"print\", None)\nif print_ is None:\n    def print_(*args, **kwargs):\n        \"\"\"The new-style print function for Python 2.4 and 2.5.\"\"\"\n        fp = kwargs.pop(\"file\", sys.stdout)\n        if fp is None:\n            return\n\n        def write(data):\n            if not isinstance(data, basestring):\n                data = str(data)\n            # If the file has an encoding, encode unicode with it.\n            if (isinstance(fp, file) and\n                    isinstance(data, unicode) and\n                    fp.encoding is not None):\n                errors = getattr(fp, \"errors\", None)\n                if errors is None:\n                    errors = \"strict\"\n                data = data.encode(fp.encoding, errors)\n            fp.write(data)\n        want_unicode = False\n        sep = kwargs.pop(\"sep\", None)\n        if sep is not None:\n            if isinstance(sep, unicode):\n                want_unicode = True\n            elif not isinstance(sep, str):\n                raise TypeError(\"sep must be None or a string\")\n        end = kwargs.pop(\"end\", None)\n        if end is not None:\n            if isinstance(end, unicode):\n                want_unicode = True\n            elif not isinstance(end, str):\n                raise TypeError(\"end must be None or a string\")\n        if kwargs:\n            raise TypeError(\"invalid keyword arguments to print()\")\n        if not want_unicode:\n            for arg in args:\n                if isinstance(arg, unicode):\n                    want_unicode = True\n                    break\n        if want_unicode:\n            newline = unicode(\"\\n\")\n            space = unicode(\" \")\n        else:\n            newline = \"\\n\"\n            space = \" \"\n        if sep is None:\n            sep = space\n        if end is None:\n            end = newline\n        for i, arg in enumerate(args):\n            if i:\n                write(sep)\n            write(arg)\n        write(end)\nif sys.version_info[:2] < (3, 3):\n    _print = print_\n\n    def print_(*args, **kwargs):\n        fp = kwargs.get(\"file\", sys.stdout)\n        flush = kwargs.pop(\"flush\", False)\n        _print(*args, **kwargs)\n        if flush and fp is not None:\n            fp.flush()\n\n_add_doc(reraise, \"\"\"Reraise an exception.\"\"\")\n\nif sys.version_info[0:2] < (3, 4):\n    def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,\n              updated=functools.WRAPPER_UPDATES):\n        def wrapper(f):\n            f = functools.wraps(wrapped, assigned, updated)(f)\n            f.__wrapped__ = wrapped\n            return f\n        return wrapper\nelse:\n    wraps = functools.wraps\n\n\ndef with_metaclass(meta, *bases):\n    \"\"\"Create a base class with a metaclass.\"\"\"\n    # This requires a bit of explanation: the basic idea is to make a dummy\n    # metaclass for one level of class instantiation that replaces itself with\n    # the actual metaclass.\n    class metaclass(meta):\n\n        def __new__(cls, name, this_bases, d):\n            return meta(name, bases, d)\n    return type.__new__(metaclass, 'temporary_class', (), {})\n\n\ndef add_metaclass(metaclass):\n    \"\"\"Class decorator for creating a class with a metaclass.\"\"\"\n    def wrapper(cls):\n        orig_vars = cls.__dict__.copy()\n        slots = orig_vars.get('__slots__')\n        if slots is not None:\n            if isinstance(slots, str):\n                slots = [slots]\n            for slots_var in slots:\n                orig_vars.pop(slots_var)\n        orig_vars.pop('__dict__', None)\n        orig_vars.pop('__weakref__', None)\n        return metaclass(cls.__name__, cls.__bases__, orig_vars)\n    return wrapper\n\n\ndef python_2_unicode_compatible(klass):\n    \"\"\"\n    A decorator that defines __unicode__ and __str__ methods under Python 2.\n    Under Python 3 it does nothing.\n\n    To support Python 2 and 3 with a single code base, define a __str__ method\n    returning text and apply this decorator to the class.\n    \"\"\"\n    if PY2:\n        if '__str__' not in klass.__dict__:\n            raise ValueError(\"@python_2_unicode_compatible cannot be applied \"\n                             \"to %s because it doesn't define __str__().\" %\n                             klass.__name__)\n        klass.__unicode__ = klass.__str__\n        klass.__str__ = lambda self: self.__unicode__().encode('utf-8')\n    return klass\n\n\n# Complete the moves implementation.\n# This code is at the end of this module to speed up module loading.\n# Turn this module into a package.\n__path__ = []  # required for PEP 302 and PEP 451\n__package__ = __name__  # see PEP 366 @ReservedAssignment\nif globals().get(\"__spec__\") is not None:\n    __spec__.submodule_search_locations = []  # PEP 451 @UndefinedVariable\n# Remove other six meta path importers, since they cause problems. This can\n# happen if six is removed from sys.modules and then reloaded. (Setuptools does\n# this for some reason.)\nif sys.meta_path:\n    for i, importer in enumerate(sys.meta_path):\n        # Here's some real nastiness: Another \"instance\" of the six module might\n        # be floating around. Therefore, we can't use isinstance() to check for\n        # the six meta path importer, since the other six instance will have\n        # inserted an importer with different class.\n        if (type(importer).__name__ == \"_SixMetaPathImporter\" and\n                importer.name == __name__):\n            del sys.meta_path[i]\n            break\n    del i, importer\n# Finally, add the importer to the meta path import hook.\nsys.meta_path.append(_importer)\n"
  }
]