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 😉
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)
Commit naprawiający: 658aec6227a61b848f66b004ebd16fadcf24b5e7
CVE: CVE-2016-1000290
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"
Commit naprawiający: cfbfe09cc64c3682779c6ba1b7932aa8d4b3c5c9
CVE: CVE-2016-1000291