コード例 #1
0
ファイル: beaconserver.py プロジェクト: simudream/PyFuzz2
class BeaconServer:
    def __init__(self, port, task_queue):
        self._port = port
        self._serving = False
        self._serving_greenlet = None
        self._beacon_server = None
        self._logger = logging.getLogger(__name__)
        self._task_queue = task_queue

    def __serve(self):
        self._logger.info("[Beacon Server] initialized on port " +
                          str(self._port) + " ...")
        self._beacon_server = DatagramServer(('', self._port),
                                             self.__beacon_receiver)
        self._beacon_server.serve_forever()

    def __beacon_receiver(self, msg, address):
        self._task_queue.put([address, msg])

    def serve(self):
        if not self._serving:
            self._serving_greenlet = gevent.spawn(self.__serve)
            self._serving = True
            gevent.sleep(0)
        else:
            pass
コード例 #2
0
ファイル: beaconserver.py プロジェクト: susperius/PyFuzz2
class BeaconServer(Server):
    def __init__(self, port, task_queue):
        self._port = port
        self._serving = False
        self._serving_greenlet = None
        self._beacon_server = None
        self._logger = logging.getLogger(__name__)
        self._task_queue = task_queue

    def __serve(self):
        self._logger.info("[BeaconServer] initialized on port " + str(self._port) + " ...")
        self._beacon_server = DatagramServer(('', self._port), self.__beacon_receiver)
        self._beacon_server.serve_forever()

    def __beacon_receiver(self, msg, address):
        self._task_queue.put([address, msg])

    def start_server(self):
        if not self._serving:
            self._serving_greenlet = gevent.spawn(self.__serve)
            self._serving = True
            gevent.sleep(0)

    def stop_server(self):
        if self._serving:
            gevent.kill(self._serving_greenlet)
            self._serving = False
            self._beacon_server.close()
            self._logger.info("[BeaconServer] shut down")
コード例 #3
0
ファイル: bjdns.py プロジェクト: akiasprin/bjdns
def serv_start(handle):
    global socket, server, cache
    geventsocks.set_default_proxy(config['socks5_ip'], config['socks5_port'])
    server = DatagramServer((config['listen_ip'], config['listen_port']),
                            handle)
    cache = {}
    return server.serve_forever()
コード例 #4
0
def serv_start(handle):
    global socket, server, cache
    mode = config['mode']
    if mode == 'gevent':
        global geventsocks
        from gevent.server import DatagramServer
        from gevent import socket
        import geventsocks
        geventsocks.set_default_proxy(config['socks5_ip'],
                                      config['socks5_port'])
        server = DatagramServer((config['listen_ip'], config['listen_port']),
                                handle)
        cache = {}
        return server.serve_forever()

    elif mode == 'multiprocessing':
        global socks
        import socket
        import multiprocessing
        import socks
        socks.set_default_proxy(socks.SOCKS5, config['socks5_ip'],
                                config['socks5_port'])
        server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server.bind((config['listen_ip'], config['listen_port']))
        cache = multiprocessing.Manager().dict()
        pool = multiprocessing.Pool(config['the_num_of_processes'])
        while True:
            data, cli_addr = server.recvfrom(512)
            pool.apply_async(handle, args=(
                data,
                cli_addr,
            ))
コード例 #5
0
ファイル: bacnet_server.py プロジェクト: saegel/conpot
class BacnetServer(object):
    def __init__(self, template, template_directory, args):
        self.dom = etree.parse(template)
        device_info_root = self.dom.xpath("//bacnet/device_info")[0]
        name_key = device_info_root.xpath("./device_name/text()")[0]
        id_key = device_info_root.xpath("./device_identifier/text()")[0]
        vendor_name_key = device_info_root.xpath("./vendor_name/text()")[0]
        vendor_identifier_key = device_info_root.xpath(
            "./vendor_identifier/text()")[0]
        apdu_length_key = device_info_root.xpath(
            "./max_apdu_length_accepted/text()")[0]
        segmentation_key = device_info_root.xpath(
            "./segmentation_supported/text()")[0]

        self.thisDevice = LocalDeviceObject(
            objectName=name_key,
            objectIdentifier=int(id_key),
            maxApduLengthAccepted=int(apdu_length_key),
            segmentationSupported=segmentation_key,
            vendorName=vendor_name_key,
            vendorIdentifier=int(vendor_identifier_key),
        )
        self.bacnet_app = None
        self.server = None  # Initialize later
        logger.info("Conpot Bacnet initialized using the %s template.",
                    template)

    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)

    def start(self, host, port):
        connection = (host, port)
        self.server = DatagramServer(connection, self.handle)
        # start to init the socket
        self.server.start()
        self.server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST,
                                      1)
        self.host = self.server.server_host
        self.port = self.server.server_port
        # create application instance
        # not too beautiful, but the BACnetApp needs access to the socket's sendto method
        # this could properly be refactored in a way such that sending operates on it's own
        # (non-bound) socket.
        self.bacnet_app = BACnetApp(self.thisDevice, self.server)
        # get object_list and properties
        self.bacnet_app.get_objects_and_properties(self.dom)

        logger.info("Bacnet server started on: %s", (self.host, self.port))
        self.server.serve_forever()

    def stop(self):
        self.server.stop()
コード例 #6
0
class BacnetServer(object):
    def __init__(self, template, template_directory, args):
        self.dom = etree.parse(template)
        databus = conpot_core.get_databus()
        device_info_root = self.dom.xpath('//bacnet/device_info')[0]

        name_key = databus.get_value(
            device_info_root.xpath('./device_name/text()')[0])
        id_key = device_info_root.xpath('./device_identifier/text()')[0]
        vendor_name_key = device_info_root.xpath('./vendor_name/text()')[0]
        vendor_identifier_key = device_info_root.xpath(
            './vendor_identifier/text()')[0]
        apdu_length_key = device_info_root.xpath(
            './max_apdu_length_accepted/text()')[0]
        segmentation_key = device_info_root.xpath(
            './segmentation_supported/text()')[0]

        # self.local_device_address = dom.xpath('./@*[name()="host" or name()="port"]')

        self.thisDevice = LocalDeviceObject(
            objectName=name_key,
            objectIdentifier=int(id_key),
            maxApduLengthAccepted=int(apdu_length_key),
            segmentationSupported=segmentation_key,
            vendorName=vendor_name_key,
            vendorIdentifier=int(vendor_identifier_key))
        self.bacnet_app = None

        logger.info('Conpot Bacnet initialized using the %s template.',
                    template)

    def handle(self, data, address):
        session = conpot_core.get_session('bacnet', address[0], address[1],
                                          self.host, self.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 = 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)

    def start(self, host, port):
        self.host = host
        self.port = port
        connection = (host, port)
        self.server = DatagramServer(connection, self.handle)
        # start to init the socket
        self.server.start()
        self.server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST,
                                      1)

        # create application instance
        # not too beautifull, but the BACnetApp needs access to the socket's sendto method
        # this could properly be refactored in a way such that sending operates on it's own
        # (non-bound) socket.
        self.bacnet_app = BACnetApp(self.thisDevice, self.server)
        # get object_list and properties
        self.bacnet_app.get_objects_and_properties(self.dom)

        logger.info('Bacnet server started on: %s', connection)
        self.server.serve_forever()

    def stop(self):
        self.server.stop()
