Exemplo n.º 1
0
    def __init__(self, *args, **kwargs):
        PupyWebSocketTransport.__init__(self, *args, **kwargs)

        self.upgraded = False
        self.missing_bytes = 0
        self.offset = 0
        self.decoded = Buffer()
        self.upgraded_buf = Buffer()
        self.user_agent = kwargs.get('user-agent')
        self.path = kwargs.get('path')
        self.connect = kwargs.get('connect', None)

        self.proxy = kwargs.get('proxy', False)
        self.auth = kwargs.get('auth', None)
        self.host = kwargs.get('host', None)

        if self.connect is None and self.host is not None:
            if ':' in self.host:
                host, port = self.host.rsplit(':', 1)
                port = int(port)
                self.connect = host, port
            else:
                self.connect = self.host, 80

        if self.host is None:
            self.host = 'www.' + ''.join(
                random.sample(string.lowercase + '.-', 16)) + '.net'

        if __debug__:
            logger.debug('WS Client, path=%s, user-agent=%s host=%s',
                         self.path, self.user_agent, self.host)
Exemplo n.º 2
0
    def __init__(self, *args, **kwargs):
        super(ECMTransport, self).__init__(*args, **kwargs)
        if not self.pubkey and not self.privkey:
            raise ValueError('Public or Private key required for ECM')

        if self.pubkey:
            self.encoder = ECPV(
                curve='brainpoolP384r1',
                public_key=self.pubkey,
                hash=sha384
            )
        else:
            self.encoder = ECPV(
                curve='brainpoolP384r1',
                public_key=self.privkey,
                hash=sha384
            )

        self.encryptor       = None
        self.decryptor       = None
        self.up_buffer       = Buffer()
        self.dec_buffer      = Buffer()
        self.nonce           = None
        self.key             = None
        self.chunk_len       = 0
        self.need_validation = False
Exemplo n.º 3
0
    def __init__(self,
                 transport_class,
                 transport_kwargs={},
                 peername=None,
                 on_receive=None):
        self.on_receive = None
        self.closed = True

        # buffers for transport
        self.upstream = Buffer(shared=True)

        self.downstream = None

        self.upstream_lock = threading.Lock()
        self.downstream_lock = threading.Lock()

        self.transport_class = transport_class
        self.transport_kwargs = transport_kwargs

        # buffers for streams
        self.buf_in = Buffer(shared=True)
        self.buf_out = Buffer()

        self.peername = peername

        if peername and on_receive:
            self.activate(peername, on_receive)

        logger.debug('Allocated (%s)', self)
Exemplo n.º 4
0
 def __init__(self, manager, event_id=None,
         name=None, winsize=None, tty_private=None):
     super(TTYRec, self).__init__(manager)
     self._ttymon = TTYMon(
         name, winsize, tty_private, ignore=[os.getpid(), os.getppid()]
     )
     self._results_lock = Lock()
     self._buffer = Buffer()
     self._compressor = zlib.compressobj(9)
     self._event_id = event_id
     self._session = 0
Exemplo n.º 5
0
    def __init__(self, *args, **kwargs):
        super(PupyHTTPWrapperServer, self).__init__(*args, **kwargs)

        self.parser = HttpParser()
        self.is_http = None
        self.body = []
        self.downstream_buffer = Buffer()

        self.well_known = ('GET', 'POST', 'OPTIONS', 'HEAD', 'PUT', 'DELETE')
        self.omit = tuple('{} {}'.format(x, y) for x in self.well_known
                          for y in (self.path, '/ws/', 'ws/'))
        self.probe_len = max(len(x) for x in self.omit)
Exemplo n.º 6
0
    def __init__(self, *args, **kwargs):
        PupyWebSocketTransport.__init__(self, *args, **kwargs)
        self.upgraded = False
        self.user_agent = kwargs.pop('user-agent')
        self.path = kwargs.pop('path')
        self.mask = True
        self.offset = 0
        self.missing_bytes = 0
        self.decoded = Buffer()
        self.upgraded_buf = Buffer()

        if __debug__:
            logger.debug('WS Server, path=%s, user-agent=%s', self.path,
                         self.user_agent)
Exemplo n.º 7
0
class TTYRec(Task):
    __slots__ = ( '_ttymon', '_results_lock', '_state' )
    
    def __init__(self, manager):
        super(TTYRec, self).__init__(manager)
        self._ttymon = TTYMon(ignore=[os.getpid(), os.getppid()])
        self._results_lock = Lock()
        self._buffer = Buffer()
        self._compressor = zlib.compressobj(9)

    def task(self):
        for comm, pid, probe, sec, usec, buf in self._ttymon:
            with self._results_lock:
                packet = self._compressor.compress(
                    struct.pack(
                        '<16ssIIII',
                        comm[:16], probe, pid,
                        sec, usec, len(buf)) + buf)
                self._buffer.append(packet)
                self._dirty = True

    @property
    def results(self):
        result = None
        
        with self._results_lock:
            if not self._dirty:
                return None

            try:
                packet = self._compressor.flush()
                self._buffer.append(packet)
            except zlib.error:
                pass
            
            result = self._buffer
            self._buffer = Buffer()
            self._compressor = zlib.compressobj(9)
            self._dirty = False

        return result

    @property
    def active(self):
        return self._ttymon.active

    def stop(self):
        super(TTYRec, self).stop()
        self._ttymon.stop()
