Zaproszenie na Confidence 2018

Drugi post z rzędu z zaproszeniem na konferencje – tym razem krakowski Confidence 2018 🙂 Jestem szczerze przekonany, że eventu nie trzeba nikomu przedstawiać – jest to jedna z najstarszych i najpopularniejszych konferencji poświęconych bezpieczeństwu IT, odbywająca się regularnie na przełomie maja i czerwca (w tym roku: 04 – 05.06.2018).

Co? Jak? Dlaczego?

Wśród prelegentów pojawią się uznane marki z takich gigantów jak jak: Mozilla, Microsoft czy Positive Technologies – reprezentowane przez Michała PurzyńskiegoAdama “pi3” ZabrockiegoIdo Naora oraz Maxima Goryachy’ego. Również znalazłem się w gronie prelegentów i opowiem o autorskim systemie “Cloudfuzz”, który pomógł mi w znalezieniu prawie 400 błędów w oprogramowaniu open-source – część z nich została opisana na blogu 🙂

Moja roadmapa konferencji

Swoją obecność zaplanowałem na następujących sesjach – aczkolwiek lista może się zmienić:

Nie pozostaje mi nic innego jak życzyć owocnej konferencji i do zobaczenia w Krakowie! 🙂

Zaproszenie na SECURE Early Bird 2018

Dla każdego, kto chce poczuć przedsmak jesiennej edycji SECURE 2018, CERT Polska / NASK przygotował jednodniowe wydarzenie w nieco luźniejszym stylu – SECURE Early Bird 2018. Odbędzie się ono 23 maja w warszawskim centrum konferencyjnym Adgar Plaza – event jest całkowicie za darmo!

Zapowiedź ze strony:

SECURE Early Bird to nasza wiosenna jaskółka, krótki zwiastun jesiennej konferencji SECURE 2018. Przygotowaliśmy dla Was solidną porcję eksperckiej wiedzy w pigułce – konkretne problemy i propozycje technicznych rozwiązań od osób na co dzień zajmujących się walką z zagrożeniami.
I to całkowicie za darmo!

Kogo będzie można spotkać?

Prelegentami będą: Carsten Willems z VMRay, Jarek Jedynak z Google, Tomek Bukowski z Banku Millenium oraz ja jako reprezentacja CERT.PL.

W swojej prezentacji opowiem o różnych błędach (część z nich opisywałem na blogu) znalezionych we wszelakiej maści narzędziach analitycznych (lub bibliotekach) użytecznych przy analizie malware. Wiele podatności to bardzo podstawowe błędy, które, chyba tylko z pomocą promieniowania kosmicznego znalazły się w kodzie źródłowym 🙂

Program

  • Carsten Willems – Countering Innovative Sandbox Evasion Techniques Used by Malware
  • Jarek Jedynak – mquery, czyli jak znaleźć malware w morzu próbek. Indeksowanie i wyszukiwanie złośliwego oprogramowania
  • Kamil Frankowicz – Niebezpieczne przygody podczas analizy binarek – trochę o fuckupach narzędzi analitycznych
  • Tomek Bukowski – TBA

Zapraszam do rejestracji i do zobaczenia! 🙂

 

pwnable.kr – fenomenalna platforma do nauki exploitacji & CTF

Ostatnio dużo czasu spędzam na rozwiązywaniu zadań z CTF i praktykowaniu różnych metod exploitacji. Jeden z moich współpracowników (dzięki Mateusz!) polecił mi pwnable.kr jako ciekawe uzupełnienie kursu Modern Binary Exploitation z którego korzystałem (i bardzo polecam 🙂 ).

Platforma zachęca do siebie 64 zadaniami o czterech poziomach trudności oraz prawie 16000 użytkowników – niestety większość z nich “wymięka” po pierwszym lub drugim zadaniu (jeżeli Czytelniku będziesz chciał zrobić to samo polecam przeczytanie tego posta Ivana Fratrica).

