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
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")
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()
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, ))
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()
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()
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()
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()
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()
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) )
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()
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()
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()
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()
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()
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()
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()