Exemplo n.º 8
0
    def __init__(self, sock, transport_class, transport_kwargs):
        super(PupySocketStream, self).__init__(sock)

        self.MAX_IO_CHUNK = 32000
        self.KEEP_ALIVE_REQUIRED = False
        self.compress = True

        #buffers for transport
        self.upstream = Buffer(transport_func=addGetPeer(("127.0.0.1", 443)),
                               shared=True)

        if sock is None:
            peername = '127.0.0.1', 0
        elif type(sock) is tuple:
            peername = sock[0], sock[1]
        else:
            peername = sock.getpeername()

        self.downstream = Buffer(on_write=self._upstream_recv,
                                 transport_func=addGetPeer(peername),
                                 shared=True)

        self.upstream_lock = threading.Lock()
        self.downstream_lock = threading.Lock()

        self.transport = transport_class(self, **transport_kwargs)

        #buffers for streams
        self.buf_in = Buffer()
        self.buf_out = Buffer()

        self.on_connect()
Exemplo n.º 9
0
    def activate(self, peername, on_receive):
        logger.debug('Activating (%s/%s)', self, peername)

        if not self.closed:
            return

        self.closed = False
        self.peername = peername
        self.on_receive = on_receive
        self.downstream = Buffer(on_write=self._flush, shared=True)

        self.transport = self.transport_class(self, **self.transport_kwargs)

        logger.debug('Activating ..  (%s) - transport - %s', self,
                     self.transport)

        self.transport.on_connect()
        logger.debug('Activated (%s)', self)
Exemplo n.º 10
0
    def results(self):
        result = None

        with self._results_lock:
            if not self._dirty:
                return None

            try:
                packet = self._compressor.flush()
                self._buffer.append(packet)
            except zlib.error:
                pass

            result = self._buffer
            self._buffer = Buffer()
            self._compressor = zlib.compressobj(9)
            self._dirty = False

        return result
Exemplo n.º 11
0
    def upstream_recv(self, data):
        if self.encryptor:
            buf = Buffer()

            ldata = len(data)
            buf.write(self.encryptor.encrypt(struct.pack('<I', ldata)))
            _, nw = data.write_to(buf, modificator=self.encryptor.encrypt, n=ldata)
            d = self.update_encryptor()
            buf.write(d)

            buf.write_to(self.downstream)
        else:
            data.write_to(self.up_buffer)
Exemplo n.º 12
0
    def __init__(self, sock, transport_class, transport_kwargs={}, client_side=True, close_cb=None, lsi=5):

        if not (type(sock) is tuple and len(sock) in (2,3)):
            raise Exception(
                'dst_addr is not supplied for UDP stream, '
                'PupyUDPSocketStream needs a reply address/port')

        self.client_side = client_side
        self.closed = False

        self.LONG_SLEEP_INTERRUPT_TIMEOUT = lsi
        self.KEEP_ALIVE_REQUIRED = lsi * 3
        self.INITIALIZED = False

        self.sock, self.dst_addr = sock[0], sock[1]
        if len(sock) == 3:
            self.kcp = sock[2]
        else:
            import kcp
            if client_side:
                dst = self.sock.fileno()
            else:
                # dst = lambda data: self.sock.sendto(data, self.dst_addr)
                dst = (
                    self.sock.fileno(), self.sock.family, self.dst_addr[0], self.dst_addr[1]
                )

            self.kcp = kcp.KCP(dst, 0, interval=64)

        self.kcp.window = 32768

        self.buf_in = Buffer()
        self.buf_out = Buffer()

        #buffers for transport
        self.upstream = Buffer(
            transport_func=addGetPeer(("127.0.0.1", 443)),
            shared=True
        )

        self.downstream = Buffer(
            on_write=self._send,
            transport_func=addGetPeer(self.dst_addr),
            shared=True
        )

        self.upstream_lock = threading.Lock()
        self.downstream_lock = threading.Lock()

        self.transport = transport_class(self, **transport_kwargs)

        self.MAX_IO_CHUNK = self.kcp.mtu - 24
        self.compress = True
        self.close_callback = close_cb

        self._wake_after = None

        self.on_connect()
Exemplo n.º 13
0
    def _worker_run(self):
        try:
            buf = Buffer()
            self._worker_run_unsafe(buf)
        finally:
            del buf

            if self._current_file:
                try:
                    self._current_file.close()
                except:
                    pass

                self._current_file = None
Exemplo n.º 14
0
    def __init__(self, *args, **kwargs):
        """Initialize the obfs3 pluggable transport."""
        super(Obfs3Transport, self).__init__(*args, **kwargs)

        # Our state.
        self.state = ST_WAIT_FOR_KEY

        # Uniform-DH object
        self.dh = obfs3_dh.UniformDH()

        # DH shared secret
        self.shared_secret = None

        # Bytes of padding scanned so far.
        self.scanned_padding = 0
        # Last padding bytes scanned.
        self.last_padding_chunk = ''

        # Magic value that the other party is going to send
        # (initialized after deriving shared secret)
        self.other_magic_value = None
        # Crypto to encrypt outgoing data.
        self.send_crypto = None
        # Crypto to decrypt incoming data.
        self.recv_crypto = None

        # Buffer for the first data, Tor is trying to send but can't right now
        # because we have to handle the DH handshake first.
        self.queued_data = Buffer()

        # Attributes below are filled by classes that inherit Obfs3Transport.
        self.send_keytype = None
        self.recv_keytype = None
        self.send_magic_const = None
        self.recv_magic_const = None
        self.we_are_initiator = None
