Browse Source

Fix payload modification problem

aidmar.wainakh 6 years ago
parent
commit
6d244bd7ea
1 changed files with 64 additions and 38 deletions
  1. 64 38
      code/Attack/JoomlaRegPrivExploit.py

+ 64 - 38
code/Attack/JoomlaRegPrivExploit.py

@@ -69,7 +69,7 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
             most_used_ip_address = most_used_ip_address[0]
         self.add_param_value(Param.IP_SOURCE, most_used_ip_address)
         self.add_param_value(Param.MAC_SOURCE, self.statistics.get_mac_address(most_used_ip_address))
-        self.add_param_value(Param.TARGET_URI, "/")
+        self.add_param_value(Param.TARGET_URI, '/')
         self.add_param_value(Param.TARGET_HOST, "www.hackme.com")
         self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
         self.add_param_value(Param.PACKETS_PER_SECOND,self.maxDefaultPPS)
@@ -84,6 +84,7 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
             destination_mac = self.generate_random_mac_address()
         self.add_param_value(Param.MAC_DESTINATION, destination_mac)
 
+    @property
     def generate_attack_pcap(self):
         def update_timestamp(timestamp, pps, maxdelay):
             """
@@ -123,40 +124,55 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
         target_host = self.get_param_value(Param.TARGET_HOST)
         target_uri = self.get_param_value(Param.TARGET_URI)
 
-        # Aidmar - check ip.src == ip.dst
+        # Check ip.src == ip.dst
         if ip_source == ip_destination:
             print("\nERROR: Invalid IP addresses; source IP is the same as destination IP: " + ip_source + ".")
             import sys
             sys.exit(0)
 
         path_attack_pcap = None
-        replyDelay = self.get_reply_delay(ip_destination)
+        minDelay, maxDelay = self.get_reply_delay(ip_destination)
 
         # Inject Joomla_registration_privesc
         # Read joomla_registration_privesc pcap file
         orig_ip_dst = None
-        exploit_raw_packets = RawPcapReader("joomla_registration_privesc.pcap")
+        exploit_raw_packets = RawPcapReader("resources/joomla_registration_privesc.pcap")
 
         port_source = randint(self.minDefaultPort,self.maxDefaultPort) # experiments show this range of ports
 
+        # Random TCP sequence numbers
+        global attacker_seq
+        attacker_seq = randint(1000,50000)
+        global victim_seq
+        victim_seq = randint(1000,50000)
+
         for pkt_num, pkt in enumerate(exploit_raw_packets):
             eth_frame = Ether(pkt[0])
             ip_pkt = eth_frame.payload
             tcp_pkt = ip_pkt.payload
-            str_http_pkt = str(tcp_pkt.payload)
+            str_tcp_seg = str(tcp_pkt.payload)
+
+            # Clean payloads
+            eth_frame.payload = b''
+            ip_pkt.payload = b''
+            tcp_pkt.payload = b''
 
             if pkt_num == 0:
                 prev_orig_port_source = tcp_pkt.getfieldval("sport")
                 if tcp_pkt.getfieldval("dport") == self.http_port:
                     orig_ip_dst = ip_pkt.getfieldval("dst") # victim IP
 
-            # Request
+            # Request: Attacker --> vicitm
             if ip_pkt.getfieldval("dst") == orig_ip_dst: # victim IP
-
                 # There are 7 TCP connections with different source ports, for each of them we generate random port
                 if tcp_pkt.getfieldval("sport") != prev_orig_port_source:
                     port_source = randint(self.minDefaultPort, self.maxDefaultPort)
                     prev_orig_port_source = tcp_pkt.getfieldval("sport")
+                    # New connection, new random TCP sequence numbers
+                    attacker_seq = randint(1000, 50000)
+                    victim_seq = randint(1000, 50000)
+                    # First packet in a connection has ACK = 0
+                    tcp_pkt.setfieldval("ack", 0)
 
                 # Ether
                 eth_frame.setfieldval("src", mac_source)
@@ -167,29 +183,33 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
                 # TCP
                 tcp_pkt.setfieldval("sport",port_source)
 
-
-                eth_frame.payload = b''
-                ip_pkt.payload = b''
-                tcp_pkt.payload = b''
-                #temp = "GET / HTTP/1.0\r\n\r\n"
-                #temp = "GET / HTTP/1.1\r\nHost: 192.168.189.1\r\nUser-Agent: Mozilla/4.0(compatible;MSIE6.0;WindowsNT5.1)\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n"
-
-                if len(str_http_pkt) > 0:
-                    # convert payload bytes to str => str = "b'..\\r\\n..'"
-                    str_http_pkt = str_http_pkt[2:-1]
-                    str_http_pkt = str_http_pkt.replace('/joomla360', target_uri)
-                    str_http_pkt = str_http_pkt.replace(orig_ip_dst, target_host)
-                    str_http_pkt = str_http_pkt.replace("\\n", "\n")
-                    str_http_pkt = str_http_pkt.replace("\\r", "\r")
-
-                new_pkt = (eth_frame / ip_pkt/ tcp_pkt / str_http_pkt)
+                if len(str_tcp_seg) > 0:
+                    # convert payload bytes to string => str = "b'..\\r\\n..'" additional characters are added in the string,
+                    # mainly backslashes to escape single quotes and whitespaces
+                    str_tcp_seg = str_tcp_seg[2:-1]
+                    str_tcp_seg = str_tcp_seg.replace('/joomla360', target_uri)
+                    str_tcp_seg = str_tcp_seg.replace(orig_ip_dst, target_host)
+                    str_tcp_seg = str_tcp_seg.replace("\\n", "\n")
+                    str_tcp_seg = str_tcp_seg.replace("\\r", "\r")
+                    str_tcp_seg = str_tcp_seg.replace("\\t", "\t")
+                    str_tcp_seg = str_tcp_seg.replace("\\\'", "\'")
+
+                # TCP Seq, Ack
+                if tcp_pkt.getfieldval("ack") != 0:
+                    tcp_pkt.setfieldval("ack", victim_seq)
+                tcp_pkt.setfieldval("seq", attacker_seq)
+                if not(tcp_pkt.getfieldval("flags") == 16 and len(str_tcp_seg) == 0): # flags=A:
+                    attacker_seq += max(len(str_tcp_seg),1)
+
+                new_pkt = (eth_frame / ip_pkt/ tcp_pkt / str_tcp_seg)
                 new_pkt.time = timestamp_next_pkt
 
                 maxdelay = randomdelay.random()
                 pps = self.minDefaultPPS if getIntervalPPS(complement_interval_pps, timestamp_next_pkt) is None else max(
                     getIntervalPPS(complement_interval_pps, timestamp_next_pkt), self.minDefaultPPS)
                 timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, maxdelay)
-            # Reply
+
+            # Reply: Victim --> attacker
             else:
                 # Ether
                 eth_frame.setfieldval("src", mac_destination)
@@ -200,20 +220,26 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
                 # TCP
                 tcp_pkt.setfieldval("dport", port_source)
 
-                eth_frame.payload = b''
-                ip_pkt.payload = b''
-                tcp_pkt.payload = b''
-
-                if len(str_http_pkt) > 0:
-                    # convert payload bytes to str => str = "b'..\\r\\n..'"
-                    str_http_pkt = str_http_pkt[2:-1]
-                    str_http_pkt = str_http_pkt.replace('/joomla360', target_uri)
-                    str_http_pkt = str_http_pkt.replace(orig_ip_dst, target_host)
-                    str_http_pkt = str_http_pkt.replace("\\n", "\n")
-                    str_http_pkt = str_http_pkt.replace("\\r", "\r")
-
-                new_pkt = (eth_frame / ip_pkt / tcp_pkt / str_http_pkt)
-                timestamp_next_pkt = timestamp_next_pkt + uniform(replyDelay, 2 * replyDelay)
+                if len(str_tcp_seg) > 0:
+                    # convert payload bytes to string => str = "b'..\\r\\n..'" additional characters are added in the string,
+                    # mainly backslashes to escape single quotes and whitespaces
+                    str_tcp_seg = str_tcp_seg[2:-1]
+                    str_tcp_seg = str_tcp_seg.replace('/joomla360', target_uri)
+                    str_tcp_seg = str_tcp_seg.replace(orig_ip_dst, target_host)
+                    str_tcp_seg = str_tcp_seg.replace("\\n", "\n")
+                    str_tcp_seg = str_tcp_seg.replace("\\r", "\r")
+                    str_tcp_seg = str_tcp_seg.replace("\\t", "\t")
+                    str_tcp_seg = str_tcp_seg.replace("\\\'", "\'")
+
+                # TCP Seq, ACK
+                tcp_pkt.setfieldval("ack", attacker_seq)
+                tcp_pkt.setfieldval("seq", victim_seq)
+                strLen = len(str_tcp_seg)
+                if not(tcp_pkt.getfieldval("flags") == 16 and strLen == 0): # flags=A:
+                    victim_seq += max(strLen, 1)
+
+                new_pkt = (eth_frame / ip_pkt / tcp_pkt / str_tcp_seg)
+                timestamp_next_pkt = timestamp_next_pkt + uniform(minDelay, maxDelay)
                 new_pkt.time = timestamp_next_pkt
 
             packets.append(new_pkt)