Exploitation of an OOB Write in Netfilter [CVE-2022-25636]

We discussed this vulnerability as part of our weekly podcast on 23 March 2022

We have previously covered this bug, its an out-of-bounds access due to a broken assumption in every dup command having an associated immediate. When that assumption is broken by manually crafting netfilter rules nft_fwd_dup_netdev_offload function will perform an out of bounds access as it increments too far.

Where the post covers new ground is in the exploit strategy.

entry = &flow->rule->action.entries[ctx->num_actions++];
entry->id = id;
entry->dev = dev;

In the vulnerable code above the entries array may be access out of bound, performing two writes the the id and dev fields. The dev field was the interesting one as that it writing a pointer to the net_device structure. This provided two basic primitives depending on the rules being added (attacker controlled)

  1. Write at 24 bytes into the next block in kmalloc32 or 192 cache
  2. Write at 8 bytes into the next block in kmalloc128.

Unfortunately for the authors writes at these offsets didn’t seem too useful and he couldn’t find a good target for the write. However by performing the attack multiple times, he could write another 80bytes head, in kmalloc128, this goes from an offset of 8 to 88 to 40 (168 mod 128). That 40 byte offset he realized after reading Alexander Popov’s Four Bytes of Power exploit aligns with security pointer in a struct msg_msg

Overwriting the security field leads to an arbitrary free primitive when the msg_msg is received (attacker controlled) so if exploited in this scenario it would free the net_device. Leading to a more complete attack chain:

  1. Spray System V message queue messages (struct msg_msg) of a size to fit in kmalloc128
  2. Free some of the messages by recieving them
  3. Add a malicious netlink rule, trying to reuse one of these freed msg_msg structs
  4. Perform the OOB access three times, overwriting the among other things the security pointer of one of these messages
  5. Scan the messages for ones that have had their data corrupted to find the corrupted messages.
  6. Free the message with a corrupted security pointer, causing a free of the net_device
  7. Spray more messages this time of a size to fit in kmalloc4096, hopefully taking over the freed net_device
  8. Above control of the net_device to overwrite some of the netsec_ops function pointers for control flow hijacking