def handle(self, sock, address):
        session = conpot_core.get_session('kamstrup_management_protocol', address[0], address[1])
        logger.info('New connection from {0}:{1}. ({2})'.format(address[0], address[1], session.id))

        try:
            sock.send(self.banner.format(
                conpot_core.get_databus().get_value("mac_address")))

            while True:
                request = sock.recv(1024)
                if not request:
                    logger.info('Client disconnected. ({0})'.format(session.id))
                    break

                logdata = {'request': request}
                response = self.command_responder.respond(request)
                logdata['response'] = response
                logger.debug('Kamstrup management traffic from {0}: {1} ({2})'.format(address[0], logdata, session.id))
                session.add_event(logdata)
                gevent.sleep(0.25)  # TODO measure delay and/or RTT

                if response is None:
                    break
                sock.send(response)

        except socket.timeout:
            logger.debug('Socket timeout, remote: {0}. ({1})'.format(address[0], session.id))

        sock.close()
Пример #2
0
    def log(self,
            version,
            msg_type,
            addr,
            req_varBinds,
            res_varBinds=None,
            sock=None):
        session = conpot_core.get_session("snmp", addr[0], addr[1],
                                          get_interface_ip(addr[0]),
                                          sock.getsockname()[1])
        req_oid = req_varBinds[0][0]
        req_val = req_varBinds[0][1]
        event_type = "SNMPv{0} {1}".format(version, msg_type)
        request = {"oid": str(req_oid), "val": str(req_val)}
        response = None

        logger.info("%s request from %s: %s %s", event_type, addr, req_oid,
                    req_val)

        if res_varBinds:
            res_oid = ".".join(map(str, res_varBinds[0][0]))
            res_val = res_varBinds[0][1]
            logger.info("%s response to %s: %s %s", event_type, addr, res_oid,
                        res_val)
            response = {"oid": str(res_oid), "val": str(res_val)}

        session.add_event({
            "type": event_type,
            "request": request,
            "response": response
        })
Пример #3
0
    def handle(self, sock, address):
        sock.settimeout(self.timeout)

        session = conpot_core.get_session('modbus', address[0], address[1])

        self.start_time = time.time()
        logger.info('New connection from {0}:{1}. ({2})'.format(address[0], address[1], session.id))

        try:
            while True:
                request = sock.recv(7)
                if not request:
                    logger.info('Client disconnected. ({0})'.format(session.id))
                    break
                if request.strip().lower() == 'quit.':
                    logger.info('Client quit. ({0})'.format(session.id))
                    break
                tr_id, pr_id, length = struct.unpack(">HHH", request[:6])
                while len(request) < (length + 6):
                    new_byte = sock.recv(1)
                    request += new_byte
                query = modbus_tcp.TcpQuery()

                # logdata is a dictionary containing request, slave_id, function_code and response
                response, logdata = self._databank.handle_request(query, request)
                logdata['request'] = request.encode('hex')
                session.add_event(logdata)

                logger.debug('Modbus traffic from {0}: {1} ({2})'.format(address[0], logdata, session.id))

                if response:
                    sock.sendall(response)
        except socket.timeout:
            logger.debug('Socket timeout, remote: {0}. ({1})'.format(address[0], session.id))
Пример #4
0
    def log(self, version, request_type, addr, request, response=None):

        session = conpot_core.get_session(
            'http', addr[0], addr[1],
            self.connection._sock.getsockname()[0],
            self.connection._sock.getsockname()[1])

        log_dict = {
            'remote': addr,
            'timestamp': datetime.utcnow(),
            'data_type': 'http',
            'dst_port': self.server.server_port,
            'data': {
                0: {
                    'request':
                    '{0} {1}: {2}'.format(version, request_type, request)
                }
            }
        }

        logger.info('%s %s request from %s: %s. %s', version, request_type,
                    addr, request, session.id)

        if response:
            logger.info('%s response to %s: %s. %s', version, addr, response,
                        session.id)
            log_dict['data'][0]['response'] = '{0} response: {1}'.format(
                version, response)
            session.add_event({
                'request': str(request),
                'response': str(response)
            })
        else:
            session.add_event({'request': str(request)})
    def handle(self, data, address):
        session = conpot_core.get_session('bacnet', address[0], address[1])
        logger.info('New Bacnet connection from %s:%d. (%s)', address[0],
                    address[1], session.id)
        session.add_event({'type': 'NEW_CONNECTION'})
        # I'm not sure if gevent DatagramServer handles issues where the
        # received data is over the MTU -> fragmentation
        if data:
            pdu = PDU()
            pdu.pduData = data
            apdu = APDU()
            npdu = NPDU()
            bvlpdu = BVLPDU()
            try:
                bvlpdu.decode(pdu)
                npdu.decode(bvlpdu)
                apdu.decode(npdu)

            except DecodingError as e:
                logger.error("DecodingError: %s", e)
                logger.error("PDU: " + format(pdu))
                return
            self.bacnet_app.indication(apdu, address, self.thisDevice)
            self.bacnet_app.response(self.bacnet_app._response, npdu, bvlpdu,
                                     address)
        logger.info('Bacnet client disconnected %s:%d. (%s)', address[0],
                    address[1], session.id)
Пример #6
0
    def handle(self, sock, address):
        sock.settimeout(self.timeout)

        session = conpot_core.get_session('modbus', address[0], address[1])

        self.start_time = time.time()
        logger.info('New connection from {0}:{1}. ({2})'.format(address[0], address[1], session.id))

        try:
            while True:
                request = sock.recv(7)
                if not request:
                    logger.info('Client disconnected. ({0})'.format(session.id))
                    break
                if request.strip().lower() == 'quit.':
                    logger.info('Client quit. ({0})'.format(session.id))
                    break
                tr_id, pr_id, length = struct.unpack(">HHH", request[:6])
                while len(request) < (length + 6):
                    new_byte = sock.recv(1)
                    request += new_byte
                query = modbus_tcp.TcpQuery()

                # logdata is a dictionary containing request, slave_id, function_code and response
                response, logdata = self._databank.handle_request(query, request)
                logdata['request'] = request.encode('hex')
                session.add_event(logdata)

                logger.debug('Modbus traffic from {0}: {1} ({2})'.format(address[0], logdata, session.id))

                if response:
                    sock.sendall(response)
        except socket.timeout:
            logger.debug('Socket timeout, remote: {0}. ({1})'.format(address[0], session.id))
Пример #7
0
    def log(self, version, request_type, addr, request, response=None):

        session = conpot_core.get_session('http', addr[0], addr[1])

        log_dict = {
            'remote': addr,
            'timestamp': datetime.utcnow(),
            'data_type': 'http',
            'data': {
                0: {
                    'request':
                    '{0} {1}: {2}'.format(version, request_type, request)
                }
            }
        }

        logger.info('{0} {1} request from {2}: {3}. {4}'.format(
            version, request_type, addr, request, session.id))

        if response:
            logger.info('{0} response to {1}: {2}. {3}'.format(
                version, addr, response, session.id))
            log_dict['data'][0]['response'] = '{0} response: {1}'.format(
                version, response)
            session.add_event({
                'request': str(request),
                'response': str(response)
            })
        else:
            session.add_event({'request': str(request)})
Пример #8
0
 def handle(self, data, address):
     session = conpot_core.get_session(
         "bacnet",
         address[0],
         address[1],
         get_interface_ip(address[0]),
         self.server.server_port,
     )
     logger.info("New Bacnet connection from %s:%d. (%s)", address[0],
                 address[1], session.id)
     session.add_event({"type": "NEW_CONNECTION"})
     # I'm not sure if gevent DatagramServer handles issues where the
     # received data is over the MTU -> fragmentation
     if data:
         pdu = PDU()
         pdu.pduData = bytearray(data)
         apdu = APDU()
         try:
             apdu.decode(pdu)
         except DecodingError:
             logger.warning("DecodingError - PDU: {}".format(pdu))
             return
         self.bacnet_app.indication(apdu, address, self.thisDevice)
         # send an appropriate response from BACnet app to the attacker
         self.bacnet_app.response(self.bacnet_app._response, address)
     logger.info("Bacnet client disconnected %s:%d. (%s)", address[0],
                 address[1], session.id)
Пример #9
0
    def log(self,
            version,
            msg_type,
            addr,
            dst_host,
            dst_port,
            req_varBinds,
            res_varBinds=None):
        session = conpot_core.get_session('snmp', addr[0], addr[1], dst_host,
                                          dst_port)
        req_oid = req_varBinds[0][0]
        req_val = req_varBinds[0][1]
        event_type = 'SNMPv{0} {1}'.format(version, msg_type)
        request = {'oid': str(req_oid), 'val': str(req_val)}
        response = None

        logger.info('%s request from %s: %s %s', event_type, addr, req_oid,
                    req_val)

        if res_varBinds:
            res_oid = ".".join(map(str, res_varBinds[0][0]))
            res_val = res_varBinds[0][1]
            logger.info('%s response to %s: %s %s', event_type, addr, res_oid,
                        res_val)
            response = {'oid': str(res_oid), 'val': str(res_val)}

        session.add_event({
            'type': event_type,
            'request': request,
            'response': response
        })
    def handle(self, sock, address):
        session = conpot_core.get_session('kamstrup_management_protocol', address[0], address[1])
        logger.info('New connection from {0}:{1}. ({2})'.format(address[0], address[1], session.id))

        try:
            sock.send(self.banner.format(
                conpot_core.get_databus().get_value("mac_address")))

            while True:
                request = sock.recv(1024)
                if not request:
                    logger.info('Client disconnected. ({0})'.format(session.id))
                    break

                logdata = {'request': request}
                response = self.command_responder.respond(request)
                logdata['response'] = response
                logger.debug('Kamstrup management traffic from {0}: {1} ({2})'.format(address[0], logdata, session.id))
                session.add_event(logdata)
                gevent.sleep(0.25)  # TODO measure delay and/or RTT

                if response is None:
                    break
                sock.send(response)

        except socket.timeout:
            logger.debug('Socket timeout, remote: {0}. ({1})'.format(address[0], session.id))

        sock.close()
Пример #11
0
    def handle(self, sock, address):
        session = conpot_core.get_session(self.proxy_id, address[0],
                                          address[1])
        logger.info('New connection from {0}:{1} on {2} proxy. ({3})'.format(
            address[0], address[1], self.proxy_id, session.id))
        proxy_socket = socket()

        if self.keyfile and self.certfile:
            proxy_socket = wrap_socket(proxy_socket, self.keyfile,
                                       self.certfile)

        try:
            proxy_socket.connect((self.proxy_host, self.proxy_port))
        except _socket.error as ex:
            logger.error(
                'Error while connecting to proxied service at ({0}, {1}): {2}'.
                format(self.proxy_host, self.proxy_port, ex))
            self._close([proxy_socket, sock])
            return

        sockets = [proxy_socket, sock]
        while len(sockets) == 2:
            gevent.sleep()
            sockets_read, _, sockets_err = select.select(
                sockets, [], sockets, 10)

            if len(sockets_err) > 0:
                self._close([proxy_socket, sock])
                break

            for s in sockets_read:
                data = s.recv(1024)
                if len(data) is 0:
                    self._close([proxy_socket, sock])
                    if s is proxy_socket:
                        logging.info(
                            'Closing proxy connection because the proxied socket closed.'
                        )
                        sockets = []
                        break
                    elif s is sock:
                        logging.info(
                            'Closing proxy connection because the remote socket closed'
                        )
                        sockets = []
                        break
                    else:
                        assert False
                if s is proxy_socket:
                    self.handle_out_data(data, sock, session)
                elif s is sock:
                    self.handle_in_data(data, proxy_socket, session)
                else:
                    assert False

        proxy_socket.close()
        sock.close()
Пример #12
0
    def handle(self, sock, address):
        sock.settimeout(self.timeout)

        session = conpot_core.get_session('modbus', address[0], address[1])

        self.start_time = time.time()
        logger.info('New connection from %s:%s. (%s)', address[0], address[1], session.id)
        session.add_event({'type': 'NEW_CONNECTION'})

        try:
            while True:
                request = sock.recv(7)
                if not request:
                    logger.info('Client disconnected. (%s)', session.id)
                    session.add_event({'type': 'CONNECTION_LOST'})
                    break
                if request.strip().lower() == 'quit.':
                    logger.info('Client quit. (%s)', session.id)
                    session.add_event({'type': 'CONNECTION_QUIT'})
                    break
                tr_id, pr_id, length = struct.unpack(">HHH", request[:6])
                while len(request) < (length + 6):
                    new_byte = sock.recv(1)
                    request += new_byte
                query = modbus_tcp.TcpQuery()

                # logdata is a dictionary containing request, slave_id, function_code and response
                response, logdata = self._databank.handle_request(query, request, self.mode)
                logdata['request'] = request.encode('hex')

                session.add_event(logdata)

                logger.info('Modbus traffic from {0}: {1} ({2})'.format(address[0], logdata, session.id))
                if response:
                    sock.sendall(response)
                    logger.info('Modbus response sent to {0}'.format(address[0]))
                else:
                    # MB serial connection addressing UID=0
                    if (self.mode == 'serial' and logdata['slave_id'] == 0):
                        time.sleep(self.delay/1000) # millisecs
                        logger.debug('Modbus server\'s turnaround delay expired.')
                        logger.info('Connection terminated with client {0}.'.format(address[0]))
                        session.add_event({'type': 'CONNECTION_TERMINATED'})
                        sock.shutdown(socket.SHUT_RDWR)
                        sock.close()
                        break
                    # Invalid addressing
                    else:
                        logger.info('Client ignored due to invalid addressing. ({0})'.format(session.id))
                        session.add_event({'type': 'CONNECTION_TERMINATED'})
                        sock.shutdown(socket.SHUT_RDWR)
                        sock.close()
                        break

        except socket.timeout:
            logger.debug('Socket timeout, remote: %s. (%s)', address[0], session.id)
            session.add_event({'type': 'CONNECTION_LOST'})
