Exploiting the libwebp Vulnerability, Part 1: Playing with Huffman Code

We discussed this vulnerability during Episode 234 on 08 January 2024

This is actually a follow-up in a sense to the WebP 0day post we covered on Episode 218. So I won’t rehash how the vulnerability works, instead these two posts dive more onto the exploitation side of things.

First up, is the core primitive they gained from this Huffman table creation bug, as we suspected originally this would be a somewhat limited out-of-bounds write. First is where the write happens. This isn’t a linear overflow where it just keeps writting into adjacent memory, instead you’re able to trick the table writer into trying to write to an index that is out-of-bounds. They were able to gain some more granular control over the index by using having multiple 9-bit long prefix codes in the table. Each one of these codes could push the out-of-bounds write index up by 2, allowing the write to happen at an aligned address in multiples of 8 bytes. So that is a pretty nice base to have, not as nice as writing to any relative address, but being aligned its likely what can be written will line-up with fields in the object they can overflow into.

As for the actual value being written, it would be writing a HuffmanCode value which has two fields a uint8_t which represented the number of bits for the HuffmanCode. As the overflow would happen later in the table this would be fixed (I believe) to 15. one byte of padding that was not controlled, and a uint16_t representing the symbol value. The Symbol value had limited range depending on the type of table being written, in this case the range was 0 to 39. Definitely some restrictions there to be concerned about, not enough to write any pointers for the common technique of creating an arbitrary read/write primitive.

OOB Write to Use-After-Free

The author goes into their search for a target object to corrupt and some challenges there, ultimately discovering the CSSVariableData structure. A variaible sized object that would contain the string representation of a CSS Variable. This object began with a ref_count_ field, then a length_ and flags fields before the variaible string data. The author was able to take a fairly classic target and corrupt the reference count to have the object be freed early, putting them into a use-after-free situation.

Use-after-free to Relative Read

With use-after-free, the user side of the equation is that CSSVariableData structure which contains a length_ and a string that will be read. Which is the target of this stage. They get the freed CSSVariableData object reclaimed by an AudioArray which contains entirely attacker controlled data. Allowing them to corrupt the length_ value, so when the CSSVariableData value is read in JavaScript it would read adjacent memory.

After this point the exploit goes into taking a double-free and attacking the PartitionAlloc metadata in a style reminiscent of a FastBin attack and gets into a bit more Chrome specific work. Check out the actual post for those details (Ctrl+F Cross-Bucket Allocation in the Part2 post).