コード例 #7
0
class IpmiServer(object):
    def __init__(self, template, template_directory, args):
        dom = etree.parse(template)
        databus = conpot_core.get_databus()
        self.device_name = databus.get_value(
            dom.xpath('//ipmi/device_info/device_name/text()')[0])
        self.port = None
        self.sessions = dict()

        self.uuid = uuid.uuid4()
        self.kg = None
        self.sock = None
        self.authdata = collections.OrderedDict()
        lanchannel = 1
        authtype = 0b10000000
        authstatus = 0b00000100
        chancap = 0b00000010
        oemdata = (0, 0, 0, 0)
        self.authcap = struct.pack('BBBBBBBBB', 0, lanchannel, authtype,
                                   authstatus, chancap, *oemdata)
        self.server = None
        self.session = None
        self.bmc = self._configure_users(dom)
        logger.info('Conpot IPMI initialized using %s template', template)

    def _configure_users(self, dom):
        # XML parsing
        authdata_name = dom.xpath('//ipmi/user_list/user/user_name/text()')
        authdata_passwd = dom.xpath('//ipmi/user_list/user/password/text()')
        authdata_name = [i.encode('utf-8') for i in authdata_name]
        authdata_passwd = [i.encode('utf-8') for i in authdata_passwd]
        self.authdata = collections.OrderedDict(
            zip(authdata_name, authdata_passwd))

        authdata_priv = dom.xpath('//ipmi/user_list/user/privilege/text()')
        if False in map(lambda k: 0 < int(k) <= 4, authdata_priv):
            raise ValueError("Privilege level must be between 1 and 4")
        authdata_priv = [int(k) for k in authdata_priv]
        self.privdata = collections.OrderedDict(
            zip(authdata_name, authdata_priv))

        activeusers = dom.xpath('//ipmi/user_list/user/active/text()')
        self.activeusers = [1 if x == 'true' else 0 for x in activeusers]

        fixedusers = dom.xpath('//ipmi/user_list/user/fixed/text()')
        self.fixedusers = [1 if x == 'true' else 0 for x in fixedusers]
        self.channelaccessdata = collections.OrderedDict(
            zip(authdata_name, activeusers))

        return FakeBmc(self.authdata, self.port)

    def _checksum(self, *data):
        csum = sum(data)
        csum ^= 0xff
        csum += 1
        csum &= 0xff
        return csum

    def handle(self, data, address):
        # make sure self.session exists
        if not address[0] in self.sessions.keys() or not hasattr(
                self, 'session'):
            # new session for new source
            logger.info('New IPMI traffic from %s', address)
            self.session = FakeSession(address[0], "", "", address[1])
            self.session.server = self
            self.uuid = uuid.uuid4()
            self.kg = None

            self.session.socket = self.sock
            self.sessions[address[0]] = self.session
            self.initiate_session(data, address, self.session)
        else:
            # session already exists
            logger.info('Incoming IPMI traffic from %s', address)
            if self.session.stage == 0:
                self.close_server_session()
            else:
                self._got_request(data, address, self.session)

    def initiate_session(self, data, address, session):
        if len(data) < 22:
            self.close_server_session()
            return
        if not (chr_py3(data[0]) == b'\x06' and data[2:4] == b'\xff\x07'):
            # check rmcp version, sequencenumber and class;
            self.close_server_session()
            return
        if chr_py3(data[4]) == b'\x06':
            # ipmi v2
            session.ipmiversion = 2.0
            session.authtype = 6
            payload_type = chr_py3(data[5])
            if payload_type not in (b'\x00', b'\x10'):
                self.close_server_session()
                return
            if payload_type == b'\x10':
                # new session to handle conversation
                serversession.ServerSession(self.authdata,
                                            self.kg,
                                            session.sockaddr,
                                            self.sock,
                                            data[16:],
                                            self.uuid,
                                            bmc=self)
                serversession.ServerSession.logged = logger
                return
            # data = data[13:]
        if len(data[14:16]) < 2:
            self.close_server_session()
        else:
            myaddr, netfnlun = struct.unpack('2B', data[14:16])
            netfn = (netfnlun & 0b11111100) >> 2
            mylun = netfnlun & 0b11
            if netfn == 6:
                # application request
                if chr_py3(data[19]) == b'\x38':
                    # cmd = get channel auth capabilities
                    verchannel, level = struct.unpack('2B', data[20:22])
                    version = verchannel & 0b10000000
                    if version != 0b10000000:
                        self.close_server_session()
                        return
                    channel = verchannel & 0b1111
                    if channel != 0xe:
                        self.close_server_session()
                        return
                    (clientaddr, clientlun) = struct.unpack('BB', data[17:19])
                    level &= 0b1111
                    self.send_auth_cap(myaddr, mylun, clientaddr, clientlun,
                                       session.sockaddr)

    def send_auth_cap(self, myaddr, mylun, clientaddr, clientlun, sockaddr):
        header = b'\x06\x00\xff\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10'

        headerdata = (clientaddr, clientlun | (7 << 2))
        headersum = self._checksum(*headerdata)
        header += struct.pack('BBBBBB',
                              *(headerdata + (headersum, myaddr, mylun, 0x38)))
        header += self.authcap
        bodydata = struct.unpack('B' * len(header[17:]), header[17:])
        header += chr_py3(self._checksum(*bodydata))
        self.session.stage += 1
        logger.info('Connection established with %s', sockaddr)
        self.session.send_data(header, sockaddr)

    def close_server_session(self):
        logger.info('IPMI Session closed %s', self.session.sockaddr[0])
        # cleanup session
        del self.sessions[self.session.sockaddr[0]]
        del self.session

    def _got_request(self, data, address, session):
        if chr_py3(data[4]) in (b'\x00', b'\x02'):
            # ipmi 1.5 payload
            session.ipmiversion = 1.5
            remsequencenumber = struct.unpack('<I', data[5:9])[0]
            if hasattr(session, 'remsequencenumber'
                       ) and remsequencenumber < session.remsequencenumber:
                self.close_server_session()
                return
            session.remsequencenumber = remsequencenumber
            if ord(chr_py3(data[4])) != session.authtype:
                self.close_server_session()
                return
            remsessid = struct.unpack("<I", data[9:13])[0]
            if remsessid != session.sessionid:
                self.close_server_session()
                return
            rsp = list(struct.unpack("!%dB" % len(data), data))
            authcode = False
            if chr_py3(data[4]) == b'\x02':
                # authcode in ipmi 1.5 packet
                authcode = data[13:29]
                del rsp[13:29]
            payload = list(rsp[14:14 + rsp[13]])
            if authcode:
                expectedauthcode = session._ipmi15authcode(
                    payload, checkremotecode=True)
                expectedauthcode = struct.pack("%dB" % len(expectedauthcode),
                                               *expectedauthcode)
                if expectedauthcode != authcode:
                    self.close_server_session()
                    return
            session._ipmi15(payload)
        elif chr_py3(data[4]) == b'\x06':
            # ipmi 2.0 payload
            session.ipmiversion = 2.0
            session.authtype = 6
            session._ipmi20(data)
        else:
            # unrecognized data
            self.close_server_session()
            return

    def _got_rmcp_openrequest(self, data):
        request = struct.pack('B' * len(data), *data)
        clienttag = ord(chr_py3(request[0]))
        self.clientsessionid = list(struct.unpack('4B', request[4:8]))
        self.managedsessionid = list(struct.unpack('4B', os.urandom(4)))
        self.session.privlevel = 4
        response = ([clienttag, 0, self.session.privlevel, 0] +
                    self.clientsessionid + self.managedsessionid + [
                        0,
                        0,
                        0,
                        8,
                        1,
                        0,
                        0,
                        0,  # auth
                        1,
                        0,
                        0,
                        8,
                        1,
                        0,
                        0,
                        0,  # integrity
                        2,
                        0,
                        0,
                        8,
                        1,
                        0,
                        0,
                        0,  # privacy
                    ])
        logger.info('IPMI open session request')
        self.session.send_payload(
            response,
            constants.payload_types['rmcpplusopenresponse'],
            retry=False)

    def _got_rakp1(self, data):
        clienttag = data[0]
        self.Rm = data[8:24]
        self.rolem = data[24]
        self.maxpriv = self.rolem & 0b111
        namepresent = data[27]
        if namepresent == 0:
            self.close_server_session()
            return
        usernamebytes = data[28:]
        self.username = struct.pack('%dB' % len(usernamebytes), *usernamebytes)
        if self.username not in self.authdata:
            logger.info('User {} supplied by client not in user_db.'.format(
                self.username, ))
            self.close_server_session()
            return
        uuidbytes = self.uuid.bytes
        uuidbytes = list(struct.unpack('%dB' % len(uuidbytes), uuidbytes))
        self.uuiddata = uuidbytes
        self.Rc = list(struct.unpack('16B', os.urandom(16)))
        hmacdata = (self.clientsessionid + self.managedsessionid + self.Rm +
                    self.Rc + uuidbytes +
                    [self.rolem, len(self.username)])
        hmacdata = struct.pack('%dB' % len(hmacdata), *hmacdata)
        hmacdata += self.username
        self.kuid = self.authdata[self.username]
        if self.kg is None:
            self.kg = self.kuid
        authcode = hmac.new(self.kuid, hmacdata, hashlib.sha1).digest()
        authcode = list(struct.unpack('%dB' % len(authcode), authcode))
        newmessage = ([clienttag, 0, 0, 0] + self.clientsessionid + self.Rc +
                      uuidbytes + authcode)
        logger.info('IPMI rakp1 request')
        self.session.send_payload(newmessage,
                                  constants.payload_types['rakp2'],
                                  retry=False)

    def _got_rakp3(self, data):
        RmRc = struct.pack('B' * len(self.Rm + self.Rc), *(self.Rm + self.Rc))
        self.sik = hmac.new(
            self.kg, RmRc + struct.pack("2B", self.rolem, len(self.username)) +
            self.username, hashlib.sha1).digest()
        self.session.k1 = hmac.new(self.sik, b'\x01' * 20,
                                   hashlib.sha1).digest()
        self.session.k2 = hmac.new(self.sik, b'\x02' * 20,
                                   hashlib.sha1).digest()
        self.session.aeskey = self.session.k2[0:16]

        hmacdata = struct.pack('B' * len(self.Rc), *self.Rc) + struct.pack("4B", *self.clientsessionid) +\
            struct.pack("2B", self.rolem, len(self.username)) + self.username
        expectedauthcode = hmac.new(self.kuid, hmacdata, hashlib.sha1).digest()
        authcode = struct.pack("%dB" % len(data[8:]), *data[8:])
        if expectedauthcode != authcode:
            self.close_server_session()
            return
        clienttag = data[0]
        if data[1] != 0:
            self.close_server_session()
            return
        self.session.localsid = struct.unpack(
            '<I', struct.pack('4B', *self.managedsessionid))[0]

        logger.info('IPMI rakp3 request')
        self.session.ipmicallback = self.handle_client_request
        self._send_rakp4(clienttag, 0)

    def _send_rakp4(self, tagvalue, statuscode):
        payload = [tagvalue, statuscode, 0, 0] + self.clientsessionid
        hmacdata = self.Rm + self.managedsessionid + self.uuiddata
        hmacdata = struct.pack('%dB' % len(hmacdata), *hmacdata)
        authdata = hmac.new(self.sik, hmacdata, hashlib.sha1).digest()[:12]
        payload += struct.unpack('%dB' % len(authdata), authdata)
        logger.info('IPMI rakp4 sent')
        self.session.send_payload(payload,
                                  constants.payload_types['rakp4'],
                                  retry=False)
        self.session.confalgo = 'aes'
        self.session.integrityalgo = 'sha1'
        self.session.sessionid = struct.unpack(
            '<I', struct.pack('4B', *self.clientsessionid))[0]

    def handle_client_request(self, request):
        if request['netfn'] == 6 and request['command'] == 0x3b:
            # set session privilage level
            pendingpriv = request['data'][0]
            returncode = 0
            if pendingpriv > 1:
                if pendingpriv > self.maxpriv:
                    returncode = 0x81
                else:
                    self.clientpriv = request['data'][0]
            self.session._send_ipmi_net_payload(code=returncode,
                                                data=[self.clientpriv])
            logger.info('IPMI response sent (Set Session Privilege) to %s',
                        self.session.sockaddr)
        elif request['netfn'] == 6 and request['command'] == 0x3c:
            # close session
            self.session.send_ipmi_response()
            logger.info('IPMI response sent (Close Session) to %s',
                        self.session.sockaddr)
            self.close_server_session()
        elif request['netfn'] == 6 and request['command'] == 0x44:
            # get user access
            reschan = request['data'][0]
            channel = reschan & 0b00001111
            resuid = request['data'][1]
            usid = resuid & 0b00011111
            if self.clientpriv > self.maxpriv:
                returncode = 0xd4
            else:
                returncode = 0
            self.usercount = len(self.authdata.keys())
            self.channelaccess = 0b0000000 | self.privdata[list(
                self.authdata.keys())[usid - 1]]
            if self.channelaccessdata[list(self.authdata.keys())[usid -
                                                                 1]] == 'true':
                # channelaccess: 7=res; 6=callin; 5=link; 4=messaging; 3-0=privilege
                self.channelaccess |= 0b00110000

            data = list()
            data.append(self.usercount)
            data.append(sum(self.activeusers))
            data.append(sum(self.fixedusers))
            data.append(self.channelaccess)
            self.session._send_ipmi_net_payload(code=returncode, data=data)
            logger.info('IPMI response sent (Get User Access) to %s',
                        self.session.sockaddr)
        elif request['netfn'] == 6 and request['command'] == 0x46:
            # get user name
            userid = request['data'][0]
            returncode = 0
            username = list(self.authdata.keys())[userid - 1]
            data = list(username)
            while len(data) < 16:
                # filler
                data.append(0)
            self.session._send_ipmi_net_payload(code=returncode, data=data)
            logger.info('IPMI response sent (Get User Name) to %s',
                        self.session.sockaddr)
        elif request['netfn'] == 6 and request['command'] == 0x45:
            # set user name
            # TODO: fix issue where users can be overwritten
            # python does not support dictionary with duplicate keys
            userid = request['data'][0]
            username = ''.join(chr(x)
                               for x in request['data'][1:]).strip(b'\x00')
            oldname = list(self.authdata.keys())[userid - 1]
            # need to recreate dictionary to preserve order
            self.copyauth = collections.OrderedDict()
            self.copypriv = collections.OrderedDict()
            self.copychannel = collections.OrderedDict()
            index = 0
            for k, v in self.authdata.iteritems():
                if index == userid - 1:
                    self.copyauth.update({username: self.authdata[oldname]})
                    self.copypriv.update({username: self.privdata[oldname]})
                    self.copychannel.update(
                        {username: self.channelaccessdata[oldname]})
                else:
                    self.copyauth.update({k: v})
                    self.copypriv.update({k: self.privdata[k]})
                    self.copychannel.update({k: self.channelaccessdata[k]})
                index += 1
            self.authdata = self.copyauth
            self.privdata = self.copypriv
            self.channelaccessdata = self.copychannel

            returncode = 0
            self.session._send_ipmi_net_payload(code=returncode)
            logger.info('IPMI response sent (Set User Name) to %s',
                        self.session.sockaddr)
        elif request['netfn'] == 6 and request['command'] == 0x47:
            # set user passwd
            passwd_length = request['data'][0] & 0b10000000
            userid = request['data'][0] & 0b00111111
            username = list(self.authdata.keys())[userid - 1]
            operation = request['data'][1] & 0b00000011
            returncode = 0

            if passwd_length:
                # 20 byte
                passwd = ''.join(chr(x) for x in request['data'][2:22])
            else:
                # 16 byte
                passwd = ''.join(chr(x) for x in request['data'][2:18])
            if operation == 0:
                # disable user
                if self.activeusers[list(
                        self.authdata.keys()).index(username)]:
                    self.activeusers[list(
                        self.authdata.keys()).index(username)] = 0
            elif operation == 1:
                # enable user
                if not self.activeusers[list(
                        self.authdata.keys()).index(username)]:
                    self.activeusers[list(
                        self.authdata.keys()).index(username)] = 1
            elif operation == 2:
                # set passwd
                if len(passwd) not in [16, 20]:
                    returncode = 0x81
                self.authdata[username] = passwd.strip(b'\x00')
            else:
                # test passwd
                if len(passwd) not in [16, 20]:
                    returncode = 0x81
                if self.authdata[username] != passwd.strip(b'\x00'):
                    returncode = 0x80

            self.session._send_ipmi_net_payload(code=returncode)
            logger.info('IPMI response sent (Set User Password) to %s',
                        self.session.sockaddr)
        elif request['netfn'] in [0, 6] and request['command'] in [1, 2, 8, 9]:
            self.bmc.handle_raw_request(request, self.session)
        else:
            returncode = 0xc1
            self.session._send_ipmi_net_payload(code=returncode)
            logger.info('IPMI unrecognized command from %s',
                        self.session.sockaddr)
            logger.info('IPMI response sent (Invalid Command) to %s',
                        self.session.sockaddr)

    def start(self, host, port):
        connection = (host, port)
        self.port = port
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.setblocking(True)
        self.sock.bind(connection)
        self.server = DatagramServer(self.sock, self.handle)
        self.server.start()
        logger.info('IPMI server started on: %s',
                    (host, self.server.server_port))
        self.server.serve_forever()

    def stop(self):
        self.server.stop()