Пример #13
0
    def handle(self, sock, address):
        session = conpot_core.get_session(
            "kamstrup_management_protocol",
            address[0],
            address[1],
            sock.getsockname()[0],
            sock.getsockname()[1],
        )
        logger.info(
            "New Kamstrup connection from %s:%s. (%s)",
            address[0],
            address[1],
            session.id,
        )
        session.add_event({"type": "NEW_CONNECTION"})

        try:
            sock.send(
                str_to_bytes(
                    self.banner.format(
                        conpot_core.get_databus().get_value("mac_address")
                    )
                )
            )

            while True:
                data = sock.recv(1024)
                if not data:
                    logger.info("Kamstrup client disconnected. (%s)", session.id)
                    session.add_event({"type": "CONNECTION_LOST"})
                    break
                request = data.decode()
                logdata = {"request": request}
                response = self.command_responder.respond(request)
                logdata["response"] = response
                logger.info(
                    "Kamstrup management traffic from %s: %s (%s)",
                    address[0],
                    logdata,
                    session.id,
                )
                session.add_event(logdata)
                gevent.sleep(0.25)  # TODO measure delay and/or RTT

                if response is None:
                    session.add_event({"type": "CONNECTION_LOST"})
                    break
                # encode data before sending
                reply = str_to_bytes(response)
                sock.send(reply)

        except socket.timeout:
            logger.debug("Socket timeout, remote: %s. (%s)", address[0], session.id)
            session.add_event({"type": "CONNECTION_LOST"})

        sock.close()
Пример #14
0
 def setup(self):
     """Connect incoming connection to a FTP session"""
     self.session = conpot_core.get_session('ftp', self.client_address[0], self.client_address[1], self.request._sock.getsockname()[0] ,self.request._sock.getsockname()[1])
     logger.info('New FTP connection from {}:{}. ({})'.format(self.client_address[0], self.client_address[1],
                                                              self.session.id))
     self.session.add_event({'type': 'NEW_CONNECTION'})
     # send 200 + banner -- new client has connected!
     self.respond(b'200 ' + self.config.banner.encode())
     #  Is there a delay in command response? < gevent.sleep(0.5) ?
     return socketserver.BaseRequestHandler.setup(self)
Пример #15
0
    def handle(self, sock, address):
        session = conpot_core.get_session('kamstrup_protocol', address[0],
                                          address[1])
        logger.info('New connection from {0}:{1}. ({2})'.format(
            address[0], address[1], session.id))
        session.add_event({'type': 'NEW_CONNECTION'})

        server_active = True

        parser = request_parser.KamstrupRequestParser()
        try:
            while server_active:
                raw_request = sock.recv(1024)

                if not raw_request:
                    logger.info('Client disconnected. ({0})'.format(
                        session.id))
                    session.add_event({'type': 'CONNECTION_LOST'})
                    break

                for x in raw_request:
                    parser.add_byte(x)

                while True:
                    request = parser.get_request()
                    if not request:
                        session.add_event({'type': 'CONNECTION_LOST'})
                        break
                    else:
                        logdata = {
                            'request':
                            binascii.hexlify(bytearray(request.message_bytes))
                        }
                        response = self.command_responder.respond(request)
                        # real Kamstrup meters has delay in this interval
                        gevent.sleep(random.uniform(0.24, 0.34))
                        if response:
                            serialized_response = response.serialize()
                            logdata['response'] = binascii.hexlify(
                                serialized_response)
                            logger.debug(
                                'Kamstrup traffic from {0}: {1} ({2})'.format(
                                    address[0], logdata, session.id))
                            sock.send(serialized_response)
                            session.add_event(logdata)
                        else:
                            session.add_event(logdata)
                            break

        except socket.timeout:
            logger.debug('Socket timeout, remote: {0}. ({1})'.format(
                address[0], session.id))
            session.add_event({'type': 'CONNECTION_LOST'})

        sock.close()
Пример #16
0
 def handle(self, buffer, client_addr):
     session = conpot_core.get_session(
         "tftp",
         client_addr[0],
         client_addr[1],
         get_interface_ip(client_addr[0]),
         self.server._socket.getsockname()[1],
     )
     logger.info(
         "New TFTP client has connected. Connection from {}:{}. ".format(
             client_addr[0], client_addr[1]))
     session.add_event({"type": "NEW_CONNECTION"})
     logger.debug("Read %d bytes", len(buffer))
     context = tftp_handler.TFTPContextServer(client_addr[0],
                                              client_addr[1], self.timeout,
                                              self.root, None, None)
     context.vfs, context.data_fs = self.vfs, self.data_fs
     if self.shutdown:
         logger.info(
             "Shutting down now. Disconnecting {}".format(client_addr))
         session.add_event({"type": "CONNECTION_TERMINATED"})
     try:
         context.start(buffer)
         context.cycle()
     except TftpTimeout as err:
         logger.info("Timeout occurred %s: %s" % (context, str(err)))
         session.add_event({"type": "CONNECTION_TIMEOUT"})
         context.retry_count += 1
         # TODO: We should accept retries from the user.
         if context.retry_count >= self.TIMEOUT_RETRIES:
             logger.info("TFTP: Hit max {} retries on {}, giving up".format(
                 self.TIMEOUT_RETRIES, context))
         else:
             logger.info("TFTP: resending on session %s" % context)
             context.state.resendLast()
     except TftpException as err:
         logger.info(
             "TFTP: Fatal exception thrown from session {}: {}".format(
                 context, str(err)))
         session.add_event({"type": "CONNECTION_LOST"})
     logger.info("TFTP: terminating connection: {}".format(context))
     session.set_ended()
     context.end()
     # Gathering up metrics before terminating the connection.
     metrics = context.metrics
     if metrics.duration == 0:
         logger.info("Duration too short, rate undetermined")
     else:
         logger.info("Transferred %d bytes in %.2f seconds" %
                     (metrics.bytes, metrics.duration))
         logger.info("Average rate: %.2f kbps" % metrics.kbps)
     logger.info("%.2f bytes in resent data" % metrics.resent_bytes)
     logger.info("%d duplicate packets" % metrics.dupcount)
     del context
Пример #17
0
 def setup(self):
     """Connect incoming connection to a FTP session"""
     self.session = conpot_core.get_session(
         'ftp', self.client_address[0], self.client_address[1],
         self.request._sock.getsockname()[0],
         self.request._sock.getsockname()[1])
     logger.info('New FTP connection from {}:{}. ({})'.format(
         self.client_address[0], self.client_address[1], self.session.id))
     self.session.add_event({'type': 'NEW_CONNECTION'})
     # send 200 + banner -- new client has connected!
     self.respond(b'200 ' + self.config.banner.encode())
     #  Is there a delay in command response? < gevent.sleep(0.5) ?
     return socketserver.BaseRequestHandler.setup(self)
Пример #18
0
    def handle(self, sock, address):
        session = conpot_core.get_session(self.proxy_id, address[0], address[1])
        logger.info('New connection from {0}:{1} on {2} proxy. ({3})'.format(address[0], address[1],
                                                                             self.proxy_id, session.id))
        proxy_socket = socket()

        if self.keyfile and self.certfile:
            proxy_socket = wrap_socket(proxy_socket, self.keyfile, self.certfile)

        try:
            proxy_socket.connect((self.proxy_host, self.proxy_port))
        except _socket.error as ex:
            logger.error('Error while connecting to proxied service at ({0}, {1}): {2}'
                         .format(self.proxy_host, self.proxy_port, ex))
            self._close([proxy_socket, sock])
            return

        sockets = [proxy_socket, sock]
        while len(sockets) == 2:
            gevent.sleep()
            sockets_read, _, sockets_err = select.select(sockets, [], sockets, 10)

            if len(sockets_err) > 0:
                self._close([proxy_socket, sock])
                break

            for s in sockets_read:
                data = s.recv(1024)
                if len(data) is 0:
                    self._close([proxy_socket, sock])
                    if s is proxy_socket:
                        logging.info('Closing proxy connection because the proxied socket closed.')
                        sockets = []
                        break
                    elif s is sock:
                        logging.info('Closing proxy connection because the remote socket closed')
                        sockets = []
                        break
                    else:
                        assert False
                if s is proxy_socket:
                    self.handle_out_data(data, sock, session)
                elif s is sock:
                    self.handle_in_data(data, proxy_socket, session)
                else:
                    assert False

        proxy_socket.close()
        sock.close()
Пример #19
0
    def log(self, version, msg_type, addr, req_varBinds, res_varBinds=None):
        session = conpot_core.get_session('snmp', addr[0], addr[1])
        req_oid = req_varBinds[0][0]
        req_val = req_varBinds[0][1]
        log_dict = {'remote': addr,
                    'timestamp': datetime.utcnow(),
                    'data_type': 'snmp',
                    'data': {0: {'request': 'SNMPv{0} {1}: {2} {3}'.format(version, msg_type, req_oid, req_val)}}}

        logger.info('SNMPv%s %s request from %s: %s %s', version, msg_type, addr, req_oid, req_val)

        if res_varBinds:
            res_oid = ".".join(map(str, res_varBinds[0][0]))
            res_val = res_varBinds[0][1]
            logger.info('SNMPv%s response to %s: %s %s', version, addr, res_oid, res_val)
            log_dict['data'][0]['response'] = 'SNMPv{0} response: {1} {2}'.format(version, res_oid, res_val)
Пример #20
0
    def log(self, version, request_type, addr, request, response=None):

        session = conpot_core.get_session('http', addr[0], addr[1])

        log_dict = {'remote': addr,
                    'timestamp': datetime.utcnow(),
                    'data_type': 'http',
                    'data': {0: {'request': '{0} {1}: {2}'.format(version, request_type, request)}}}

        logger.info('{0} {1} request from {2}: {3}. {4}'.format(version, request_type, addr, request, session.id))

        if response:
            logger.info('{0} response to {1}: {2}. {3}'.format(version, addr, response, session.id))
            log_dict['data'][0]['response'] = '{0} response: {1}'.format(version, response)
            session.add_event({'request': str(request), 'response': str(response)})
        else:
            session.add_event({'request': str(request)})
Пример #21
0
    def log(self, version, msg_type, addr, req_varBinds, res_varBinds=None, sock=None):
        session = conpot_core.get_session('snmp', addr[0], addr[1],  get_interface_ip(addr[0]), sock.getsockname()[1])
        req_oid = req_varBinds[0][0]
        req_val = req_varBinds[0][1]
        event_type = 'SNMPv{0} {1}'.format(version, msg_type)
        request = {'oid': str(req_oid), 'val': str(req_val)}
        response = None

        logger.info('%s request from %s: %s %s', event_type, addr, req_oid, req_val)

        if res_varBinds:
            res_oid = ".".join(map(str, res_varBinds[0][0]))
            res_val = res_varBinds[0][1]
            logger.info('%s response to %s: %s %s', event_type, addr, res_oid, res_val)
            response = {'oid': str(res_oid), 'val': str(res_val)}

        session.add_event({'type': event_type, 'request': request, 'response': response})
Пример #22
0
    def handle(self, sock, address):
        session = conpot_core.get_session('kamstrup_protocol', address[0], address[1])
        logger.info('New Kamstrup connection from %s:%s. (%s)', address[0], address[1], session.id)
        session.add_event({'type': 'NEW_CONNECTION'})

        self.server_active = True

        parser = request_parser.KamstrupRequestParser()
        try:
            while self.server_active:
                raw_request = sock.recv(1024)

                if not raw_request:
                    logger.info('Kamstrup client disconnected. (%s)', session.id)
                    session.add_event({'type': 'CONNECTION_LOST'})
                    break

                for x in raw_request:
                    parser.add_byte(x)

                while True:
                    request = parser.get_request()
                    if not request:
                        session.add_event({'type': 'CONNECTION_LOST'})
                        break
                    else:
                        logdata = {'request': binascii.hexlify(bytearray(request.message_bytes))}
                        response = self.command_responder.respond(request)
                        # real Kamstrup meters has delay in this interval
                        gevent.sleep(random.uniform(0.24, 0.34))
                        if response:
                            serialized_response = response.serialize()
                            logdata['response'] = binascii.hexlify(serialized_response)
                            logger.info('Kamstrup traffic from %s: %s (%s)', address[0], logdata, session.id)
                            sock.send(serialized_response)
                            session.add_event(logdata)
                        else:
                            session.add_event(logdata)
                            break

        except socket.timeout:
            logger.debug('Socket timeout, remote: %s. (%s)', address[0], session.id)
            session.add_event({'type': 'CONNECTION_LOST'})

        sock.close()
Пример #23
0
    def log(self, version, msg_type, addr, req_varBinds, res_varBinds=None, sock=None):
        addr = ProxyAddresses.try_replace_addr(addr)
        session = conpot_core.get_session('snmp', addr[0], addr[1],  get_interface_ip(addr[0]), sock.getsockname()[1])
        req_oid = req_varBinds[0][0]
        req_val = req_varBinds[0][1]
        event_type = 'SNMPv{0} {1}'.format(version, msg_type)
        request = {'oid': str(req_oid), 'val': str(req_val)}
        response = None

        logger.info('%s request from %s: %s %s', event_type, addr, req_oid, req_val)

        if res_varBinds:
            res_oid = ".".join(map(str, res_varBinds[0][0]))
            res_val = res_varBinds[0][1]
            logger.info('%s response to %s: %s %s', event_type, addr, res_oid, res_val)
            response = {'oid': str(res_oid), 'val': str(res_val)}

        session.add_event({'type': event_type, 'request': request, 'response': response})
