FRRouting / frr

The FRRouting Protocol Suite
https://frrouting.org/
Other
3.37k stars 1.25k forks source link

ospfd's behavior allows a malformed Router LSA to persists in the routing domain #8728

Open tromai opened 3 years ago

tromai commented 3 years ago

Describe the bug ospfd rejects any LSA that has sequence number = MaxSeqNumber (0x7fffffff) and age different from MaxAge (3600). This is to addressed the vulnerability CVE-2017-3224. The code implementing this feature is located here. However, when a router want to generate a fight-back LSA with sequence number of MaxSeqNumber - 1 (age obviously != MaxAge), this fight-back will be rejected by its neighbor routers. Therefore, the fight-back LSA is rendered useless.

[x] Did you check if this is a duplicate issue? [] Did you test it on the latest FRRouting/frr master branch?

To Reproduce When I discovered the vulnerability, this is the topology that I used topology_labeled

With the following configurations: topo_config

The vulnerability is replicated by having the attacker flood a malformed Router LSA (modified from the current r010_1's router LSA) to the routing domain. This malformed Router LSA will have sequence number of MaxSeqNumber – 1 (0x7ffffffe) and age != 3600. When the router that originated this LSA (r010_1) receives the malformed LSA, it will issue a fight-back LSA. This fight-back LSA will have sequence number of MaxSeqNumberand age != MaxAge. However, because FRRouting’s ospfd rejects LSA with MaxSeqNumber but Age != MaxAge, this fight-back instance is rejected and will be rendered useless.

Expected behavior The malformed router LSA sent by the attacker will persists in the Link State Database (LSDB) of all other router except r010_1. r010_1 will keep sending the fight-back LSA because it's not accepted and acked by r010_5.

The attack impacts depend on the content of the malformed LSA (e.g bring down connection to r010_1)

Screenshots The log file of r010_5 indicating that it rejects the fight-back LSA.

2021/03/16 01:45:19 OSPF: DR-Election[1st]: Backup 10.255.0.14
2021/03/16 01:45:19 OSPF: DR-Election[1st]: DR     10.255.0.14
2021/03/16 01:45:19 OSPF: DR-Election[2nd]: Backup 10.255.0.13
2021/03/16 01:45:19 OSPF: DR-Election[2nd]: DR     10.255.0.14
2021/03/16 01:45:19 OSPF: interface 10.255.0.14 [2] join AllDRouters Multicast group.
2021/03/16 01:45:19 OSPF: DR-Election[1st]: Backup 10.255.0.17
2021/03/16 01:45:19 OSPF: DR-Election[1st]: DR     10.255.0.17
2021/03/16 01:45:19 OSPF: DR-Election[2nd]: Backup 10.255.0.18
2021/03/16 01:45:19 OSPF: DR-Election[2nd]: DR     10.255.0.17
2021/03/16 01:45:19 OSPF: interface 10.255.0.17 [4] join AllDRouters Multicast group.
2021/03/16 01:45:19 OSPF: Packet[DD]: Neighbor 10.10.0.4 Negotiation done (Master).
2021/03/16 01:45:19 OSPF: Packet[DD]: Neighbor 10.10.0.1 Negotiation done (Master).
2021/03/16 01:45:29 OSPF: DR-Election[1st]: Backup 10.255.0.18
2021/03/16 01:45:29 OSPF: DR-Election[1st]: DR     10.255.0.17
2021/03/16 01:45:29 OSPF: DR-Election[1st]: Backup 10.255.0.13
2021/03/16 01:45:29 OSPF: DR-Election[1st]: DR     10.255.0.14
2021/03/16 02:00:33 OSPF: Link State Update[Type1,id(10.10.0.1),ar(10.10.0.1)]: has Max Seq but not MaxAge. Dropping it
2021/03/16 02:00:40 OSPF: Link State Update[Type1,id(10.10.0.1),ar(10.10.0.1)]: has Max Seq but not MaxAge. Dropping it
2021/03/16 02:00:45 OSPF: Link State Update[Type1,id(10.10.0.1),ar(10.10.0.1)]: has Max Seq but not MaxAge. Dropping it
2021/03/16 02:00:50 OSPF: Link State Update[Type1,id(10.10.0.1),ar(10.10.0.1)]: has Max Seq but not MaxAge. Dropping it

r010_1 keeps sending the rejected fight-back LSA (note that no LS Ack is issued).

r010_1_traffic

Versions

Additional context The topology is emulated with Mininet 2.3.0

odd22 commented 3 years ago

Hello,

Thank's to report this issue. However, the incriminate code (line 2094 in ospfd/ospf_packet.c) made a reference to CVE-2017-3224:

Open Shortest Path First (OSPF) protocol implementations may improperly determine Link State Advertisement (LSA) recency for LSAs with MaxSequenceNumber. According to RFC 2328 section 13.1, for two instances of the same LSA, recency is determined by first comparing sequence numbers, then checksums, and finally MaxAge. In a case where the sequence numbers are the same, the LSA with the larger checksum is considered more recent, and will not be flushed from the Link State Database (LSDB). Since the RFC does not explicitly state that the values of links carried by a LSA must be the same when prematurely aging a self-originating LSA with MaxSequenceNumber, it is possible in vulnerable OSPF implementations for an attacker to craft a LSA with MaxSequenceNumber and invalid links that will result in a larger checksum and thus a 'newer' LSA that will not be flushed from the LSDB. Propagation of the crafted LSA can result in the erasure or alteration of the routing tables of routers within the routing domain, creating a denial of service condition or the re-routing of traffic on the network. CVE-2017-3224 has been reserved for Quagga and downstream implementations (SUSE, openSUSE, and Red Hat packages).

So, we could correct the behaviour of OSPF in order to not reject / drop fight-back LSA, but in this case, we'll go against this CVE.

Do you have an opinion about that ? Does the issue is more on the way the fight-back LSA is forge i.e. it must have seqNumber = MaxSeqNumber and age = MaxAge ?

tromai commented 3 years ago

Thank you for your comment.

From the RFC 2328 document, when a router wants to wrap around the sequence number of its router LSA (0x7fffffff to 0x80000001), it must first flush the MaxSequence LSA from the routing domain. This is accomplished by a process called premature-flooding (RFC2328 Section 14.1) in which the MaxSequence, MaxAge LSA is flooded.

The source cause of CVE-2017-3224 is how an OSPF router in FRRouting generates a fight-back LSA with its actual valid linklist instead of the linklist from the malformed router LSA. The CVE-2017-3224 vulnerability can be replicated by injecting a malformed router LSA with sequence = MaxSequenceNumber and an empty linklist to the routing domain. When a router in the routing domain generates a fight-back LSA (because the fight-back LSA must have a newer sequence number), it would try to wrap around the sequence number (this is where it floods the MaxSequence, MaxAge LSA, and the scenarios of CVE-2017-3224 happens).

FRRouting addresses this issue by rejecting LSAs with MaxSequence but not MaxAge (which causes the vulnerability reported in this github Issue). Although it can prevent CVE-2017-3224 , it does not target the source cause of CVE-2017-3224 . My theory is that instead of rejecting such LSAs, we can craft the MaxSequence, MaxAge LSA with the linklist taken from the malformed LSA itself. This way, the "fight-back MaxSequence, MaxAge LSA" will still have the same checksum as the malformed LSA and the CVE-2017-3224 scenario will not happen.

However, I currently don't have a way to prove this.

I hope that answers your question.

riw777 commented 3 years ago

This makes sense (after reading it a couple of times) ... we should probably leave this open to be addressed. It seems like a bit of a corner case, however.