コード例 #8
0
ファイル: tftp_server.py プロジェクト: renwinping/conpot
class TftpServer(object):
    """TFTP Server"""

    TIMEOUT_RETRIES = 5

    def __init__(self, template, template_directory, args, timeout=5):
        self.timeout = float(timeout)
        self.server = None  # server attr - Initialize in start
        self.root = None
        self.listener = None  # listener socket
        # A dict of sessions, where each session is keyed by a string like
        # ip:tid for the remote end.
        self.sessions = {}
        # A threading event to help threads synchronize with the server is_running state.
        self.is_running = gevent.event.Event()

        self.shutdown = False
        self._init_vfs(template)
        logger.debug("TFTP server initialized.")

    def _init_vfs(self, template):
        dom = etree.parse(template)
        self.root_path = dom.xpath("//tftp/tftp_root_path/text()")[0].lower()
        if len(dom.xpath("//tftp/add_src/text()")) == 0:
            self.add_src = None
        else:
            self.add_src = dom.xpath("//tftp/add_src/text()")[0].lower()
        self.data_fs_subdir = dom.xpath(
            "//tftp/data_fs_subdir/text()")[0].lower()
        # Create a file system.
        self.vfs, self.data_fs = conpot_core.add_protocol(
            protocol_name="tftp",
            data_fs_subdir=self.data_fs_subdir,
            vfs_dst_path=self.root_path,
            src_path=self.add_src,
        )
        if self.add_src:
            logger.info(
                "TFTP Serving File System from {} at {} in vfs. TFTP data_fs sub directory: {}"
                .format(self.add_src, self.root_path, self.data_fs._sub_dir))
        else:
            logger.info(
                "TFTP Serving File System at {} in vfs. TFTP data_fs sub directory: {}"
                .format(self.root_path, self.data_fs._sub_dir))
        logger.debug("TFTP serving list of files : {}".format(", ".join(
            self.vfs.listdir("."))))
        self.root = "/"  # Setup root dir.
        # check for permissions etc.
        logger.debug("TFTP root {} is a directory".format(self.vfs.getcwd() +
                                                          self.root))
        if self.vfs.access(self.root, 0, os.R_OK):
            logger.debug("TFTP root {} is readable".format(self.vfs.getcwd() +
                                                           self.root))
        else:
            raise TftpException("The TFTP root must be readable")
        if self.vfs.access(self.root, 0, os.W_OK):
            logger.debug("TFTP root {} is writable".format(self.vfs.getcwd() +
                                                           self.root))
        else:
            logger.warning(
                "The TFTP root {} is not writable".format(self.vfs.getcwd() +
                                                          self.root))

    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

    def start(self, host, port):
        conn = (host, port)
        # FIXME - sockets should be non-blocking
        self.listener = gevent.socket.socket(gevent.socket.AF_INET,
                                             gevent.socket.SOCK_DGRAM)
        self.listener.bind(conn)
        self.listener.settimeout(self.timeout)
        self.server = DatagramServer(self.listener, self.handle)
        logger.info("Starting TFTP server at {}".format(conn))
        self.server.serve_forever()

    def stop(self):
        self.server.close()