Aby usprawnić zdobywanie wiedzy Czytelników jak i swoje postanowiłem stworzyć repozytorium z opisami rozwiązań zadań. Na chwilę pisania posta zawiera ono jedynie notatki z czterech zadań, lecz założyłem sobie, że po każdym rozwiązanym przeze mnie zadaniu będę coś wrzucał od siebie na GitHuba. Każdy PR oraz issue mile widziane 🙂

PS. Jeżeli Czytelniku przemawia do Ciebie bardziej forma wideo to polecam kanał YT LiveOverflow oraz blog.

Ponce – Symbolic Execution dla “klikaczy”

Osobiście lubię “zwalać” pracę na mój procesor. Zwłaszcza nudne i powtarzalne czynności bo często w nich strzelam babole, które skutkują jeszcze większymi błędami na wyjściu. Fajnym dodatkiem do tego wszystkiego jest sensowna “klikalność” rozwiązania – sensowność rozumiem w ten sposób, że czynność mogę zautomatyzować za pomocą trzech kliklnięć a nie trzydziestu trzech.

Wszystkie wymienione wyżej warunki spełnia Ponce, czyli plugin do IDA’y pozwalający wyklikać sobie zadane zmienne symbolic execution / taint analysis i rozwiązać odpowiednio skonstruowane równanie. W moim mniemaniu jest to bardzo fajne narzędzie do wszelakich zadań CTF które dają się rozwiązać w prosty sposób a brakuje czasu aby to zrobić 🙂

W tym poście przedstawię rozwiązanie zadania rozgrzewkowego RE, z wrześniowego CTF Ekoparty za pomocą Ponce.

Rozwiązanie zadania

Od ogranizatorów otrzymujemy statycznie skompilowaną pod x64 binarkę ELF:

a@b:~/Desktop$ file warmup 
warmup: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=b9e93849cf9889813b7f88f5b7a0609df69bbf48, stripped

Zadanie jest klasycznym problemem do rozwiązania za pomocą symbolic execution – poniżej długi listing zdekompilowanej funkcji:

signed __int64 sub_4009D8()
{
  signed __int64 result; // rax@29

  if ( unk_6CCD62 == aO[0] )
  {
    if ( unk_6CCD72 == a_[0] )
    {
      if ( unk_6CCD6D == aU[0] )
      {
        if ( unk_6CCD67 == aT[0] )
        {
          if ( unk_6CCD69 == a1[0] )
          {
            if ( unk_6CCD63 == asc_4A1725[0] )
            {
              if ( unk_6CCD6C == aJ[0] )
              {
                if ( unk_6CCD65 == aS_0[0] )
                {
                  if ( unk_6CCD68 == asc_4A172B[0] )
                  {
                    if ( unk_6CCD64 == a1[0] )
                    {
                      if ( unk_6CCD6A == aS_0[0] )
                      {
                        if ( unk_6CCD6B == a_[0] )
                        {
                          if ( unk_6CCD66 == a_[0] )
                          {
                            if ( unk_6CCD7A == a_[0] )
                            {
                              if ( unk_6CCD6E == a5[0] )
                              {
                                if ( unk_6CCD6F == aT[0] )
                                {
                                  if ( unk_6CCD70 == a_[0] )
                                  {
                                    if ( unk_6CCD71 == off_4A1731 )
                                    {
                                      if ( unk_6CCD61 == BYTE2(off_4A1731) )
                                      {
                                        if ( unk_6CCD73 == unk_4A1735 )
                                        {
                                          if ( unk_6CCD74 == off_4A1731 )
                                          {
                                            if ( unk_6CCD75 == unk_4A1737 )
                                            {
                                              if ( unk_6CCD76 == unk_4A1739 )
                                              {
                                                if ( unk_6CCD77 == a_[0] )
                                                {
                                                  if ( unk_6CCD78 == aU[0] )
                                                  {
                                                    if ( unk_6CCD79 == off_4A173B )
                                                    {
                                                      if ( unk_6CCD60 == BYTE2(off_4A173B) )
                                                      {
                                                        if ( unk_6CCD7B == unk_4A173F )
                                                        {
                                                          sub_4101B0("valid!");
                                                          result = 1LL;
                                                        }
                                                        else
                                                        {
                                                          result = 0LL;
                                                        }
                                                      }
                                                      else
                                                      {
                                                        result = 0LL;
                                                      }
                                                    }
                                                    else
                                                    {
                                                      result = 0LL;
                                                    }
                                                  }
                                                  else
                                                  {
                                                    result = 0LL;
                                                  }
                                                }
                                                else
                                                {
                                                  result = 0LL;
                                                }
                                              }
                                              else
                                              {
                                                result = 0LL;
                                              }
                                            }
                                            else
                                            {
                                              result = 0LL;
                                            }
                                          }
                                          else
                                          {
                                            result = 0LL;
                                          }
                                        }
                                        else
                                        {
                                          result = 0LL;
                                        }
                                      }
                                      else
                                      {
                                        result = 0LL;
                                      }
                                    }
                                    else
                                    {
                                      result = 0LL;
                                    }
                                  }
                                  else
                                  {
                                    result = 0LL;
                                  }
                                }
                                else
                                {
                                  result = 0LL;
                                }
                              }
                              else
                              {
                                result = 0LL;
                              }
                            }
                            else
                            {
                              result = 0LL;
                            }
                          }
                          else
                          {
                            result = 0LL;
                          }
                        }
                        else
                        {
                          result = 0LL;
                        }
                      }
                      else
                      {
                        result = 0LL;
                      }
                    }
                    else
                    {
                      result = 0LL;
                    }
                  }
                  else
                  {
                    result = 0LL;
                  }
                }
                else
                {
                  result = 0LL;
                }
              }
              else
              {
                result = 0LL;
              }
            }
            else
            {
              result = 0LL;
            }
          }
          else
          {
            result = 0LL;
          }
        }
        else
        {
          result = 0LL;
        }
      }
      else
      {
        result = 0LL;
      }
    }
    else
    {
      result = 0LL;
    }
  }
  else
  {
    result = 0LL;
  }
  return result;
}

Naszym zadaniem jest zlokalizowanie bufora wejściowego i oznaczenie go jako symbolizowanej pamięci. Można to zrobić w prosty sposób, wpisując dowolną wartość i lokalizując ją w pamięci na początku wykonania funkcji sprawdzającej. W moim przypadku inputem będzie EKO{AAAAAAAAAAAAAAAAAAAAAAA}.

Znaleziony bufor rezyduje w pamięci pod adresem 0x06CCD60. Taki adres, wraz z rozmiarem bufora (26) wpisujemy w okienku dialogowym Ponce po wybraniu opcji “Symbolize Memory” (pomarańczowa strzałka, czerwona pokazuje log z Ponce):

Po wskazaniu Ponce co nas interesuje, przechodzimy do dalszego wykonania naszego zadania. Ponce zaznacza na grafie symbolizowane odwołania do pamięci na jasnozielono, wraz z komentarzem.

Ostatnim krokiem jest wyklikanie rozwiązania solvera SMT (i tak do ostatniego znaku flagi 😉 ). W moim wypadku klikam prawym przyciskiem myszy na warunek jaki musi być spełniony, aby przejść do interesującego mnie brancha (czerwona strzałka) i wybieram opcję: SMT -> Solve formula:

W okienku Output pojawią się rozwiązania zadanego równania (na screenie rozwiązanie dla literki “O” z flagi):

Klikając tak kilkanaście razy i składając literki do kupy, naszym oczom ukaże się rozwiązanie zadania: EKO{1s_th1s_ju5t_4_w4rm_up?}.

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 🙂