def test_request_get_register(self):
        # requesting register 1033
        request_bytes = (0x80, 0x3F, 0x10, 0x01, 0x04, 0x09, 0x18, 0x6D, 0x0D)
        for i in range(0, len(request_bytes)):
            self.request_parser.add_byte(chr(request_bytes[i]))
            if i < len(request_bytes) - 1:
                # parser returns None until it can put together an entire message
                self.assertEqual(self.request_parser.get_request(), None)

        parsed_request = self.request_parser.get_request()
        response = self.command_responder.respond(parsed_request)

        self.assertEqual(len(response.registers), 1)
        self.assertEqual(response.registers[0].name, 1033)
        # we should have no left overs
        self.assertEqual(len(self.request_parser.bytes), 0)

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(("127.0.0.1", self.kamstrup_management_server.server.server_port))
        s.sendall(
            chr_py3(0x80)
            + chr_py3(0x3F)
            + chr_py3(0x10)
            + chr_py3(0x01)
            + chr_py3(0x04)
            + chr_py3(0x09)
            + chr_py3(0x18)
            + chr_py3(0x6D)
            + chr_py3(0x0D)
        )
        data = s.recv(1024)
        s.close()
        # FIXME: verify bytes received from server - ask jkv?
        pkt = [hex(data[i]) for i in range(len(data))]
        self.assertTrue(("0x40" in pkt) and ("0x3f" in pkt) and ("0xd" in pkt))
示例#2
0
 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 test_request_get_register(self):
        # requesting register 1033
        request_bytes = (0x80, 0x3f, 0x10, 0x01, 0x04, 0x09, 0x18, 0x6d, 0x0d)
        for i in range(0, len(request_bytes)):
            self.request_parser.add_byte(chr(request_bytes[i]))
            if i < len(request_bytes) - 1:
                # parser returns None until it can put together an entire message
                self.assertEqual(self.request_parser.get_request(), None)

        parsed_request = self.request_parser.get_request()
        response = self.command_responder.respond(parsed_request)

        self.assertEqual(len(response.registers), 1)
        self.assertEqual(response.registers[0].name, 1033)
        # we should have no left overs
        self.assertEqual(len(self.request_parser.bytes), 0)

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(('127.0.0.1', self.kamstrup_management_server.server.server_port))
        s.sendall(chr_py3(0x80) + chr_py3(0x3f) + chr_py3(0x10) + chr_py3(0x01) + chr_py3(0x04) + chr_py3(0x09)
                  + chr_py3(0x18) + chr_py3(0x6d) + chr_py3(0x0d))
        data = s.recv(1024)
        s.close()
        # FIXME: verify bytes received from server - ask jkv?
        pkt = [hex(data[i]) for i in range(len(data))]
        self.assertTrue(('0x40' in pkt) and ('0x3f' in pkt) and ('0xd' in pkt))
示例#4
0
 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
示例#5
0
    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)
示例#6
0
    def handle(self, sock, address):
        session = conpot_core.get_session('kamstrup_protocol', address[0], address[1], sock.getsockname()[0], sock.getsockname()[1])
        logger.info('New Kamstrup connection from %s:%s. (%s)', address[0], address[1], session.id)
        session.add_event({'type': 'NEW_CONNECTION'})

        self.server_active = True

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

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

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

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

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

        sock.close()
示例#7
0
 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 serialize(self, message):
        final_message = list()

        # prefix message
        final_message.append(kamstrup_constants.RESPONSE_MAGIC)
        final_message.append(self.communication_address)

        # add the original content
        for c in message:
            final_message.append(c)

        # generate and append checksum
        crc = crc16.crc16xmodem(b''.join([chr_py3(item) for item in final_message[1:]]))
        final_message.append(crc >> 8)
        final_message.append(crc & 0xff)

        # trailing magic
        final_message.append(kamstrup_constants.EOT_MAGIC)

        escaped_message = self.escape(final_message)
        return escaped_message
示例#9
0
 def valid_crc(cls, message):
     supplied_crc = message[-2] * 256 + message[-1]
     calculated_crc = crc16.crc16xmodem(
         b"".join([chr_py3(item) for item in message[:-2]])
     )
     return supplied_crc == calculated_crc
示例#10
0
 def valid_crc(cls, message):
     supplied_crc = message[-2] * 256 + message[-1]
     calculated_crc = crc16.crc16xmodem(b''.join([chr_py3(item) for item in message[:-2]]))
     return supplied_crc == calculated_crc