コード例 #9
0
ファイル: bjdns.py プロジェクト: bieberg0n/bjdns
def main():
	global server, cache, cdn_list, ad
	global dns_cn_addr, dns_foreign_addr

	cdn_list = { x:True for x in open('cdnlist.txt','r').read().split('\n') if x}

	# google = { x:True for x in open('bjdns/google.txt','r').read().split('\n') if x}
	ad = { x:True for x in open('ad.txt','r').read().split('\n') if x} if os.path.isfile('ad.txt') else {}

	if len(sys.argv) >= 2:
		json_dir = sys.argv[1]
	else:
		json_dir = 'bjdns.json'
	json_str = open(json_dir).read()
	json_dict = json.loads(json_str)
	ss_ip, ss_port = json_dict['socks5_server'].split(':')
	listen_addr = (json_dict['listen_ip'], json_dict['listen_port'])
	dns_cn_addr = (json_dict['dns_cn_ip'], json_dict['dns_cn_port'])
	dns_foreign_addr = (json_dict['dns_foreign_ip'], json_dict['dns_foreign_port'])
	geventsocks.set_default_proxy(ss_ip, int(ss_port))

	if os.name == 'nt':
		# adem()
		# exit()

		import threading
		from tkinter import Tk, Menu#,messagebox

		def adem_thread(s):
			while 1:
				try:
					data, client = s.recvfrom(512)
					threading.Thread(target=eva,args=(data, client,)).start()
				except ConnectionResetError:
					pass

		def menu_func(event, x, y):
			if event == 'WM_RBUTTONDOWN':	# Right click tray icon, pop up menu
				menu.tk_popup(x, y)


		def quit():
			root.quit()
			root.destroy()
			sys.exit()
				
		s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
		s.bind( listen_addr )

		root = Tk()
		root.tk.call('package', 'require', 'Winico')
		icon = root.tk.call('winico', 'createfrom', os.path.join(os.getcwd(), 'py.ico'))	# New icon resources
		root.tk.call('winico', 'taskbar', 'add', icon,
					 '-callback', (root.register(menu_func), '%m', '%x', '%y'),
					 '-pos',0,
					 '-text','bjdns')
		menu = Menu(root, tearoff=0)
		menu.add_command(label='退出', command=quit)

		root.withdraw()
		t = threading.Thread(target=adem_thread, args=(s,))
		t.setDaemon(True)
		t.start()
		root.mainloop()

	else:
		server = DatagramServer(listen_addr, eva)
		server.serve_forever()
コード例 #10
0
from multiprocessing import Process
import time

l = []


def deadloop(addr):
    l.append(addr)
    st = time.time()
    while True:
        time.sleep(0.0001)
        cur = time.time()
        if cur - st >= 5:
            break
    l.remove(addr)


def reply(req, addr):
    serv.sendto('1'.encode(), addr)
    if addr not in l:
        Process(target=deadloop, args=(addr, )).start()