Exemplo n.º 15
0
    def _recv(self):
        """ Recv logic with interruptions """

        # print "RECV! WAIT FOR LENGTH!"

        packet = self.stream.read(self.FRAME_HEADER.size)
        # If no packet - then just return
        if not packet:
            return None

        header = packet

        while len(header) != self.FRAME_HEADER.size:
            packet = self.stream.read(self.FRAME_HEADER.size - len(header))
            if packet:
                header += packet
                del packet

        length, compressed = self.FRAME_HEADER.unpack(header)
        # print "RECV! WAIT FOR LENGTH COMPLETE!"

        required_length = length + len(self.FLUSHER)
        # print "WAIT FOR", required_length

        data = []
        decompressor = None

        if compressed:
            decompressor = zlib.decompressobj()

        buf = Buffer()

        while required_length:
            packet = self.stream.read(min(required_length, self.COMPRESSION_THRESHOLD))
            if packet:
                required_length -= len(packet)
                # print "GET", len(packet)
                if not required_length:
                    packet = packet[:-len(self.FLUSHER)]

                if compressed:
                    packet = decompressor.decompress(packet)
                    if not packet:
                        continue

                if packet:
                    buf.write(packet)

        if compressed:
            packet = decompressor.flush()
            if packet:
                buf.write(packet)

        # print "COMPLETE!"
        return buf
Exemplo n.º 16
0
    def __init__(self, *args, **kwargs):
        super(RSA_AESTransport, self).__init__(*args, **kwargs)
        if self.aes_size == 256:
            self.key_size = 32
        elif self.aes_size == 128:
            self.key_size = 16
        else:
            raise TransportError("Only AES 256 and 128 are supported")

        self._iv_enc = get_random(BLOCK_SIZE)
        self.enc_cipher = None
        self.dec_cipher = None
        self._iv_dec = None
        self.aes_key = None
        self.size_to_read = None
        self.first_block = b""
        self.buffer = Buffer()
Exemplo n.º 17
0
    def on_connect(self):
        self.exposed_namespace = {}
        self.exposed_cleanups = []
        self._conn._config.update(REVERSE_SLAVE_CONF)

        infos_buffer = Buffer()
        infos = self.exposed_get_infos()

        try:
            umsgpack.dump(infos, infos_buffer, ext_handlers=MSG_TYPES_PACK)
        except Exception as e:
            pupy.remote_error('on_connect failed: {}; infos={}', e, infos)

        self._conn.root.initialize_v1(self.exposed_namespace, pupy.namespace,
                                      __import__('__builtin__'),
                                      self.exposed_register_cleanup,
                                      self.exposed_unregister_cleanup,
                                      self.exposed_obtain_call,
                                      self.exposed_exit, self.exposed_eval,
                                      self.exposed_execute,
                                      __import__('pupyimporter'), infos_buffer)
Exemplo n.º 18
0
 def __init__(self, manager):
     super(TTYRec, self).__init__(manager)
     self._ttymon = TTYMon(ignore=[os.getpid(), os.getppid()])
     self._results_lock = Lock()
     self._buffer = Buffer()
     self._compressor = zlib.compressobj(9)
Exemplo n.º 19
0
class PupySocketStream(SocketStream):
    def __init__(self, sock, transport_class, transport_kwargs):
        super(PupySocketStream, self).__init__(sock)

        self.MAX_IO_CHUNK = 32000
        self.KEEP_ALIVE_REQUIRED = False
        self.compress = True

        #buffers for transport
        self.upstream = Buffer(
            transport_func=addGetPeer(("127.0.0.1", 443)),
            shared=True
        )

        if sock is None:
            peername = '127.0.0.1', 0
        elif type(sock) is tuple:
            peername = sock[0], sock[1]
        else:
            peername = sock.getpeername()

        self.downstream = Buffer(
            on_write=self._upstream_recv,
            transport_func=addGetPeer(peername),
            shared=True
        )

        self.upstream_lock = threading.Lock()
        self.downstream_lock = threading.Lock()

        self.transport = transport_class(self, **transport_kwargs)

        #buffers for streams
        self.buf_in = Buffer()
        self.buf_out = Buffer()

        self.on_connect()

    def on_connect(self):
        self.transport.on_connect()
        self._upstream_recv()

    def _read(self):
        try:
            buf = self.sock.recv(self.MAX_IO_CHUNK)
            if __debug__:
                logger.debug('stream: read={}'.format(len(buf) if buf else None))

        except socket.timeout:
            return

        except socket.error:
            ex = sys.exc_info()[1]
            if get_exc_errno(ex) in (errno.EAGAIN, errno.EWOULDBLOCK):
                # windows just has to be a b**ch
                # edit: some politeness please ;)
                return
            self.close()
            raise EOFError(ex)

        if not buf:
            self.close()
            raise EOFError("connection closed by peer")

        self.buf_in.write(buf)

    # The root of evil
    def poll(self, timeout):
        if self.closed:
            raise EOFError('polling on already closed connection')
        result = ( len(self.upstream)>0 or self.sock_poll(timeout) )
        return result

    def sock_poll(self, timeout):
        with self.downstream_lock:
            to_close = None
            to_read = None

            while not (to_close or to_read or self.closed):
                try:
                    to_read, _, to_close = select([self.sock], [], [self.sock], timeout)
                except select_error as r:
                    if not r.args[0] == errno.EINTR:
                        to_close = True
                    continue

                break

            if to_close:
                raise EOFError('sock_poll error')

            if to_read:
                self._read()
                self.transport.downstream_recv(self.buf_in)
                return True
            else:
                return False

    def _upstream_recv(self):
        """ called as a callback on the downstream.write """
        if len(self.downstream)>0:
            if __debug__:
                logger.debug('stream: send={}'.format(len(self.downstream)))

            self.downstream.write_to(super(PupySocketStream, self))

    def waitfor(self, count):
        if __debug__:
            logger.debug('stream: waitfor={}'.format(count))

        try:
            while len(self.upstream)<count:
                if not self.sock_poll(None) and self.closed:
                    return None

            return self.upstream

        except (EOFError, socket.error):
            self.close()
            raise

        except Exception as e:
            logger.debug(traceback.format_exc())
            self.close()
            raise

    def read(self, count):
        promise = self.waitfor(count)
        if promise:
            return promise.read(count)

    def insert(self, data):
        with self.upstream_lock:
            self.buf_out.insert(data)

    def flush(self):
        self.buf_out.flush()

    def write(self, data, notify=True):
        if __debug__:
            logger.debug('stream: write={} / n={}'.format(
                len(data) if data else None, notify))

        try:
            with self.upstream_lock:
                self.buf_out.write(data, notify)
                del data
                if notify:
                    self.transport.upstream_recv(self.buf_out)
            #The write will be done by the _upstream_recv callback on the downstream buffer

        except (EOFError, socket.error):
            self.close()
            raise

        except Exception as e:
            logger.debug(traceback.format_exc())
            self.close()
            raise
