\[ \definecolor{data}{RGB}{18,110,213} \definecolor{unknown}{RGB}{217,86,16} \definecolor{learned}{RGB}{175,114,176} \]

Bugs, bugs, bugs...

Bugs everywhere!

Kamil Frankowicz

$whoami

Kamil Frankowicz

  • IT Security Specialist @ CERT.pl
  • Bughunting + analiza podatności
  • Analiza malware + RE
  • Fan fuzzingu i wszelakich przepełnień (stack, heap)
  • Ostatnie 3 miesiące - 72 podatności w różnych projektach open source
  • frankowicz.me

Agenda

  • Wiele podatności różnej klasy
    • Routery SOHO
    • Narzędzia używane przeze mnie na codzień
    • Złośliwe chochliki w Internecie
  • Narzędzia + tips & tricks

Low hanging fruits

Routery SOHO - dosyć duży problem...

Routery SOHO - dosyć duży problem...

Z tym sprzętem od kilku lat wiąże się sporo problemów:

  • Podmiana DNS - 2014 (w PL)
  • Tunelowanie ruchu operacji fraudowych - 2015+
  • Ransomware IoT - 2015+
  • Botnety IoT (Mirai i następcy) - 2016+
  • Brak nacisku na bezpieczeństwo (plaga w branży) i krótki support producenta lub telkomu

Stack buffer overflow - routery UPC

Stack buffer overflow - routery UPC

  • Technicolor TC7200 & Thomson TWG870
  • Wystarczyło ~180 bajtów URI do ataku
  • Urządzenie czyściło swoje logi, wyłączało WiFi oraz ochronę przed IP Floodingiem
  • Dodatkowo brak ochrony przed CSRF umożliwiał zdalny restart routera
  • Znalezione za pomocą fuzzera HTTP z Metasploita
  • Do dzisiaj TWG870 jest podatny (!!!)

Stack buffer overflow - routery UPC

http://192.168.0.1/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Dump rejestrów po ataku:

[--- snip! ---]
r16/s0 =41414141 r17/s1 =41414141 r18/s2 =41414141 r19/s3 =41414141
r20/s4 =828070fc r21/s5 =8280ab68 r22/s6 =8280ab38 r23/s7 =00000000
r24/t8 =00000000 r25/t9 =00000000 r26/k0 =41414141 r27/k1 =41414141
r28/gp =817b2e80 r29/sp =8280a8c0 r30/fp =8280ab38 r31/ra =41414141
PC : 0x41414141 error addr: 0x41414140
cause: 0x00000008 status: 0x1000ff03

Stack buffer overflow - routery UPC

Backdoor & other stuff - D-Link DWR

Backdoor & other stuff - D-Link DWR

  • Rodzina urządzeń D-Link DWR oraz inne pracujące pod kontrolą softu firmy Amit Network
  • Konto o nazwie guest bez hasła, za to z uprawnieniami admina :-)
  • Brak ochrony przed atakami CSRF - możliwa zdalna rekonfiguracja urządzenia
  • Ręczne "dłubanie" w IDA - na szczęście binarka httpd była skompilowana z symbolami :-)

PoC - Zmiana DNS za pomocą backdoora

Narzędzia na codzień

Projekty używane w security też mają błędy :-)

Projekty & narzędzia ITSec

  • "Szewc bez butów chodzi"
  • Świetny target - często duża powierzchnia ataku oraz interesujący profit
  • Jeżeli jest ktoś na sali kto przed załadowaniem pliku do IDA Pro \ r2 pomyślał o jakichkolwiek konsekwencjach niech pierwszy rzuci kamień ;-)
  • Temat poruszał j00ru w swojej prezentacji na Secure 2014 - “Ucieczka z Matrixa: (nie)bezpieczna analiza malware”

Yara + AFL

Yara

  • VT: "The pattern matching swiss knife"
  • Idealny cel do fuzzingu:
    • Skomplikowany "codebase" parsera
    • Bardzo szybka (nawet z ASAN)
    • Masa gotowych reguł w Internecie
    • Wykorzystywany przez wiele firm w swoich produktach
  • Łącznie 4 błędy związane z obsługą pamięci

Yara #1 - Integer Underflow

  • Payload: import "\x00"
  • Następstwo nieostrożnej refaktoryzacji
  • Niewłaściwa długość stringa zwracana z funkcji:
YR_API void* yr_hash_table_lookup(
    YR_HASH_TABLE* table,
    const char* key,
    const char* ns)
{
  return yr_hash_table_lookup_raw_key(
      table,
      (void*) key,
      strlen(key),
      ns);
}

Yara #1 - Integer Underflow

  • Bardzo mnie cieszy jak widzę w pętlach "len - 1" :-)
  • Zmienna len = 0
  • Następnie wykorzystywana w pętli poszukującej wartość w tablicy:
uint32_t hash(uint32_t seed, const void* buffer, size_t len)
{
  const uint8_t* b = (uint8_t*) buffer;
  uint32_t result = seed;
  size_t i;

  for (i = len - 1; i > 0; i--)
  {
    result ^= ROTATE_INT32(byte_to_int32[*b], i);
    b++;
  }
}

Yara #2 - Use-After-Free

  • Jako argument funkcji strcmp() uprzednio zwolniony string na heapie
  • Podatności UAF "najłatwiej" znaleźć za pomocą fuzzingu (w tym wypadku AFL + 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)