print('start...')
serv = DatagramServer(('0.0.0.0', 2323), reply)
serv.serve_forever()
# import socket
# s = socket.socket(2,2)
# s.bind(('0.0.0.0', 2323))
# print( s.recvfrom(16) )
コード例 #11
0
ファイル: bjdns2_client.py プロジェクト: zhezhe168/bjdns
class Bjdns2:
    def __init__(self, listen, bjdns2_url):
        self.cache = Cache()

        ip, port_str = listen.split(':')
        self.server = DatagramServer((ip, int(port_str)), self.handle)
        self.session = requests.Session()

        url = urlparse(bjdns2_url).netloc
        self.bjdns2_host = url[:url.rfind(':')]
        # self.bjdns2_ip = bjdns2_ip

    def query_by_https(self, host, cli_ip):
        url_template = bjdns2_url + '/?dn={}&ip={}'

        # if host == self.bjdns2_host:
        #     return self.bjdns2_ip, 3600

        # else:
        if is_private_ip(cli_ip):
            url = url_template.format(host, '')
        else:
            url = url_template.format(host, cli_ip)

        r = self.session.get(url)
        result = json.loads(r.text)
        if result['Status'] == 0:
            self.cache.write(cli_ip, result['Question'][0], result, None)
            ip, ttl = resp_from_json(result)
            return ip, ttl
        else:
            return '', 0

    def query(self, data, host, q_type, cli_addr) -> bytes:
        src_ip, _ = cli_addr
        question = dict(name=host, type=q_type)
        cache_resp = self.cache.select(src_ip, question)

        if cache_resp:
            if host == self.bjdns2_host or q_type != 1:
                resp = data[:2] + cache_resp
                log(cli_addr, '[cache]', '[Type:{}]'.format(q_type), host)
            else:
                ip, ttl = resp_from_json(cache_resp)
                log(cli_addr, '[cache]', host, ip, '(ttl:{})'.format(ttl))
                resp = make_data(data, ip, ttl)

        else:
            if host == self.bjdns2_host or q_type != 1:
                resp = query_by_udp(data)
                self.cache.write(src_ip, question, None, resp[2:])
                log(cli_addr, '[Type:{}]'.format(q_type), host)

            else:
                ip, ttl = self.query_by_https(host, src_ip)
                log(cli_addr, host, ip, '(ttl:{})'.format(ttl))
                resp = make_data(data, ip, ttl)

        # if ip:
        # log(data, resp)
        return resp
        # else:
        #     return b''

    def handle(self, data, cli_addr):
        host, q_type = parse_query(data)

        # if host == self.bjdns2_host or type != 1:
        #     log(host, type)
        #     resp = query_by_udp(data)
        #     log(cli_addr, '[Type:{}]'.format(type), host)

        # elif type == 1:
        try:
            resp = self.query(data, host, q_type, cli_addr)
        except Exception as e:
            log(e)
            resp = b''

        self.server.sendto(resp, cli_addr)

    def start(self):
        self.server.serve_forever()
コード例 #12
0
ファイル: bjdns.py プロジェクト: mwylaoma/bjdns
def main():
    global server, google_ip, cache, cdn_list, google, ad
    global dns_cn_addr, dns_foreign_addr

    cdn_list = {
        x: True
        for x in open('bjdns/cdnlist.txt', 'r').read().split('\n') if x
    }

    google = {
        x: True
        for x in open('bjdns/google.txt', 'r').read().split('\n') if x
    }
    ad = {x: True
          for x in open('bjdns/ad.txt', 'r').read().split('\n')
          if x} if os.path.isfile('ad.txt') else {}

    if len(sys.argv) >= 2:
        json_dir = sys.argv[1]
    else:
        json_dir = 'bjdns/bjdns.json'
    json_str = open(json_dir).read()
    json_dict = json.loads(json_str)
    ss_ip, ss_port = json_dict['socks5_server'].split(':')
    listen_addr = (json_dict['listen_ip'], json_dict['listen_port'])
    dns_cn_addr = (json_dict['dns_cn_ip'], json_dict['dns_cn_port'])
    dns_foreign_addr = (json_dict['dns_foreign_ip'],
                        json_dict['dns_foreign_port'])
    geventsocks.set_default_proxy(ss_ip, int(ss_port))

    if os.name == 'nt':
        # adem()
        # exit()

        import threading
        from tkinter import Tk, Menu  #,messagebox

        def adem_thread(s):
            while 1:
                try:
                    data, client = s.recvfrom(512)
                    threading.Thread(target=eva, args=(
                        data,
                        client,
                    )).start()
                except ConnectionResetError:
                    pass

        def menu_func(event, x, y):
            if event == 'WM_RBUTTONDOWN':  # Right click tray icon, pop up menu
                menu.tk_popup(x, y)

        def quit():
            root.quit()
            root.destroy()
            sys.exit()

        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.bind(listen_addr)

        root = Tk()
        root.tk.call('package', 'require', 'Winico')
        icon = root.tk.call('winico', 'createfrom',
                            os.path.join(os.getcwd(),
                                         'py.ico'))  # New icon resources
        root.tk.call('winico', 'taskbar', 'add', icon, '-callback',
                     (root.register(menu_func), '%m', '%x', '%y'), '-pos', 0,
                     '-text', 'bjdns')
        menu = Menu(root, tearoff=0)
        menu.add_command(label='退出', command=quit)

        root.withdraw()
        t = threading.Thread(target=adem_thread, args=(s, ))
        t.setDaemon(True)
        t.start()
        root.mainloop()

    else:
        server = DatagramServer(listen_addr, eva)
        server.serve_forever()
コード例 #13
0
ファイル: protocol.py プロジェクト: xandfury/pygftlib
class Receiver(object):
    """
    - Start the UDP server on a host and port. Check for permissions to write on the CWD
    - Accept an incoming connection. Check if the packet is INITRQ type else discard the packet.
    - Send the ACK with block_no 0. Wait to receive DATA packet
    - Verify DATA has block_no == ACK block_no + 1
        - If yes, write to file. Else discard packet with appropriate error code  <No error codes at the moment>
        - Send ACK with block_no += 1
    - repeat till transfer_complete. size(DATA) < or != blk_size. Close File pointers
    """

    def __init__(self, timeout=None):
        self.client_state = {}  # a data structure to store block_number etc per respective socket.
        # TODO: check whether appending/insertion to a dictionary would be more efficient for any other DS?
        self.packet_factory = PacketFactory
        self.listener = None
        self.timeout = timeout

    def handle(self, data, address):
        self._clean_up()   # clean-up
        if address not in self.client_state.keys():
            logger.info('New client has connected. Connection from {}:{}'.format(address[0], address[1]))
            # check data is valid INITRQ. If not, no point in continuing!
            if self.packet_factory.check_type('initrq', data) and self.packet_factory.is_valid('initrq', data):
                self.client_state[address] = {
                    'transfer_complete': False,
                    'block_number': 0,
                    'file_obj': None,
                    'file_name': None,
                    'last_active': None,
                    'inactive': (lambda: int(time.time() - self.client_state[address]['last_active']))
                }
                # build_up context - update the last_activity period
                self.client_state[address]['last_active'] = time.time()
                # parse the initrq packet
                # get the filename of the file - store it!
                self.client_state[address]['file_name'] = self.packet_factory.from_bytes(data)
                logger.info('Creating new file with name: {} for client {}'.format(
                    self.client_state[address]['file_name'], address
                ))
                # next create a file_obj to that file.
                self.client_state[address]['file_obj'] = FileWriter(
                    self.client_state[address]['file_name'], DATA_SIZE
                )
                # send ack_packet
                self.send_ack(address)
            else:
                logger.warning('Invalid/Malformed INITRQ packet received from client {}'.format(address))
        else:
            # we have already received some data from this client before!
            # determine type of packet
            if self.packet_factory.check_type('initrq', data):
                # May be client hasn't received an ACK.
                # send the ack again
                self.send_ack(address)
            elif self.packet_factory.check_type('data', data):
                # The packet is DATAPacket. Nice! Parse the contents of the packet
                block_no, content = self.packet_factory.from_bytes(data)
                block_no = int(block_no)  # covert block no to int if it is a str
                # check the block_no on the file. Only write when the block_no on the packet +1 than block_number in
                # client's state
                if self.client_state[address]['block_number'] == (block_no - 1):
                    # Write to file
                    self.client_state[address]['file_obj'].write_chunk(content)
                    # increment block_no
                    self.client_state[address]['block_number'] += 1
                    # client is active
                    self.client_state[address]['last_active'] = time.time ()
                elif self.client_state[address]['block_number'] == block_no:
                    # client must have sent the duplicate DATA packet because it received no ack
                    self.send_ack(address)
                    # Ignore all other cases! -- # FIXME: see if there are corner cases remaining
                # check to see if the size of packet is < MAX_SIZE
                # If it is, gracefully disconnect the client. Close the file etc.
                if len(data) < MAX_PACKET_SIZE:
                    logger.info('File Transfer Complete! Wrote {} to disk'.format(
                        self.client_state[address]['file_obj'].name
                    ))
                    self.disconnect_client(address)
            else:
                logger.info('Received data from client. But Not of a valid packet type')

    def send_ack(self, address):
        # client is active
        self.client_state[address]['last_active'] = time.time()
        temp_block_no = self.client_state[address]['block_number']
        # create a awk packet. send that packet
        temp_packet = self.packet_factory.to_bytes(type='ack', block_no=temp_block_no)
        self.listener.socket.sendto(temp_packet, address)

    def disconnect_client(self, address):
        """
        Strictly speaking there is no defined way of gracefully closing a UDP connection.
        We just set the transfer_complete so that buffer is removed by clean_up function
        :return:
        """
        self.client_state[address]['transfer_complete'] = True

    def _clean_up(self, purge=False):
        """
        Cleanup our buffer --> client_state. Remove the entries if the client is not longer active
        """
        for client in list(self.client_state):
            if purge is False:
                if self.client_state[client]['inactive']() > CONN_TIMEOUT \
                        or self.client_state[client]['transfer_complete']:
                    _ = self.client_state.pop(client, None)
                    logger.info('Removing client {} context. Either transfer has completed or client has been inactive '
                                'for over {} seconds'.format(client, CONN_TIMEOUT))
            else:
                _ = self.client_state.pop(client, None)
                logger.info('Forcefully purging client {}'.format(client))

    def start(self, host, port):
        conn = (host, port)
        sock = gevent.socket.socket(gevent.socket.AF_INET, gevent.socket.SOCK_DGRAM)
        sock.settimeout(self.timeout)
        sock.bind(conn)
        self.listener = DatagramServer(sock, self.handle)
        try:
            self.listener.serve_forever()
        except PYGFTError:
            # FIXME: proper exception handling
            logger.exception('Unable to parse contents, create file for INITRQ')
        except socket.timeout:
            pass
        except socket.error:
            pass
        except KeyboardInterrupt:
            logger.exception('Received Keyboard Interrupt. Server would gracefully shutdown')
            self.stop()

    def stop(self):
        """Clean up."""
        # Delete files if transfer not complete?
        # Do anything else?
        self._clean_up(purge=True)
        self.listener.close()