Exemplo n.º 20
0
class PupyUDPSocketStream(object):
    MAGIC = b'\x00'*512

    def __init__(self, sock, transport_class, transport_kwargs={}, client_side=True, close_cb=None, lsi=5):

        if not (type(sock) is tuple and len(sock) in (2,3)):
            raise Exception(
                'dst_addr is not supplied for UDP stream, '
                'PupyUDPSocketStream needs a reply address/port')

        self.client_side = client_side
        self.closed = False

        self.LONG_SLEEP_INTERRUPT_TIMEOUT = lsi
        self.KEEP_ALIVE_REQUIRED = lsi * 3
        self.INITIALIZED = False

        self.sock, self.dst_addr = sock[0], sock[1]
        if len(sock) == 3:
            self.kcp = sock[2]
        else:
            import kcp
            if client_side:
                dst = self.sock.fileno()
            else:
                # dst = lambda data: self.sock.sendto(data, self.dst_addr)
                dst = (
                    self.sock.fileno(), self.sock.family, self.dst_addr[0], self.dst_addr[1]
                )

            self.kcp = kcp.KCP(dst, 0, interval=64)

        self.kcp.window = 32768

        self.buf_in = Buffer()
        self.buf_out = Buffer()

        #buffers for transport
        self.upstream = Buffer(
            transport_func=addGetPeer(("127.0.0.1", 443)),
            shared=True
        )

        self.downstream = Buffer(
            on_write=self._send,
            transport_func=addGetPeer(self.dst_addr),
            shared=True
        )

        self.upstream_lock = threading.Lock()
        self.downstream_lock = threading.Lock()

        self.transport = transport_class(self, **transport_kwargs)

        self.MAX_IO_CHUNK = self.kcp.mtu - 24
        self.compress = True
        self.close_callback = close_cb

        self._wake_after = None

        self.on_connect()

    def on_connect(self):
        # Poor man's connection initialization
        # Without this client side bind payloads will not be able to
        # determine when our connection was established
        # So first who knows where to send data will trigger other side as well

        self._emulate_connect()
        self.transport.on_connect()

    def _emulate_connect(self):
        self.kcp.send(self.MAGIC)
        self.kcp.flush()

    def poll(self, timeout):
        if self.closed:
            return None

        return len(self.upstream)>0 or self._poll_read(timeout)

    def close(self):
        if self.close_callback:
            self.close_callback('{}:{}'.format(
                self.dst_addr[0], self.dst_addr[1]))

        self.closed = True
        self.kcp = None

        if self.client_side:
            self.sock.close()

    def _send(self):
        """ called as a callback on the downstream.write """
        if self.closed or not self.kcp:
            raise EOFError('Connection is not established yet')

        if len(self.downstream)>0:
            while len(self.downstream) > 0:
                data = self.downstream.read(self.MAX_IO_CHUNK)
                self.kcp.send(data)

            if self.kcp:
                self.kcp.flush()

    def _poll_read(self, timeout=None):
        if not self.client_side:
            # In case of strage hangups change None to timeout
            self._wake_after = time.time() + timeout
            return self.buf_in.wait(None)

        buf = self.kcp.recv()
        if buf is None:
            if timeout is not None:
                timeout = int(timeout * 1000)

            try:
                buf = self.kcp.pollread(timeout)
            except OSError, e:
                raise EOFError(str(e))

        have_data = False
        while buf is not None:
            if buf:
                if self.INITIALIZED:
                    with self.buf_in:
                        self.buf_in.write(buf, notify=False)
                    have_data = True
                elif buf == self.MAGIC:
                    self.INITIALIZED = True
                else:
                    raise EOFError('Invalid magic')
            else:
                return False

            buf = self.kcp.recv()

        if have_data:
            self.buf_in.flush()
            return True

        return False
