Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2021-43311: [bug] multi heap buffer overflows in get_le32() · Issue #380 · upx/upx

A heap-based buffer overflow was discovered in upx, during the generic pointer ‘p’ points to an inaccessible address in func get_le32(). The problem is essentially caused in PackLinuxElf32::elf_lookup() at p_lx_elf.cpp:5382.

CVE
#vulnerability#ubuntu#linux#dos#git#java#intel#buffer_overflow

What’s the problem (or question)?

Multi heap-based buffer overflows were discovered in upx, during the genric pointer ‘p’ points to an inaccessible address in func get_le32(). The issue can be triggered by different places, which can cause a denial of service. The issue is diff from issue365

ASAN reports:

==112024==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61d00001f3b1 at pc 0x0000005292cb bp 0x7fffc3995640 sp 0x7fffc3995630 READ of size 4 at 0x61d00001f3b1 thread T0 #0 0x5292ca in get_le32(void const*) /home/test/Desktop/EVAULATION/upx/src/bele.h:164 #1 0x5292ca in N_BELE_RTP::LEPolicy::get32(void const*) const /home/test/Desktop/EVAULATION/upx/src/bele_policy.h:192 #2 0x4589c1 in Packer::get_te32(void const*) const /home/test/Desktop/EVAULATION/upx/src/packer.h:296 #3 0x4589c1 in PackLinuxElf32::elf_lookup(char const*) const /home/test/Desktop/EVAULATION/upx/src/p_lx_elf.cpp:5382 #4 0x463d30 in PackLinuxElf32::PackLinuxElf32help1(InputFile*) /home/test/Desktop/EVAULATION/upx/src/p_lx_elf.cpp:315 #5 0x464e96 in PackLinuxElf32Le::PackLinuxElf32Le(InputFile*) /home/test/Desktop/EVAULATION/upx/src/p_lx_elf.h:395 #6 0x464e96 in PackLinuxElf32x86::PackLinuxElf32x86(InputFile*) /home/test/Desktop/EVAULATION/upx/src/p_lx_elf.cpp:4800 #7 0x464e96 in PackBSDElf32x86::PackBSDElf32x86(InputFile*) /home/test/Desktop/EVAULATION/upx/src/p_lx_elf.cpp:4817 #8 0x464e96 in PackFreeBSDElf32x86::PackFreeBSDElf32x86(InputFile*) /home/test/Desktop/EVAULATION/upx/src/p_lx_elf.cpp:4828 #9 0x4f337a in PackMaster::visitAllPackers(Packer* (*)(Packer*, void*), InputFile*, options_t const*, void*) /home/test/Desktop/EVAULATION/upx/src/packmast.cpp:190 #10 0x4f50f9 in PackMaster::getUnpacker(InputFile*) /home/test/Desktop/EVAULATION/upx/src/packmast.cpp:248 #11 0x4f521f in PackMaster::unpack(OutputFile*) /home/test/Desktop/EVAULATION/upx/src/packmast.cpp:266 #12 0x52a1e6 in do_one_file(char const*, char*) /home/test/Desktop/EVAULATION/upx/src/work.cpp:160 #13 0x52a69e in do_files(int, int, char**) /home/test/Desktop/EVAULATION/upx/src/work.cpp:271 #14 0x403ace in main /home/test/Desktop/EVAULATION/upx/src/main.cpp:1538 #15 0x7efc08e6182f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) #16 0x404828 in _start (/home/test/Desktop/EVAULATION/upx/src/upx.out+0x404828)

0x61d00001f3b1 is located 189 bytes to the right of 2164-byte region [0x61d00001ea80,0x61d00001f2f4) allocated by thread T0 here: #0 0x7efc09a55602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602) #1 0x42732a in MemBuffer::alloc(unsigned long long) /home/test/Desktop/EVAULATION/upx/src/mem.cpp:194

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/test/Desktop/EVAULATION/upx/src/bele.h:164 get_le32(void const*) Shadow bytes around the buggy address: 0x0c3a7fffbe20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c3a7fffbe30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c3a7fffbe40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c3a7fffbe50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 fa 0x0c3a7fffbe60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c3a7fffbe70: fa fa fa fa fa fa[fa]fa fa fa fa fa fa fa fa fa 0x0c3a7fffbe80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c3a7fffbe90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c3a7fffbea0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c3a7fffbeb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c3a7fffbec0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe ==112024==ABORTING

Debug