コード例 #14
0
def udp():
    global config
    host = config['udp_server']['host']
    port = config['udp_server']['port']
    udp_server = DatagramServer((host, port), router_handler)
    udp_server.serve_forever()
コード例 #15
0
ファイル: bacnet_server.py プロジェクト: jlthames2/conpot
class BacnetServer(object):
    def __init__(self, template, template_directory, args):
        self.dom = etree.parse(template)
        databus = conpot_core.get_databus()
        device_info_root = self.dom.xpath('//bacnet/device_info')[0]

        name_key = databus.get_value(device_info_root.xpath('./device_name/text()')[0])
        id_key = device_info_root.xpath('./device_identifier/text()')[0]
        vendor_name_key = device_info_root.xpath('./vendor_name/text()')[0]
        vendor_identifier_key = device_info_root.xpath(
            './vendor_identifier/text()')[0]
        apdu_length_key = device_info_root.xpath(
            './max_apdu_length_accepted/text()')[0]
        segmentation_key = device_info_root.xpath(
            './segmentation_supported/text()')[0]

        # self.local_device_address = dom.xpath('./@*[name()="host" or name()="port"]')

        self.thisDevice = LocalDeviceObject(
            objectName=name_key,
            objectIdentifier=int(id_key),
            maxApduLengthAccepted=int(apdu_length_key),
            segmentationSupported=segmentation_key,
            vendorName=vendor_name_key,
            vendorIdentifier=int(vendor_identifier_key)
        )
        self.bacnet_app = None

        logger.info('Conpot Bacnet initialized using the %s template.', template)

    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)

    def start(self, host, port):
        connection = (host, port)
        self.server = DatagramServer(connection, self.handle)
        # start to init the socket
        self.server.start()
        self.server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)


        # create application instance
        # not too beautifull, but the BACnetApp needs access to the socket's sendto method
        # this could properly be refactored in a way such that sending operates on it's own
        # (non-bound) socket.
        self.bacnet_app = BACnetApp(self.thisDevice, self.server)
        # get object_list and properties
        self.bacnet_app.get_objects_and_properties(self.dom)

        logger.info('Bacnet server started on: %s', connection)
        self.server.serve_forever()

    def stop(self):
        self.server.stop()