Exemplo n.º 21
0
class PupyWebSocketServer(PupyWebSocketTransport):
    __slots__ = (
        'user_agent',
        'path',
        'offset',
        'upgraded_buf',
        'missing_bytes',
        'upgraded',
        'decoded',
        'mask',
    )

    def __init__(self, *args, **kwargs):
        PupyWebSocketTransport.__init__(self, *args, **kwargs)
        self.upgraded = False
        self.user_agent = kwargs.pop('user-agent')
        self.path = kwargs.pop('path')
        self.mask = True
        self.offset = 0
        self.missing_bytes = 0
        self.decoded = Buffer()
        self.upgraded_buf = Buffer()

        if __debug__:
            logger.debug('WS Server, path=%s, user-agent=%s', self.path,
                         self.user_agent)

    def calculate_response_key(self, key):
        GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
        hsh = sha1(key.encode() + GUID.encode())
        response_key = base64.b64encode(hsh.digest()).strip()
        return response_key.decode('ASCII')

    def bad_request(self, msg):
        if __debug__:
            logger.debug(msg)

        self.downstream.write(error_response)
        self.close()

    def upstream_recv(self, data):
        """
            Encoding server -> client messages
            Messsages shouldn't be masked
        """
        try:
            if self.upgraded:
                add_ws_encapsulation(data, self.downstream)
            else:
                add_ws_encapsulation(data, self.upgraded_buf)

        except Exception as e:
            raise EOFError(str(e))

    def downstream_recv(self, data):
        """
            Decoding client -> server messages
            Message should be masked coming from client
        """

        if not self.upgraded:
            if __debug__:
                logger.debug('WS: Wait for upgrade requet')

            d = data.peek()
            # Handle HTTP GET requests, strip websocket keys, verify UA etc
            if not d.startswith('GET '):
                self.bad_request('Invalid HTTP method or data ({})'.format(
                    repr(d)))

            if '\r\n\r\n' not in d:
                if __debug__:
                    logger.debug('Short read, incomplete header')
                return

            _, path, _ = d.split(' ', 2)
            if path != self.path:
                self.bad_request('Path does not match ({} != {})!'.format(
                    path, self.path))
                return

            wskey = None

            key = re.search(
                r'\n[sS]ec-[wW]eb[sS]ocket-[kK]ey[\s]*:[\s]*(.*)\r\n', d)
            if key:
                wskey = key.group(1)
            else:
                if __debug__:
                    logger.debug('Unable to get WebSocketKey')

            if self.user_agent:
                ua = re.search(r'\n[uU]ser-[aA]gent:[\s]*(.*)\r\n', d)
                if ua:
                    ua = ua.group(1)
                else:
                    self.bad_request('No User-Agent provided')
                    return

                if ua != self.user_agent:
                    self.bad_request(
                        'Bad User-Agent provided. May be counter-intel ({} != {})'
                        .format(ua, self.user_agent))
                    return

            payload = 'HTTP/1.1 101 Switching Protocols\r\n'
            payload += 'Upgrade: websocket\r\n'
            payload += 'Connection: Upgrade\r\n'

            if wskey:
                payload += 'Sec-WebSocket-Accept: %s\r\n' % (
                    self.calculate_response_key(wskey))

            payload += '\r\n'

            data.drain(d.index('\r\n\r\n') + 4)

            if __debug__:
                logger.debug('Flush upgrade response')

            self.downstream.write(payload)

            if self.upgraded_buf:
                if __debug__:
                    logger.debug('Flush buffer %d', len(self.upgraded_buf))

                self.upgraded_buf.write_to(self.downstream)

            self.upgraded = True

        while data:
            msg_len, self.offset, self.missing_bytes, self.mask = remove_ws_encapsulation(
                data, self.upstream, self.decoded, self.offset,
                self.missing_bytes, self.mask)

            if __debug__:
                logger.debug('Parsed: %d, offset: %d, missing: %d, left: %d',
                             msg_len, self.offset, self.missing_bytes,
                             len(data))

            if not msg_len:
                break