Program received signal SIGSEGV, Segmentation fault. 0x000000000066f8f8 in get_le32 (p=0xa1fffd) at bele.h:164 164 return ACC_UA_GET_LE32§; [ Legend: Modified register | Code | Heap | Stack | String ] ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ──── $rax : 0x0
$rbx : 0xa7ce93
$rcx : 0x2
$rdx : 0xae
$rsp : 0x00007fffffffcc18 → 0x000000000051249b → <PackLinuxElf32::elf_lookup(char+0> xor eax, ebp $rbp : 0x8e8223e2
$rsi : 0x0000000000a1fffd → 0x0000000000a1fffd $rdi : 0x00000000009ed3c0 → 0x00000000007cd9c0 → 0x000000000066fe00 → <N_BELE_RTP::LEPolicy::~LEPolicy()+0> lea rsp, [rsp-0x98] $rip : 0x000000000066f8f8 → <N_BELE_RTP::LEPolicy::get32(void+0> mov eax, DWORD PTR [rsi] $r8 : 0x1f
$r9 : 0x3fdf
$r10 : 0xae
$r11 : 0x1d9577c0
$r12 : 0x0000000000a00030 → 0x00000000007267a0 → <vtable+0> add BYTE PTR [rax], al $r13 : 0x0000000000a1fffd → 0x0000000000a1fffd $r14 : 0x0000000000a00a51 → 0x0000000000000000 $r15 : 0x00000000007cd9c0 → 0x000000000066fe00 → <N_BELE_RTP::LEPolicy::~LEPolicy()+0> lea rsp, [rsp-0x98] $eflags: [carry PARITY adjust ZERO sign trap INTERRUPT direction overflow RESUME virtualx86 identification] $cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ──── 0x00007fffffffcc18│+0x0000: 0x000000000051249b → <PackLinuxElf32::elf_lookup(char+0> xor eax, ebp ← $rsp 0x00007fffffffcc20│+0x0008: 0x00000000006cdffe → “JNI_OnLoad” 0x00007fffffffcc28│+0x0010: 0x0000000200000000 0x00007fffffffcc30│+0x0018: 0x000000000900457f 0x00007fffffffcc38│+0x0020: 0x0000000000000068 ("h"?) 0x00007fffffffcc40│+0x0028: 0x0000000000000000 0x00007fffffffcc48│+0x0030: 0x0000000000070000 0x00007fffffffcc50│+0x0038: 0x0000000000000000 ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ──── 0x66f8e7 <N_BELE_RTP::LEPolicy::get32(void+0> mov rcx, QWORD PTR [rsp+0x8] 0x66f8ec <N_BELE_RTP::LEPolicy::get32(void+0> mov rdx, QWORD PTR [rsp] 0x66f8f0 <N_BELE_RTP::LEPolicy::get32(void+0> lea rsp, [rsp+0x98] → 0x66f8f8 <N_BELE_RTP::LEPolicy::get32(void+0> mov eax, DWORD PTR [rsi] 0x66f8fa <N_BELE_RTP::LEPolicy::get32(void+0> ret
0x66f8fb nop DWORD PTR [rax+rax*1+0x0] 0x66f900 <N_BELE_RTP::LEPolicy::get64(void+0> lea rsp, [rsp-0x98] 0x66f908 <N_BELE_RTP::LEPolicy::get64(void+0> mov QWORD PTR [rsp], rdx 0x66f90c <N_BELE_RTP::LEPolicy::get64(void+0> mov QWORD PTR [rsp+0x8], rcx ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:bele.h+164 ──── 159 } 160
161 inline unsigned get_le32(const void *p) 162 { 163 #if defined(ACC_UA_GET_LE32) → 164 return ACC_UA_GET_LE32§; 165 #else 166 return acc_ua_get_le32§; 167 #endif 168 } 169
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ──── [#0] Id 1, Name: "upx.out", stopped, reason: SIGSEGV ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ──── [#0] 0x66f8f8 → get_le32(p=0xa1fffd) [#1] 0x66f8f8 → N_BELE_RTP::LEPolicy::get32(this=0x9ed3c0 <N_BELE_RTP::le_policy>, p=0xa1fffd) [#2] 0x51249b → Packer::get_te32(this=0xa00030, p=0xa1fffd) [#3] 0x51249b → PackLinuxElf32::elf_lookup(this=0xa00030, name=0x6cdffe “JNI_OnLoad”) [#4] 0x529509 → PackLinuxElf32::PackLinuxElf32help1(this=0xa00030, f=0x7fffffffce10) [#5] 0x52c65e → PackLinuxElf32Le::PackLinuxElf32Le(f=0x7fffffffce10, this=0xa00030) [#6] 0x52c65e → PackLinuxElf32x86::PackLinuxElf32x86(f=0x7fffffffce10, this=0xa00030) [#7] 0x52c65e → PackBSDElf32x86::PackBSDElf32x86(f=0x7fffffffce10, this=0xa00030) [#8] 0x52c65e → PackFreeBSDElf32x86::PackFreeBSDElf32x86(this=0xa00030, f=0x7fffffffce10) [#9] 0x60448c → PackMaster::visitAllPackers(func=0x602c30 <try_unpack(Packer*, void*)>, f=0x7fffffffce10, o=0x7fffffffcfc8, user=0x7fffffffce10) ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── gef➤ bt #0 0x000000000066f8f8 in get_le32 (p=0xa1fffd) at bele.h:164 #1 N_BELE_RTP::LEPolicy::get32 (this=0x9ed3c0 <N_BELE_RTP::le_policy>, p=0xa1fffd) at bele_policy.h:192 #2 0x000000000051249b in Packer::get_te32 (this=0xa00030, p=0xa1fffd) at packer.h:296 #3 PackLinuxElf32::elf_lookup (this=0xa00030, name=0x6cdffe “JNI_OnLoad”) at p_lx_elf.cpp:5382 #4 0x0000000000529509 in PackLinuxElf32::PackLinuxElf32help1 (this=this@entry=0xa00030, f=f@entry=0x7fffffffce10) at p_lx_elf.cpp:315 #5 0x000000000052c65e in PackLinuxElf32Le::PackLinuxElf32Le (f=0x7fffffffce10, this=0xa00030) at p_lx_elf.h:395 #6 PackLinuxElf32x86::PackLinuxElf32x86 (f=0x7fffffffce10, this=0xa00030) at p_lx_elf.cpp:4800 #7 PackBSDElf32x86::PackBSDElf32x86 (f=0x7fffffffce10, this=0xa00030) at p_lx_elf.cpp:4817 #8 PackFreeBSDElf32x86::PackFreeBSDElf32x86 (this=0xa00030, f=0x7fffffffce10) at p_lx_elf.cpp:4828 #9 0x000000000060448c in PackMaster::visitAllPackers (func=0x602c30 <try_unpack(Packer*, void*)>, f=0x7fffffffce10, o=0x7fffffffcfc8, user=0x7fffffffce10) at packmast.cpp:190 #10 0x00000000006072ca in PackMaster::getUnpacker (f=<optimized out>) at packmast.cpp:248 #11 PackMaster::unpack (this=0x7fffffffcfb0, fo=0x7fffffffcee0) at packmast.cpp:266 #12 0x0000000000670dc5 in do_one_file (iname=iname@entry=0x7fffffffdf15 "id:000089,sig:11,src:001286,op:MOpt-core-havoc,rep:2", oname=oname@entry=0x7fffffffd550 “/dev/null”) at work.cpp:160 #13 0x000000000067157c in do_files (i=i@entry=0x4, argc=0x5, argv=0x7fffffffdac8) at work.cpp:271 #14 0x00000000004056a1 in main (argc=0x5, argv=0x7fffffffdac8) at main.cpp:1538

Deferencing a generic poniter ‘p’ trigger the overflow.

gef➤ p *p Attempt to dereference a generic pointer. gef➤ p p $1 = (const void *) 0xa1fffd

Essentially, the problem is caused in PackLinuxElf32::elf_lookup() at p_lx_elf.cpp:5382

do if (0==((h ^ get_te32(hp))>>1)) { unsigned st_name = get_te32(&dsp->st_name); char const *const p = get_str_name(st_name, (unsigned)-1); if (0==strcmp(name, p)) { return dsp; } } while (++dsp, 0==(1u& get_te32(hp++)));

Several locations will also trigger vulnerabilities:
PackLinuxElf32::elf_lookup() at p_lx_elf.cpp:5368

unsigned const w = get_te32(&bitmask[(n_bitmask -1) & (h>>5)]);

PackLinuxElf64::elf_lookup() at p_lx_elf.cpp:5404

for (si= get_te32(&buckets[m]); 0!=si; si= get_te32(&chains[si]))

PackLinuxElf32::elf_lookup() at p_lx_elf.cpp:5349

for (si= get_te32(&buckets[m]); 0!=si; si= get_te32(&chains[si])) { char const *const p= get_dynsym_name(si, (unsigned)-1); if (0==strcmp(name, p)) { return &dynsym[si]; } }

What should have happened?

Decompress a crafted/suspicious file.

Do you have an idea for a solution?

We are very grateful to @jreiser for patching the bucket in p_lx_elf.cpp in the issue 365. However, in fact, all places involving get_te32 () should be strengthened in upx, especially in p_lx_elf.cpp. The four positions we reported should be patched at least:

  1. p_lx_elf.cpp:5382
  2. p_lx_elf.cpp:5368
  3. p_lx_elf.cpp:5404
  4. p_lx_elf.cpp:5349

How can we reproduce the issue?

  1. compile upx with address-sanitize
  2. execute cmd

upx.out -df $PoC -o /dev/null

p_lx_elf.cpp:5382
Poc can be found here.

p_lx_elf.cpp:5368
Poc can be found here.

p_lx_elf.cpp:5404
Poc can be found here.

p_lx_elf.cpp:5349
Poc can be found here.

Please tell us details about your environment.

  • UPX version used (upx --version):

upx 4.0.0-git-c6b9e3c62d15 (latest-devel-branch) UCL data compression library 1.03 zlib data compression library 1.2.8 LZMA SDK version 4.43

  • Host Operating System and version:
    Ubuntu 16.04 64-bit
  • Host CPU architecture:
    Intel® Core™ i5-6200U CPU @ 2.30GHz with 8GB
  • Target Operating System and version:
    same as Host
  • Target CPU architecture:
    same as Host

CVE: Latest News

CVE-2023-50976: Transactions API Authorization by oleiman · Pull Request #14969 · redpanda-data/redpanda
CVE-2023-6905
CVE-2023-6903
CVE-2023-6904
CVE-2023-3907