コード例 #16
0
ファイル: ipmi_server.py プロジェクト: PASER/conpot
class IpmiServer(object):

    def __init__(self, template, template_directory, args):
        dom = etree.parse(template)
        databus = conpot_core.get_databus()
        self.device_name = databus.get_value(dom.xpath('//ipmi/device_info/device_name/text()')[0])
        self.host = ''
        self.port = 623
        self.sessions = dict()

        self.uuid = uuid.uuid4()
        self.kg = None

        self.authdata = collections.OrderedDict()

        lanchannel = 1
        authtype = 0b10000000
        authstatus = 0b00000100
        chancap = 0b00000010
        oemdata = (0, 0, 0, 0)
        self.authcap = struct.pack('BBBBBBBBB', 0, lanchannel, authtype, authstatus, chancap, *oemdata)

        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.setblocking(1)
        self.sock.bind(('', 623))
        self.bmc = self._configure_users(dom)
        logger.info('Conpot IPMI initialized using %s template', template)

    def _configure_users(self, dom):
        # XML parsing
        authdata_name = dom.xpath('//ipmi/user_list/user/user_name/text()')
        authdata_passwd = dom.xpath('//ipmi/user_list/user/password/text()')
        self.authdata = collections.OrderedDict(zip(authdata_name, authdata_passwd))

        authdata_priv = dom.xpath('//ipmi/user_list/user/privilege/text()')
        if False in map(lambda k: 0 < int(k) <= 4, authdata_priv):
            raise ValueError("Privilege level must be between 1 and 4")
        authdata_priv = [int(k) for k in authdata_priv]
        self.privdata = collections.OrderedDict(zip(authdata_name, authdata_priv))

        activeusers = dom.xpath('//ipmi/user_list/user/active/text()')
        self.activeusers = [1 if x == 'true' else 0 for x in activeusers]

        fixedusers = dom.xpath('//ipmi/user_list/user/fixed/text()')
        self.fixedusers = [1 if x == 'true' else 0 for x in fixedusers]

        self.channelaccessdata = collections.OrderedDict(zip(authdata_name, activeusers))

        return FakeBmc(self.authdata, self.port)

    def _checksum(self, *data):
        csum = sum(data)
        csum ^= 0xff
        csum += 1
        csum &= 0xff
        return csum

    def handle(self, data, address):
        if not address[0] in self.sessions.keys():
            # new session for new source
            logger.info('New IPMI traffic from %s', address)
            self.session = FakeSession(address[0], "", "", address[1])
            self.session.server = self

            self.uuid = uuid.uuid4()
            self.kg = None

            self.session.socket = self.sock
            self.sessions[address[0]] = self.session
            self.initiate_session(data, address, self.session)
        else:
            # session already exists
            logger.info('Incoming IPMI traffic from %s', address)
            if self.session.stage == 0:
                self.close_server_session()
            else:
                self._got_request(data, address, self.session)

    def initiate_session(self, data, address, session):
        if len(data) < 22:
            self.ipmiserver.close_server_session()
            return
        if not (data[0] == '\x06' and data[2:4] == '\xff\x07'):
            # check rmcp version, sequencenumber and class;
            self.close_server_session()
            return
        if data[4] == '\x06':
            # ipmi v2
            session.ipmiversion = 2.0
            session.authtype = 6
            payload_type = data[5]
            if payload_type not in ('\x00', '\x10'):
                self.close_server_session()
                return
            if payload_type == '\x10':
                # new session to handle conversation
                serversession.ServerSession(self.authdata, self.kg, session.sockaddr,
                                            self.sock, data[16:], self.uuid, bmc=self)
                return
            data = data[13:]
        myaddr, netfnlun = struct.unpack('2B', data[14:16])
        netfn = (netfnlun & 0b11111100) >> 2
        mylun = netfnlun & 0b11
        if netfn == 6:
            # application request
            if data[19] == '\x38':
                # cmd = get channel auth capabilities
                verchannel, level = struct.unpack('2B', data[20:22])
                version = verchannel & 0b10000000
                if version != 0b10000000:
                    self.close_server_session()
                    return
                channel = verchannel & 0b1111
                if channel != 0xe:
                    self.close_server_session()
                    return
                (clientaddr, clientlun) = struct.unpack('BB', data[17:19])
                level &= 0b1111
                self.send_auth_cap(myaddr, mylun, clientaddr, clientlun, session.sockaddr)

    def send_auth_cap(self, myaddr, mylun, clientaddr, clientlun, sockaddr):
        header = '\x06\x00\xff\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10'

        headerdata = (clientaddr, clientlun | (7 << 2))
        headersum = self._checksum(*headerdata)
        header += struct.pack('BBBBBB', *(headerdata + (headersum, myaddr, mylun, 0x38)))
        header += self.authcap
        bodydata = struct.unpack('B' * len(header[17:]), header[17:])
        header += chr(self._checksum(*bodydata))
        self.session.stage += 1
        logger.info('Connection established with %s', sockaddr)
        self.session.send_data(header, sockaddr)

    def close_server_session(self):
        logger.info('IPMI Session closed %s', self.session.sessionid)
        # cleanup session
        del self.sessions[self.session.sockaddr[0]]
        del self.session

        pass

    def _got_request(self, data, address, session):
        if data[4] in ('\x00', '\x02'):
            # ipmi 1.5 payload
            session.ipmiversion = 1.5
            remsequencenumber = struct.unpack('<I', data[5:9])[0]
            if hasattr(session, 'remsequencenumber') and remsequencenumber < session.remsequencenumber:
                self.close_server_session()
                return
            session.remsequencenumber = remsequencenumber
            if ord(data[4]) != session.authtype:
                self.close_server_session()
                return
            remsessid = struct.unpack("<I", data[9:13])[0]
            if remsessid != session.sessionid:
                self.close_server_session()
                return
            rsp = list(struct.unpack("!%dB" % len(data), data))
            authcode = False
            if data[4] == '\x02':
                # authcode in ipmi 1.5 packet
                authcode = data[13:29]
                del rsp[13:29]
            payload = list(rsp[14:14 + rsp[13]])
            if authcode:
                expectedauthcode = session._ipmi15authcode(payload, checkremotecode=True)
                expectedauthcode = struct.pack("%dB" % len(expectedauthcode), *expectedauthcode)
                if expectedauthcode != authcode:
                    self.close_server_session()
                    return
            session._ipmi15(payload)
        elif data[4] == '\x06':
            # ipmi 2.0 payload
            session.ipmiversion = 2.0
            session.authtype = 6
            session._ipmi20(data)
        else:
            # unrecognized data
            self.close_server_session()
            return

    def _got_rmcp_openrequest(self, data):
        request = struct.pack('B' * len(data), *data)
        clienttag = ord(request[0])
        self.clientsessionid = list(struct.unpack('4B', request[4:8]))
        self.managedsessionid = list(struct.unpack('4B', os.urandom(4)))
        self.session.privlevel = 4
        response = ([clienttag, 0, self.session.privlevel, 0] +
                    self.clientsessionid + self.managedsessionid +
                    [
                        0, 0, 0, 8, 1, 0, 0, 0,  # auth
                        1, 0, 0, 8, 1, 0, 0, 0,  # integrity
                        2, 0, 0, 8, 1, 0, 0, 0,  # privacy
        ])
        logger.info('IPMI open session request')
        self.session.send_payload(response, constants.payload_types['rmcpplusopenresponse'], retry=False)

    def _got_rakp1(self, data):
        clienttag = data[0]
        self.Rm = data[8:24]
        self.rolem = data[24]
        self.maxpriv = self.rolem & 0b111
        namepresent = data[27]
        if namepresent == 0:
            self.close_server_session()
            return
        usernamebytes = data[28:]
        self.username = struct.pack('%dB' % len(usernamebytes), *usernamebytes)
        if self.username not in self.authdata:
            self.close_server_session()
            return
        uuidbytes = self.uuid.bytes
        uuidbytes = list(struct.unpack('%dB' % len(uuidbytes), uuidbytes))
        self.uuiddata = uuidbytes
        self.Rc = list(struct.unpack('16B', os.urandom(16)))
        hmacdata = (self.clientsessionid + self.managedsessionid + self.Rm + self.Rc + uuidbytes +
                    [self.rolem, len(self.username)])
        hmacdata = struct.pack('%dB' % len(hmacdata), *hmacdata)
        hmacdata += self.username
        self.kuid = self.authdata[self.username]
        if self.kg is None:
            self.kg = self.kuid
        authcode = hmac.new(self.kuid, hmacdata, hashlib.sha1).digest()
        authcode = list(struct.unpack('%dB' % len(authcode), authcode))
        newmessage = ([clienttag, 0, 0, 0] + self.clientsessionid + self.Rc + uuidbytes + authcode)
        logger.info('IPMI rakp1 request')
        self.session.send_payload(newmessage, constants.payload_types['rakp2'], retry=False)

    def _got_rakp3(self, data):
        RmRc = struct.pack('B' * len(self.Rm + self.Rc), *(self.Rm + self.Rc))
        self.sik = hmac.new(self.kg, RmRc + struct.pack("2B", self.rolem, len(self.username)) +
                            self.username, hashlib.sha1).digest()
        self.session.k1 = hmac.new(self.sik, '\x01' * 20, hashlib.sha1).digest()
        self.session.k2 = hmac.new(self.sik, '\x02' * 20, hashlib.sha1).digest()
        self.session.aeskey = self.session.k2[0:16]

        hmacdata = struct.pack('B' * len(self.Rc), *self.Rc) + struct.pack("4B", *self.clientsessionid) +\
            struct.pack("2B", self.rolem, len(self.username)) + self.username
        expectedauthcode = hmac.new(self.kuid, hmacdata, hashlib.sha1).digest()
        authcode = struct.pack("%dB" % len(data[8:]), *data[8:])
        if expectedauthcode != authcode:
            self.close_server_session()
            return
        clienttag = data[0]
        if data[1] != 0:
            self.close_server_session()
            return
        self.session.localsid = struct.unpack('<I', struct.pack('4B', *self.managedsessionid))[0]

        logger.info('IPMI rakp3 request')
        self.session.ipmicallback = self.handle_client_request
        self._send_rakp4(clienttag, 0)

    def _send_rakp4(self, tagvalue, statuscode):
        payload = [tagvalue, statuscode, 0, 0] + self.clientsessionid
        hmacdata = self.Rm + self.managedsessionid + self.uuiddata
        hmacdata = struct.pack('%dB' % len(hmacdata), *hmacdata)
        authdata = hmac.new(self.sik, hmacdata, hashlib.sha1).digest()[:12]
        payload += struct.unpack('%dB' % len(authdata), authdata)
        logger.info('IPMI rakp4 sent')
        self.session.send_payload(payload, constants.payload_types['rakp4'], retry=False)
        self.session.confalgo = 'aes'
        self.session.integrityalgo = 'sha1'
        self.session.sessionid = struct.unpack('<I', struct.pack('4B', *self.clientsessionid))[0]

    def handle_client_request(self, request):
        if request['netfn'] == 6 and request['command'] == 0x3b:
            # set session privilage level
            pendingpriv = request['data'][0]
            returncode = 0
            if pendingpriv > 1:
                if pendingpriv > self.maxpriv:
                    returncode = 0x81
                else:
                    self.clientpriv = request['data'][0]
            self.session._send_ipmi_net_payload(code=returncode, data=[self.clientpriv])
            logger.info('IPMI response sent (Set Session Privilege) to %s', self.session.sockaddr)
        elif request['netfn'] == 6 and request['command'] == 0x3c:
            # close session
            self.session.send_ipmi_response()
            logger.info('IPMI response sent (Close Session) to %s', self.session.sockaddr)
            self.close_server_session()
        elif request['netfn'] == 6 and request['command'] == 0x44:
            # get user access
            reschan = request['data'][0]
            channel = reschan & 0b00001111
            resuid = request['data'][1]
            usid = resuid & 0b00011111
            if self.clientpriv > self.maxpriv:
                returncode = 0xd4
            else:
                returncode = 0
            self.usercount = len(self.authdata.keys())
            self.channelaccess = 0b0000000 | self.privdata[self.authdata.keys()[usid - 1]]
            if self.channelaccessdata[self.authdata.keys()[usid - 1]] == 'true':
                # channelaccess: 7=res; 6=callin; 5=link; 4=messaging; 3-0=privilege
                self.channelaccess |= 0b00110000

            data = list()
            data.append(self.usercount)
            data.append(sum(self.activeusers))
            data.append(sum(self.fixedusers))
            data.append(self.channelaccess)
            self.session._send_ipmi_net_payload(code=returncode, data=data)
            logger.info('IPMI response sent (Get User Access) to %s', self.session.sockaddr)
        elif request['netfn'] == 6 and request['command'] == 0x46:
            # get user name
            userid = request['data'][0]
            returncode = 0
            username = self.authdata.keys()[userid - 1]
            data = map(ord, list(username))
            while len(data) < 16:
                # filler
                data.append(0)
            self.session._send_ipmi_net_payload(code=returncode, data=data)
            logger.info('IPMI response sent (Get User Name) to %s', self.session.sockaddr)
        elif request['netfn'] == 6 and request['command'] == 0x45:
            # set user name
            # TODO: fix issue where users can be overwritten
            # python does not support dictionary with duplicate keys
            userid = request['data'][0]
            username = ''.join(chr(x) for x in request['data'][1:]).strip('\x00')
            oldname = self.authdata.keys()[userid - 1]
            # need to recreate dictionary to preserve order
            self.copyauth = collections.OrderedDict()
            self.copypriv = collections.OrderedDict()
            self.copychannel = collections.OrderedDict()
            index = 0
            for k, v in self.authdata.iteritems():
                if index == userid - 1:
                    self.copyauth.update({username: self.authdata[oldname]})
                    self.copypriv.update({username: self.privdata[oldname]})
                    self.copychannel.update({username: self.channelaccessdata[oldname]})
                else:
                    self.copyauth.update({k: v})
                    self.copypriv.update({k: self.privdata[k]})
                    self.copychannel.update({k: self.channelaccessdata[k]})
                index += 1
            self.authdata = self.copyauth
            self.privdata = self.copypriv
            self.channelaccessdata = self.copychannel

            returncode = 0
            self.session._send_ipmi_net_payload(code=returncode)
            logger.info('IPMI response sent (Set User Name) to %s', self.session.sockaddr)
        elif request['netfn'] == 6 and request['command'] == 0x47:
            # set user passwd
            passwd_length = request['data'][0] & 0b10000000
            userid = request['data'][0] & 0b00111111
            username = self.authdata.keys()[userid - 1]
            operation = request['data'][1] & 0b00000011
            returncode = 0

            if passwd_length:
                # 20 byte
                passwd = ''.join(chr(x) for x in request['data'][2:22])
            else:
                # 16 byte
                passwd = ''.join(chr(x) for x in request['data'][2:18])
            if operation == 0:
                # disable user
                if self.activeusers[self.authdata.keys().index(username)]:
                    self.activeusers[self.authdata.keys().index(username)] = 0
            elif operation == 1:
                # enable user
                if not self.activeusers[self.authdata.keys().index(username)]:
                    self.activeusers[self.authdata.keys().index(username)] = 1
            elif operation == 2:
                # set passwd
                if len(passwd) not in [16, 20]:
                    returncode = 0x81
                self.authdata[username] = passwd.strip('\x00')
            else:
                # test passwd
                if len(passwd) not in [16, 20]:
                    returncode = 0x81
                if self.authdata[username] != passwd.strip('\x00'):
                    returncode = 0x80

            self.session._send_ipmi_net_payload(code=returncode)
            logger.info('IPMI response sent (Set User Password) to %s', self.session.sockaddr)
        elif request['netfn'] in [0, 6] and request['command'] in [1, 2, 8, 9]:
            self.bmc.handle_raw_request(request, self.session)
        else:
            returncode = 0xc1
            self.session._send_ipmi_net_payload(code=returncode)
            logger.info('IPMI unrecognized command from %s', self.session.sockaddr)
            logger.info('IPMI response sent (Invalid Command) to %s', self.session.sockaddr)

    def start(self, host, port):
        connection = (host, port)
        self.server = DatagramServer(connection, self.handle)
        logger.info('IPMI server started on: %s', connection)
        self.server.serve_forever()

    def stop(self):
        self.server.stop()