Exemplo n.º 22
0
class PupyUDPSocketStream(object):
    NEW = '\x00'
    DAT = '\x01'
    END = '\x02'

    def __init__(self,
                 sock,
                 transport_class,
                 transport_kwargs={},
                 client_side=True,
                 close_cb=None,
                 lsi=5):

        if not (type(sock) is tuple and len(sock) in (2, 3)):
            raise Exception('dst_addr is not supplied for UDP stream, '
                            'PupyUDPSocketStream needs a reply address/port')

        self.client_side = client_side
        self.closed = False

        self.local_connid = os.urandom(4)
        self.remote_connid = None

        self.LONG_SLEEP_INTERRUPT_TIMEOUT = lsi
        self.KEEP_ALIVE_REQUIRED = lsi * 3
        self.INITIALIZED = False
        self.NEW_SENT = False

        self.sock, self.dst_addr = sock[0], sock[1]
        if len(sock) == 3:
            self.kcp = sock[2]
        else:
            if client_side:
                dst = self.sock.fileno()
            else:
                # dst = lambda data: self.sock.sendto(data, self.dst_addr)
                dst = (self.sock.fileno(), self.sock.family, self.dst_addr[0],
                       self.dst_addr[1])

            self.kcp = kcp.KCP(dst, 0, interval=64)

        self.kcp.window = 32768

        self.buf_in = Buffer(shared=True)
        self.buf_out = Buffer()

        #buffers for transport
        self.upstream = Buffer(transport_func=addGetPeer(("127.0.0.1", 443)),
                               shared=True)

        self.downstream = Buffer(on_write=self._send,
                                 transport_func=addGetPeer(self.dst_addr),
                                 shared=True)

        self.upstream_lock = threading.Lock()
        self.downstream_lock = threading.Lock()

        self.transport = transport_class(self, **transport_kwargs)

        self.MAX_IO_CHUNK = self.kcp.mtu - (24 + 5)
        self.compress = True
        self.close_callback = close_cb

        self._wake_after = None

        self.failed = False
        try:
            self.on_connect()

        except Exception:
            self.failed = True
            raise

    def on_connect(self):
        self.transport.on_connect()

    def _send_packet(self, flag, data=''):
        need_flush = False
        if flag in (self.NEW, self.END):
            need_flush = True

        if flag == self.DAT and not self.NEW_SENT:
            flag = self.NEW
            self.NEW_SENT = True

        self.kcp.send(flag + self.local_connid + data)
        if need_flush:
            self.kcp.flush()

    def poll(self, timeout):
        if self.closed:
            return None

        return len(self.upstream) > 0 or self._poll_read(timeout)

    def close(self):
        self._send_packet(self.END)

        if self.close_callback:
            self.close_callback('{}:{}'.format(self.dst_addr[0],
                                               self.dst_addr[1]))

        self.closed = True
        self.kcp = None

        if self.client_side:
            self.sock.close()

    def _send(self):
        """ called as a callback on the downstream.write """
        if self.closed or not self.kcp:
            raise EOFError('Connection is not established yet')

        if len(self.downstream) > 0:
            while len(self.downstream) > 0:
                data = self.downstream.read(self.MAX_IO_CHUNK)
                self._send_packet(self.DAT, data)

            if self.kcp:
                self.kcp.flush()

    def _process_buf(self, buf):
        flag = buf[0]
        connid = buf[1:5]
        buf = buf[5:]

        if not self.INITIALIZED:
            if flag == self.NEW:
                self.INITIALIZED = True
                self.remote_connid = connid
            else:
                if flag == self.DAT:
                    self._send_packet(self.END)

                raise EOFError('Unexpected flag')
        elif flag == self.END:
            raise EOFError('EOF Flag received')

        elif connid != self.remote_connid:
            raise EOFError('Unexpected connection id')

        return buf

    def _poll_read(self, timeout=None):
        if not self.client_side:
            # In case of strage hangups change None to timeout
            self._wake_after = time.time() + timeout
            return self.buf_in.wait(None)

        buf = self.kcp.recv()
        if buf is None:
            if timeout is not None:
                timeout = int(timeout * 1000)

            try:
                buf = self.kcp.pollread(timeout)
            except OSError, e:
                raise EOFError(str(e))

        have_data = False
        while buf:
            buf = self._process_buf(buf)
            if buf:
                with self.buf_in:
                    self.buf_in.write(buf, notify=False)
                have_data = True

            buf = self.kcp.recv()

        if have_data:
            self.buf_in.flush()
            return True

        return False
Exemplo n.º 23
0
class TTYRec(Task):
    __slots__ = ('_ttymon', '_results_lock', '_state', '_event_id')

    def __init__(self, manager, event_id=None,
            name=None, winsize=None, tty_private=None):
        super(TTYRec, self).__init__(manager)
        self._ttymon = TTYMon(
            name, winsize, tty_private, ignore=[os.getpid(), os.getppid()]
        )
        self._results_lock = Lock()
        self._buffer = Buffer()
        self._compressor = zlib.compressobj(9)
        self._event_id = event_id
        self._session = 0

    def task(self):
        self._session, = struct.unpack('<I', get_random(4))

        for tty_name, comm, pid, probe, ts, buf in self._ttymon:

            tty_name = tty_name[:8].ljust(8)
            comm = comm[:16].ljust(16)

            if probe == 'R':
                buf = struct.pack('<HH', *buf)

            with self._results_lock:
                packet = self._compressor.compress(
                    struct.pack(
                        '<I8s16ssIfI',
                        self._session, tty_name, comm, probe, pid,
                        ts, len(buf)) + buf)
                self._buffer.append(packet)

                fire_event = False

                if not self._dirty:
                    fire_event = True

                self._dirty = True

                try:
                    if fire_event and self._event_id is not None:
                        self.broadcast_event(self._event_id)
                except Exception:
                    pass

    @property
    def results(self):
        result = None

        with self._results_lock:
            if not self._dirty:
                return None

            try:
                packet = self._compressor.flush()
                self._buffer.append(packet)
            except zlib.error:
                pass

            result = self._buffer
            self._buffer = Buffer()
            self._compressor = zlib.compressobj(9)
            self._dirty = False

        return result

    @property
    def active(self):
        return self._ttymon.active

    def stop(self):
        self._ttymon.stop()
        super(TTYRec, self).stop()
Exemplo n.º 24
0
def stream_dump(obj):
    buf = Buffer()
    brine._dump(obj, buf)
    return buf
