d33tah's weblog

jogger.pl, bez komentarza

Tak tylko chciałem zauważyć, że według strony głównej jogger.pl, od 48 godzin nie było tu żadnego komentarza.


( 7 komentarzy )

"Poor people don’t plan long-term."

At one chain I was required to sign a contract stating that I was an at-will employee, that I would be part-time with no benefits, and that if I took another job without permission I would be subject to termination because the company expected me to be able to come in whenever they found it necessary. And yes, this is legal.

http://www.theguardian.com/society/2014/sep/21/linda-tirado-poverty-hand-to-mouth-extract?CMP=fb_gu


( 3 komentarze )

...ale czemu Madzia?

...Schodzę na chwilę na dół, rodzice siedzą przy telewizorze. Wiadomości. Tyle w tym kraju potencjalnie ciekawych, istotnych społecznie rzeczy się dzieje, a ja słyszę o tym, że jakiemuś gościowi zmarła w wypadku najbliższa rodzina, a teraz prokuratura podejrzewa, że to on do tego doprowadził. A ja się zastanawiam - w jaki sposób mnie to dotyczy, czemu jako Szary Obywatel miałoby mnie to obchodzić? Czy tego typu newsy mają zaspakajać moją potrzebę "rozrywki", mam się poczuć gorzej przez moją znieczulicę? A może znowu jest coś, od czego trzeba odciągnąć moją uwagę, kolejna podwyżka podatków, jak za czasów Madzi?

Przy okazji, Tool - Vicarious, z tekstem w temacie:


( 5 komentarzy )

"Hacking: Art of Exploitation" - pierwsze eksperymenty

Ostatnio mój znajomy żalił mi się, że jest już po dwudziestce, a jeszcze nie napisał żadnego exploita. Trochę mnie to rozbawiło, bo przecież jeszcze sporo czasu mu zostało ;). Chciałem go jednak przekonać (a przy okazji sam się upewnić), że faktycznie nie jest to jakaś tajemna wiedza i sam mechanizm dość łatwo zrozumieć. Postanowiłem, że wypróbuję w końcu podstawy wykorzystywania błędów pamięci i spróbuję napisać prosty program, który łączy się z danym serwerem, pobiera od niego dane i wykonuje je jako kod maszynowy. Dodatkowo, chciałem obyć się bez korzystania z dokumentacji w internecie. Na samym początku przekonałem się, że schemat nawiązywania połączeń TCP w POSIX jest dość skomplikowany i mógłbym mieć duże trudności gdyby nie program "strace" oraz komenda "LC_ALL=C man 3 getaddrinfo" (w polskiej wersji jest dużo słabiej). W końcu, napisałem taki, raczej pokraczny kod:

  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <netdb.h>
  4. #include <stdlib.h>
  5. #include <errno.h>
  6. #include <sys/mman.h>
  7. #include <unistd.h>
  8.  
  9. int main()
  10. {
  11.         void (*f)(void);
  12.         char buf[4096];
  13.         int fd = socket(AF_INET, SOCK_STREAM, 0);
  14.         struct addrinfo* sa = malloc(sizeof(struct addrinfo));
  15.         sa->ai_family = AF_INET;
  16.         sa->ai_flags = 0;
  17.         sa->ai_socktype = SOCK_STREAM;
  18.         sa->ai_protocol = 0;
  19.  
  20.         printf("%d\n", getaddrinfo("localhost", "31337",  NULL, &sa));
  21.  
  22.         sa->ai_addr->sa_family = AF_INET;
  23.  
  24.         printf("%d\n", connect(fd, sa->ai_addr, sa->ai_addrlen));
  25.         perror("connect");
  26.         read(fd, buf, sizeof(buf));
  27.         printf("%s\n", buf);
  28.         f = buf;
  29.         f();
  30. }

Rozumiejąc, co sugeruje mi GCC sypiąc warningami, zignorowałem jego ostrzeżenia i przeszedłem do pisania prostego payloadu. Wymyśliłem sobie, że dość łatwo będzie zauważyć, kiedy program po prostu zakończy pracę, wracając do powłoki z wybranym przeze mnie kodem powrotnym. Napisałem i zdeasembowałem program w stylu "main(){exit(4);}" i przekonałem się, że z takiego kodu nie wyłowię interesujących mnie instrukcji. Pamiętałem, że kiedyś podałem konkretne instrukcje asemblera na tym blogu i jako, że byłem już znudzony tym, ile czasu bez pomocy internetu pisałem prostego klienta TCP w C, pozwoliłem sobie na małe "oszustwo" i zerknąłem do mojego bloga. Chwilę później miałem gotowy payload, który w asemblerze wyglądał tak:

  1. xor eax, eax
  2. inc eax ; eax=1 => exit(ebx)
  3. xor ebx, ebx
  4. inc ebx ; ebx=1 => exit(1)
  5. int 0x80

Przepuściłem go przez NASMa, otrzymałem kod maszynowy, stworzyłem Ncatem serwer, który go przekazuje klientowi... po czym otrzymałem "segmentation fault". Grzebiąc przez chwilę debuggerem nie dowiedziałem się, na czym polega problem i zwróciłem się pomoc do kanału #hackerspace-pl. Tam podsunęli mi następujące teorie:

  1. Wykonuję kod 32-bitowy na 64-bitowym procesorze,
  2. Mój system wymusza W^X,
  3. Z mojego bufora nie można wykonywać kodu.