Пример #24
0
    def log(self, version, request_type, addr, request, response=None):

        session = conpot_core.get_session('http', addr[0], addr[1], self.connection._sock.getsockname()[0], self.connection._sock.getsockname()[1])

        log_dict = {'remote': addr,
                    'timestamp': datetime.utcnow(),
                    'data_type': 'http',
                    'dst_port': self.server.server_port,
                    'data': {0: {'request': '{0} {1}: {2}'.format(version, request_type, request)}}}

        logger.info('%s %s request from %s: %s. %s', version, request_type, addr, request, session.id)

        if response:
            logger.info('%s response to %s: %s. %s', version, addr, response, session.id)
            log_dict['data'][0]['response'] = '{0} response: {1}'.format(version, response)
            session.add_event({'request': str(request), 'response': str(response)})
        else:
            session.add_event({'request': str(request)})
Пример #25
0
    def handle(self, conn, address, enip_process=None, delay=None, **kwds):
        """
        Handle an incoming connection
        """
        host, port = address if address else ("UDP", "UDP")
        name = "ENIP_%s" % port
        session = conpot_core.get_session(
            "enip", host, port, conn.getsockname()[0], conn.getsockname()[1]
        )
        logger.debug("ENIP server %s begins serving client %s", name, address)
        session.add_event({"type": "NEW_CONNECTION"})

        tcp = conn.family == socket.AF_INET and conn.type == socket.SOCK_STREAM
        udp = conn.family == socket.AF_INET and conn.type == socket.SOCK_DGRAM

        if tcp:
            try:
                conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
            except Exception as e:
                logger.error(
                    "%s unable to set TCP_NODELAY for client %r: %s", name, address, e
                )
            try:
                conn.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
            except Exception as e:
                logger.error(
                    "%s unable to set SO_KEEPALIVE for client %r: %s", name, address, e
                )
            self.handle_tcp(
                conn,
                address,
                session,
                name=name,
                enip_process=enip_process,
                delay=delay,
                **kwds
            )
        elif udp:
            self.handle_udp(
                conn, name=name, enip_process=enip_process, session=session, **kwds
            )
        else:
            raise NotImplementedError("Unknown socket protocol for EtherNet/IP CIP")
Пример #26
0
 def handle(self, data, address):
     session = conpot_core.get_session('bacnet', address[0], address[1], get_interface_ip(address[0]), self.server.server_port)
     logger.info('New Bacnet connection from %s:%d. (%s)', address[0], address[1], session.id)
     session.add_event({'type': 'NEW_CONNECTION'})
     # I'm not sure if gevent DatagramServer handles issues where the
     # received data is over the MTU -> fragmentation
     if data:
         pdu = PDU()
         pdu.pduData = bytearray(data)
         apdu = APDU()
         try:
             apdu.decode(pdu)
         except DecodingError:
             logger.warning("DecodingError - PDU: {}".format(pdu))
             return
         self.bacnet_app.indication(apdu, address, self.thisDevice)
         # send an appropriate response from BACnet app to the attacker
         self.bacnet_app.response(self.bacnet_app._response, address)
     logger.info('Bacnet client disconnected %s:%d. (%s)', address[0], address[1], session.id)
Пример #27
0
 def handle(self, data, address):
     session = conpot_core.get_session('bacnet', address[0], address[1])
     logger.info('New Bacnet connection from %s:%d. (%s)', address[0], address[1], session.id)
     session.add_event({'type': 'NEW_CONNECTION'})
     # I'm not sure if gevent DatagramServer handles issues where the
     # received data is over the MTU -> fragmentation
     if data:
         pdu = PDU()
         pdu.pduData = data
         apdu = APDU()
         try:
             apdu.decode(pdu)
         except DecodingError as e:
             logger.error("DecodingError: %s", e)
             logger.error("PDU: " + format(pdu))
             return
         self.bacnet_app.indication(apdu, address, self.thisDevice)
         self.bacnet_app.response(self.bacnet_app._response, address)
     logger.info('Bacnet client disconnected %s:%d. (%s)', address[0], address[1], session.id)
Пример #28
0
    def log(self, version, request_type, addr, request, response=None):

        session = conpot_core.get_session(
            "http",
            addr[0],
            addr[1],
            self.connection._sock.getsockname()[0],
            self.connection._sock.getsockname()[1],
        )

        log_dict = {
            "remote": addr,
            "timestamp": datetime.utcnow(),
            "data_type": "http",
            "dst_port": self.server.server_port,
            "data": {
                0: {
                    "request":
                    "{0} {1}: {2}".format(version, request_type, request)
                }
            },
        }

        logger.info(
            "%s %s request from %s: %s. %s",
            version,
            request_type,
            addr,
            request,
            session.id,
        )

        if response:
            logger.info("%s response to %s: %s. %s", version, addr, response,
                        session.id)
            log_dict["data"][0]["response"] = "{0} response: {1}".format(
                version, response)
            session.add_event({
                "request": str(request),
                "response": str(response)
            })
        else:
            session.add_event({"request": str(request)})
Пример #29
0
    def handle(self, sock, address):
        session = conpot_core.get_session('kamstrup_management_protocol',
                                          address[0], address[1], self.host,
                                          self.port)
        logger.info('New Kamstrup connection from %s:%s. (%s)', address[0],
                    address[1], session.id)
        session.add_event({'type': 'NEW_CONNECTION'})

        try:
            sock.send(
                self.banner.format(
                    conpot_core.get_databus().get_value("mac_address")))

            while True:
                request = sock.recv(1024)
                if not request:
                    logger.info('Kamstrup client disconnected. (%s)',
                                session.id)
                    session.add_event({'type': 'CONNECTION_LOST'})
                    break

                logdata = {'request': request}
                response = self.command_responder.respond(request)
                logdata['response'] = response
                logger.info('Kamstrup management traffic from %s: %s (%s)',
                            address[0], logdata, session.id)
                session.add_event(logdata)
                gevent.sleep(0.25)  # TODO measure delay and/or RTT

                if response is None:
                    session.add_event({'type': 'CONNECTION_LOST'})
                    break
                sock.send(response)

        except socket.timeout:
            logger.debug('Socket timeout, remote: %s. (%s)', address[0],
                         session.id)
            session.add_event({'type': 'CONNECTION_LOST'})

        sock.close()
Пример #30
0
 def handle(self, buffer, client_addr):
     session = conpot_core.get_session('tftp', client_addr[0], client_addr[1],  get_interface_ip(client_addr[0]), self.server._socket.getsockname()[1])
     logger.info('New TFTP client has connected. Connection from {}:{}. '.format(client_addr[0], client_addr[1]))
     session.add_event({'type': 'NEW_CONNECTION'})
     logger.debug("Read %d bytes", len(buffer))
     context = tftp_handler.TFTPContextServer(client_addr[0], client_addr[1], self.timeout, self.root, None, None)
     context.vfs, context.data_fs = self.vfs, self.data_fs
     if self.shutdown:
         logger.info("Shutting down now. Disconnecting {}".format(client_addr))
         session.add_event({'type': 'CONNECTION_TERMINATED'})
     try:
         context.start(buffer)
         context.cycle()
     except TftpTimeout as err:
         logger.info("Timeout occurred %s: %s" % (context, str(err)))
         session.add_event({'type': 'CONNECTION_TIMEOUT'})
         context.retry_count += 1
         # TODO: We should accept retries from the user.
         if context.retry_count >= self.TIMEOUT_RETRIES:
             logger.info("TFTP: Hit max {} retries on {}, giving up".format(self.TIMEOUT_RETRIES, context))
         else:
             logger.info("TFTP: resending on session %s" % context)
             context.state.resendLast()
     except TftpException as err:
         logger.info("TFTP: Fatal exception thrown from session {}: {}".format(context, str(err)))
         session.add_event({'type': 'CONNECTION_LOST'})
     logger.info('TFTP: terminating connection: {}'.format(context))
     session.set_ended()
     context.end()
     # Gathering up metrics before terminating the connection.
     metrics = context.metrics
     if metrics.duration == 0:
         logger.info("Duration too short, rate undetermined")
     else:
         logger.info("Transferred %d bytes in %.2f seconds" % (metrics.bytes, metrics.duration))
         logger.info("Average rate: %.2f kbps" % metrics.kbps)
     logger.info("%.2f bytes in resent data" % metrics.resent_bytes)
     logger.info("%d duplicate packets" % metrics.dupcount)
     del context
Пример #31
0
    def handle(self, sock, address):
        session = conpot_core.get_session('kamstrup_management_protocol', address[0], address[1], sock.getsockname()[0], sock.getsockname()[1])
        logger.info('New Kamstrup connection from %s:%s. (%s)', address[0], address[1], session.id)
        session.add_event({'type': 'NEW_CONNECTION'})

        try:
            sock.send(
                str_to_bytes(self.banner.format(conpot_core.get_databus().get_value("mac_address")))
            )

            while True:
                data = sock.recv(1024)
                if not data:
                    logger.info('Kamstrup client disconnected. (%s)', session.id)
                    session.add_event({'type': 'CONNECTION_LOST'})
                    break
                request = data.decode()
                logdata = {'request': request}
                response = self.command_responder.respond(request)
                logdata['response'] = response
                logger.info('Kamstrup management traffic from %s: %s (%s)', address[0], logdata, session.id)
                session.add_event(logdata)
                gevent.sleep(0.25)  # TODO measure delay and/or RTT

                if response is None:
                    session.add_event({'type': 'CONNECTION_LOST'})
                    break
                # encode data before sending
                reply = str_to_bytes(response)
                sock.send(reply)

        except socket.timeout:
            logger.debug('Socket timeout, remote: %s. (%s)', address[0], session.id)
            session.add_event({'type': 'CONNECTION_LOST'})

        sock.close()
Пример #32
0
    def handle(self, sock, address):
        sock.settimeout(self.timeout)

        session = conpot_core.get_session('modbus', address[0], address[1])

        self.start_time = time.time()
        logger.info('New Modbus connection from %s:%s. (%s)', address[0],
                    address[1], session.id)
        session.add_event({'type': 'NEW_CONNECTION'})

        try:
            while True:
                request = sock.recv(7)
                if not request:
                    logger.info('Modbus client disconnected. (%s)', session.id)
                    session.add_event({'type': 'CONNECTION_LOST'})
                    break
                if request.strip().lower() == 'quit.':
                    logger.info('Modbus client quit. (%s)', session.id)
                    session.add_event({'type': 'CONNECTION_QUIT'})
                    break
                tr_id, pr_id, length = struct.unpack(">HHH", request[:6])
                while len(request) < (length + 6):
                    new_byte = sock.recv(1)
                    request += new_byte
                query = modbus_tcp.TcpQuery()

                # logdata is a dictionary containing request, slave_id,
                # function_code and response
                response, logdata = self._databank.handle_request(
                    query, request, self.mode)
                logdata['request'] = request.encode('hex')
                session.add_event(logdata)

                logger.info('Modbus traffic from %s: %s (%s)', address[0],
                            logdata, session.id)

                if response:
                    sock.sendall(response)
                    logger.info('Modbus response sent to %s', address[0])
                else:
                    # MB serial connection addressing UID=0
                    if (self.mode == 'serial' and logdata['slave_id'] == 0):
                        # delay is in milliseconds
                        time.sleep(self.delay / 1000)
                        logger.debug(
                            'Modbus server\'s turnaround delay expired.')
                        logger.info(
                            'Modbus connection terminated with client %s.',
                            address[0])
                        session.add_event({'type': 'CONNECTION_TERMINATED'})
                        sock.shutdown(socket.SHUT_RDWR)
                        sock.close()
                        break
                    # Invalid addressing
                    else:
                        logger.info(
                            'Modbus client ignored due to invalid addressing.'
                            ' (%s)', session.id)
                        session.add_event({'type': 'CONNECTION_TERMINATED'})
                        sock.shutdown(socket.SHUT_RDWR)
                        sock.close()
                        break
        except socket.timeout:
            logger.debug('Socket timeout, remote: %s. (%s)', address[0],
                         session.id)
            session.add_event({'type': 'CONNECTION_LOST'})