Exemplo n.º 25
0
class ECMTransport(BasePupyTransport):
    __slots__ = ('encryptor', 'decryptor', 'up_buffer', 'dec_buffer', 'nonce',
                 'key', 'chunk_len', 'need_validation', 'encoder')

    privkey = None
    pubkey = None

    def __init__(self, *args, **kwargs):
        super(ECMTransport, self).__init__(*args, **kwargs)
        if not self.pubkey and not self.privkey:
            raise ValueError('Public or Private key required for ECM')

        if self.pubkey:
            self.encoder = ECPV(curve='brainpoolP384r1',
                                public_key=self.pubkey,
                                hash=SHA384)
        else:
            self.encoder = ECPV(curve='brainpoolP384r1',
                                public_key=self.privkey,
                                hash=SHA384)

        self.encryptor = None
        self.decryptor = None
        self.up_buffer = Buffer()
        self.dec_buffer = Buffer()
        self.nonce = None
        self.key = None
        self.chunk_len = 0
        self.need_validation = False

    def update_encryptor(self):
        vblock = self.encryptor.digest()

        h = SHA3_224.new()
        h.update(self.key[0])
        h.update(vblock)
        self.encryptor = AES.new(key=self.key[0],
                                 mode=AES.MODE_GCM,
                                 nonce=h.digest())

        return vblock

    def update_decryptor(self, vblock):
        self.decryptor.verify(vblock)

        h = SHA3_224.new()
        h.update(self.key[1])
        h.update(vblock)
        self.decryptor = AES.new(key=self.key[1],
                                 mode=AES.MODE_GCM,
                                 nonce=h.digest())

    def kex(self, data):
        if len(data) < 4:
            return False

        reqlen, noncelen = struct.unpack_from('<HH', data.peek(4))
        if len(data) < 4 + reqlen + noncelen:
            return False

        data.drain(4)

        request = data.read(reqlen)
        remote_nonce = data.read(noncelen)

        if self.privkey:
            response, key = self.encoder.process_kex_request(request, 0)
            # Add jitter, tinyec is quite horrible
            time.sleep(random.random())
            nonce = get_random_bytes(16)
            self.downstream.write(
                struct.pack('<HH', len(response), len(nonce)) + response +
                nonce)
        else:
            key = self.encoder.process_kex_response(request, 0)
            nonce = self.nonce

        eh = SHA3_224.new()
        eh.update(key[0])
        eh.update(remote_nonce)
        ek = eh.digest()[:16]

        dh = SHA3_224.new()
        dh.update(key[1])
        dh.update(nonce)
        dk = dh.digest()[:16]

        self.key = (ek, dk)

        self.encryptor = AES.new(key=self.key[0],
                                 mode=AES.MODE_GCM,
                                 nonce=nonce)
        self.decryptor = AES.new(key=self.key[1],
                                 mode=AES.MODE_GCM,
                                 nonce=remote_nonce)

        return True

    def downstream_recv(self, data):
        if self.decryptor:
            while len(data):
                if not self.chunk_len:
                    if self.need_validation:
                        if len(data) < 16:
                            return

                        vblock = data.read(16)
                        self.update_decryptor(vblock)
                        self.need_validation = False
                        self.dec_buffer.write_to(self.upstream)

                    if len(data) < 4:
                        break

                    raw_chunk_len = self.decryptor.decrypt(data.read(4))
                    self.chunk_len, = struct.unpack('<I', raw_chunk_len)

                if not len(data):
                    break

                nr, nw = data.write_to(self.dec_buffer,
                                       modificator=self.decryptor.decrypt,
                                       n=self.chunk_len)

                self.chunk_len -= nr
                if not self.chunk_len:
                    self.need_validation = True

        elif self.kex(data):
            if len(self.up_buffer):
                self.upstream_recv(self.up_buffer)

            if len(data):
                self.downstream_recv(data)

    def upstream_recv(self, data):
        if self.encryptor:
            buf = Buffer()

            ldata = len(data)
            buf.write(self.encryptor.encrypt(struct.pack('<I', ldata)))
            _, nw = data.write_to(buf,
                                  modificator=self.encryptor.encrypt,
                                  n=ldata)
            d = self.update_encryptor()
            buf.write(d)

            buf.write_to(self.downstream)
        else:
            data.write_to(self.up_buffer)
Exemplo n.º 26
0
class EC4Transport(BasePupyTransport):

    __slots__ = ('encryptor', 'decryptor', 'up_buffer')

    privkey = None
    pubkey = None

    def __init__(self, *args, **kwargs):
        super(EC4Transport, self).__init__(*args, **kwargs)
        if not self.pubkey and not self.privkey:
            raise ValueError('Public or Private key required for EC4')

        if self.pubkey:
            self.encoder = ECPV(curve='brainpoolP384r1',
                                public_key=self.pubkey,
                                hash=SHA384)
        else:
            self.encoder = ECPV(curve='brainpoolP384r1',
                                private_key=self.privkey,
                                hash=SHA384)

        self.encryptor = None
        self.decryptor = None
        self.up_buffer = Buffer()

    def kex(self, data):
        if len(data) < 2:
            return False

        length, = struct.unpack_from('H', data.peek(2))
        if len(data) < 2 + length:
            return False

        request = data.read(2 + length)

        if self.privkey:
            try:
                response, key = self.encoder.process_kex_request(request[2:],
                                                                 0,
                                                                 key_size=128)
            except ValueError as e:
                raise EOFError(str(e))

            # Add jitter, tinyec is quite horrible
            time.sleep(random.random())
            self.downstream.write(struct.pack('H', len(response)) + response)
        else:
            try:
                key = self.encoder.process_kex_response(request[2:],
                                                        0,
                                                        key_size=128)
            except ValueError as e:
                raise EOFError(str(e))

        self.encryptor = RC4(key=key[0])
        self.decryptor = RC4(key=key[1])

        # https://wikileaks.org/ciav7p1/cms/files/NOD%20Cryptographic%20Requirements%20v1.1%20TOP%20SECRET.pdf
        # Okay...
        self.encryptor.encrypt('\x00' * 3072)
        self.decryptor.decrypt('\x00' * 3072)
        return True

    def downstream_recv(self, data):
        if self.encryptor:
            data.write_to(self.upstream, modificator=self.decryptor.decrypt)

        elif self.kex(data):
            if self.up_buffer:
                self.up_buffer.write_to(self.downstream,
                                        modificator=self.encryptor.encrypt)
                self.up_buffer = None

            if len(data):
                data.write_to(self.upstream,
                              modificator=self.decryptor.decrypt)

    def upstream_recv(self, data):
        if self.encryptor:
            data.write_to(self.downstream, modificator=self.encryptor.encrypt)
        else:
            data.write_to(self.up_buffer)
