
I have attached a bad LZMA file generated by modifying a valid LZMA's size to 0 as described. The attached `create_bad_lzma.py` was used for this.
I have also attached a dummy proof-of-concept that mimic's U-Boots calls to LzmaDecode(). When ran on linux, this segfaults off the page within the memcpy(): ``` root@ubuntu:~/7z/7-Zip/C# gcc -I`pwd` LzmaDec.c test.c -o test root@ubuntu:~/7z/7-Zip/C# ./test uncompressed size: 0x0 compressed size: 0xfffffffffffffffa 7z Release: 19.00 Segmentation fault (core dumped) ```
I can get another PoC working in U-Boot to show that it can be used to gain code execution, but I would need some time to get another environment setup.
Please let me know if have questions. Thank you, Darek
On Wed, Jul 31, 2024 at 4:31 PM Darek x64x6a@gmail.com wrote:
Hello! I hope this is all the correct contacts for reporting this issue.
I have discovered that there is a vulnerability in the version of 7z LZMA that U-Boot is using (9.20). I've found this to lead to code execution when used with `lzmadec`. I have found no issued CVEs or public disclosures announcing this vulnerability, but it appears to have been patched in 7z LZMA version 21.02 alpha. I've patched locally with 24.07 and U-Boot appeared to LZMA decompress successfully, but I'm unaware of other use cases within the project. I would also be curious if another LZMA implementation would be considered.
I'm separately coordinating disclosure with the 7z maintainers and planning on requesting a CVE. Since your project uses an older version that is unlikely to get a backported patch, and the issue is already fixed in newer versions, I am disclosing this to U-Boot maintainers at the same time.
The bug triggers when an LZMA has the 8-byte length field in the header set to 0. This field is located at offset 5 from the start of an LZMA file. Due to how the logic of `LzmaDec_DecodeToDic()` works, this eventually reaches a `memcpy(p->tempBuf, src, inSize)` on this line - https://github.com/u-boot/u-boot/blob/8877bc51a8a4d921ba2f163208b8b1a57ba47c...
The `inSize` value here is allowed to be greater than the buffer size due to the previous if-statement ignoring this value if `checkEndMarkNow` is set. The return value from `LzmaDec_TryDummy()` also needs to return `DUMMY_ERROR` to reach the `memcpy()`.
The value of `dicLimit` in this function is initially the value read from the LZMA header, which for this case is 0. Under my testing, when this was 0, it hits the memcpy call, using the passed `srcLen` value (`inSize`).
Within `lmzadec`, this value is originally set to max size_t as the default here - https://github.com/u-boot/u-boot/blob/8877bc51a8a4d921ba2f163208b8b1a57ba47c...
And passed to the `LzmaDecode()` function here - https://github.com/u-boot/u-boot/blob/8877bc51a8a4d921ba2f163208b8b1a57ba47c...
Under my testing, when `lzmadec` is passed an LZMA file with a 0-length field, this ends up calling:
memcpy(p->tempBuf, src, 0xFFFFFFFFFFFFFFF5)
This is no longer max size_t due to previous subtractions in this loop and within a previous function:
https://github.com/u-boot/u-boot/blob/8877bc51a8a4d921ba2f163208b8b1a57ba47c... and
https://github.com/u-boot/u-boot/blob/8877bc51a8a4d921ba2f163208b8b1a57ba47c...
This leads to code execution when the corrupted LZMA file is large enough to overwrite `memcpy()`'s instructions, or if the memory past the LZMA file is also controlled previously.
In my testing, I created a small LZMA file and modified the header's size to 0. I then appended assembly instructions that performed a loop to this file, so that when code execution would occur, I could easily verify by seeing the loop. I repeated this until the file was over 1GB. In U-Boot CLI, I then used TFTP to load the LZMA file from my server and then ran `lzmadec`with my selected source and destination address far away from U-Boot's code. When I attached a debugger at this point, the program was stuck in my infinite loop code.
I believe this is especially a concern for secure boot implementations that utilize U-Boot's LZMA decompression, as it could bypass their secure boot implementation.
Please let me know if any additional details are needed or if a proof-of-concept video/script would be required for further evidence.
Thank you, Darek