# Network Security Assignment 2
### Using ICMP channel for communication
The Internet Control Message Protocol (ICMP) is a protocol that uses a type of packet to indicate the success or failure when communicating with other IPs. This could for example be informing if the host can be reached or not.
However, it can be used to send additional payloads aswell, which is what I will be taking advantage of in this assignement.
Since ICMP has the ability to send packets with a custom payload, I will use that to exfiltrate encrypted messages over a network.
The first thing is to create a custom packet, in this case using ICMP Type 47 which is currently unassigned. After creating the ICMP packet I can append a payload to be sent along with it, for example a message. Sending this out should look like a regular ICMP packet.
On the receiving end of this communication the packet is captured, which will have an IP header prepended, as it is sent over the network. To get the added payload, the packet is then parsed into the three parts: IP header, ICMP header and the payload.
This completes the one-way communication between the two parties.
Furthermore, the message can be encrypted before sending it, so that no other services know what is in the added payload.
A way to achieve this would be for the sender and the reciever to have a preshared key, which they can use for encryption and decryption, for example using Stream Cipher encryption.
### Stream Cipher
For this assignment I decided to use Stream Cipher to encrypt the messages, as it creates a ciphertext with the same length as the original message. This is important, as we want to keep the ICMP packet small.
Other ways of encrypting could make the ciphertext longer than the original message, which would make the ICMP packet bigger, which we do not want.
For shorter messages, only part of the key is used, and messages can not be longer than the key. I could have implemented repeating the key for longer messages, but I did not want to introduce this, as it weakens the security, and I did not find it necessary for the use of this covert channel, as it is intended to be used for short messages.
The fact that a preshared symmetric key should be used, means that the same key is used for every message, which makes it less secure than using a new key every time.
### Implementation
To solve the task, I have implemented a client and a server, which allows messages to be sent through a one-way covert channel using the ICMP protocol.
The client gets a destination and a message, encrypts the message and creates an ICMP packet with the ciphertext appended and sends the message to the server.
The server recieves the packet containing headers and the ciphertext. This packet gets parsed to get the ciphertext, which is then decrypted, obtaining the original plaintext.
The client and server have a preshared symmetric key, which is used for encryption and decryption.
##### Choosing key size:
The largest possible ICMP packet is 65535 bytes, so the largest possible key is 65307 characters, as the packet also includes the IP and ICMP header (28 bytes). However, having a key this large in this case would not make sense, as sending messages of that size could be easily caught by something like a firewall, which is not wanted for a covert channel.
On the other hand, having a very short key will only allow very short messages, which means that the message might have to be split into many small packets, and that will increase the number of packets sent, which could also easily be detected.
Instead, I imagine that the channel will be used to send short concise messages, for example to exfiltrate information. Therefore, the chosen key has a size of 128 characters, which means that the message can have at most 128 characters.
The key was created using this website: https://www.fourmilab.ch/onetime/otpjs.html
##### Encryption:
Every character in the message is converted into its numeric ASCII code and XORed with the corresponding character in the preshared symmetric key, which is also converted into ASCII code. This returns a numeric code, which is converted into a character (although it may not always be a printable character) and appended to the ciphertext.
In case the message is shorter than the key, only part of the key will be used.
The way I implemented the encryption, the message can not be longer than the key, which is 128 characters.
##### Handling the ICMP packet:
After completing the encryption of the message to be sent, an ICMP packet needs to be created and the message added to it.
Creating the packet is relatively easy using the python module Scapy.
Scapy is a powerfull module that allows users to have full control over sending, sniffing, dissecting as well as forging network packets.
In this particular case, the only information needed to forge the ICMP packet is the Type and Code.
From the task description it is requested to use Type 47, as mentioned in the introduction.
The Code value is usually defined relative to the Type value, but since this particular Type is unassigned there is also no corresponding Code.
Using Scapy to forge the ICMP packet with the payload, has the advantage of not needing to worry about contstructing the packet from scratch using struct nor having to calculate the checksum, as the module does it all automatically.
Since I am using python sockets to send the package from the client to the server, I purposely omitted the IP header while forging the ICMP packet as this will get added by the socket.
So to actually send the packet via raw sockets, a socket needs to be created before anything can be sent through it.
The arguments the socket function takes are: family, type and protocol.
These arguments are simple constants, for the family socket.AF_INET is used as it is the one that corresponds to IPv4.
Since ICMP is its own protocol, the created socket needs to be of type socket.SOCK_RAW, as to not specify the protocol like SOCK_STREAM does for TCP.
Lastly socket.IPPROTO_ICMP is used for the protocol.
With the newly created socket, packets can now be sent through it.
To send the packet, a destination and a port need to be specified, even though ICMP does not use ports to communicate, the socket requires one to be present.
A socket is created on the receiving end using the same configurations as on the client.
With a while loop the socket is constantly listening for incoming packets.
Knowing that the message can never be bigger than the preshared key, and that the ICMP and IP headers are part of the packet, the most that can be sent in one single packet is 156 bytes.
Once a packet arrives it gets stored along with the IP that sent it.
The packet is then parsed into three different parts, the IP header, the ICMP header and the payload.
The payload is what contains the encrypted message. IP headers are always 20 bytes long and the ICMP header is 8 bytes, so I spliced the data starting from the 28th byte forward.
Having isolated the encrypted message, now I can decrypt the message.
##### Decryption:
Since the key is symmetric, I can apply the same methods as I did for encryption. So every character in the ciphertext is XORed with the corresponding character in the key to obtain the original plaintext.
The plaintext is then printed to the console, thus completing the one-way covert channel.
The implementation is further explained in the two python scripts (client.py and server.py) as comments.