Пример #33
0
    def handle(self, sock, addr):
        session = conpot_core.get_session('guardian_ast', addr[0], addr[1], sock.getsockname()[0], sock.getsockname()[1])
        logger.info('New GuardianAST connection from %s:%d. (%s)', addr[0], addr[1], session.id)
        session.add_event({'type': 'NEW_CONNECTION'})
        current_time = datetime.datetime.utcnow()
        fill_start = self.fill_offset_time - datetime.timedelta(minutes=313)
        fill_stop = self.fill_offset_time - datetime.timedelta(minutes=303)
        # Default Product names, change based off country needs
        product1 = self.databus.get_value('product1').ljust(22)
        product1 = self.databus.get_value('product1').ljust(22)
        product2 = self.databus.get_value('product2').ljust(22)
        product3 = self.databus.get_value('product3').ljust(22)
        product4 = self.databus.get_value('product4').ljust(22)

        # Create random Numbers for the volumes
        #
        # this will crate an initial Volume and then the second value based
        # off the orig value.
        vol1 = self.databus.get_value('vol1')
        vol1tc = random.randint(vol1, vol1+200)
        vol2 = self.databus.get_value('vol2')
        vol2tc = random.randint(vol2, vol2+200)
        vol3 = self.databus.get_value('vol3')
        vol3tc = random.randint(vol3, vol3+200)
        vol4 = self.databus.get_value('vol4')
        vol4tc = random.randint(vol4, vol4+200)

        # unfilled space ULLAGE
        ullage1 = str(self.databus.get_value('ullage1'))
        ullage2 = str(self.databus.get_value('ullage2'))
        ullage3 = str(self.databus.get_value('ullage3'))
        ullage4 = str(self.databus.get_value('ullage3'))

        # Height of tank
        height1 = str(self.databus.get_value('height1')).ljust(5, '0')
        height2 = str(self.databus.get_value('height2')).ljust(5, '0')
        height3 = str(self.databus.get_value('height3')).ljust(5, '0')
        height4 = str(self.databus.get_value('height4')).ljust(5, '0')

        # Water in tank, this is a variable that needs to be low
        h2o1 = str(self.databus.get_value('h2o1')).ljust(4, '0')
        h2o2 = str(self.databus.get_value('h2o2')).ljust(4, '0')
        h2o3 = str(self.databus.get_value('h2o3')).ljust(4, '0')
        h2o4 = str(self.databus.get_value('h2o4')).ljust(4, '0')

        # Temperature of the tank, this will need to be between 50 - 60
        temp1 = str(self.databus.get_value('temp1')).ljust(5, '0')
        temp2 = str(self.databus.get_value('temp2')).ljust(5, '0')
        temp3 = str(self.databus.get_value('temp3')).ljust(5, '0')
        temp4 = str(self.databus.get_value('temp4')).ljust(5, '0')

        station = self.databus.get_value('station_name')

        # This function is to set-up up the message to be sent upon a successful I20100 command being sent
        # The final message is sent with a current date/time stamp inside of the main loop.
        def I20100():
            ret = '\nI20100\n' + str(current_time.strftime('%m/%d/%Y %H:%M'))
            ret += '\n\n' + station + '\n\n\n\nIN-TANK INVENTORY\n\n'
            ret += 'TANK PRODUCT             VOLUME TC VOLUME   ULLAGE   HEIGHT    WATER     TEMP'
            ret += '\n  1  ' + product1 + str(vol1) + '      ' + str(vol1tc) + '     ' + ullage1 + '    ' + height1 + '     ' + h2o1 + '    ' + temp1
            ret += '\n  2  ' + product2 + str(vol2) + '      ' + str(vol2tc) + '     ' + ullage2 + '    ' + height2 + '     ' + h2o2 + '    ' + temp2
            ret += '\n  3  ' + product3 + str(vol3) + '      ' + str(vol3tc) + '     ' + ullage3 + '    ' + height3 + '     ' + h2o3 + '    ' + temp3
            ret += '\n  4  ' + product4 + str(vol4) + '      ' + str(vol4tc) + '     ' + ullage4 + '    ' + height4 + '     ' + h2o4 + '    ' + temp4
            ret += '\n'
            return ret

        ###########################################################################
        #
        # Only one Tank is listed currently in the I20200 command
        #
        ###########################################################################
        def I20200():
            ret = '\nI20200\n' + str(current_time.strftime('%m/%d/%Y %H:%M'))
            ret += '\n\n' + station + '\n\n\n\nDELIVERY REPORT\n\n'
            ret += 'T 1:' + product1 + '\nINCREASE   DATE / TIME             GALLONS TC GALLONS WATER  TEMP DEG F  HEIGHT\n\n'

            ret += '      END: ' + str(fill_stop.strftime('%m/%d/%Y %H:%M')) + '         ' + str(vol1 + 300) + '       ' + str(vol1tc + 300) + '   ' + h2o1 + '      ' + temp1 + '    ' + height1 + '\n'
            ret += '    START: ' + str(fill_start.strftime('%m/%d/%Y %H:%M')) + '         ' + str(vol1 - 300) + '       ' + str(vol1tc - 300) + '   ' + h2o1 + '      ' + temp1 + '    ' + str(float(height1) - 23) + '\n'
            ret += '   AMOUNT:                          ' + str(vol1) + '       ' + str(vol1tc) + '\n\n'
            return ret

        ###########################################################################
        #
        # I20300 In-Tank Leak Detect Report
        #
        ###########################################################################
        def I20300():
            ret = '\nI20300\n' + str(current_time.strftime('%m/%d/%Y %H:%M'))
            ret += '\n\n' + station + '\n\n\n'
            ret += 'TANK 1    ' + product1 + '\n    TEST STATUS: OFF\nLEAK DATA NOT AVAILABLE ON THIS TANK\n\n'
            ret += 'TANK 2    ' + product2 + '\n    TEST STATUS: OFF\nLEAK DATA NOT AVAILABLE ON THIS TANK\n\n'
            ret += 'TANK 3    ' + product3 + '\n    TEST STATUS: OFF\nLEAK DATA NOT AVAILABLE ON THIS TANK\n\n'
            ret += 'TANK 4    ' + product4 + '\n    TEST STATUS: OFF\nLEAK DATA NOT AVAILABLE ON THIS TANK\n\n'
            return ret

        ###########################################################################
        # Shift report command I20400 only one item in report at this time,
        # but can always add more if needed
        ###########################################################################
        def I20400():
            ret = '\nI20400\n' + str(current_time.strftime('%m/%d/%Y %H:%M'))
            ret += '\n\n' + station + '\n\n\n\nSHIFT REPORT\n\n'
            ret += 'SHIFT 1 TIME: 12:00 AM\n\nTANK PRODUCT\n\n'
            ret += '  1  ' + product1 + ' VOLUME TC VOLUME  ULLAGE  HEIGHT  WATER   TEMP\n'
            ret += 'SHIFT  1 STARTING VALUES      ' + str(vol1) + '     ' + str(vol1tc) + '    ' + ullage1 + '   ' + height1 + '   ' + h2o1 + '    ' + temp1 + '\n'
            ret += '         ENDING VALUES        ' + str(vol1 + 940) + '     ' + str(vol1tc + 886) + '    ' + str(int(ullage1) + 345) + '   ' + str(float(height1) + 53) + '  ' + h2o1 + '    ' + temp1 + '\n'
            ret += '         DELIVERY VALUE          0\n'
            ret += '         TOTALS                940\n\n'
            return ret

        ###########################################################################
        # I20500 In-Tank Status Report
        ###########################################################################
        def I20500():
            ret = '\nI20500\n' + str(current_time.strftime('%m/%d/%Y %H:%M'))
            ret += '\n\n\n' + station + '\n\n\n'
            ret += 'TANK   PRODUCT                 STATUS\n\n'
            ret += '  1    ' + product1 + '  NORMAL\n\n'
            ret += '  2    ' + product2 + '  HIGH WATER ALARM\n'
            ret += '                               HIGH WATER WARNING\n\n'
            ret += '  3    ' + product3 + '  NORMAL\n\n'
            ret += '  4    ' + product4 + '  NORMAL\n\n'
            return ret

        while True:
            try:
                # Get the initial data
                request = sock.recv(4096)
                # The connection has been closed
                if not request:
                    break
                while not (b'\n' in request or b'00' in request):
                    request += sock.recv(4096)
                # if first value is not ^A then do nothing
                # thanks John(achillean) for the help
                if request[:1] != b'\x01':
                    logger.info('Non ^A command attempt %s:%d. (%s)', addr[0], addr[1], session.id)
                    break
                # if request is less than 6, than do nothing
                if len(request) < 6:
                    logger.info('Invalid command attempt %s:%d. (%s)', addr[0], addr[1], session.id)
                    break

                cmds = {"I20100": I20100, "I20200": I20200, "I20300": I20300, "I20400": I20400, "I20500": I20500}
                cmd = request[1:7].decode()  # strip ^A and \n out
                response = None
                if cmd in cmds:
                    logger.info('%s command attempt %s:%d. (%s)', cmd, addr[0], addr[1], session.id)
                    response = cmds[cmd]()
                elif cmd.startswith("S6020"):
                    # change the tank name
                    if cmd.startswith("S60201"):
                        # split string into two, the command, and the data
                        TEMP = request.split(b'S60201')
                        # if length is less than two, print error
                        if len(TEMP) < 2:
                            response = AST_ERROR
                        # Else the command was entered correctly and continue
                        else:
                            # Strip off the carrage returns and new lines
                            TEMP1 = TEMP[1].rstrip(b'\r\n').decode()
                            # if Length is less than 22
                            if len(TEMP1) < 22:
                                # pad the result to have 22 chars
                                product1 = TEMP1.ljust(22)
                            elif len(TEMP1) > 22:
                                # else only print 22 chars if the result was longer
                                product1 = TEMP1[:20] + "  "
                            else:
                                # else it fits fine (22 chars)
                                product1 = TEMP1
                        logger.info('S60201: %s command attempt %s:%d. (%s)', TEMP1, addr[0], addr[1], session.id)
                    # Follows format for S60201 for comments
                    elif cmd.startswith("S60202"):
                        TEMP = request.split(b'S60202')
                        if len(TEMP) < 2:
                            response = AST_ERROR
                        else:
                            TEMP1 = TEMP[1].rstrip(b'\r\n').decode()
                            if len(TEMP1) < 22:
                                product2 = TEMP1.ljust(22)
                            elif len(TEMP1) > 22:
                                product2 = TEMP1[:20] + "  "
                            else:
                                product2 = TEMP1
                        logger.info('S60202: %s command attempt %s:%d. (%s)', TEMP1, addr[0], addr[1], session.id)
                    # Follows format for S60201 for comments
                    elif cmd.startswith("S60203"):
                        TEMP = request.split(b'S60203')
                        if len(TEMP) < 2:
                            response = AST_ERROR
                        else:
                            TEMP1 = TEMP[1].rstrip(b'\r\n').decode()
                            if len(TEMP1) < 22:
                                product3 = TEMP1.ljust(22)
                            elif len(TEMP1) > 22:
                                product3 = TEMP1[:20] + "  "
                            else:
                                product3 = TEMP1
                        logger.info('S60203: %s command attempt %s:%d. (%s)', TEMP1, addr[0], addr[1], session.id)
                    # Follows format for S60201 for comments
                    elif cmd.startswith("S60204"):
                        TEMP = request.split(b'S60204')
                        if len(TEMP) < 2:
                            response = AST_ERROR
                        else:
                            TEMP1 = TEMP[1].rstrip(b'\r\n').decode()
                            if len(TEMP1) < 22:
                                product4 = TEMP1.ljust(22)
                            elif len(TEMP1) > 22:
                                product4 = TEMP1[:20] + "  "
                            else:
                                product4 = TEMP1
                        logger.info('S60204: %s command attempt %s:%d. (%s)', TEMP1, addr[0], addr[1], session.id)
                    # Follows format for S60201 for comments
                    elif cmd.startswith("S60200"):
                        TEMP = request.split(b'S60200')
                        if len(TEMP) < 2:
                            response = AST_ERROR
                        else:
                            TEMP1 = TEMP[1].rstrip(b'\r\n').decode()
                            if len(TEMP1) < 22:
                                product1 = TEMP1.ljust(22)
                                product2 = TEMP1.ljust(22)
                                product3 = TEMP1.ljust(22)
                                product4 = TEMP1.ljust(22)
                            elif len(TEMP1) > 22:
                                product1 = TEMP1[:20] + "  "
                                product2 = TEMP1[:20] + "  "
                                product3 = TEMP1[:20] + "  "
                                product4 = TEMP1[:20] + "  "
                            else:
                                product1 = TEMP1
                                product2 = TEMP1
                                product3 = TEMP1
                                product4 = TEMP1
                        logger.info('S60200: %s command attempt %s:%d. (%s)', TEMP1, addr[0], addr[1], session.id)
                    else:
                        response = AST_ERROR
                else:
                    response = AST_ERROR
                    # log what was entered
                    logger.info('%s command attempt %s:%d. (%s)', request, addr[0], addr[1], session.id)
                if response:
                    sock.send(str_to_bytes(response))
                session.add_event({"type": "AST {0}".format(cmd), "request": request, "response": response})
            except Exception as e:
                logger.exception(('Unknown Error: {}'.format(str(e))))
        logger.info('GuardianAST client disconnected %s:%d. (%s)', addr[0], addr[1], session.id)
        session.add_event({'type': 'CONNECTION_LOST'})