コード例 #17
0
ファイル: tftp_server.py プロジェクト: agnivesh/conpot
class TftpServer(object):
    """TFTP Server"""
    TIMEOUT_RETRIES = 5

    def __init__(self, template, template_directory, args, timeout=5):
        self.timeout = float(timeout)
        self.server = None   # server attr - Initialize in start
        self.root = None
        self.listener = None   # listener socket
        # A dict of sessions, where each session is keyed by a string like
        # ip:tid for the remote end.
        self.sessions = {}
        # A threading event to help threads synchronize with the server is_running state.
        self.is_running = gevent.event.Event()

        self.shutdown = False
        self._init_vfs(template)
        logger.debug('TFTP server initialized.')

    def _init_vfs(self, template):
        dom = etree.parse(template)
        self.root_path = dom.xpath('//tftp/tftp_root_path/text()')[0].lower()
        if len(dom.xpath('//tftp/add_src/text()')) == 0:
            self.add_src = None
        else:
            self.add_src = dom.xpath('//tftp/add_src/text()')[0].lower()
        self.data_fs_subdir = dom.xpath('//tftp/data_fs_subdir/text()')[0].lower()
        # Create a file system.
        self.vfs, self.data_fs = conpot_core.add_protocol(protocol_name='tftp',
                                                          data_fs_subdir=self.data_fs_subdir,
                                                          vfs_dst_path=self.root_path,
                                                          src_path=self.add_src)
        if self.add_src:
            logger.info('TFTP Serving File System from {} at {} in vfs. TFTP data_fs sub directory: {}'.format(
                self.add_src, self.root_path, self.data_fs._sub_dir
            ))
        else:
            logger.info('TFTP Serving File System at {} in vfs. TFTP data_fs sub directory: {}'.format(
                self.root_path, self.data_fs._sub_dir
            ))
        logger.debug('TFTP serving list of files : {}'.format(', '.join(self.vfs.listdir('.'))))
        self.root = '/'  # Setup root dir.
        # check for permissions etc.
        logger.debug("TFTP root {} is a directory".format(self.vfs.getcwd() + self.root))
        if self.vfs.access(self.root, 0, os.R_OK):
            logger.debug("TFTP root {} is readable".format(self.vfs.getcwd() + self.root))
        else:
            raise TftpException("The TFTP root must be readable")
        if self.vfs.access(self.root, 0, os.W_OK):
            logger.debug("TFTP root {} is writable".format(self.vfs.getcwd() + self.root))
        else:
            logger.warning("The TFTP root {} is not writable".format(self.vfs.getcwd() + self.root))

    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

    def start(self, host, port):
        conn = (host, port)
        # FIXME - sockets should be non-blocking
        self.listener = gevent.socket.socket(gevent.socket.AF_INET, gevent.socket.SOCK_DGRAM)
        self.listener.bind(conn)
        self.listener.settimeout(self.timeout)
        self.server = DatagramServer(self.listener, self.handle)
        logger.info('Starting TFTP server at {}'.format(conn))
        self.server.serve_forever()

    def stop(self):
        self.server.close()