In part 1 of this series I covered how flexible Scapy could be out of the box. With Sniffing, Spoofing, and Fuzzing ready to rock most people stop there. But there is still more to explore. In this post I discuss how packets are constructed and layout the creation of a new type of Packet: a "Doorman Port Knocking Encrypted Packet" (DEPKP). This protocol will hide services on a network behind a packet filter called the Door Man.
The Door Man's job is to check for encrypted and signed packets that match a user Pre-Shared Key (Really long password file). In part 3, I will cover more on this part. For now I want to focus on the Packet itself, and how I constructed it using Scapy's intuitive framework. of course when I say intuitive I mean 'if you have a moderate understanding of IP and/or the OSI model'. For instance: if I say to you the Ethernet header deals with OSI Layer 2 addressing you should know that I mean MAC.
Basic Protocol
To understand how to construct custom packets and protocols it is best to start with one that already exists and go from there. The best description I have ever heard of building packets in Scapy came from Phillippe Biondi is paper on packet forgery:Phillippe Biondi's great packet analogy (see the resources for a link) |
Ether (dst="FF:FF:FF:FF:FF:FF") - OSI Layer 2 (Data Link)
The above example defines a hardware MAC address to target with the packet. In this case the Broadcast MAC. If you want to forge the source MAC address of a packet you could also set the src field. (e.g. Ether(src="AA:BB:13:37:CC:DD")).
IP(dst=["a.com","b.com"], ttl=(1,9)) - OSI Layer 3 (Network Link)
This layer defines the network and routing structure. In the example the IP dst is a list of two Domain Names. Scapy is smart enough to handle single values or sets of values. Another place you can see the value range capability is the ttl field. Which in this case would range from 1 to 9. I am going to change to "a.com" and "b.com" for brevity.
UDP() - OSI Layer 4 (Transport)
The example adds the UDP protocol, which has a default destination port of 53 in Scapy.
What it all means
To sum up what this series of packets would actually do we can describe each layer in turn. Essentially: Find a route to "A.com" and "b.com" on port 53 within a maximum of 9 hops. In more detail: these packets would ask every machine on the network (Broadcast MAC) to try to reach the addresses "a.com" and "b.com" (IP dst field) on UDP port 53 (default UDP port) nine times (because of the variable layer 3 ttl). Each time increment the TTL value by 1 and try again".Custom Protocols in Scapy (DEPKP)
Now that I have shown how you can construct a packet using built-in classes it is time to cover extending it with a protocol definition. A protocol in Scapy is really just a collection of field definitions. The syntax for the field depends on the context but a general rule of thumb is:DataType("field_name",Default_value,special_params)
For a list of DataTypes and fields you can check out the documentation under the resources section
The first thing to cover is what exactly the goal for the packet is:
- Single Packet (under the network's fragmentation break point)
- 'Do not Fragment (DF)' Flags set
- Ability to completely spoof source (mac and ip)
- Use randomized data in the payload
- Include real mac, username, and packet creation time in payload
- encrypt payload with a Pre-Shared Key (PSK, really long password)
- post-encryption payload signed with a known key
- Shouldn't trigger standard IDS detection
- Resistant to Forgery, Replay, and Brute Forcing attacks
DEPKP Packet Structure |
DEPKP Packet Field Definitions
The blue portion of the packet diagram above is the DEPKP portion of the packet. As you can see there are two length fields: Signature Length and Data Length. Scapy has a special data Type for fields designated to hold the size of other fields: FieldLenField. Inside the field there is a parameter length_of where you can define which field it holds the length of. Next we have two data sections each of which contains a string of base 64 encoded data. For each of those I used a StrLenField. The StrLenField is a field who's length is defined in another field. Pretty nifty how that works huh? The documentation describes a fancy ways to create custom fields which will automatically parse the length field for you, but that is beyond the scope of this discussion. Here is the definition in Python:
DEPKP is born |
Defense against Brute Force, Replay, and Forgery
The packet will be broadcast (thereby hiding the location of the door man listener), so the security of the payload is important. That is why I chose to do '2 factor' authentication. I put the quotes around 2 factor because traditionally the 2 factors would be of different types (e.g. something you know and something you have). In this case, the PSK portion is also kept in a file. Ideally it will be to long and contain unprintable characters. Brute forcing the password should be out of the question if you generate >=256 bit PSK file. This means that an attacker still needs to recover two keys to forge a packet.To counter replay attacks, I include two pieces of information in the data payload. The first is a packet creation time. This requires both systems' internal clocks to be relatively in sync (depending on how short you want a packet to be valid). I have not run into this being a problem but it could very well pose issues trying to use it across a WAN. The second piece a pseudo-randomly generated 16 character Alphanumeric packet ID. Once a packet is validated this ID can be added to a list of previously processed IDs. The packet processor should validate it has not already seen this packet.
Hiding the Source
The requirement to be able to spoof the source MAC and IP means the payload will also need to contain the real MAC address to grant access to. Aside from that, setting the Ether(src=fake_mac) and the IP(src=fake_ip) will hide the true source. The Username (which is the name of the key used to sign the packet) is also included so the server can use this name to lookup the proper verification key.Payload Structure
So far I have defined the payload as having the following pieces of information:- The MAC to allow access to
- A Random Alphanumeric ID
- A User/Key Name
- A Creation Time
Filling in the custom packet is fast and simple |
This is what the DEPKP packet looks like in Scapy. Generated by the line e.show() in the code:
DEPKP Packet viewed in Scapy |
You can verify the packet traverses the network by firing up Wireshark (or another sniffer) on a different machine. Here is the result of sniffing a DEPKP packet in Wireshark :
DEPKP packet capture in Wireshark |
Conclusion
Creating and extending protocols is easy in Scapy as long as you understand where it fits in the communication model. When combined with the knowledge from the first post (https://the-it-ninja.blogspot.com/2017/04/scapy-python-packet-swiss-army-knife.html) you can start to see where this is going. The Door Man sniffer will reverse the order of the packet protection and create a firewall exception which will allow the MAC included in the payload to access the guarded resource. It is not completely secure since an attacker could spoof the MAC address of a legitimate user after they authenticate and the FW is opened for them. This relies on the attacker knowing a few things- The actual MAC of the user granted access
- The IP and Port of the protected resource
- Watching for the moment a user broadcasts the DEPKP packet
Coming up in part 3, I will discuss how to use this packet and some modifications to the sniffing code from part 1 to complete the Door Man project.
Resources
Phillippe Biondi's presentation notes:http://www.secdev.org/conf/scapy_pacsec05.handout.pdf
Moxie's Port Knocking Write-up and (way better) implementation:
https://moxie.org/software/knockknock/
Scapy Documentation
http://www.secdev.org/projects/scapy/doc/build_dissect.html
No comments:
Post a Comment