Пример #34
0
    def handle(self, sock, address):
        sock.settimeout(self.timeout)
        session = conpot_core.get_session('s7comm', address[0], address[1])

        self.start_time = time.time()
        logger.info('New connection from {0}:{1}. ({2})'.format(address[0], address[1], session.id))

        try:
            while True:

                data = sock.recv(4, socket.MSG_WAITALL)
                if len(data) == 0:
                    break

                _, _, length = unpack('!BBH', data[:4])
                data += sock.recv(length - 4)

                tpkt_packet = TPKT().parse(data)
                cotp_base_packet = COTP_BASE_packet().parse(tpkt_packet.payload)
                if cotp_base_packet.tpdu_type == 0xe0:

                    # connection request
                    cotp_cr_request = COTP_ConnectionRequest().dissect(cotp_base_packet.payload)
                    logger.debug('Received COTP Connection Request: dst-ref:{0} src-ref:{1} dst-tsap:{2} src-tsap:{3} '
                                 'tpdu-size:{4}. ({5})'.format(cotp_cr_request.dst_ref, cotp_cr_request.src_ref,
                                                               cotp_cr_request.dst_tsap, cotp_cr_request.src_tsap,
                                                               cotp_cr_request.tpdu_size, session.id))

                    # confirm connection response
                    cotp_cc_response = COTP_ConnectionConfirm(cotp_cr_request.src_ref, cotp_cr_request.dst_ref, 0,
                                                              cotp_cr_request.src_tsap, cotp_cr_request.dst_tsap,
                                                              0x0a).assemble()

                    # encapsulate and transmit
                    cotp_resp_base_packet = COTP_BASE_packet(0xd0, 0, cotp_cc_response).pack()
                    tpkt_resp_packet = TPKT(3, cotp_resp_base_packet).pack()
                    sock.send(tpkt_resp_packet)

                    session.add_event({'request': data.encode('hex'), 'response': tpkt_resp_packet.encode('hex')})

                    data = sock.recv(1024)

                    # another round of parsing payloads
                    tpkt_packet = TPKT().parse(data)
                    cotp_base_packet = COTP_BASE_packet().parse(tpkt_packet.payload)

                    if cotp_base_packet.tpdu_type == 0xf0:
                        logger.debug('Received known COTP TPDU: {0}. ({1})'.format(cotp_base_packet.tpdu_type,
                                                                                   session.id))

                        # will throw exception if the packet does not contain the S7 magic number (0x32)
                        S7_packet = S7().parse(cotp_base_packet.trailer)
                        logger.debug('Received S7 packet: magic:{0} pdu_type:{1} reserved:{2} req_id:{3} param_len:{4} '
                                     'data_len:{5} result_inf:{6}'.format(
                            S7_packet.magic, S7_packet.pdu_type,
                            S7_packet.reserved, S7_packet.request_id,
                            S7_packet.param_length, S7_packet.data_length,
                            S7_packet.result_info, session.id))

                        # request pdu
                        if S7_packet.pdu_type == 1:

                            # 0xf0 == Request for connect / pdu negotiate
                            if S7_packet.param == 0xf0:

                                # create S7 response packet
                                s7_resp_negotiate_packet = S7(3, 0, S7_packet.request_id, 0,
                                                              S7_packet.parameters).pack()
                                # wrap s7 the packet in cotp
                                cotp_resp_negotiate_packet = COTP_BASE_packet(0xf0, 0x80,
                                                                              s7_resp_negotiate_packet).pack()
                                # wrap the cotp packet
                                tpkt_resp_packet = TPKT(3, cotp_resp_negotiate_packet).pack()
                                sock.send(tpkt_resp_packet)

                                session.add_event({'request': data.encode('hex'), 'response': tpkt_resp_packet.encode('hex')})

                                # handshake done, give some more data.
                                data = sock.recv(1024)

                                while data:
                                    tpkt_packet = TPKT().parse(data)
                                    cotp_base_packet = COTP_BASE_packet().parse(tpkt_packet.payload)

                                    if cotp_base_packet.tpdu_type == 0xf0:
                                        S7_packet = S7().parse(cotp_base_packet.trailer)
                                        logger.debug('Received S7 packet: magic:{0} pdu_type:{1} reserved:{2} '
                                                     'req_id:{3} param_len:{4} data_len:{5} result_inf:{6}'.format(
                                            S7_packet.magic, S7_packet.pdu_type,
                                            S7_packet.reserved, S7_packet.request_id,
                                            S7_packet.param_length, S7_packet.data_length,
                                            S7_packet.result_info, session.id))

                                        response_param, response_data = S7_packet.handle()
                                        s7_resp_ssl_packet = S7(7, 0, S7_packet.request_id, 0, response_param,
                                                                response_data).pack()
                                        cotp_resp_ssl_packet = COTP_BASE_packet(0xf0, 0x80, s7_resp_ssl_packet).pack()
                                        tpkt_resp_packet = TPKT(3, cotp_resp_ssl_packet).pack()
                                        sock.send(tpkt_resp_packet)

                                        session.add_event({'request': data.encode('hex'), 'response': tpkt_resp_packet.encode('hex')})

                                    data = sock.recv(1024)
                    else:
                        logger.debug(
                            'Received unknown COTP TPDU after handshake: {0}'.format(cotp_base_packet.tpdu_type))
                else:
                    logger.debug('Received unknown COTP TPDU before handshake: {0}'.format(cotp_base_packet.tpdu_type))

        except socket.timeout:
            logger.debug('Socket timeout, remote: {0}. ({1})'.format(address[0], session.id))
Пример #35
0
    def handle(self, sock, address):
        sock.settimeout(self.timeout)

        session = conpot_core.get_session(
            "modbus",
            address[0],
            address[1],
            sock.getsockname()[0],
            sock.getsockname()[1],
        )

        self.start_time = time.time()
        logger.info("New Modbus connection from %s:%s. (%s)", address[0],
                    address[1], session.id)
        session.add_event({"type": "NEW_CONNECTION"})

        try:
            while True:
                request = None
                try:
                    request = sock.recv(7)
                except Exception as e:
                    logger.error(
                        "Exception occurred in ModbusServer.handle() "
                        "at sock.recv(): %s",
                        str(e),
                    )

                if not request:
                    logger.info("Modbus client disconnected. (%s)", session.id)
                    session.add_event({"type": "CONNECTION_LOST"})
                    break
                if request.strip().lower() == "quit.":
                    logger.info("Modbus client quit. (%s)", session.id)
                    session.add_event({"type": "CONNECTION_QUIT"})
                    break
                if len(request) < 7:
                    logger.info(
                        "Modbus client provided data {} but invalid.".format(
                            session.id))
                    session.add_event({"type": "CONNECTION_TERMINATED"})
                    break
                _, _, length = struct.unpack(">HHH", request[:6])
                while len(request) < (length + 6):
                    try:
                        new_byte = sock.recv(1)
                        request += new_byte
                    except Exception:
                        break
                query = modbus_tcp.TcpQuery()

                # logdata is a dictionary containing request, slave_id,
                # function_code and response
                response, logdata = self._databank.handle_request(
                    query, request, self.mode)
                logdata["request"] = codecs.encode(request, "hex")
                session.add_event(logdata)

                logger.info("Modbus traffic from %s: %s (%s)", address[0],
                            logdata, session.id)

                if response:
                    sock.sendall(response)
                    logger.info("Modbus response sent to %s", address[0])
                else:
                    # TODO:
                    # response could be None under several different cases

                    # MB serial connection addressing UID=0
                    if (self.mode == "serial") and (logdata["slave_id"] == 0):
                        # delay is in milliseconds
                        time.sleep(self.delay / 1000)
                        logger.debug(
                            "Modbus server's turnaround delay expired.")
                        logger.info(
                            "Modbus connection terminated with client %s.",
                            address[0])
                        session.add_event({"type": "CONNECTION_TERMINATED"})
                        sock.shutdown(socket.SHUT_RDWR)
                        sock.close()
                        break
                    # Invalid addressing
                    else:
                        logger.info(
                            "Modbus client ignored due to invalid addressing."
                            " (%s)",
                            session.id,
                        )
                        session.add_event({"type": "CONNECTION_TERMINATED"})
                        sock.shutdown(socket.SHUT_RDWR)
                        sock.close()
                        break
        except socket.timeout:
            logger.debug("Socket timeout, remote: %s. (%s)", address[0],
                         session.id)
            session.add_event({"type": "CONNECTION_LOST"})
Пример #36
0
    def handle(self, sock, address):
        session = conpot_core.get_session(
            "kamstrup_protocol",
            address[0],
            address[1],
            sock.getsockname()[0],
            sock.getsockname()[1],
        )
        logger.info(
            "New Kamstrup connection from %s:%s. (%s)",
            address[0],
            address[1],
            session.id,
        )
        session.add_event({"type": "NEW_CONNECTION"})

        self.server_active = True

        parser = request_parser.KamstrupRequestParser()
        try:
            while self.server_active:
                raw_request = sock.recv(1024)

                if not raw_request:
                    logger.info("Kamstrup client disconnected. (%s)",
                                session.id)
                    session.add_event({"type": "CONNECTION_LOST"})
                    break

                for x in raw_request:
                    parser.add_byte(chr_py3(x))

                while True:
                    request = parser.get_request()
                    if not request:
                        session.add_event({"type": "CONNECTION_LOST"})
                        break
                    else:
                        logdata = {
                            "request":
                            binascii.hexlify(bytearray(request.message_bytes))
                        }
                        response = self.command_responder.respond(request)
                        # real Kamstrup meters has delay in this interval
                        gevent.sleep(random.uniform(0.24, 0.34))
                        if response:
                            serialized_response = response.serialize()
                            logdata["response"] = binascii.hexlify(
                                serialized_response)
                            logger.info(
                                "Kamstrup traffic from %s: %s (%s)",
                                address[0],
                                logdata,
                                session.id,
                            )
                            sock.send(serialized_response)
                            session.add_event(logdata)
                        else:
                            session.add_event(logdata)
                            break

        except socket.timeout:
            logger.debug("Socket timeout, remote: %s. (%s)", address[0],
                         session.id)
            session.add_event({"type": "CONNECTION_LOST"})

        sock.close()
Пример #37
0
    def handle(self, sock, address):
        sock.settimeout(self.timeout)
        session = conpot_core.get_session("s7comm", address[0], address[1])

        self.start_time = time.time()
        logger.info("New connection from {0}:{1}. ({2})".format(address[0], address[1], session.id))
        session.add_event({"type": "NEW_CONNECTION"})

        try:
            while True:

                data = sock.recv(4, socket.MSG_WAITALL)
                if len(data) == 0:
                    session.add_event({"type": "CONNECTION_LOST"})
                    break

                _, _, length = unpack("!BBH", data[:4])
                data += sock.recv(length - 4, socket.MSG_WAITALL)

                tpkt_packet = TPKT().parse(data)
                cotp_base_packet = COTP_BASE_packet().parse(tpkt_packet.payload)
                if cotp_base_packet.tpdu_type == 0xE0:

                    # connection request
                    cotp_cr_request = COTP_ConnectionRequest().dissect(cotp_base_packet.payload)
                    logger.debug(
                        "Received COTP Connection Request: dst-ref:{0} src-ref:{1} dst-tsap:{2} src-tsap:{3} "
                        "tpdu-size:{4}. ({5})".format(
                            cotp_cr_request.dst_ref,
                            cotp_cr_request.src_ref,
                            cotp_cr_request.dst_tsap,
                            cotp_cr_request.src_tsap,
                            cotp_cr_request.tpdu_size,
                            session.id,
                        )
                    )

                    # confirm connection response
                    cotp_cc_response = COTP_ConnectionConfirm(
                        cotp_cr_request.src_ref,
                        cotp_cr_request.dst_ref,
                        0,
                        cotp_cr_request.src_tsap,
                        cotp_cr_request.dst_tsap,
                        0x0A,
                    ).assemble()

                    # encapsulate and transmit
                    cotp_resp_base_packet = COTP_BASE_packet(0xD0, 0, cotp_cc_response).pack()
                    tpkt_resp_packet = TPKT(3, cotp_resp_base_packet).pack()
                    sock.send(tpkt_resp_packet)

                    session.add_event({"request": data.encode("hex"), "response": tpkt_resp_packet.encode("hex")})

                    data = sock.recv(1024)

                    # another round of parsing payloads
                    tpkt_packet = TPKT().parse(data)
                    cotp_base_packet = COTP_BASE_packet().parse(tpkt_packet.payload)

                    if cotp_base_packet.tpdu_type == 0xF0:
                        logger.debug(
                            "Received known COTP TPDU: {0}. ({1})".format(cotp_base_packet.tpdu_type, session.id)
                        )

                        # will throw exception if the packet does not contain the S7 magic number (0x32)
                        S7_packet = S7().parse(cotp_base_packet.trailer)
                        logger.debug(
                            "Received S7 packet: magic:%s pdu_type:%s reserved:%s req_id:%s param_len:%s "
                            "data_len:%s result_inf:%s session_id:%s",
                            S7_packet.magic,
                            S7_packet.pdu_type,
                            S7_packet.reserved,
                            S7_packet.request_id,
                            S7_packet.param_length,
                            S7_packet.data_length,
                            S7_packet.result_info,
                            session.id,
                        )

                        # request pdu
                        if S7_packet.pdu_type == 1:

                            # 0xf0 == Request for connect / pdu negotiate
                            if S7_packet.param == 0xF0:

                                # create S7 response packet
                                s7_resp_negotiate_packet = S7(
                                    3, 0, S7_packet.request_id, 0, S7_packet.parameters
                                ).pack()
                                # wrap s7 the packet in cotp
                                cotp_resp_negotiate_packet = COTP_BASE_packet(
                                    0xF0, 0x80, s7_resp_negotiate_packet
                                ).pack()
                                # wrap the cotp packet
                                tpkt_resp_packet = TPKT(3, cotp_resp_negotiate_packet).pack()
                                sock.send(tpkt_resp_packet)

                                session.add_event(
                                    {"request": data.encode("hex"), "response": tpkt_resp_packet.encode("hex")}
                                )

                                # handshake done, give some more data.
                                data = sock.recv(1024)

                                while data:
                                    tpkt_packet = TPKT().parse(data)
                                    cotp_base_packet = COTP_BASE_packet().parse(tpkt_packet.payload)

                                    if cotp_base_packet.tpdu_type == 0xF0:
                                        S7_packet = S7().parse(cotp_base_packet.trailer)
                                        logger.debug(
                                            "Received S7 packet: magic:%s pdu_type:%s reserved:%s "
                                            "req_id:%s param_len:%s data_len:%s result_inf:%s session_id:%s",
                                            S7_packet.magic,
                                            S7_packet.pdu_type,
                                            S7_packet.reserved,
                                            S7_packet.request_id,
                                            S7_packet.param_length,
                                            S7_packet.data_length,
                                            S7_packet.result_info,
                                            session.id,
                                        )

                                        response_param, response_data = S7_packet.handle()
                                        s7_resp_ssl_packet = S7(
                                            7, 0, S7_packet.request_id, 0, response_param, response_data
                                        ).pack()
                                        cotp_resp_ssl_packet = COTP_BASE_packet(0xF0, 0x80, s7_resp_ssl_packet).pack()
                                        tpkt_resp_packet = TPKT(3, cotp_resp_ssl_packet).pack()
                                        sock.send(tpkt_resp_packet)

                                        session.add_event(
                                            {"request": data.encode("hex"), "response": tpkt_resp_packet.encode("hex")}
                                        )

                                    data = sock.recv(1024)
                    else:
                        logger.debug(
                            "Received unknown COTP TPDU after handshake: {0}".format(cotp_base_packet.tpdu_type)
                        )
                        session.add_event(
                            {
                                "error": "Received unknown COTP TPDU after handshake: {0}".format(
                                    cotp_base_packet.tpdu_type
                                )
                            }
                        )
                else:
                    logger.debug("Received unknown COTP TPDU before handshake: {0}".format(cotp_base_packet.tpdu_type))
                    session.add_event(
                        {"error": "Received unknown COTP TPDU before handshake: {0}".format(cotp_base_packet.tpdu_type)}
                    )

        except socket.timeout:
            session.add_event({"type": "CONNECTION_LOST"})
            logger.debug("Socket timeout, remote: {0}. ({1})".format(address[0], session.id))