Exemplo n.º 27
0
class PupyHTTPWrapperServer(BasePupyTransport):
    path = '/index.php?d='
    allowed_methods = ('GET')
    server = None
    headers = {
        'Content-Type': 'text/html; charset=utf-8',
        'Server': 'Apache',
        'Connection': 'close',
    }

    __slots__ = ('parser', 'is_http', 'body', 'downstream_buffer',
                 'well_known', 'omit', 'probe_len')

    def __init__(self, *args, **kwargs):
        super(PupyHTTPWrapperServer, self).__init__(*args, **kwargs)

        self.parser = HttpParser()
        self.is_http = None
        self.body = []
        self.downstream_buffer = Buffer()

        self.well_known = ('GET', 'POST', 'OPTIONS', 'HEAD', 'PUT', 'DELETE')
        self.omit = tuple('{} {}'.format(x, y) for x in self.well_known
                          for y in (self.path, '/ws/', 'ws/'))
        self.probe_len = max(len(x) for x in self.omit)

    def _http_response(self,
                       code,
                       status,
                       headers=None,
                       datasize=None,
                       content=None):
        headers = {}
        headers.update(self.headers)

        if headers:
            headers.update(headers)

        if datasize:
            headers.update({
                'Content-Length': datasize,
                'Content-Type': 'application/octet-stream',
            })

        data = '\r\n'.join([
            'HTTP/1.1 {} {}'.format(code, status), '\r\n'.join([
                '{}: {}'.format(key, value)
                for key, value in headers.iteritems()
            ])
        ]) + '\r\n\r\n'

        self.downstream.write(data)

    def _handle_file(self, filepath):
        try:
            with open(filepath) as infile:
                size = stat(filepath).st_size
                self._http_response(200, 'OK', datasize=size)

                while True:
                    data = infile.read(65535)
                    if data:
                        self.downstream.write(data)
                    else:
                        break

        except:
            self._http_response(404, 'Not found', 'Not found')

    def _handle_not_found(self):
        self._http_response(404, 'Not found', 'Not found')

    def _handle_http(self, data):
        self.parser.execute(data, len(data))

        if self.parser.is_headers_complete():
            try:
                if not self.parser.get_method() in self.allowed_methods:
                    self._http_response(405, 'Method Not Allowed')

                else:
                    urlpath = self.parser.get_path()
                    urlpath = [
                        x.strip() for x in urlpath.split('/')
                        if (x and not str(x) in ('.', '..'))
                    ]

                    root = self.server.config.get_folder('wwwroot')
                    secret = self.server.config.getboolean('httpd', 'secret')
                    log = self.server.config.getboolean('httpd', 'log')

                    if secret:
                        wwwsecret = self.server.config.get('randoms',
                                                           'wwwsecret',
                                                           random=5)
                        if not (urlpath and urlpath[0] == wwwsecret):
                            self._handle_not_found()
                            if log:
                                self.server.info(
                                    '{}: GET {} | SECRET = {}'.format(
                                        '{}:{}'.format(*self.downstream.
                                                       transport.peer[:2]),
                                        urlpath, wwwsecret),
                                    error=True)
                            return

                        urlpath = urlpath[1:]

                    urlpath = path.sep.join([
                        self.server.config.get('randoms', x, new=False) or x
                        for x in urlpath
                    ])

                    if not urlpath:
                        urlpath = 'index.html'

                    filepath = path.join(root, urlpath)

                    if path.exists(filepath):
                        self._handle_file(filepath)
                        if log:
                            message = urlpath
                            if filepath in self.server.served_content:
                                message = message + ' <' + self.server.served_content[
                                    filepath] + '>'

                            self.server.info('{}: GET /{}'.format(
                                '{}:{}'.format(
                                    *self.downstream.transport.peer[:2]),
                                message))

                    else:
                        self._handle_not_found()
                        if log:
                            self.server.info('{}: GET {}'.format(
                                '{}:{}'.format(
                                    *self.downstream.transport.peer[:2]),
                                urlpath),
                                             error=True)
            finally:
                self.close()

    def downstream_recv(self, data):
        header = data.peek(self.probe_len)

        if __debug__:
            logger.debug('Recv: len=%d // header = %s', len(data), header)

        if self.server and self.is_http is None:
            self.is_http = header.startswith(self.well_known) and \
              not header.startswith(self.omit)

            if __debug__:
                logger.debug('Http: %s', self.is_http)

        if self.is_http:
            self._handle_http(data.read())
        else:
            if __debug__:
                logger.debug('Write to upstream: len=%d, handler=%s',
                             len(data), self.upstream.on_write_f)

            data.write_to(self.upstream)

            if self.downstream_buffer:
                if __debug__:
                    logger.debug(
                        'Flush buffer to downstream: len=%d, handler=%s',
                        len(self.downstream_buffer),
                        self.downstream.on_write_f)

                self.downstream_buffer.write_to(self.downstream)

            if __debug__:
                logger.debug('Release transport')

            raise ReleaseChainedTransport()

    def upstream_recv(self, data):
        if __debug__:
            logger.debug('Send intent: len=%d', len(data))

        if self.is_http is None:
            data.write_to(self.downstream_buffer)

            if __debug__:
                logger.debug('HTTP? Append to pending buffer: total len=%d',
                             len(self.downstream_buffer))

        elif not self.is_http:
            if __debug__:
                logger.debug('Non-HTTP: Direct pass (handler=%s)',
                             self.downstream.on_write_f)

            if self.downstream_buffer:
                self.downstream_buffer.write_to(self.downstream)

            data.write_to(self.downstream)
        else:
            if __debug__:
                logger.debug('HTTP: Omit data')

            pass