Yara 3.5.0 – Błędy Double Free oraz Integer Underflow

Yara jest narzędziem do wyszukiwania wzorców tekstowych oraz binarnych w plikach. Z racji na jej specyficzne “moce” jest używana głównie przez analityków malware, oraz firmy \ projekty zajmujące się bezpieczeństwem IT.

Z racji tego, że lubię wiedzieć czego używam, postanowiłem ją trochę pofuzzować za pomocą American Fuzzy Loop. Projekt czasowo “wstrzelił” się chwilę po wydaniu wersji 3.5.0 – wersji w której część kodu odpowiedzialna za parsowanie reguł YARA została zrefaktoryzowana. Jak się później okazało fuzzing + niedawna refaktoryzacja kodu to niezła kombinacja 😉

Double free podczas parsowania wyrażeń regularnych (CVE-2016-1000290)

Podczas parsowania tokenu /[NUL]/ w wyrażeniu regularnym, lexer interpretuje je jako “puste wyrażenie regularne”. Z racji tego, że lexer nie obsługiwał poprawnie tego typu sytuacji, tworzony było token z wartością yylval z poprzedniego tokenu wyrażenia regularnego (w przypadku payloadu jest to 0xdeadbeef). Podczas kończenia działania Yary następuje próba zwolnienia pamięci z adresu podanego “przed” tokenem /[NUL]/ i w rezultacie awaria programu.

Log z Valgrinda:

» valgrind yara segfault_deadbeef.yar strings
==4930== Memcheck, a memory error detector
==4930== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==4930== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==4930== Command: yara segfault_deadbeef.yar strings
==4930== 
segfault_deadbeef.yar(4): error: syntax error, unexpected _NUMBER_, expecting '='
segfault_deadbeef.yar(4): error: empty regular expression
==4930== Invalid free() / delete / delete[] / realloc()
==4930==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4930==    by 0x4B9A38: yara_yyparse (grammar.c:3796)
==4930==    by 0x425DCA: yr_lex_parse_rules_file (lexer.l:808)
==4930==    by 0x4031AD: main (yara.c:1104)
==4930==  Address 0xdeadbeef is not stack'd, malloc'd or (recently) free'd
==4930== 
==4930== 
==4930== HEAP SUMMARY:
==4930==     in use at exit: 0 bytes in 0 blocks
==4930==   total heap usage: 59 allocs, 60 frees, 853,729 bytes allocated
==4930== 
==4930== All heap blocks were freed -- no leaks are possible
==4930== 
==4930== For counts of detected and suppressed errors, rerun with: -v
==4930== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Błąd został wprowadzony w commicie: 11fd5e4784fa135cbdb64906cc628edb9e9d50ee

Payload (próba zwolnienia adresu 0xdeadbeef)

Issue #517 na GitHubie

Commit naprawiający: 658aec6227a61b848f66b004ebd16fadcf24b5e7

CVE: CVE-2016-1000290

Integer underflow – błędna obsługa importów (CVE-2016-1000291)

W sytuacji kiedy importujemy moduł “\x00”, nazwa importu jest przekazywana do funkcji yr_parser_reduce_import() w strukturze SIZED_STRING. Wartość pola length w strukturze jest ustawiona na 1, a c_string ma wartość “\x00”.

Następnie do funkcji yr_hash_table_lookup() przekazywany jest wskaźnik do pola c_string, gdzie sprawdzana jest jego długość za pomocą strlen(), która zwraca długość stringa c_string równą 0 i przekazuje ją do funkcji yr_hash_table_lookup_raw_key().

To powoduje, że do funkcji yr_hash_table_lookup_raw_key() przekazany jest wskaźnik ze stringiem “\x00” i jego niewłaściwą długością równą 0. Następnie funkcja hash() odejmuje 1 od długości, celem znalezienia wartości w tablicy byte_to_int32, co powoduje błąd integer underflow.

Log z Valgrinda:

» valgrind yara exploit_min.yar strings
==3981== Memcheck, a memory error detector
==3981== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==3981== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==3981== Command: yara exploit_min.yar strings
==3981== 
==3981== Use of uninitialised value of size 8
==3981==    at 0x4069FE: yr_hash_table_lookup_raw_key (in /usr/local/bin/yara)
==3981==    by 0x433AB0: yr_parser_reduce_import (in /usr/local/bin/yara)
==3981==    by 0x4270AA: yara_yyparse (in /usr/local/bin/yara)
==3981==    by 0x409BD9: yr_lex_parse_rules_file (in /usr/local/bin/yara)
==3981==    by 0x402E53: main (in /usr/local/bin/yara)
==3981== 
==3981== Invalid read of size 1
==3981==    at 0x4069F0: yr_hash_table_lookup_raw_key (in /usr/local/bin/yara)
==3981==    by 0x433AB0: yr_parser_reduce_import (in /usr/local/bin/yara)
==3981==    by 0x4270AA: yara_yyparse (in /usr/local/bin/yara)
==3981==    by 0x409BD9: yr_lex_parse_rules_file (in /usr/local/bin/yara)
==3981==    by 0x402E53: main (in /usr/local/bin/yara)
==3981==  Address 0x5ec339d is 0 bytes after a block of size 13 alloc'd
==3981==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3981==    by 0x408302: yara_yylex (in /usr/local/bin/yara)
==3981==    by 0x426AD2: yara_yyparse (in /usr/local/bin/yara)
==3981==    by 0x409BD9: yr_lex_parse_rules_file (in /usr/local/bin/yara)
==3981==    by 0x402E53: main (in /usr/local/bin/yara)
==3981== 
==3981== 
==3981== Process terminating with default action of signal 11 (SIGSEGV)
==3981==  Access not within mapped region at address 0x6188000
==3981==    at 0x4069F0: yr_hash_table_lookup_raw_key (in /usr/local/bin/yara)
==3981==    by 0x433AB0: yr_parser_reduce_import (in /usr/local/bin/yara)
==3981==    by 0x4270AA: yara_yyparse (in /usr/local/bin/yara)
==3981==    by 0x409BD9: yr_lex_parse_rules_file (in /usr/local/bin/yara)
==3981==    by 0x402E53: main (in /usr/local/bin/yara)
==3981==  If you believe this happened as a result of a stack
==3981==  overflow in your program's main thread (unlikely but
==3981==  possible), you can try to increase the size of the
==3981==  main thread stack using the --main-stacksize= flag.
==3981==  The main thread stack size used in this run was 8388608.
==3981== 
==3981== HEAP SUMMARY:
==3981==     in use at exit: 852,295 bytes in 73 blocks
==3981==   total heap usage: 1,686 allocs, 1,613 frees, 1,176,251 bytes allocated
==3981== 
==3981== LEAK SUMMARY:
==3981==    definitely lost: 0 bytes in 0 blocks
==3981==    indirectly lost: 0 bytes in 0 blocks
==3981==      possibly lost: 0 bytes in 0 blocks
==3981==    still reachable: 852,295 bytes in 73 blocks
==3981==         suppressed: 0 bytes in 0 blocks
==3981== Rerun with --leak-check=full to see details of leaked memory
==3981== 
==3981== For counts of detected and suppressed errors, rerun with: -v
==3981== Use --track-origins=yes to see where uninitialised values come from
==3981== ERROR SUMMARY: 2903143 errors from 2 contexts (suppressed: 0 from 0)
fish: “valgrind yara exploit_min.yar s…” terminated by signal SIGSEGV (Address boundary error)

Log z ASAN:

==39208==ERROR: AddressSanitizer: heap-buffer-overflow on address
0x60200000ef9d at pc 0x0000004f2b43 bp 0x7ffd78dd6cf0 sp 0x7ffd78dd6ce8
READ of size 1 at 0x60200000ef9d thread T0
    #0 0x4f2b42  (/usr/local/bin/yara+0x4f2b42)
    #1 0x4f2de4  (/usr/local/bin/yara+0x4f2de4)
    #2 0x551737  (/usr/local/bin/yara+0x551737)
    #3 0x533210  (/usr/local/bin/yara+0x533210)
    #4 0x4fb7fa  (/usr/local/bin/yara+0x4fb7fa)
    #5 0x4ee8dc  (/usr/local/bin/yara+0x4ee8dc)
    #6 0x7f34280aa82f  (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #7 0x419b68  (/usr/local/bin/yara+0x419b68)

0x60200000ef9d is located 0 bytes to the right of 13-byte region
[0x60200000ef90,0x60200000ef9d)
allocated by thread T0 here:
    #0 0x4b9c98  (/usr/local/bin/yara+0x4b9c98)
    #1 0x4f6300  (/usr/local/bin/yara+0x4f6300)
    #2 0x53102f  (/usr/local/bin/yara+0x53102f)
    #3 0x4fb7fa  (/usr/local/bin/yara+0x4fb7fa)
    #4 0x4ee8dc  (/usr/local/bin/yara+0x4ee8dc)
    #5 0x7f34280aa82f  (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

SUMMARY: AddressSanitizer: heap-buffer-overflow
(/usr/local/bin/yara+0x4f2b42)
Shadow bytes around the buggy address:
  0x0c047fff9da0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9db0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9dc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9dd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9de0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c047fff9df0: fa fa 00[05]fa fa 00 fa fa fa 00 00 fa fa 06 fa
  0x0c047fff9e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e40: 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
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==39208==ABORTING

Payload:

import "\x00"

Issue #516 na GitHubie

Commit naprawiający: cfbfe09cc64c3682779c6ba1b7932aa8d4b3c5c9

CVE: CVE-2016-1000291

Zasoby dodatkowe