Przy okazji w ten sposób odkryłem, że mój (i właściwie każdy inny) 64-bitowy procesor x86 nie odpali tak po prostu 32-bitowego payloadu w 64-bitowej aplikacji. Na szczęście po dopisaniu na początku kodu w asemblerze linijki "bits 64", wygenerowałem 64-bitową wersję mojego payloada... która także prowadziła do "segmentation fault". Zdecydowałem się więc sprawdzić, jakie uprawnienia ma pamięć. Uruchomiłem gdb, ustawiłem breakpoint przed wskoczeniem w bufor, po czym zczytałem /proc/`pgrep -f /tmp/test`/maps i wrzuciłem jego zawartość do napisanego na szybko (tak, wiem, brzydkiego) skryptu:

  1. #!/usr/bin/python
  2.  
  3. import sys
  4.  
  5. maps = """00400000-00401000 r-xp 00000000 00:20 256968                             /tmp/test
  6. 00600000-00601000 r--p 00000000 00:20 256968                             /tmp/test
  7. 00601000-00602000 rw-p 00001000 00:20 256968                             /tmp/test
  8. 3c38a00000-3c38a20000 r-xp 00000000 fd:00 1318992                        /usr/lib64/ld-2.18.so
  9. 3c38c1f000-3c38c20000 r--p 0001f000 fd:00 1318992                        /usr/lib64/ld-2.18.so
  10. 3c38c20000-3c38c21000 rw-p 00020000 fd:00 1318992                        /usr/lib64/ld-2.18.so
  11. 3c38c21000-3c38c22000 rw-p 00000000 00:00 0
  12. 3c38e00000-3c38fb4000 r-xp 00000000 fd:00 1325806                        /usr/lib64/libc-2.18.so
  13. 3c38fb4000-3c391b4000 ---p 001b4000 fd:00 1325806                        /usr/lib64/libc-2.18.so
  14. 3c391b4000-3c391b8000 r--p 001b4000 fd:00 1325806                        /usr/lib64/libc-2.18.so
  15. 3c391b8000-3c391ba000 rw-p 001b8000 fd:00 1325806                        /usr/lib64/libc-2.18.so
  16. 3c391ba000-3c391bf000 rw-p 00000000 00:00 0
  17. 7ffff7fbf000-7ffff7fc2000 rw-p 00000000 00:00 0
  18. 7ffff7ffc000-7ffff7ffd000 rw-p 00000000 00:00 0
  19. 7ffff7ffd000-7ffff7fff000 r-xp 00000000 00:00 0                          [vdso]
  20. 7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
  21. ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]""".split("\n")
  22.  
  23. addr = int(sys.argv[1],16)
  24. for line in maps:
  25.         start, end = map(lambda x: int(x, 16), line.split()[0].split('-'))
  26.         if start <= addr and end >= addr:
  27.                 print(line)

Moje obawy się potwierdziły - fragment pamięci, w którym był bufor, jest tylko do odczytu i zapisu. W moim rozumieniu tak napisany program nie jest więc raczej podatny na wykonywanie dowolnego kodu... postanowiłem go więc zmienić, zastępując linijkę "char buf[4096];" instrukcją "char * buf = mmap(0, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);". Oczywiście po drodze zrobiłem błąd i zamiast "-1, 0" napisałem "0, -1" i parę minut błądziłem po manualu do mmap. Gdy już byłem pewien, że mmap zadziałał, spróbowałem znowu i... "segmentation fault!". Zdesperowany eksperymentowałem z różnymi NOPami i innymi bezsensownymi pomysłami, po czym poddałem się i postanowiłem do tematu wrócić później.

Dwa dni później, zacząłem do programu dopisywać wykrywanie błędów i zauważyłem coś dziwnego... wywołanie read() mówi mi, że wczytano tylko 8 bajtów. Skróciłem mojego payloada do 8 bajtów i wykonał się on poprawnie. Chwilę później dotarło do mnie, że zapomniałem poprawić "sizeof(buf)" po zmianie typu zmiennej buf... Po poprawieniu błędu wszystko zaczęło działać poprawnie. Nie chciałem jednak na tym kończyć - zacząłem się zastanawiać, czy w 8 bajtach mógłbym zrobić odpowiednik wywołania "exit(4)". Po paru nieudanych eksperymentach zadałem to pytanie na #hackerspace-pl, usłyszałem, że nie ma co na to liczyć bez założenia z góry co może się znajdować w rejestrach procesora. Zostałem też pokierowany, żeby wypróbować instrukcje w stylu "mov bl, 4", która mieści się w dwóch bajtach.

Znowu zajrzałem w program debuggerem i sprawdziłem zawartość rejestrów zaraz po wskoczeniu w bufor. Wyglądało na to, że EAX zawiera adres bufora, ale ebx jest puste. Sprawdziłem więc taki kod:

  1. bits 64
  2. xor eax, eax
  3. inc eax
  4. mov bh, 4
  5. int 0x80

Uruchomiłem NASMa, zerknąłem na wynikową binarkę... miała dokładnie 8 bajtów - tyle co potrzeba. Wychodzi więc na to, że tyle wystarczy by wykonać to, co chciałem. Na sam koniec zerknąłem jeszcze do logów kernela:

[12879.929065] test[12681]: segfault at 7fc3fe494000 ip 00007fc3fe493fff sp 00007fffcfdf4620 error 15

W przypadku debuggowania tajemniczego "segmentation fault", może nas zainteresować numer znajdujący się po słowie "error". Przy dekodowaniu go, warto zerknąć do tutaj.


( Dodaj komentarz )

Wcześniejsze wpisy

Kategorie

Profile

Sponsorowane

Wolna kultura - książki

Wolna kultura - muzyka