Пример #38
0
    def handle(self, sock, address):
        session = conpot_core.get_session(
            self.proxy_id,
            address[0],
            address[1],
            sock.getsockname()[0],
            sock.getsockname()[1],
        )
        logger.info(
            "New connection from %s:%s on %s proxy. (%s)",
            address[0],
            address[1],
            self.proxy_id,
            session.id,
        )
        proxy_socket = socket()

        if self.keyfile and self.certfile:
            proxy_socket = wrap_socket(
                proxy_socket, keyfile=self.keyfile, certfile=self.certfile
            )

        try:
            proxy_socket.connect((self.proxy_host, self.proxy_port))
        except _socket.error:
            logger.exception(
                "Error while connecting to proxied service at ({}, {})".format(
                    self.proxy_host, self.proxy_port
                )
            )
            self._close([proxy_socket, sock])
            return

        sockets = [proxy_socket, sock]
        while len(sockets) == 2:
            gevent.sleep(0)
            sockets_read, _, sockets_err = select.select(sockets, [], sockets, 10)

            if len(sockets_err) > 0:
                self._close([proxy_socket, sock])
                break

            for s in sockets_read:
                socket_close_reason = "socket closed"
                try:
                    data = s.recv(1024)
                except _socket.error as socket_err:
                    data = []
                    socket_close_reason = str(socket_err)
                if len(data) is 0:
                    self._close([proxy_socket, sock])
                    if s is proxy_socket:
                        logging.warning(
                            "Closing proxied socket while receiving (%s, %s): %s.",
                            self.proxy_host,
                            self.proxy_port,
                            socket_close_reason,
                        )
                        sockets = []
                        break
                    elif s is sock:
                        logging.warning(
                            "Closing connection to remote while receiving from remote (%s, %s): %s",
                            socket_close_reason,
                            address[0],
                            address[1],
                        )
                        sockets = []
                        break
                    else:
                        assert False

                try:
                    if s is proxy_socket:
                        self.handle_out_data(data, sock, session)
                    elif s is sock:
                        self.handle_in_data(data, proxy_socket, session)
                    else:
                        assert False
                except _socket.error as socket_err:
                    if s is proxy_socket:
                        destination = "proxied socket"
                    else:
                        destination = "remote connection"
                    logger.warning(
                        "Error while sending data to %s: %s.",
                        destination,
                        str(socket_err),
                    )
                    sockets = []
                    break

        session.set_ended()
        proxy_socket.close()
        sock.close()
Пример #39
0
 def _new_session_event(remote_ip, data):
     session = conpot_core.get_session('snap7', remote_ip, None)
     session.add_event(data)
     return session.id
Пример #40
0
    def handle(self, sock, address):
        sock.settimeout(self.timeout)
        session = conpot_core.get_session(
            "IEC104",
            address[0],
            address[1],
            sock.getsockname()[0],
            sock.getsockname()[1],
        )
        logger.info(
            "New IEC 104 connection from %s:%s. (%s)",
            address[0],
            address[1],
            session.id,
        )
        session.add_event({"type": "NEW_CONNECTION"})
        iec104_handler = IEC104(self.device_data_controller, sock, address,
                                session.id)
        try:
            while True:
                timeout_t3 = gevent.Timeout(
                    conpot_core.get_databus().get_value("T_3"), Timeout_t3)
                timeout_t3.start()
                try:
                    try:
                        request = sock.recv(6)
                        if not request:
                            logger.info("IEC104 Station disconnected. (%s)",
                                        session.id)
                            session.add_event({"type": "CONNECTION_LOST"})
                            iec104_handler.disconnect()
                            break
                        while request and len(request) < 2:
                            new_byte = sock.recv(1)
                            request += new_byte

                        _, length = struct.unpack(">BB", request[:2])
                        while len(request) < (length + 2):
                            new_byte = sock.recv(1)
                            if not new_byte:
                                break
                            request += new_byte

                        # check if IEC 104 packet or for the first occurrence of the indication 0x68 for IEC 104
                        for elem in list(request):
                            if 0x68 == elem:
                                index = request.index(elem)

                                iec_request = request[index:]
                                timeout_t3.cancel()
                                response = None
                                # check which frame type
                                if not (iec_request[2] & 0x01):  # i_frame
                                    response = iec104_handler.handle_i_frame(
                                        iec_request)
                                elif iec_request[2] & 0x01 and not (
                                        iec_request[2] & 0x02):  # s_frame
                                    iec104_handler.handle_s_frame(iec_request)
                                elif iec_request[2] & 0x03:  # u_frame
                                    response = iec104_handler.handle_u_frame(
                                        iec_request)
                                else:
                                    logger.warning(
                                        "%s ---> No valid IEC104 type (%s)",
                                        address,
                                        session.id,
                                    )

                                if response:
                                    for resp_packet in response:
                                        if resp_packet:
                                            sock.send(resp_packet)
                                break

                    except Timeout_t3:
                        pkt = iec104_handler.send_104frame(TESTFR_act)
                        if pkt:
                            sock.send(pkt)
                    finally:
                        timeout_t3.cancel()
                except gevent.Timeout:
                    logger.warning("T1 timed out. (%s)", session.id)
                    logger.info("IEC104 Station disconnected. (%s)",
                                session.id)
                    session.add_event({"type": "CONNECTION_LOST"})
                    iec104_handler.disconnect()
                    break
        except socket.timeout:
            logger.debug("Socket timeout, remote: %s. (%s)", address[0],
                         session.id)
            session.add_event({"type": "CONNECTION_LOST"})
        except socket.error as err:
            if isinstance(err.args, tuple):
                if err.errno == errno.EPIPE:
                    # remote peer disconnected
                    logger.info("IEC104 Station disconnected. (%s)",
                                session.id)
                    session.add_event({"type": "CONNECTION_LOST"})
                else:
                    # determine and handle different error
                    pass
            else:
                print(("socket error ", err))
            iec104_handler.disconnect()
    def handle(self, sock, addr):
        session = conpot_core.get_session('guardian_ast', addr[0], addr[1],
                                          sock.getsockname()[0],
                                          sock.getsockname()[1])
        logger.info('New GuardianAST connection from %s:%d. (%s)', addr[0],
                    addr[1], session.id)
        session.add_event({'type': 'NEW_CONNECTION'})
        current_time = datetime.datetime.utcnow()
        fill_start = self.fill_offset_time - datetime.timedelta(minutes=313)
        fill_stop = self.fill_offset_time - datetime.timedelta(minutes=303)
        # Default Product names, change based off country needs
        product1 = self.databus.get_value('product1').ljust(22)
        product1 = self.databus.get_value('product1').ljust(22)
        product2 = self.databus.get_value('product2').ljust(22)
        product3 = self.databus.get_value('product3').ljust(22)
        product4 = self.databus.get_value('product4').ljust(22)

        # Create random Numbers for the volumes
        #
        # this will crate an initial Volume and then the second value based
        # off the orig value.
        vol1 = self.databus.get_value('vol1')
        vol1tc = random.randint(vol1, vol1 + 200)
        vol2 = self.databus.get_value('vol2')
        vol2tc = random.randint(vol2, vol2 + 200)
        vol3 = self.databus.get_value('vol3')
        vol3tc = random.randint(vol3, vol3 + 200)
        vol4 = self.databus.get_value('vol4')
        vol4tc = random.randint(vol4, vol4 + 200)

        # unfilled space ULLAGE
        ullage1 = str(self.databus.get_value('ullage1'))
        ullage2 = str(self.databus.get_value('ullage2'))
        ullage3 = str(self.databus.get_value('ullage3'))
        ullage4 = str(self.databus.get_value('ullage3'))

        # Height of tank
        height1 = str(self.databus.get_value('height1')).ljust(5, '0')
        height2 = str(self.databus.get_value('height2')).ljust(5, '0')
        height3 = str(self.databus.get_value('height3')).ljust(5, '0')
        height4 = str(self.databus.get_value('height4')).ljust(5, '0')

        # Water in tank, this is a variable that needs to be low
        h2o1 = str(self.databus.get_value('h2o1')).ljust(4, '0')
        h2o2 = str(self.databus.get_value('h2o2')).ljust(4, '0')
        h2o3 = str(self.databus.get_value('h2o3')).ljust(4, '0')
        h2o4 = str(self.databus.get_value('h2o4')).ljust(4, '0')

        # Temperature of the tank, this will need to be between 50 - 60
        temp1 = str(self.databus.get_value('temp1')).ljust(5, '0')
        temp2 = str(self.databus.get_value('temp2')).ljust(5, '0')
        temp3 = str(self.databus.get_value('temp3')).ljust(5, '0')
        temp4 = str(self.databus.get_value('temp4')).ljust(5, '0')

        station = self.databus.get_value('station_name')

        # This function is to set-up up the message to be sent upon a successful I20100 command being sent
        # The final message is sent with a current date/time stamp inside of the main loop.
        def I20100():
            ret = '\nI20100\n' + str(current_time.strftime('%m/%d/%Y %H:%M'))
            ret += '\n\n' + station + '\n\n\n\nIN-TANK INVENTORY\n\n'
            ret += 'TANK PRODUCT             VOLUME TC VOLUME   ULLAGE   HEIGHT    WATER     TEMP'
            ret += '\n  1  ' + product1 + str(vol1) + '      ' + str(
                vol1tc
            ) + '     ' + ullage1 + '    ' + height1 + '     ' + h2o1 + '    ' + temp1
            ret += '\n  2  ' + product2 + str(vol2) + '      ' + str(
                vol2tc
            ) + '     ' + ullage2 + '    ' + height2 + '     ' + h2o2 + '    ' + temp2
            ret += '\n  3  ' + product3 + str(vol3) + '      ' + str(
                vol3tc
            ) + '     ' + ullage3 + '    ' + height3 + '     ' + h2o3 + '    ' + temp3
            ret += '\n  4  ' + product4 + str(vol4) + '      ' + str(
                vol4tc
            ) + '     ' + ullage4 + '    ' + height4 + '     ' + h2o4 + '    ' + temp4
            ret += '\n'
            return ret

        ###########################################################################
        #
        # Only one Tank is listed currently in the I20200 command
        #
        ###########################################################################
        def I20200():
            ret = '\nI20200\n' + str(current_time.strftime('%m/%d/%Y %H:%M'))
            ret += '\n\n' + station + '\n\n\n\nDELIVERY REPORT\n\n'
            ret += 'T 1:' + product1 + '\nINCREASE   DATE / TIME             GALLONS TC GALLONS WATER  TEMP DEG F  HEIGHT\n\n'

            ret += '      END: ' + str(
                fill_stop.strftime('%m/%d/%Y %H:%M')
            ) + '         ' + str(vol1 + 300) + '       ' + str(
                vol1tc + 300
            ) + '   ' + h2o1 + '      ' + temp1 + '    ' + height1 + '\n'
            ret += '    START: ' + str(
                fill_start.strftime('%m/%d/%Y %H:%M')
            ) + '         ' + str(vol1 - 300) + '       ' + str(
                vol1tc - 300) + '   ' + h2o1 + '      ' + temp1 + '    ' + str(
                    float(height1) - 23) + '\n'
            ret += '   AMOUNT:                          ' + str(
                vol1) + '       ' + str(vol1tc) + '\n\n'
            return ret

        ###########################################################################
        #
        # I20300 In-Tank Leak Detect Report
        #
        ###########################################################################
        def I20300():
            ret = '\nI20300\n' + str(current_time.strftime('%m/%d/%Y %H:%M'))
            ret += '\n\n' + station + '\n\n\n'
            ret += 'TANK 1    ' + product1 + '\n    TEST STATUS: OFF\nLEAK DATA NOT AVAILABLE ON THIS TANK\n\n'
            ret += 'TANK 2    ' + product2 + '\n    TEST STATUS: OFF\nLEAK DATA NOT AVAILABLE ON THIS TANK\n\n'
            ret += 'TANK 3    ' + product3 + '\n    TEST STATUS: OFF\nLEAK DATA NOT AVAILABLE ON THIS TANK\n\n'
            ret += 'TANK 4    ' + product4 + '\n    TEST STATUS: OFF\nLEAK DATA NOT AVAILABLE ON THIS TANK\n\n'
            return ret

        ###########################################################################
        # Shift report command I20400 only one item in report at this time,
        # but can always add more if needed
        ###########################################################################
        def I20400():
            ret = '\nI20400\n' + str(current_time.strftime('%m/%d/%Y %H:%M'))
            ret += '\n\n' + station + '\n\n\n\nSHIFT REPORT\n\n'
            ret += 'SHIFT 1 TIME: 12:00 AM\n\nTANK PRODUCT\n\n'
            ret += '  1  ' + product1 + ' VOLUME TC VOLUME  ULLAGE  HEIGHT  WATER   TEMP\n'
            ret += 'SHIFT  1 STARTING VALUES      ' + str(vol1) + '     ' + str(
                vol1tc
            ) + '    ' + ullage1 + '   ' + height1 + '   ' + h2o1 + '    ' + temp1 + '\n'
            ret += '         ENDING VALUES        ' + str(
                vol1 + 940) + '     ' + str(vol1tc + 886) + '    ' + str(
                    int(ullage1) + 345) + '   ' + str(float(
                        height1) + 53) + '  ' + h2o1 + '    ' + temp1 + '\n'
            ret += '         DELIVERY VALUE          0\n'
            ret += '         TOTALS                940\n\n'
            return ret

        ###########################################################################
        # I20500 In-Tank Status Report
        ###########################################################################
        def I20500():
            ret = '\nI20500\n' + str(current_time.strftime('%m/%d/%Y %H:%M'))
            ret += '\n\n\n' + station + '\n\n\n'
            ret += 'TANK   PRODUCT                 STATUS\n\n'
            ret += '  1    ' + product1 + '  NORMAL\n\n'
            ret += '  2    ' + product2 + '  HIGH WATER ALARM\n'
            ret += '                               HIGH WATER WARNING\n\n'
            ret += '  3    ' + product3 + '  NORMAL\n\n'
            ret += '  4    ' + product4 + '  NORMAL\n\n'
            return ret

        while True:
            try:
                # Get the initial data
                request = sock.recv(4096)
                # The connection has been closed
                if not request:
                    break
                while not (b'\n' in request or b'00' in request):
                    request += sock.recv(4096)
                # if first value is not ^A then do nothing
                # thanks John(achillean) for the help
                if request[:1] != b'\x01':
                    logger.info('Non ^A command attempt %s:%d. (%s)', addr[0],
                                addr[1], session.id)
                    break
                # if request is less than 6, than do nothing
                if len(request) < 6:
                    logger.info('Invalid command attempt %s:%d. (%s)', addr[0],
                                addr[1], session.id)
                    break

                cmds = {
                    "I20100": I20100,
                    "I20200": I20200,
                    "I20300": I20300,
                    "I20400": I20400,
                    "I20500": I20500
                }
                cmd = request[1:7].decode()  # strip ^A and \n out
                response = None
                if cmd in cmds:
                    logger.info('%s command attempt %s:%d. (%s)', cmd, addr[0],
                                addr[1], session.id)
                    response = cmds[cmd]()
                elif cmd.startswith("S6020"):
                    # change the tank name
                    if cmd.startswith("S60201"):
                        # split string into two, the command, and the data
                        TEMP = request.split(b'S60201')
                        # if length is less than two, print error
                        if len(TEMP) < 2:
                            response = AST_ERROR
                        # Else the command was entered correctly and continue
                        else:
                            # Strip off the carrage returns and new lines
                            TEMP1 = TEMP[1].rstrip(b'\r\n').decode()
                            # if Length is less than 22
                            if len(TEMP1) < 22:
                                # pad the result to have 22 chars
                                product1 = TEMP1.ljust(22)
                            elif len(TEMP1) > 22:
                                # else only print 22 chars if the result was longer
                                product1 = TEMP1[:20] + "  "
                            else:
                                # else it fits fine (22 chars)
                                product1 = TEMP1
                        logger.info('S60201: %s command attempt %s:%d. (%s)',
                                    TEMP1, addr[0], addr[1], session.id)
                    # Follows format for S60201 for comments
                    elif cmd.startswith("S60202"):
                        TEMP = request.split(b'S60202')
                        if len(TEMP) < 2:
                            response = AST_ERROR
                        else:
                            TEMP1 = TEMP[1].rstrip(b'\r\n').decode()
                            if len(TEMP1) < 22:
                                product2 = TEMP1.ljust(22)
                            elif len(TEMP1) > 22:
                                product2 = TEMP1[:20] + "  "
                            else:
                                product2 = TEMP1
                        logger.info('S60202: %s command attempt %s:%d. (%s)',
                                    TEMP1, addr[0], addr[1], session.id)
                    # Follows format for S60201 for comments
                    elif cmd.startswith("S60203"):
                        TEMP = request.split(b'S60203')
                        if len(TEMP) < 2:
                            response = AST_ERROR
                        else:
                            TEMP1 = TEMP[1].rstrip(b'\r\n').decode()
                            if len(TEMP1) < 22:
                                product3 = TEMP1.ljust(22)
                            elif len(TEMP1) > 22:
                                product3 = TEMP1[:20] + "  "
                            else:
                                product3 = TEMP1
                        logger.info('S60203: %s command attempt %s:%d. (%s)',
                                    TEMP1, addr[0], addr[1], session.id)
                    # Follows format for S60201 for comments
                    elif cmd.startswith("S60204"):
                        TEMP = request.split(b'S60204')
                        if len(TEMP) < 2:
                            response = AST_ERROR
                        else:
                            TEMP1 = TEMP[1].rstrip(b'\r\n').decode()
                            if len(TEMP1) < 22:
                                product4 = TEMP1.ljust(22)
                            elif len(TEMP1) > 22:
                                product4 = TEMP1[:20] + "  "
                            else:
                                product4 = TEMP1
                        logger.info('S60204: %s command attempt %s:%d. (%s)',
                                    TEMP1, addr[0], addr[1], session.id)
                    # Follows format for S60201 for comments
                    elif cmd.startswith("S60200"):
                        TEMP = request.split(b'S60200')
                        if len(TEMP) < 2:
                            response = AST_ERROR
                        else:
                            TEMP1 = TEMP[1].rstrip(b'\r\n').decode()
                            if len(TEMP1) < 22:
                                product1 = TEMP1.ljust(22)
                                product2 = TEMP1.ljust(22)
                                product3 = TEMP1.ljust(22)
                                product4 = TEMP1.ljust(22)
                            elif len(TEMP1) > 22:
                                product1 = TEMP1[:20] + "  "
                                product2 = TEMP1[:20] + "  "
                                product3 = TEMP1[:20] + "  "
                                product4 = TEMP1[:20] + "  "
                            else:
                                product1 = TEMP1
                                product2 = TEMP1
                                product3 = TEMP1
                                product4 = TEMP1
                        logger.info('S60200: %s command attempt %s:%d. (%s)',
                                    TEMP1, addr[0], addr[1], session.id)
                    else:
                        response = AST_ERROR
                else:
                    response = AST_ERROR
                    # log what was entered
                    logger.info('%s command attempt %s:%d. (%s)', request,
                                addr[0], addr[1], session.id)
                if response:
                    sock.send(str_to_bytes(response))
                session.add_event({
                    "type": "AST {0}".format(cmd),
                    "request": request,
                    "response": response
                })
            except Exception as e:
                logger.exception(('Unknown Error: {}'.format(str(e))))
        logger.info('GuardianAST client disconnected %s:%d. (%s)', addr[0],
                    addr[1], session.id)
        session.add_event({'type': 'CONNECTION_LOST'})
