Stack-based buffer overflow vulnerability in UDP packet handling in Toxcore (CVE-2021-44847)

A stack-based buffer overflow vulnerability was discovered in Toxcore’s networking code that allows a remote attacker to crash the Toxcore process or potentially execute arbitrary code by sending a specially crafted packet. The vulnerability was assigned CVE-2021-44847 identifier.

All users of Toxcore that don’t have UDP disabled are affected. An attacker, knowing the target’s DHT public key, IP and port, can easily craft a packet exploiting the vulnerability. DHT public key, IP and port are all public information, publicly available on the DHT, so an attacker can target any and all Toxcore users by scraping this information from the DHT. This attack can also be used to target DHT bootstrap nodes, thus making new users unable to connect to the DHT network.

The vulnerability was introduced in 71260e38e8d12547b0e55916daf6cadd72f52e19 and fixed in 1b02bad36864fdfc36694e3f96d2dc6c58a891e4. It affects Toxcore versions 0.1.9 – 0.1.11, 0.2.0 – 0.2.12. Toxcore 0.2.13 has the vulnerability patched.

We urge everyone to update to Toxcore 0.2.13 as soon as possible.

If you are unable to update at the moment, you can immediately mitigate the vulnerability by disabling UDP, as this vulnerability happens only on the UDP code path. If you are using a Tox client, look for an option to disable UDP or for a TCP-only mode option. If you are using the library directly, you can disable UDP via the tox_options_set_udp_enabled() API function call.

Thanks to sudden6 for finding and fixing the vulnerability, irungentoo for writing a proof-of-concept attack, and iphy and nurupo for analyzing the vulnerability.

Technical details

The buffer being overflown is temp in the handle_request() function, located at DHT.c:365 in Toxcore 0.2.12. The overflow happens on the following line, a few stack frames inside the decrypt_data() function call, due to the 5th argument of decrypt_data() being incorrectly calculated. The 5th argument, length – CRYPTO_SIZE, incorrectly expands to length – 1 + 32 * 2 + 24, when the intention was for it to expand to length – (1 + 32 * 2 + 24). This allows decrypt_data() to write more data into temp buffer than intended, overflowing the buffer and writing past handle_request() function’s stack frame, smashing the stack.