Yara #2 - Use-After-Free + ASAN

ASAN <3 UAFs

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

radare2 (r2)

  • "Opensource'owa IDA w terminalu"
  • W CERT zawsze testujemy "następców" IDA Pro :-)
  • 20+ rozpoznawanych formatów plików (33 zestawy instrukcji CPU)
  • Duży i skomplikowany codebase - ale wolę go bardziej niż Yarę
  • Deweloperzy utrzymują repozytorium z plikami testowymi - niski próg wejścia

radare2 - Use-After-Free

  • Podatna funkcja ustalająca konwencję wywołania funkcji w analizowanej binarce
  • Nieszczęśliwie funkcja jest używana przez wszystkie formaty wejściowe (możliwość triggerowania błędu na wiele sposobów)
  • Crash spowodowany za pomocą skompilowanej klasy Javy (i z takim PoC zgłoszony)
  • Cieszy bardzo szybka reakcja deweloperów: niecałe 24h do załatania błędu

radare2 - Use-After-Free + 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
    #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

W Internetach również mało bezpiecznie

O parserach w dużych projektach

Parsery JS w przeglądarkach

  • Mało doceniany wektor ataku na użytkownika
    • Wyparte przez malwertrising i luki w Flash Player
  • W sieci nie da się żyć bez JS
  • Należy pamiętać, że w pamięci przeglądarki często leżą wrażliwe informacje
  • Sporo problemów w tej kwestii miał ostatnio MS Edge - 10 bugów zgłoszonych przez Project Zero w parserze JS
  • Prewencyjnie polecam uMatrix lub NoScript

Webkit JSCore #1 - Out of bounds read

  • JSON.parse(new Proxy([undefined], {})); wystarczyło do naruszenia pamięci przeglądarki
  • Problem związany z różną wartością (w zależności od kontekstu) zwracaną z funkcji serializującej
  • Następnie wartość ta używana w funkcji konkatenującej stringi = odczyt poza zaalokowaną pamięcią
  • Do znalezienia błędu wykorzystany fuzzer wraz ze słownikiem

Webkit JSCore #1 - Out of bounds read

Subtelne różnice w serializacji (Standard ECMAScript):

  • JSON.stringify({ value: undefined }); -> "{}"
  • JSON.stringify([undefined]); -> "[null]"

Do czasu znalezienia błędu, niestety w tej kwestii brak zgodności ze standardem.

Webkit JSCore #2 - Out of bounds read

  • function test(){return JSON.stringify(new Proxy([00._],{}))==0}(test())
  • Błąd w parserze tokenów przetworzonych przez lexer (analiza leksykalna)
  • Niektóre tokeny słów kluczowych błędnie interpretowane jako "unary tokens"
  • Efekt: Odczyt błędnej ilości pamięci podczas parsowania
  • Również wykorzystany fuzzer wraz ze słownikiem

PCRE2 - Stack Buffer Overflow

  • Używana m.in w Apache, PHP, KDE, Postfix czy Nmapie
  • Przepełnienie następowało po przekazaniu niewłaściwego inputu z wyłączoną walidacją UTF-8
  • Walidację UTF-8 można wyłączyć w payloadzie
  • Bajty niezgodne z UTF-8 powodowały złe obliczenie kopiowanego bufora
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 */
}

Jak szukać, żeby znaleźć?

Narzędzia oraz protipy

Narzędzia - Fuzzery

Główni gracze:

  • American Fuzzy Loop (AFL)
  • LibFuzzer (LLVM)
  • Hongfuzz
  • CERT-CC Basic Fuzzing Framework
  • Peach Fuzzer Framework (komercyjny)

Narzędzia - Analiza crashy

  • IDA Pro + HexRays
  • Valgrind
  • GDB
    • Exploitable Plugin
  • ASAN, MSAN, UBSAN
  • WinDBG

Narzędzia - Analiza crashy

  • IDA Pro + HexRays
  • Valgrind
  • GDB
    • Exploitable Plugin
  • ASAN, MSAN, UBSAN
  • WinDBG

Tips & tricks #1

  • Mało kodu - code review
  • Dużo kodu - zazwyczaj fuzzing
  • Przypadki testowe - idźmy w "szerokość" a nie ilość
  • Minimalny rozmiar test case'ów
  • Wykorzystajmy poprzednie podatności
  • Wykorzystajmy kolejkę z poprzedniej iteracji fuzzingu

Tips & tricks #2

  • Czasem warto wykorzystać dane testowe z innych programów, jeżeli testujemy podobne komponenty
  • Wykorzystanie ASAN, MSAN, UBSAN
  • Przed przystąpnieniem do analizy zalecam rzucić okiem na bug tracker \ repozytorium i poszukać "zapomnianych" lub najczęściej łatanych komponentów
  • Twitter jest bardzo dobrym źródłem informacji i materiałów o fuzzingu

Tips & tricks #3

  • [AFL] Warto dać szansę i przez pierwsze 48h fuzzować z przełącznikiem "-d" (Quick and Dirty mode)
  • [AFL] Po skończeniu iteracji fuzzingu, ze znalezionymi crashami, dobrym zwyczajem jest minimalizacja crashy i uruchomienie ich w trybie "Crash Exploration" - przełącznik "-C"

Zbiór materiałów dt. fuzzingu



frankowicz.me/bsides2016

Web cert.pl
Web frankowicz.me
Mail kamil.frankowicz@cert.pl
Twitter @fumfel