# Lista 9 (6 maja 2021) ###### tags: `ask21` `ćwiczenia` `kba` ## Deklaracje Gotowość rozwiązania zadania należy wyrazić poprzez postawienie X w odpowiedniej kolumnie! Jeśli pożądasz zreferować dane zadanie (co najwyżej jedno!) w trakcie dyskusji oznacz je znakiem ==X== na żółtym tle. **UWAGA: Tabelkę wolno edytować tylko wtedy, gdy jest na zielonym tle!** :::danger | | 1 | 2 | 3 | 4 | 5 | 6 | 7(2) | | ---------------------:| --- | --- | --- | --- | --- | --- | ---- | | Andriy Bernad | X | X | | | X | | | 3 | Wojciech Bogucki | X | X | X | X | | | X | 6 | Michał Doros | X | X | X | X | X | X | X | 8 | Marko Golovko | | | | | | | | 0 | Magdalena Jarecka | X | X | | | X | | X | 5 | Szymon Jędras | X |==X==| X | X | X | | | 5 | Heorhii Karpenko | X |==X==| | | X | | | 3 | Szymon Kosakowski | | X | X | X | X | | | 4 | Izabella Kozioł | | | | | | | | 0 | Franciszek Malinka | X | X | X | X | X | |==X== | 7 | Filip Pazera | | X | X | X | X | | | 4 | Franciszek Pindel | X | X | X | X | X | X | X | 8 | Kacper Puchalski | | X | X | | X | | | 3 | Kacper Solecki | X | X | X | X | X | | | 5 | Andrzej Tkaczyk | X | X | X | X | X | | | 5 | Łukasz Wasilewski | | X | X | | | | | 2 | Vladyslav Yablonskyi | X | X | | | X | | | 3 | Adam Zyzik |~~X~~| X | X | | | | | 1 (1 punkt karny) ::: ## Zadanie 1 :::success Autor: Adam Zyzik ::: ```c= int relo3(int val) { switch (val) { case 100: return val; case 101: return val + 1; case 103: case 104: return val + 3; case 105: return val + 5; case 106: return val + 10; default: return val + 6; } } ``` Kompilujemy z flagami `-static -fno-pic -O1`, żeby wyniki były bardziej zrozumiałe. > `objdump -d relo3.o` ```= relo3.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <relo3>: 0: f3 0f 1e fa endbr64 4: 8d 47 9c lea -0x64(%rdi),%eax 7: 83 f8 06 cmp $0x6,%eax a: 77 20 ja 2c <relo3+0x2c> c: 89 c0 mov %eax,%eax e: 3e ff 24 c5 00 00 00 notrack jmpq *0x0(,%rax,8) 15: 00 16: b8 66 00 00 00 mov $0x66,%eax 1b: c3 retq 1c: 8d 47 03 lea 0x3(%rdi),%eax 1f: c3 retq 20: b8 6e 00 00 00 mov $0x6e,%eax 25: c3 retq 26: b8 74 00 00 00 mov $0x74,%eax 2b: c3 retq 2c: 8d 47 06 lea 0x6(%rdi),%eax 2f: c3 retq 30: 89 f8 mov %edi,%eax 32: c3 retq ``` W sekcji `.text` pod adresem `0x12` chcemy mieć adres tablicy skoków, czyli adres sekcji `.rodata`. Tablicę skoków chcemy uzupełnić offsetami sekcji `.text`. > `objdump -r relo3.o` ``` relo3.o: file format elf64-x86-64 RELOCATION RECORDS FOR [.text]: OFFSET TYPE VALUE 0000000000000012 R_X86_64_32S .rodata RELOCATION RECORDS FOR [.rodata]: OFFSET TYPE VALUE 0000000000000000 R_X86_64_64 .text+0x0000000000000030 0000000000000008 R_X86_64_64 .text+0x0000000000000016 0000000000000010 R_X86_64_64 .text+0x000000000000002c 0000000000000018 R_X86_64_64 .text+0x000000000000001c 0000000000000020 R_X86_64_64 .text+0x000000000000001c 0000000000000028 R_X86_64_64 .text+0x0000000000000020 0000000000000030 R_X86_64_64 .text+0x0000000000000026 RELOCATION RECORDS FOR [.eh_frame]: OFFSET TYPE VALUE 0000000000000020 R_X86_64_PC32 .text ``` ~~Jeżeli procedura relo3 (a więc i sekcja `.text`) została umieszczona pod adresem `0x1000`, to tablicę skoków należy uzupełnić wartościami z tablicy rekordów realokacji z podmienionym `.text` na `0x1000`.~~ ~~Np. pierwszy adres -- `0x1030`.~~ ~~W sekcji `.text` pod adresem `0x12` znajdować się będzie adres `0x2000`.~~ ## Zadanie 2 :::success Autor: Szymon Jędras ::: ![](https://i.imgur.com/G6AElt8.png) #### Dekorowanie nazw (ang. name mangling) technika stosowana przez kompilatory w celu wygenerowania unikatowych nazw funkcji, struktur, klas oraz innych typów danych. #### Przekształcone sygnatury funkcji: ``` _Z4funcPKcRi -> func(char const*, int&) _Z - zawsze dodawane 4 - długość nazwy funkcji func - nazwa funkcji P - pointer K - const c - char R - reference i - int _ZN3Bar3bazEPc -> Bar::baz(char*) _Z - zawsze dodawane N - namespace/klasa 3 - długość nazwy namespace-u/klasy Bar - nazwa namespace-u/klasy 3 - długość nazwy funkcji baz - nazwa funkcji E - sygnalizator że ostatnia nazwa była nazwą funkcji/teraz będą argumenty P - pointer c - char _ZN3BarC1ERKS_ -> Bar::Bar(Bar const&) _Z - zawsze dodawane N - namespace/klasa 3 - długość nazwy namespace-u/klasy Bar - nazwa namespace-u/klasy C1 - sygnalizator konstruktora z pełną konstrukcją obiektu, (complete object constructor) E - zaczynają się argumenty R - reference K - const S_ - argument typu klasy (Bar) _ZN3foo6strlenER6string -> foo::strlen(string&) _Z - zawsze dodawane N - namespace/klasa 3 - długość nazwy namespace-u/klasy foo - nazwa namespace-u/klasy 6 - długość nazwy funkcji strlen - nazwa funkcji E - sygnalizator że ostatnia nazwa była nazwą funkcji/teraz będą argumenty R - reference 6 - długość nazwy typu string - nazwa typu ``` #### Które elementy składni podlegają dekorowaniu? nazwy funkcji, właściwości argumentów (ref, const, pointer,...), typy argumentów, nazwy klas, nazwy namespace-ów, szablony, argumenty szablonowe, modyfikatory (const). Dekorowaniu nie podlegają typ wyniku, nazwy argumentów, modyfikatory (static, constexpr, noexcept, virtual, override) #### Czy funkcja dekorująca jest różnowartościowa? Nie, ponieważ na sygnaturę nie wpływa np. typ zwracany. ## Zadanie 3 :::success Autor: Wojciech Bogucki ::: **Przepełnienie bufora** (ang. buffer overflow) Błąd programistyczny polegający na zapisaniu do wyznaczonego obszaru pamięci (bufora) większej ilości danych niż zarezerwował na ten cel programista. Taka sytuacja prowadzi do zamazania danych znajdujących się w pamięci bezpośrednio za buforem, a w rezultacie do błędnego działania programu. Gdy dane, które wpisywane są do bufora, podlegają kontroli osoby o potencjalnie wrogich intencjach, może dojść do nadpisania struktur kontrolnych programu w taki sposób, by zaczął on wykonywać operacje określone przez atakującego. **Programowanie zorientowane na powroty** (ang. return-oriented programming) Technika wykorzystująca lukę w zabezpieczeniach komputera , która umożliwia atakującemu wykonanie kodu w obecności zabezpieczeń, takich jak ochrona przestrzeni wykonywalnej i podpisywanie kodu . W tej technice atakujący przejmuje kontrolę nad stosem wywołań w celu przejęcia przepływu sterowania programem, a następnie wykonuje starannie wybrane sekwencje instrukcji maszynowych , które są już obecne w pamięci maszyny, zwane „gadżetami”. Każdy gadżet zwykle kończy się instrukcją powrotu i znajduje się w podprogramie w ramach istniejącego programu i / lub kodu biblioteki współdzielonej. Połączone ze sobą gadżety umożliwiają atakującemu wykonywanie dowolnych operacji na maszynie wykorzystującej mechanizmy obronne, które udaremniają prostsze ataki. Wyszukujemy adresów `gadget` i jakiegoś wywołania `syscall` ``` $ objdump -d ropex | grep gadget 0000000000400bf3 <gadget>: ``` ``` $ objdump -d ropex | grep syscall 40127c: 0f 05 syscall ``` czyli w porządku little-endian będzie: * f3 0b 40 00 * 7c 12 40 00 Zmieniamy w pliku ropex.in.txt fragmenty `baad f00d` na znalezione adresy. Po wywołaniu funkcji, po tym jak na wejsciu podamy `ropex.in` pojawi się nyancat. Można sprawdzić, ze przed wywołaniem funkcji `readline` adres powrotu jest dobry, ale po nim juz został zmieniony na `gadget`. Instrukcja `lea 0x10(%rsp),%rdi` wydobywa nam adres `/usr/bin/nyancat` hexadecymalnie, a pozniej daje go jako parametr do `syscall`. ## Zadanie 4 :::success Autor: Filip Pazera ::: ![](https://i.imgur.com/aIoQii8.png) **kanarek** - specjalna wartość umieszczana na stosie. Jeżeli w trakcie wykonywania procedury ulegnie zmianie, wiemy, że nastąpiło uszkodzenie stosu. **uszkodzenie stosu** - nadpisanie zawartości stosu w niekontrolowany sposób, np. poprzez przepełnienie bufora. Po włączeniu opcji `-fstack-protector` widzimy, że uszkodzenie stosu jest już wykrywane: ``` $ ./ropex ropex.in ��ޭ��ޭ��ޭ��ޭ��ޭ��ޭ��ޭ��ޭ��ޭ��ޭ��ޭ��ޭ��ޭ��g@ *** stack smashing detected ***: terminated Aborted (core dumped) ``` **randomizacja rozkładu przestrzeni adresowej** - technika obrony przed atakami wykorzystującymi przepełnienie bufora. Polega na umieszczaniu sekcji programu, stosu i sterty pod losowymi adresami za każdym uruchomieniem programu. Utrudnia to atakującemu przewidzenie pozycji interesujących go instrukcji. **gadżet** - krótki fragment kodu programu zakończony instrukcją `ret`. Złożenie kilku gadżetów umożliwia wykonanie wielu instrukcji z rzędu. Wykorzystywany między innymi w atakach ROP. Aby włączyć randomizację w `gdb` można użyć instrukcji: `>>> set disable-randomization off` Po włączeniu opcji `-z noexestack` widzimy, że stos nie jest wykonywalny: ``` $ pmap `pidof ropex` ... 00007ffe6cb5b000 132K rw--- [ stack ] ... ``` ## Zadanie 5 :::info Autor: Michał Doros ::: ```c= .globl foobar #sprawia, że symbol jest widoczny dla linkera .type foobar, @function #ustawienie typu symbolu foobar: // .LFB0: // .cfi_startproc // pushq %rbp // .cfi_def_cfa_offset 16 // .cfi_offset 6, -16 // movq %rsp, %rbp // .cfi_def_cfa_register 6 // movl $5, %eax // popq %rbp // .cfi_def_cfa 7, 8 // ret // .cfi_endproc // .LFE0: .size foobar, .-foobar #ustawienie rozmiaru symbolu, -foobar oblicza odległość do labela foobar ``` ```c= .section .rodata .align 16 .type baz, @object #ustawienie typu symbolu .size baz, 24 #ustawienie rozmiaru symbolu baz: .ascii "abc" #przyjmuje string .zero 1 #wypełnienie zerami .long 42 #przyjmuje 4 bajtową liczbę .quad -3 #przyjmuje 8 bajtową liczbę .long 1068827777 #przyjmuje 4 bajtową liczbę .zero 4 #wypełnianie zerami .text .globl main .type main, @function ``` ```c= .globl array .bss .align 32 #wyrównuje sekcje do 32 .type array, @object .size array, 800 array: .zero 800 .text .globl main .type main, @function ``` ## Zadanie 6 :::success Autor: Franciszek Pindel ::: > Jądro systemu Linux nie potrafi samodzielnie załadować do pamięci pliku wykonywalnego skonsolidowanego dynamicznie. Musi o to poprosić konsolidator dynamiczny opisany w podręczniku systemowym ld.so(8). Na podstawie ld.elf_so(1) opisz proces ładowania pliku pliku wykonywalnego «/bin/sleep» do pamięci. Wyświetl jego sekcję «.dynamic» i wskaż pliki konfiguracyjne na podstawie których konsolidator odnajdzie na dysku bibliotekę «libc.so.6». Wykonaj polecenie «LD_DEBUG=all /bin/sleep 1». Wskaż w wydruku proces wyszukiwania i ładowania bibliotek, wiązania symboli (ang. symbol resolution) w trakcie ładowania programu i po jego uruchomieniu. - konsolidator dynamiczny - program ładujący plik elf używający bibliotek dynamicznych i odnajdujący potrzebne odwołania - wiązanie symboli - proces skojarzania odwołań z odpowiednimi symbolami z zewnętrznych bibliotek 1. Jądro ładuje `/bin/sleep`, zamiast je uruchomić, przekazuje kontrole konsolidatorowi dynamicznemu (poprawka: jądro ładuje konsolidator określony w nagłówku `/bin/sleep` - sekcja `.init`, który ładuje potrzebne biblioteki i uruchamia `/bin/sleep`) 3. Na podstawie sekcji dynamic odbywa się odnajdywanie potrzebnych plików 4. Odbywa się relokacja odwołań do symboli 5. Następuje inizjalizacja i przekazanie kontroli programowi `/bin/sleep` ``` $ readelf -d /bin/sleep Dynamic section at offset 0x8c78 contains 27 entries: Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] ``` Pliki konfiguracyjne z ścieżkami ``` $ cat /etc/ld.so.conf include /etc/ld.so.conf.d/*.conf $ cat /etc/ls.so.conf.d/x86_64-linux-gnu.conf # Multiarch support /usr/local/lib/x86_64-linux-gnu /lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu ``` ``` ... 74890: symbol=__vdso_getcpu; lookup in file=linux-vdso.so.1 [0] 74890: binding file linux-vdso.so.1 [0] to linux-vdso.so.1 [0]: normal symbol `__vdso_getcpu' [LINUX_2.6] 74890: symbol=__vdso_clock_getres; lookup in file=linux-vdso.so.1 [0] 74890: binding file linux-vdso.so.1 [0] to linux-vdso.so.1 [0]: normal symbol `__vdso_clock_getres' [LINUX_2.6] 74890: 74890: file=libc.so.6 [0]; needed by /bin/sleep [0] 74890: find library=libc.so.6 [0]; searching 74890: search cache=/etc/ld.so.cache 74890: trying file=/lib/x86_64-linux-gnu/libc.so.6 ... 75008: symbol=malloc; lookup in file=/bin/sleep [0] 75008: symbol=malloc; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0] 75008: binding file /bin/sleep [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `malloc' [GLIBC_2.2.5] ... 74890: calling init: /lib/x86_64-linux-gnu/libc.so.6 74890: 74890: 74890: initialize program: /bin/sleep 74890: 74890: 74890: transferring control: /bin/sleep 74890: 74890: symbol=_dl_find_dso_for_object; lookup in file=/bin/sleep [0] 74890: symbol=_dl_find_dso_for_object; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0] 74890: symbol=_dl_find_dso_for_object; lookup in file=/lib64/ld-linux-x86-64.so.2 [0] 74890: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib64/ld-linux-x86-64.so.2 [0]: normal symbol `_dl_find_dso_for_object' [GLIBC_PRIVATE] ``` ## Zadanie 7 :::success Autor: Franciszek Malinka ::: **Kod relokowalny** - po angielsku PIC, Position-Independent Code, to część kodu, który nie potrzebuje wykonania relokacji. Można kompilator poprosić o wygenerowanie takiego kodu używając flagi `-fpic`. **Leniwe wiązanie** - rozwiązywanie adresu procedury w kodzie relokowalnym dopiero w momencie, kiedy wołamy ją poraz pierwszy. Użyteczne np. korzystając z bibliotek współdzielonych. W momencie uruchomienia programu nie wiemy w jakim miejscu w pamięci znajdują się funkcje z tych bibliotek, więc konsolidator dynamiczny wskaże to miejsce dopiero w run-time. Aby leniwe wiązanie mogło się udać potrzebne nam są dwie dodatkowe sekcje: **.got** (*global offset table*) oraz **.plt** (*procedure linkage table*). W sekcji `.got` znajduje się tablica 8-bajtowych elementów, w których utrzymywane są adresy na odpowiednie miejsca bibliotek współdzieonych czy do zmiennych globalnych (to jest konieczne, jeśli chcemy żeby wszystkie relokacje zostały rozwiązane w momencie kompilacji). W tablicy `GOT` pod adresem 0 znajduje się adres sekcji `.dynamic` (potrzebny konsolidatorowi dynamicznemu), pod adresem znajduje się adres tablicy relokacji, pod adresem 2 znajduje się adres linkerda dynamicznego, a pod następnymi znajdują się (początkowo takie "mock" adresy) adresy do procedur z bibliotek współdzielonych. Kompilator kompilując kod który ma być `PIC` generuje dla każdego elementu z `GOT` relo entry, po to, żeby konsolidator dynamiczny wiedział gdzie ma rozwiązywać potrzebne adresy. Sekcja `.plt` składa się z tablicy 16-bajtowych **wykonywalnych** elementów, które są regułkami leniwego rozwiązywania adresów współdzielonych bibliotek (dlatego jest tylko do odczytu). W sekcji .dynamic znajdują się informacje dla konsolidatora dynamicznego. Dokładny opis jak wyglądają te informacje można [znaleźć tutaj](https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-42444.html). Dla przykadu, sekcja `.dynamic` programu `lazy`: ![](https://i.imgur.com/skK515l.png) Wpisy w tej sekcji mają postać `tag:int`. `tag` to tak naprawdę informacja o tym jak należy interpretować to co znajduje się w `int`. Dla przykładu, `tag = 1` oznacza, że w `int` jest informacja o bibliotece współdzielonej potrzebnej naszemu programowi. Przykład: Dajmy na to, że mamy kod który korzysta ze współdzielonej biblioteki `libvector.so`. Początkowo w tablicy `GOT` pod adresami potrzebnych nam procedur znajdują się adresy do odpowiednich wpisów w tablicy `PLT`. Jeżeli program (podczas run-time) pierszy raz wywoła którąś funkcję z biblioteki współdzielonej, to na podstawie `GOT` wskoczy (dzięki skokowi pośredniemu) do `PLT`, która następnie przekieruje flow programu do konsolidatora dynamicznego, który zmieni wpis w tablicy `GOT` na faktyczny adres potrzebnej nam procedury, po czym odda sterowanie spowrotem naszemu procesowi. Teraz, przy następnych wywołaniach procedury, w tablicy `GOT` będzie się znajdował jej faktyczny adres, więc od razu będziemy już mogli do niej przechodzić. ![](https://i.imgur.com/QPiuKfk.png) Oryginalny opis krok po kroku co tu się dzieje: ![](https://i.imgur.com/Rgclgpe.png) Przy każdych następnych wywołaniach funkcji `addvec` tabica `GOT` będzie juz zaktualizowana, i proces wołania tej procedury będzie znacznie krótszy: ![](https://i.imgur.com/RaihGTy.png)