In the previous post I described the first exploit I was able to prepare, working against RIPv2. In this one, I am going to present another attack, this time having OSPF as target.
Routing theory: types of routing protocols
We have already seen what a routing protocol is and which is its purpose. It is now time to dive more deeply into them to understand the difference between each other.
The schema above introduces two concepts: the family of the protocol (interior or exterior) and the type (distance vector, link state and path-vector). Once again, all the details can be found either in “Computer Networking: A Top-Down Approach” (ISBN-13: 978-0133594140) or in “Computer Networks” (ISBN-13: 978-0132126953), but let’s recap here the basic concepts.
First of all, we have to introduce what is an an autonomous system (abbreviated in AS): we can define it as a group of networks that are controlled by a single administrative entity. An administrative entity could be an Internet Service Provider, an international enterprise or something similar. To deal with the routing inside an AS, we can use interior gateway protocols; whenever we have to exchange information between different AS, we use exterior gateway protocols.
This is a simple concept, but then you could ask: why do we need multiple routing protocols types? Because they use a different approach to deal with the needs of a network administrator (e.g.: how the cost of a path is calculated, how fast they converge, etc… ).
Trying to be concise, we can define the three types in the schema as follows:
- Distance vector routing protocols: with those protocols, every router advertise its routing table, defining each known network using the concept of distance (e.g.: hop count, delay, …) and a vector, that is the direction of the next hop;
- Link state routing protocols: those protocols use a different approach, by sharing with all the other routers in the AS the state of the links they are connected with and by letting every other router to construct its own map of the whole AS;
- Path-vector routing protocols: those protocols share the whole path used to reach a destination, specifying which AS the packets are going to traverse to travel from the origin to the destination.
OSPF: the theory
OSPF stands for Open Shortest Path First and it is probably one of the most used routing protocols for interior-gateway routing because it works fairy well, it is robust, it has built-in security features and it is widely supported by network devices. There are three version of the protocol:
- OSPFv1: described in RFC 1131 (has never gone beyond the experimental phase, as far as I know);
- OSPFv2: described in RFC 2328, it superseeds v1 and it is the version deployed worldwide for dealing with IPv4 networks;
- OSPFv3: it supports IPv6 and is described in RFC 6340.
While OSPF protocol is quite complex, we can summarise the main concepts as follows:
- neighbors: every router establish a trust relationship with the neighbors routers, that are those residing in the same subnet and sharing some characteristics (e.g.: areaID, area type, subnet, …);
- hello, advertisements and updates: these are different messages sent by the routers to share their routing links information;
- fight-back mechanism: whenever a router receives a fake advertisement / update containing its own information it sends, to the OSPF multicast address (220.127.116.11), a new advertisement / update, overwriting the fake one.
In practice, after configuring the routers, the information is exchanged automatically and after some minutes (at least, in the GNS3 scenario), the routing tables inside the AS converge, meaning that every router has a stable routing table it can use.
OSPF: attack analysis
There are various attacks known against OSPF (see on Google Scholar), but they are normally able to “only” generate a DoS condition.
In 2011, Alex Kirshon, Dima Gonikman, Dr. Gabi Nakibly demonstrated an attack, during the Black Hat USA, that was able to circumvent the fightback packets.
The idea behind the attack is quite simple.
Imagine two neighbours routers, A and B. The attacker generates two packets, one sent to the victim router A to trigger the fightback and another sent, at the very same time, to the router B inside which the malicious routes have to be injected. The fightback packet, sent by A is received by B after the malicious one and it is discarded because seen as identical, even tough the content of the two packets is different.
From the rest of the article, we are going to speak about trigger packet, referring to the first one, and disguised packet, referring to the second one.
This is possible because two OSPF LSA (Link State Advertisement) packets are considered identical if they have:
- the same sequence number;
- the same 16 bits checksum value;
- approximately the same age (within a 15 minutes time difference).
The sequence number and the age are quite easy to spot and fake, while the checksum has to be calculated. Luckily, it can be predicted, because it is calculated on LSA fields that have values that can be inferred in advance.
I let you carefully read the paper linked above for all the detail, because in the next paragraphs I would like to concentrate on the practical side of the attack.
OSPF: exploit lab
Even in this case, the whole scenario will be simulated using GNS3, with Cisco based firmware emulated inside it. What follows is a screenshot of the result, where the attacking machine, the victim router and the target router are highlighted.
OSPF: exploit development
If an attack is known and publicly described, the exploit should also be easy to find or, in the worst case, easy to write. Well, no.
Thanks to the fact that Google is my friend, I started looking for a public exploit but I soon realised that the only PoC available was contained in a paper provided by nes.fr, but it was not complete.
So the first thing I did was to import some OSPF packets in Scapy to get used to them, but I discovered that it was not able to dissect them correctly. Theory VS practice.
After spending some days trying to figure out what was wrong, I discovered a bug and I submitted a patch, so now Scapy is working as expected. I then used the partial code provided by nes.fr to prepare the first draft of the exploit, but the most difficult part, at least for me, was to understand how to made the checksum of the two packets to collide. The guys from nes.fr suggest to use NumPy to solve a system of linear equations. Unluckily, this is not so trivial to do and, moreover, this generates a packet that is malformed, because the values inside the various fields do not follow any rule. In another paper, from 2012, the original authors state that “The value [of the checksum] can be either directly calculated or found by an exhaustive search within a few seconds.“, that is interesting to say but led to the same, malformed packets.
I then went back to the nes.fr article and I discovered, by looking at the system of linear equation, that the last field of the link used, inside the LSA packet, to generate the collision, was 2 bytes long. Due to the fact that the checksum has the same length, all the possible values of the checksum can be generated by keeping constant all the fields in the link and by trying every possible value of the last field, from 0 to 32768.
My exploit was then able to sniff for the first LSA packet generated by the victim router and to use it as a template for both the trigger and the malicious ones. By comparing them, the checksum, the sequence and the age were actually the same, but the malicious one was never accepted. Theory VS practice.
After literally spending days on troubleshooting the problem, I discovered that the Cisco firmware was discarding my disguised packet, because both the packets were sent to the multicast address and the second one was arriving to fast and was discarded – I think – as a security measure.
The final exploit is available on my GitHub profile has been extensively tested against Cisco firmwares, but feel free to test it in other scenarios and let me know if you encounter any problem.
OSPF: exploit impact
If defining the real impact for the RIPv2 attack was hard, defining it for OSPF is even harder, because it is used in very different scenarios. Probably, due to the fact that it can replace RIP (that is older and not so powerful), it is currently more used and, hence, the impact of this attack is bigger.
A good network engineer could argue that normally the OSPF packets use a dedicated VLAN, that is accessible by no one but the administrators. While this is the theory (and it is luckily also the practice in some networks), from my experience it is absolutely not always the case.
Another mitigation of the attack could be constituted by the MD5 signature added to the packets, right? In theory, yes. In practice, no. MD5 is badly broken, the same password has to be shared on every router attached to the link and too often it can be simply guessed or broken through a dictionary attack. Last but not least, the original paper reports also this note, regarding MD5:
“OSPF computes the packet integrity tag as MD5(data||key||pad||length) where || denotes concatenation. While this integrity method is now known to be insecure, we do not use this fact in our attacks. OSPF does not use HMAC for historical reasons.”
So, from my point of view, if an attacker is able to interact with the routers through OSPF, probably his or her possibilities are only limited by his or her imagination.
I would thank both the researchers who discovered this attack and also the researchers of nes.fr for providing me the starting point for my own exploit!
2 thoughts on “Practical routing attacks (2/3): OSPF”
I tried running your script using Python3 and Scapy 2.4.5 on Mac M1, but it stuck on “Staring sniffing for LSUpdate from the victim’s router..”
Any input is deeply appreciated.