Пример #42
0
    def handle(self, sock, address):
        session = conpot_core.get_session(self.proxy_id, address[0], address[1])
        logger.info('New connection from {0}:{1} on {2} proxy. ({3})'.format(address[0], address[1],
                                                                             self.proxy_id, session.id))
        proxy_socket = socket()

        if self.keyfile and self.certfile:
            proxy_socket = wrap_socket(proxy_socket, self.keyfile, self.certfile)

        try:
            proxy_socket.connect((self.proxy_host, self.proxy_port))
        except _socket.error as ex:
            logger.error('Error while connecting to proxied service at ({0}, {1}): {2}'
                         .format(self.proxy_host, self.proxy_port, ex))
            self._close([proxy_socket, sock])
            return

        sockets = [proxy_socket, sock]
        while len(sockets) == 2:
            gevent.sleep()
            sockets_read, _, sockets_err = select.select(sockets, [], sockets, 10)

            if len(sockets_err) > 0:
                self._close([proxy_socket, sock])
                break

            for s in sockets_read:
                socket_close_reason = 'socket closed'
                try:
                    data = s.recv(1024)
                except _socket.error as socket_err:
                    data = []
                    socket_close_reason = str(socket_err)
                if len(data) is 0:
                    self._close([proxy_socket, sock])
                    if s is proxy_socket:
                        logging.warning('Closing proxied socket while receiving ({0}, {1}): {2}.'
                                        .format(self.proxy_host, self.proxy_port, socket_close_reason))
                        sockets = []
                        break
                    elif s is sock:
                        logging.warning('Closing connection to remote while receiving from remote ({0}, {1}): {2}'
                                        .format(socket_close_reason, address[0], address[1]))
                        sockets = []
                        break
                    else:
                        assert False

                try:
                    if s is proxy_socket:
                        self.handle_out_data(data, sock, session)
                    elif s is sock:
                        self.handle_in_data(data, proxy_socket, session)
                    else:
                        assert False
                except _socket.error as socket_err:
                    if s is proxy_socket:
                        destination = 'proxied socket'
                    else:
                        destination = 'remote connection'
                    logger.warning('Error while sending data to {0}: {1}.'.format(destination, str(socket_err)))
                    sockets = []
                    break

        session.set_ended()
        proxy_socket.close()
        sock.close()
Пример #43
0
    def handle(self, sock, address):
        sock.settimeout(self.timeout)
        session = conpot_core.get_session('s7comm', address[0], address[1],
                                          sock.getsockname()[0],
                                          sock.getsockname()[1])
        self.start_time = time.time()
        logger.info('New S7 connection from {0}:{1}. ({2})'.format(
            address[0], address[1], session.id))
        session.add_event({'type': 'NEW_CONNECTION'})

        try:
            while True:

                data = sock.recv(4, socket.MSG_WAITALL)
                if len(data) == 0:
                    session.add_event({'type': 'CONNECTION_LOST'})
                    break

                _, _, length = unpack('!BBH', data[:4])
                # check for length
                if length <= 4:
                    logger.info('S7 error: Invalid length')
                    session.add_event({'error': 'S7 error: Invalid length'})
                    break
                data += sock.recv(length - 4, socket.MSG_WAITALL)

                try:
                    tpkt_packet = TPKT().parse(cleanse_byte_string(data))
                    cotp_base_packet = COTP_BASE_packet().parse(
                        tpkt_packet.payload)
                except Exception as e:
                    break

                if cotp_base_packet.tpdu_type == 0xe0:

                    # connection request
                    cotp_cr_request = COTP_ConnectionRequest().dissect(
                        cotp_base_packet.payload)
                    logger.info(
                        'Received COTP Connection Request: dst-ref:{0} src-ref:{1} dst-tsap:{2} src-tsap:{3} '
                        'tpdu-size:{4}. ({5})'.format(
                            cotp_cr_request.dst_ref, cotp_cr_request.src_ref,
                            cotp_cr_request.dst_tsap, cotp_cr_request.src_tsap,
                            cotp_cr_request.tpdu_size, session.id))

                    # confirm connection response
                    cotp_cc_response = COTP_ConnectionConfirm(
                        cotp_cr_request.src_ref, cotp_cr_request.dst_ref, 0,
                        cotp_cr_request.src_tsap, cotp_cr_request.dst_tsap,
                        0x0a).assemble()

                    # encapsulate and transmit
                    cotp_resp_base_packet = COTP_BASE_packet(
                        0xd0, 0, cotp_cc_response).pack()
                    tpkt_resp_packet = TPKT(3, cotp_resp_base_packet).pack()
                    sock.send(tpkt_resp_packet)

                    session.add_event({
                        'request':
                        codecs.encode(data, 'hex'),
                        'response':
                        codecs.encode(tpkt_resp_packet, 'hex')
                    })

                    data = sock.recv(1024)

                    # another round of parsing payloads
                    tpkt_packet = TPKT().parse(data)
                    cotp_base_packet = COTP_BASE_packet().parse(
                        tpkt_packet.payload)

                    if cotp_base_packet.tpdu_type == 0xf0:
                        logger.info(
                            'Received known COTP TPDU: {0}. ({1})'.format(
                                cotp_base_packet.tpdu_type, session.id))

                        # will throw exception if the packet does not contain the S7 magic number (0x32)
                        S7_packet = S7().parse(cotp_base_packet.trailer)
                        logger.info(
                            'Received S7 packet: magic:%s pdu_type:%s reserved:%s req_id:%s param_len:%s '
                            'data_len:%s result_inf:%s session_id:%s',
                            S7_packet.magic, S7_packet.pdu_type,
                            S7_packet.reserved, S7_packet.request_id,
                            S7_packet.param_length, S7_packet.data_length,
                            S7_packet.result_info, session.id)

                        # request pdu
                        if S7_packet.pdu_type == 1:

                            # 0xf0 == Request for connect / pdu negotiate
                            if S7_packet.param == 0xf0:

                                # create S7 response packet
                                s7_resp_negotiate_packet = S7(
                                    3, 0, S7_packet.request_id, 0,
                                    S7_packet.parameters).pack()
                                # wrap s7 the packet in cotp
                                cotp_resp_negotiate_packet = COTP_BASE_packet(
                                    0xf0, 0x80,
                                    s7_resp_negotiate_packet).pack()
                                # wrap the cotp packet
                                tpkt_resp_packet = TPKT(
                                    3, cotp_resp_negotiate_packet).pack()
                                sock.send(tpkt_resp_packet)

                                session.add_event({
                                    'request':
                                    codecs.encode(data, 'hex'),
                                    'response':
                                    codecs.encode(tpkt_resp_packet, 'hex')
                                })

                                # handshake done, give some more data.
                                data = sock.recv(1024)

                                while data:
                                    tpkt_packet = TPKT().parse(data)
                                    cotp_base_packet = COTP_BASE_packet(
                                    ).parse(tpkt_packet.payload)

                                    if cotp_base_packet.tpdu_type == 0xf0:
                                        S7_packet = S7().parse(
                                            cotp_base_packet.trailer)
                                        logger.info(
                                            'Received S7 packet: magic:%s pdu_type:%s reserved:%s '
                                            'req_id:%s param_len:%s data_len:%s result_inf:%s session_id:%s',
                                            S7_packet.magic,
                                            S7_packet.pdu_type,
                                            S7_packet.reserved,
                                            S7_packet.request_id,
                                            S7_packet.param_length,
                                            S7_packet.data_length,
                                            S7_packet.result_info, session.id)

                                        response_param, response_data = S7_packet.handle(
                                        )
                                        s7_resp_ssl_packet = S7(
                                            7, 0, S7_packet.request_id, 0,
                                            response_param,
                                            response_data).pack()
                                        cotp_resp_ssl_packet = COTP_BASE_packet(
                                            0xf0, 0x80,
                                            s7_resp_ssl_packet).pack()
                                        tpkt_resp_packet = TPKT(
                                            3, cotp_resp_ssl_packet).pack()
                                        sock.send(tpkt_resp_packet)

                                        session.add_event({
                                            'request':
                                            codecs.encode(data, 'hex'),
                                            'response':
                                            codecs.encode(
                                                tpkt_resp_packet, 'hex')
                                        })

                                    data = sock.recv(1024)
                    else:
                        logger.info(
                            'Received unknown COTP TPDU after handshake: {0}'.
                            format(cotp_base_packet.tpdu_type))
                        session.add_event({
                            'error':
                            'Received unknown COTP TPDU after handshake: {0}'.
                            format(cotp_base_packet.tpdu_type)
                        })
                else:
                    logger.info(
                        'Received unknown COTP TPDU before handshake: {0}'.
                        format(cotp_base_packet.tpdu_type))
                    session.add_event({
                        'error':
                        'Received unknown COTP TPDU before handshake: {0}'.
                        format(cotp_base_packet.tpdu_type)
                    })

        except socket.timeout:
            session.add_event({'type': 'CONNECTION_LOST'})
            logger.debug('Socket timeout, remote: {0}. ({1})'.format(
                address[0], session.id))
        except socket.error:
            session.add_event({'type': 'CONNECTION_LOST'})
            logger.debug('Connection reset by peer, remote: {0}. ({1})'.format(
                address[0], session.id))
        except Exception as e:
            logger.exception('Exception caught {0}, remote: {1}. ({2})'.format(
                e, address[0], session.id))
Пример #44
0
    def handle(self, sock, address):
        session = conpot_core.get_session(self.proxy_id, address[0], address[1], sock.getsockname()[0], sock.getsockname()[1])
        logger.info(
            'New connection from %s:%s on %s proxy. (%s)',
            address[0], address[1], self.proxy_id, session.id)
        proxy_socket = socket()

        if self.keyfile and self.certfile:
            proxy_socket = wrap_socket(proxy_socket, self.keyfile, self.certfile)

        try:
            proxy_socket.connect((self.proxy_host, self.proxy_port))
        except _socket.error:
            logger.exception('Error while connecting to proxied service at ({}, {})'.format(self.proxy_host,
                             self.proxy_port))
            self._close([proxy_socket, sock])
            return

        sockets = [proxy_socket, sock]

        while len(sockets) == 2:
            if Proxy.stop_servers:
                self._close([proxy_socket, sock])
                break

            gevent.sleep(0)
            ProxyAddresses.put(proxy_socket, [address[0], address[1]])
            sockets_read, _, sockets_err = select.select(sockets, [], sockets, 10)

            if len(sockets_err) > 0:
                self._close([proxy_socket, sock])
                break

            for s in sockets_read:
                socket_close_reason = 'socket closed'
                try:
                    data = s.recv(1024)
                except _socket.error as socket_err:
                    data = []
                    socket_close_reason = str(socket_err)
                if len(data) is 0:
                    ProxyAddresses.clear_unused(proxy_socket)
                    self._close([proxy_socket, sock])
                    if s is proxy_socket:
                        logging.warning(
                            'Closing proxied socket while receiving (%s, %s): %s.',
                            self.proxy_host, self.proxy_port, socket_close_reason)
                        sockets = []
                        break
                    elif s is sock:
                        logging.warning(
                            'Closing connection to remote while receiving from remote (%s, %s): %s',
                            socket_close_reason, address[0], address[1])
                        sockets = []
                        break
                    else:
                        assert False

                try:
                    if s is proxy_socket:
                        self.handle_out_data(data, sock, session)
                    elif s is sock:
                        self.handle_in_data(data, proxy_socket, session)
                    else:
                        assert False
                except _socket.error as socket_err:
                    if s is proxy_socket:
                        destination = 'proxied socket'
                    else:
                        destination = 'remote connection'
                    logger.warning('Error while sending data to %s: %s.', destination, str(socket_err))
                    sockets = []
                    break

        session.set_ended()
        proxy_socket.close()
        sock.close()
Пример #45
0
    def handle(self, sock, address):
        session = conpot_core.get_session(self.proxy_id, address[0],
                                          address[1])
        logger.info('New connection from {0}:{1} on {2} proxy. ({3})'.format(
            address[0], address[1], self.proxy_id, session.id))
        proxy_socket = socket()

        if self.keyfile and self.certfile:
            proxy_socket = wrap_socket(proxy_socket, self.keyfile,
                                       self.certfile)

        try:
            proxy_socket.connect((self.proxy_host, self.proxy_port))
        except _socket.error as ex:
            logger.error(
                'Error while connecting to proxied service at ({0}, {1}): {2}'.
                format(self.proxy_host, self.proxy_port, ex))
            self._close([proxy_socket, sock])
            return

        sockets = [proxy_socket, sock]
        while len(sockets) == 2:
            gevent.sleep()
            sockets_read, _, sockets_err = select.select(
                sockets, [], sockets, 10)

            if len(sockets_err) > 0:
                self._close([proxy_socket, sock])
                break

            for s in sockets_read:
                socket_close_reason = 'socket closed'
                try:
                    data = s.recv(1024)
                except _socket.error as socket_err:
                    data = []
                    socket_close_reason = str(socket_err)
                if len(data) is 0:
                    self._close([proxy_socket, sock])
                    if s is proxy_socket:
                        logging.warning(
                            'Closing proxied socket while receiving ({0}, {1}): {2}.'
                            .format(self.proxy_host, self.proxy_port,
                                    socket_close_reason))
                        sockets = []
                        break
                    elif s is sock:
                        logging.warning(
                            'Closing connection to remote while receiving from remote ({0}, {1}): {2}'
                            .format(socket_close_reason, address[0],
                                    address[1]))
                        sockets = []
                        break
                    else:
                        assert False

                try:
                    if s is proxy_socket:
                        self.handle_out_data(data, sock, session)
                    elif s is sock:
                        self.handle_in_data(data, proxy_socket, session)
                    else:
                        assert False
                except _socket.error as socket_err:
                    if s is proxy_socket:
                        destination = 'proxied socket'
                    else:
                        destination = 'remote connection'
                    logger.warning(
                        'Error while sending data to {0}: {1}.'.format(
                            destination, str(socket_err)))
                    sockets = []
                    break

        session.set_ended()
        proxy_socket.close()
        sock.close()
Пример #46
0
    def handle(self, sock, address):
        sock.settimeout(self.timeout)
        session = conpot_core.get_session('IEC104',address[0], address[1], sock.getsockname()[0], sock.getsockname()[1])
        logger.info('New IEC 104 connection from %s:%s. (%s)', address[0], address[1], session.id)
        session.add_event({'type': 'NEW_CONNECTION'})
        iec104_handler = IEC104(self.device_data_controller, sock, address, session.id)
        try:
            while True:
                timeout_t3 = gevent.Timeout(conpot_core.get_databus().get_value('T_3'), Timeout_t3)
                timeout_t3.start()
                try:
                    try:
                        request = sock.recv(6)
                        if not request:
                            logger.info('IEC104 Station disconnected. (%s)', session.id)
                            session.add_event({'type': 'CONNECTION_LOST'})
                            iec104_handler.disconnect()
                            break
                        while request and len(request) < 2:
                            new_byte = sock.recv(1)
                            request += new_byte

                        protocol_identifier, length = struct.unpack(">BB", request[:2])
                        while len(request) < (length + 2):
                            new_byte = sock.recv(1)
                            if not new_byte:
                                break
                            request += new_byte

                        # check if IEC 104 packet or for the first occurrence of the indication 0x68 for IEC 104
                        for elem in list(request):
                            if 0x68 == elem:
                                index = request.index(elem)

                                iec_request = request[index:]
                                timeout_t3.cancel()
                                response = None
                                # check which frame type
                                if not (iec_request[2] & 0x01):  # i_frame
                                    response = iec104_handler.handle_i_frame(iec_request)
                                elif iec_request[2] & 0x01 and not(iec_request[2] & 0x02):  # s_frame
                                    response = iec104_handler.handle_s_frame(iec_request)
                                elif iec_request[2] & 0x03:  # u_frame
                                    response = iec104_handler.handle_u_frame(iec_request)
                                else:
                                    logger.warning("%s ---> No valid IEC104 type (%s)", address, session.id)

                                if response:
                                    for resp_packet in response:
                                        if resp_packet:
                                            sock.send(resp_packet)
                                            # response_string = (" ".join(hex(n) for n in resp_packet))

                                break

                    except Timeout_t3:
                        pkt = iec104_handler.send_104frame(TESTFR_act)
                        if pkt:
                            sock.send(pkt)
                    finally:
                        timeout_t3.cancel()
                except gevent.Timeout:
                    logger.warning("T1 timed out. (%s)", session.id)
                    logger.info('IEC104 Station disconnected. (%s)', session.id)
                    session.add_event({'type': 'CONNECTION_LOST'})
                    iec104_handler.disconnect()
                    break
        except socket.timeout:
            logger.debug('Socket timeout, remote: %s. (%s)', address[0], session.id)
            session.add_event({'type': 'CONNECTION_LOST'})
        except socket.error as err:
            if isinstance(err.args, tuple):
                if err[0] == errno.EPIPE:
                    # remote peer disconnected
                    logger.info('IEC104 Station disconnected. (%s)', session.id)
                    session.add_event({'type': 'CONNECTION_LOST'})
                else:
                    # determine and handle different error
                    pass
            else:
                print(("socket error ", err))
            iec104_handler.disconnect()
Пример #47
0
    def handle(self, sock, address):
        sock.settimeout(self.timeout)

        session = conpot_core.get_session('modbus', address[0], address[1], sock.getsockname()[0], sock.getsockname()[1])

        self.start_time = time.time()
        logger.info(
            'New Modbus connection from %s:%s. (%s)',
            address[0], address[1], session.id)
        session.add_event({'type': 'NEW_CONNECTION'})

        try:
            while True:
                request = None
                try:
                    request = sock.recv(7)
                except Exception as e:
                    logger.error('Exception occurred in ModbusServer.handle() '
                                 'at sock.recv(): %s', str(e))

                if not request:
                    logger.info('Modbus client disconnected. (%s)', session.id)
                    session.add_event({'type': 'CONNECTION_LOST'})
                    break
                if request.strip().lower() == 'quit.':
                    logger.info('Modbus client quit. (%s)', session.id)
                    session.add_event({'type': 'CONNECTION_QUIT'})
                    break
                if len(request) < 7:
                    logger.info('Modbus client provided data {} but invalid.'.format(session.id))
                    session.add_event({'type': 'CONNECTION_TERMINATED'})
                    break
                tr_id, pr_id, length = struct.unpack(">HHH", request[:6])
                while len(request) < (length + 6):
                    new_byte = sock.recv(1)
                    request += new_byte
                query = modbus_tcp.TcpQuery()

                # logdata is a dictionary containing request, slave_id,
                # function_code and response
                response, logdata = self._databank.handle_request(
                    query, request, self.mode
                )
                logdata['request'] = codecs.encode(request, 'hex')
                session.add_event(logdata)

                logger.info(
                    'Modbus traffic from %s: %s (%s)',
                    address[0], logdata, session.id)

                if response:
                    sock.sendall(response)
                    logger.info('Modbus response sent to %s', address[0])
                else:
                    # TODO:
                    # response could be None under several different cases

                    # MB serial connection addressing UID=0
                    if (self.mode == 'serial') and (logdata['slave_id'] == 0):
                        # delay is in milliseconds
                        time.sleep(self.delay / 1000)
                        logger.debug(
                            'Modbus server\'s turnaround delay expired.')
                        logger.info('Modbus connection terminated with client %s.',
                                    address[0])
                        session.add_event({'type': 'CONNECTION_TERMINATED'})
                        sock.shutdown(socket.SHUT_RDWR)
                        sock.close()
                        break
                    # Invalid addressing
                    else:
                        logger.info('Modbus client ignored due to invalid addressing.'
                                    ' (%s)', session.id)
                        session.add_event({'type': 'CONNECTION_TERMINATED'})
                        sock.shutdown(socket.SHUT_RDWR)
                        sock.close()
                        break
        except socket.timeout:
            logger.debug(
                'Socket timeout, remote: %s. (%s)', address[0], session.id)
            session.add_event({'type': 'CONNECTION_LOST'})