Tomasz Woszczyński
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
# Architektury systemów komputerowych - rozbrajanie bomby W tej notatce opiszę jak przebiegało rozbrajanie bomby w moim przypadku, na pewno nie jest to najskuteczniejsze (ani najmądrzejsze) podejście, ale udało mi się rozwiązać wszystkie fazy, włącznie z ukrytą, także może mi się uda kogoś naprowadzić na sensowne rozwiązanie. Na samym początku przygotowałem sobie zbiór plików `txt` z wydrukami deasemblowanych funkcji kolejnych faz, który powiększał się w trakcie rozbrajania (np. gdy natrafiałem na funkcje używane w kolejnych fazach), posłużyło mi do tego polecenie: ``` objdump -d bomb | awk -F"\n" -v RS="\n\n" '$1 ~/nazwa_funkcji/' > nazwa_funkcji.txt ``` Dzięki temu przed rozpoczęciem zadania wiedziałem, jakich inputów oczekują kolejne fazy, co znacznie przyspieszyło moje działanie. Do łatwiejszego debugowania użyłem [GDB Dashboard](https://github.com/cyrus-and/gdb-dashboard) wspomnianego na SKOSie, dzięki temu mamy podgląd rejestrów, flag, stosu, części kodu itp. bez wpisywania żadnych dodatkowych komend, dzięki czemu wszystko przebiega znacznie szybciej. Rozwiązania kolejnych faz warto zapisywać do jakiegoś pliku `txt`, a następnie po uruchomieniu `gdb` z bombą wpisujemy `set args nazwapliku.txt`, aby niepotrzebnie nie wpisywać wcześniejszych rozwiązań przy każdym uruchomieniu programu. ## Faza pierwsza Wydruk objdump: ``` 0000000000001405 <phase_1>: 1405: 48 83 ec 08 sub $0x8,%rsp 1409: 48 8d 35 3c 1d 00 00 lea 0x1d3c(%rip),%rsi # 314c <_IO_stdin_used+0x14c> 1410: e8 54 04 00 00 callq 1869 <strings_not_equal> 1415: 85 c0 test %eax,%eax 1417: 75 05 jne 141e <phase_1+0x19> 1419: 48 83 c4 08 add $0x8,%rsp 141d: c3 retq 141e: e8 52 05 00 00 callq 1975 <explode_bomb> 1423: eb f4 jmp 1419 <phase_1+0x14> ``` Widzimy, że porównywane są dwa stringi (`<strings_not_equal>`), w razie gdy są różne od siebie, następuje skok do instrukcji `<explode_bomb>`, a więc musimy tego uniknąć. String ten musi znajdować się w pamięci programu, więc poniższym poleceniem możemy podejrzeć, jakie znajdują się w bombie, a następnie poszukamy najbardziej wyróżniającego się. ``` strings bomb ``` Jest ich dosyć dużo, ale nas interesują te "sensowne", część z nich znajduje się tutaj: ``` That's number 2. Keep going! Halfway there! Good work! On to the next... Welcome to my fiendish little bomb. You have 6 phases with which to blow yourself up. Have a nice day! Phase 1 defused. How about the next one? So you got that one. Try this one. Public speaking is very easy. oilers maduiersnfotvbylWow! You've defused the secret stage! So you think you can stop the bomb with ctrl-c, do you? Curses, you've found the secret phase! But finding it and solving it are quite different... Congratulations! You've defused the bomb! Well... OK. :-) ``` Moją uwagę najbardziej przykuły te trzy: ``` Public speaking is very easy. oilers maduiersnfotvbyl ``` A więc próbujemy po kolei je wpisywać, okazuje się, że pierwszy string jest poprawny, a więc przechodzimy do następnej fazy! ## Faza druga Wydruk objdump: ``` 0000000000001425 <phase_2>: 1425: 55 push %rbp 1426: 53 push %rbx 1427: 48 83 ec 28 sub $0x28,%rsp 142b: 48 89 e6 mov %rsp,%rsi 142e: e8 68 05 00 00 callq 199b <read_six_numbers> 1433: 83 3c 24 01 cmpl $0x1,(%rsp) 1437: 75 09 jne 1442 <phase_2+0x1d> 1439: 48 89 e3 mov %rsp,%rbx 143c: 48 8d 6b 14 lea 0x14(%rbx),%rbp 1440: eb 15 jmp 1457 <phase_2+0x32> 1442: e8 2e 05 00 00 callq 1975 <explode_bomb> 1447: eb f0 jmp 1439 <phase_2+0x14> 1449: e8 27 05 00 00 callq 1975 <explode_bomb> 144e: 48 83 c3 04 add $0x4,%rbx 1452: 48 39 eb cmp %rbp,%rbx 1455: 74 0b je 1462 <phase_2+0x3d> 1457: 8b 03 mov (%rbx),%eax 1459: 01 c0 add %eax,%eax 145b: 39 43 04 cmp %eax,0x4(%rbx) 145e: 74 ee je 144e <phase_2+0x29> 1460: eb e7 jmp 1449 <phase_2+0x24> 1462: 48 83 c4 28 add $0x28,%rsp 1466: 5b pop %rbx 1467: 5d pop %rbp 1468: c3 retq ``` Pierwszą rzeczą, jaka rzuca się w oczy, jest wywołanie funkcji `<read_six_numbers>` - jej nazwa mówi sama za siebie. Po wczytaniu sześciu liczb (całkowitych) `a b c d e f` przechodzimy do kolejnych instrukcji: trafiamy na `cmpl $0x1,(%rsp)` - porównujemy naszą pierwszą liczbę `a` z wartością `0x1`, gdy nie są one równe, bomba wybucha. Wiemy więc, że nasz ciąg musi zaczynać się od wartości `0x1`, aby ominąć pierwszy warunek. Przechodzimy więc dalej, do instrukcji o adresie `0x1457`, a więc do `mov (%rbx), %eax`, a następnie do `add %eax, %eax`. Pierwsza z nich przypisuje wartość z rejestru `%rbx` do `%eax`, a druga dodaje do siebie `%eax` (a więc mnoży wartość `%eax` przez 2). Następnie porównywana jest uzyskana wartość po pomnożeniu z `0x4(%rbx)` i w razie równości idziemy na początek pętli do adresu `0x144e`. Można łatwo wywnioskować, że skoro przy każdym wywołaniu mnożymy wartość przez 2, a pierwszą z nich jest 1, to będziemy mieli do czynienia z ciągiem geometrycznym `1 2 4 8 16 32`, który przeniesie nas do fazy trzeciej! ## Faza trzecia Wydruk objdump: ``` 0000000000001469 <phase_3>: 1469: 48 83 ec 18 sub $0x18,%rsp 146d: 48 8d 4c 24 08 lea 0x8(%rsp),%rcx 1472: 48 8d 54 24 0c lea 0xc(%rsp),%rdx 1477: 48 8d 35 69 1e 00 00 lea 0x1e69(%rip),%rsi # 32e7 <array.3195+0x147> 147e: b8 00 00 00 00 mov $0x0,%eax 1483: e8 a8 fc ff ff callq 1130 <__isoc99_sscanf@plt> 1488: 83 f8 01 cmp $0x1,%eax 148b: 7e 1f jle 14ac <phase_3+0x43> 148d: 83 7c 24 0c 07 cmpl $0x7,0xc(%rsp) 1492: 0f 87 8b 00 00 00 ja 1523 <phase_3+0xba> 1498: 8b 44 24 0c mov 0xc(%rsp),%eax 149c: 48 8d 15 dd 1c 00 00 lea 0x1cdd(%rip),%rdx # 3180 <_IO_stdin_used+0x180> 14a3: 48 63 04 82 movslq (%rdx,%rax,4),%rax 14a7: 48 01 d0 add %rdx,%rax 14aa: ff e0 jmpq *%rax 14ac: e8 c4 04 00 00 callq 1975 <explode_bomb> 14b1: eb da jmp 148d <phase_3+0x24> 14b3: b8 ce 02 00 00 mov $0x2ce,%eax 14b8: eb 05 jmp 14bf <phase_3+0x56> 14ba: b8 00 00 00 00 mov $0x0,%eax 14bf: 2d e2 03 00 00 sub $0x3e2,%eax 14c4: 05 bf 03 00 00 add $0x3bf,%eax 14c9: 2d 24 03 00 00 sub $0x324,%eax 14ce: 05 24 03 00 00 add $0x324,%eax 14d3: 2d 24 03 00 00 sub $0x324,%eax 14d8: 05 24 03 00 00 add $0x324,%eax 14dd: 2d 24 03 00 00 sub $0x324,%eax 14e2: 83 7c 24 0c 05 cmpl $0x5,0xc(%rsp) 14e7: 7f 06 jg 14ef <phase_3+0x86> 14e9: 39 44 24 08 cmp %eax,0x8(%rsp) 14ed: 74 05 je 14f4 <phase_3+0x8b> 14ef: e8 81 04 00 00 callq 1975 <explode_bomb> 14f4: 48 83 c4 18 add $0x18,%rsp 14f8: c3 retq 14f9: b8 00 00 00 00 mov $0x0,%eax 14fe: eb c4 jmp 14c4 <phase_3+0x5b> 1500: b8 00 00 00 00 mov $0x0,%eax 1505: eb c2 jmp 14c9 <phase_3+0x60> 1507: b8 00 00 00 00 mov $0x0,%eax 150c: eb c0 jmp 14ce <phase_3+0x65> 150e: b8 00 00 00 00 mov $0x0,%eax 1513: eb be jmp 14d3 <phase_3+0x6a> 1515: b8 00 00 00 00 mov $0x0,%eax 151a: eb bc jmp 14d8 <phase_3+0x6f> 151c: b8 00 00 00 00 mov $0x0,%eax 1521: eb ba jmp 14dd <phase_3+0x74> 1523: e8 4d 04 00 00 callq 1975 <explode_bomb> 1528: b8 00 00 00 00 mov $0x0,%eax 152d: eb b3 jmp 14e2 <phase_3+0x79> ``` Tutaj dzieje się już troszkę więcej niż w dwóch poprzednich fazach. W komentarzu widnieje adres pamięci w tablicy (`32e7 <array.3195+0x147>`), jednak sam wydruk z objdump'a nic nam tutaj nie da. Musimy odpalić GDB i ustawiając breakpoint na `phase_3` wpisać cokolwiek (aby dostać się do fazy trzeciej). W miejscu tego komentarza pojawia się adres `0x5555555572e7`, warto więc sprawdzić co się tam znajduje, gdyż dwie instrukcje dalej wywoływana jest funkcja `sscanf`, która jako jeden z argumentów przyjmuje "styl" wejścia. Wiemy, że jest to string, a więc w GDB używamy polecenia: ``` >>> x/s 0x5555555572e7 0x5555555572e7: "%d %d" ``` Zwrócona wartość `"%d %d"` mówi o tym, że na wejściu przyjmowane są dwie liczby całkowite, więc możemy zacząć debugowanie od nowa (bo kto by się spodziewał, że akurat należy wpisać dwie liczby). Znów mamy porównanie wartości `$0x1`, więc nasz input będzie postaci `1 x`. Gdy drugi argument (ten `x`) jest zbyt duży, to nie przejdziemy późniejszych testów. Dość szybko rzucają się w oczy instrukcje: ``` 14ba: b8 00 00 00 00 mov $0x0,%eax 14bf: 2d e2 03 00 00 sub $0x3e2,%eax 14c4: 05 bf 03 00 00 add $0x3bf,%eax 14c9: 2d 24 03 00 00 sub $0x324,%eax 14ce: 05 24 03 00 00 add $0x324,%eax 14d3: 2d 24 03 00 00 sub $0x324,%eax 14d8: 05 24 03 00 00 add $0x324,%eax 14dd: 2d 24 03 00 00 sub $0x324,%eax ``` Postanowiłem obliczyć wartość `%eax` po wykonaniu ich, a więc szukamy rozwiązania następującego równania: `0 - a + b - c`, gdzie `a = 0x3e2 = 994`, `b = 0x3bf = 959`, `c = 0x324 = 804`. Wynikiem jest `-839`, wpisujemy to jako drugi argument i jesteśmy w kolejnej fazie! ## Faza czwarta Wydruk objdump: ``` 0000000000001567 <phase_4>: 1567: 48 83 ec 18 sub $0x18,%rsp 156b: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx 1570: 48 8d 54 24 08 lea 0x8(%rsp),%rdx 1575: 48 8d 35 6b 1d 00 00 lea 0x1d6b(%rip),%rsi # 32e7 <array.3195+0x147> 157c: b8 00 00 00 00 mov $0x0,%eax 1581: e8 aa fb ff ff callq 1130 <__isoc99_sscanf@plt> 1586: 83 f8 02 cmp $0x2,%eax 1589: 75 0c jne 1597 <phase_4+0x30> 158b: 8b 44 24 0c mov 0xc(%rsp),%eax 158f: 83 e8 02 sub $0x2,%eax 1592: 83 f8 02 cmp $0x2,%eax 1595: 76 05 jbe 159c <phase_4+0x35> 1597: e8 d9 03 00 00 callq 1975 <explode_bomb> 159c: 8b 74 24 0c mov 0xc(%rsp),%esi 15a0: bf 06 00 00 00 mov $0x6,%edi 15a5: e8 85 ff ff ff callq 152f <func4> 15aa: 39 44 24 08 cmp %eax,0x8(%rsp) 15ae: 75 05 jne 15b5 <phase_4+0x4e> 15b0: 48 83 c4 18 add $0x18,%rsp 15b4: c3 retq 15b5: e8 bb 03 00 00 callq 1975 <explode_bomb> 15ba: eb f4 jmp 15b0 <phase_4+0x49> ``` ``` 000000000000152f <func4>: 152f: b8 00 00 00 00 mov $0x0,%eax 1534: 85 ff test %edi,%edi 1536: 7e 2e jle 1566 <func4+0x37> 1538: 89 f0 mov %esi,%eax 153a: 83 ff 01 cmp $0x1,%edi 153d: 74 27 je 1566 <func4+0x37> 153f: 41 54 push %r12 1541: 55 push %rbp 1542: 53 push %rbx 1543: 41 89 f4 mov %esi,%r12d 1546: 89 fb mov %edi,%ebx 1548: 8d 7f ff lea -0x1(%rdi),%edi 154b: e8 df ff ff ff callq 152f <func4> 1550: 42 8d 2c 20 lea (%rax,%r12,1),%ebp 1554: 8d 7b fe lea -0x2(%rbx),%edi 1557: 44 89 e6 mov %r12d,%esi 155a: e8 d0 ff ff ff callq 152f <func4> 155f: 01 e8 add %ebp,%eax 1561: 5b pop %rbx 1562: 5d pop %rbp 1563: 41 5c pop %r12 1565: c3 retq 1566: c3 retq ``` Tutaj znów sprawdzamy co powinno znajdować się argumentach (tak samo jak w fazie trzeciej). Nie będę ukrywał, że tej fazy nie chciało mi się robić manualnie, ze względu na rekurencyjne wywołania w `func4`, dlatego napisałem skrypt sprawdzający wszystkie kombinacje dla dwóch liczb z przedziału od 1 do 1000: ```bash= #!/bin/bash > brute.txt # stworzenie lub wyczyszczenie zawartości pliku test() { out=$(./bomb psol.txt <<< "$1 $2") # uruchomienie bomby z argumentem i, j echo $out # wypisanie wszystkiego ze stdout } for ((i=0; i<1000;i++)) do for ((j=0; j<1000;j++)) do echo "i: $i j: $j $(test $i $j)" >> brute.txt # wypisujemy dane w postaci i: val_i j: val_j test_output # i zapisujemy je w nowej linijce brute.txt done done ``` Ostrzegam, że skrypt troszkę się wykonuje (u mnie było to około 40 minut) i plik wyjściowy zajmuje 223MB, ale spełnia swoją rolę. Mając już cały plik wyszukałem zapytaniem regex'owym wyrażenia `.*BOMB.*\n`, a więc każdej linijki, w której występuje słowo `BOMB` (pojawia się tylko przy nieudanym rozbrojeniu) i skasowałem otrzymane wyniki. Pozostałe otrzymane wartości to `40 2`, `60 3` oraz `80 3`. Z ciekawości odpaliłem breakpoint na tej fazie, aby zobaczyć czy na pewno wszystko dobrze przebiega, w pewnym momencie (po zakończeniu fazy) pokazał mi się kod źródłowy, a że nie przeglądałem go wcześniej, postanowiłem zdeasemblować funkcję `phase_defused`. ```c=94 input = read_line(); phase_4(input); phase_defused(); ``` ``` 0000000000001b20 <phase_defused>: 1b20: 83 3d 59 38 00 00 06 cmpl $0x6,0x3859(%rip) # 5380 <num_input_strings> 1b27: 74 01 je 1b2a <phase_defused+0xa> 1b29: c3 retq 1b2a: 48 83 ec 68 sub $0x68,%rsp 1b2e: 48 8d 4c 24 08 lea 0x8(%rsp),%rcx 1b33: 48 8d 54 24 0c lea 0xc(%rsp),%rdx 1b38: 4c 8d 44 24 10 lea 0x10(%rsp),%r8 1b3d: 48 8d 35 ed 17 00 00 lea 0x17ed(%rip),%rsi # 3331 <array.3195+0x191> 1b44: 48 8d 3d 65 3d 00 00 lea 0x3d65(%rip),%rdi # 58b0 <input_strings+0xf0> 1b4b: b8 00 00 00 00 mov $0x0,%eax 1b50: e8 db f5 ff ff callq 1130 <__isoc99_sscanf@plt> 1b55: 83 f8 03 cmp $0x3,%eax 1b58: 74 11 je 1b6b <phase_defused+0x4b> 1b5a: 48 8d 3d 0f 17 00 00 lea 0x170f(%rip),%rdi # 3270 <array.3195+0xd0> 1b61: e8 fa f4 ff ff callq 1060 <puts@plt> 1b66: 48 83 c4 68 add $0x68,%rsp 1b6a: c3 retq 1b6b: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi 1b70: 48 8d 35 c3 17 00 00 lea 0x17c3(%rip),%rsi # 333a <array.3195+0x19a> 1b77: e8 ed fc ff ff callq 1869 <strings_not_equal> 1b7c: 85 c0 test %eax,%eax 1b7e: 75 da jne 1b5a <phase_defused+0x3a> 1b80: 48 8d 3d 89 16 00 00 lea 0x1689(%rip),%rdi # 3210 <array.3195+0x70> 1b87: e8 d4 f4 ff ff callq 1060 <puts@plt> 1b8c: 48 8d 3d a5 16 00 00 lea 0x16a5(%rip),%rdi # 3238 <array.3195+0x98> 1b93: e8 c8 f4 ff ff callq 1060 <puts@plt> 1b98: b8 00 00 00 00 mov $0x0,%eax 1b9d: e8 d8 fb ff ff callq 177a <secret_phase> 1ba2: eb b6 jmp 1b5a <phase_defused+0x3a> ``` Okazało się, że to właśnie w tej funkcji zawarta jest funkcja `secret_phase`, do której rozwiązania przejdę później. Póki co interesuje nas to, że w jakiś sposób możemy do niej się dostać. Przeczytajmy więc kod źródłowy dołączony do zadania, będą nas interesować (o dziwo najbardziej) komentarze: ```c= /*************************************************************************** * Dr. Evil's Insidious Bomb, Version 1.1 * Copyright 2011, Dr. Evil Incorporated. All rights reserved. * * LICENSE: * * Dr. Evil Incorporated (the PERPETRATOR) hereby grants you (the * VICTIM) explicit permission to use this bomb (the BOMB). This is a * time limited license, which expires on the death of the VICTIM. * The PERPETRATOR takes no responsibility for damage, frustration, * insanity, bug-eyes, carpal-tunnel syndrome, loss of sleep, or other * harm to the VICTIM. Unless the PERPETRATOR wants to take credit, * that is. The VICTIM may not distribute this bomb source code to * any enemies of the PERPETRATOR. No VICTIM may debug, * reverse-engineer, run "strings" on, decompile, decrypt, or use any * other technique to gain knowledge of and defuse the BOMB. BOMB * proof clothing may not be worn when handling this program. The * PERPETRATOR will not apologize for the PERPETRATOR's poor sense of * humor. This license is null and void where the BOMB is prohibited * by law. ***************************************************************************/ #include <stdio.h> #include <stdlib.h> #include "support.h" #include "phases.h" /* * Note to self: Remember to erase this file so my victims will have no * idea what is going on, and so they will all blow up in a * spectaculary fiendish explosion. -- Dr. Evil */ ``` Wiele razy jest wspominana fraza `Dr. Evil`, którą mogliśmy zauważyć już w wydruku `strings bomb` (nie ująłem tego w fazie pierwszej), jednak w postaci `DrEvil`. Skoro pojawia się ona w symbolach, to musi być gdzieś użyta w kodzie. Aktywować ukrytą fazę możemy dopisując `DrEvil` na końcu wejścia, np. `40 2 DrEvil`. Teraz spokojnie, po wyczerpującym bruteforce możemy przejść do kolejnej fazy. ## Faza piąta Wydruk objdump: ``` 00000000000015bc <phase_5>: 15bc: 53 push %rbx 15bd: 48 83 ec 10 sub $0x10,%rsp 15c1: 48 89 fb mov %rdi,%rbx 15c4: e8 83 02 00 00 callq 184c <string_length> 15c9: 83 f8 06 cmp $0x6,%eax 15cc: 75 45 jne 1613 <phase_5+0x57> 15ce: b8 00 00 00 00 mov $0x0,%eax 15d3: 48 8d 0d c6 1b 00 00 lea 0x1bc6(%rip),%rcx # 31a0 <array.3195> 15da: 0f b6 14 03 movzbl (%rbx,%rax,1),%edx 15de: 83 e2 0f and $0xf,%edx 15e1: 0f b6 14 11 movzbl (%rcx,%rdx,1),%edx 15e5: 88 54 04 09 mov %dl,0x9(%rsp,%rax,1) 15e9: 48 83 c0 01 add $0x1,%rax 15ed: 48 83 f8 06 cmp $0x6,%rax 15f1: 75 e7 jne 15da <phase_5+0x1e> 15f3: c6 44 24 0f 00 movb $0x0,0xf(%rsp) 15f8: 48 8d 7c 24 09 lea 0x9(%rsp),%rdi 15fd: 48 8d 35 66 1b 00 00 lea 0x1b66(%rip),%rsi # 316a <_IO_stdin_used+0x16a> 1604: e8 60 02 00 00 callq 1869 <strings_not_equal> 1609: 85 c0 test %eax,%eax 160b: 75 0d jne 161a <phase_5+0x5e> 160d: 48 83 c4 10 add $0x10,%rsp 1611: 5b pop %rbx 1612: c3 retq 1613: e8 5d 03 00 00 callq 1975 <explode_bomb> 1618: eb b4 jmp 15ce <phase_5+0x12> 161a: e8 56 03 00 00 callq 1975 <explode_bomb> 161f: eb ec jmp 160d <phase_5+0x51> ``` Bardzo mocno rzuca się w oczy kolejna funkcja, jeszcze nie użyta - `<string_length>`. Zwracana przez nią wartość jest porównywana z 6, a więc nasz string musi mieć 6 znaków. Odwołujemy się w całej funkcji do dwóch stringów (adresy z komentarzy), sprawdzając je poleceniem `x/s` otrzymujemy `"maduiersnfotvbylWow! You've defused the secret stage"` oraz `"oilers"`. Skoro nasz string może mieć 6 znaków, to prawdopodobnie `"oilers"` będzie rozwiązaniem lub czymś, co nas na nie naprowadzi. Wiemy też, że wiadomość `"Wow! You've defused the secret stage"` nie pasuje do naszej fazy, stąd pozostaje nam ciąg `"maduiersnfotvbyl"`. Po przejściu `phase_5` w GDB zobaczyć możemy, że wykonujemy 6 razy pętlę i w każdym przejściu wykonywana jest instrukcja `and $0xf, %edx`. W każdej iteracji pętli w `%edx` przechowywane są kolejne litery naszego ciągu, a więc ich wartość (z ASCII) andujemy z `0xf`, dzięki czemu uzyskamy indeksy od 0 do 15 - pokryją się idealnie z pozostałym ciągiem. Możemy sobie zrobić prostą tabelkę, którą wypełnimy w następujący sposób: litery `a-z` zapiszemy jako liczby całkowite, w kolejnym wierszu będą przechowywane wartości `(int)ch AND 0xf`, a w ostatnim wierszu odszukamy litery o odpowiednich indeksach z ciągu `"maduiersnfotvbyl"`. | char | a | b | c | ... | x | y | z | |:------------:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| | **ASCII** | 97 | 98 | 99 | ... | 120 | 121 | 122 | | `AND 0xf` | 1 | 2 | 3 | ... | 8 | 9 | 10 | | zaszyfrowane | a | d | u | ... | n | f | o | Z tak utworzonej tabelki szukamy liter "zaszyfrowanych" odpowiadających tym z wyrazu `"oilers"`, znajdujemy w ten sposób jeden z kilku ciągów będących odpowiedzią: `"jdoefg"` i idziemy do ostatniej znanej fazy. ## Faza szósta Wydruk objdump: ``` 0000000000001621 <phase_6>: 1621: 41 57 push %r15 1623: 41 56 push %r14 1625: 41 55 push %r13 1627: 41 54 push %r12 1629: 55 push %rbp 162a: 53 push %rbx 162b: 48 83 ec 58 sub $0x58,%rsp 162f: 4c 8d 74 24 30 lea 0x30(%rsp),%r14 1634: 4c 89 f6 mov %r14,%rsi 1637: e8 5f 03 00 00 callq 199b <read_six_numbers> 163c: 4d 89 f4 mov %r14,%r12 163f: 41 bf 01 00 00 00 mov $0x1,%r15d 1645: 4c 8d 6c 24 30 lea 0x30(%rsp),%r13 164a: e9 a4 00 00 00 jmpq 16f3 <phase_6+0xd2> 164f: e8 21 03 00 00 callq 1975 <explode_bomb> 1654: e9 ac 00 00 00 jmpq 1705 <phase_6+0xe4> 1659: 48 89 e6 mov %rsp,%rsi 165c: 49 8d 7c 24 18 lea 0x18(%r12),%rdi 1661: 41 8b 0c 24 mov (%r12),%ecx 1665: b8 01 00 00 00 mov $0x1,%eax 166a: 48 8d 15 7f 3c 00 00 lea 0x3c7f(%rip),%rdx # 52f0 <node1> 1671: 83 f9 01 cmp $0x1,%ecx 1674: 7e 0b jle 1681 <phase_6+0x60> 1676: 48 8b 52 08 mov 0x8(%rdx),%rdx 167a: 83 c0 01 add $0x1,%eax 167d: 39 c8 cmp %ecx,%eax 167f: 75 f5 jne 1676 <phase_6+0x55> 1681: 48 89 16 mov %rdx,(%rsi) 1684: 49 83 c4 04 add $0x4,%r12 1688: 48 83 c6 08 add $0x8,%rsi 168c: 4c 39 e7 cmp %r12,%rdi 168f: 75 d0 jne 1661 <phase_6+0x40> 1691: 48 8b 1c 24 mov (%rsp),%rbx 1695: 48 8b 44 24 08 mov 0x8(%rsp),%rax 169a: 48 89 43 08 mov %rax,0x8(%rbx) 169e: 48 8b 54 24 10 mov 0x10(%rsp),%rdx 16a3: 48 89 50 08 mov %rdx,0x8(%rax) 16a7: 48 8b 44 24 18 mov 0x18(%rsp),%rax 16ac: 48 89 42 08 mov %rax,0x8(%rdx) 16b0: 48 8b 54 24 20 mov 0x20(%rsp),%rdx 16b5: 48 89 50 08 mov %rdx,0x8(%rax) 16b9: 48 8b 44 24 28 mov 0x28(%rsp),%rax 16be: 48 89 42 08 mov %rax,0x8(%rdx) 16c2: 48 c7 40 08 00 00 00 movq $0x0,0x8(%rax) 16c9: 00 16ca: bd 05 00 00 00 mov $0x5,%ebp 16cf: eb 4c jmp 171d <phase_6+0xfc> 16d1: e8 9f 02 00 00 callq 1975 <explode_bomb> 16d6: 48 83 c3 01 add $0x1,%rbx 16da: 83 fb 05 cmp $0x5,%ebx 16dd: 7f 0c jg 16eb <phase_6+0xca> 16df: 41 8b 44 9d 00 mov 0x0(%r13,%rbx,4),%eax 16e4: 39 45 00 cmp %eax,0x0(%rbp) 16e7: 75 ed jne 16d6 <phase_6+0xb5> 16e9: eb e6 jmp 16d1 <phase_6+0xb0> 16eb: 49 83 c7 01 add $0x1,%r15 16ef: 49 83 c6 04 add $0x4,%r14 16f3: 4c 89 f5 mov %r14,%rbp 16f6: 41 8b 06 mov (%r14),%eax 16f9: 83 e8 01 sub $0x1,%eax 16fc: 83 f8 05 cmp $0x5,%eax 16ff: 0f 87 4a ff ff ff ja 164f <phase_6+0x2e> 1705: 49 83 ff 06 cmp $0x6,%r15 1709: 0f 84 4a ff ff ff je 1659 <phase_6+0x38> 170f: 4c 89 fb mov %r15,%rbx 1712: eb cb jmp 16df <phase_6+0xbe> 1714: 48 8b 5b 08 mov 0x8(%rbx),%rbx 1718: 83 ed 01 sub $0x1,%ebp 171b: 74 11 je 172e <phase_6+0x10d> 171d: 48 8b 43 08 mov 0x8(%rbx),%rax 1721: 8b 00 mov (%rax),%eax 1723: 39 03 cmp %eax,(%rbx) 1725: 7e ed jle 1714 <phase_6+0xf3> 1727: e8 49 02 00 00 callq 1975 <explode_bomb> 172c: eb e6 jmp 1714 <phase_6+0xf3> 172e: 48 83 c4 58 add $0x58,%rsp 1732: 5b pop %rbx 1733: 5d pop %rbp 1734: 41 5c pop %r12 1736: 41 5d pop %r13 1738: 41 5e pop %r14 173a: 41 5f pop %r15 173c: c3 retq ``` Jest to najdłuższa faza z rozpatrywanych, po przeanalizowaniu instrukcji możemy dojrzeć komentarz z odnośnikiem `52f0 <node1>` - prawdopodobnie będziemy pracować z jakąś strukturą danych z węzłami. Powyżej widzimy znaną już nam funkcję `<read_six_numbers>`, możemy się spodziewać, że będziemy operować na sześciu węzłach. Podejrzyjmy poleceniem `x/3x` wspomniany adres (jednak nie z objdumpa, a GDB), otrzymamy wtedy: ``` 0x5555555592f0 <node1>: 0x0000038c 0x00000001 0x55559300 ``` Kolejne wartości odpowiadają: wartości węzła, indeksowi węzła, adresowi kolejnego węzła (uciętego do 8 ostatnich cyfr). Sporządźmy sobie tabelkę, w której zapiszemy wszystkie wartości, od razu obliczmy wartość dziesiętną węzłów: | wartość HEX | wartość DEC | indeks | adres (kolejny węzeł) | |:-----------:|:-----------:|:------:|:---------------------:| | `0x38c` | `908` | 1 | `0x555555559300` | | `0x36d` | `877` | 2 | `0x555555559310` | | `0x10d` | `269` | 3 | `0x555555559320` | | `0x2af` | `687` | 4 | `0x555555559330` | | `0x06c` | `108` | 5 | `0x5555555591f0` | | `0x0d9` | `217` | 6 | `0x0` | Mając tak przygotowaną tabelkę, możemy przejść do kolejnej części tej fazy. Po dość długiej i żmudnej analizie instrukcji można dojść do wniosku, że program oczekuje na wejściu posortowanych rosnąco po wartościach indeksów węzłów, a więc dużo łatwiej jest znów puścić bruteforce, żeby znaleźć poprawne rozwiązanie (zaoszczędzimy dużo czasu, bo jest tylko $6!=720$ możliwości). W moim przypadku rozwiązaniem tej fazy jest ciąg `5 6 3 4 2 1`. ## Faza siódma (ukryta) Wydruk objdump: ``` 000000000000177a <secret_phase>: 177a: 53 push %rbx 177b: e8 5c 02 00 00 callq 19dc <read_line> 1780: ba 0a 00 00 00 mov $0xa,%edx 1785: be 00 00 00 00 mov $0x0,%esi 178a: 48 89 c7 mov %rax,%rdi 178d: e8 7e f9 ff ff callq 1110 <strtol@plt> 1792: 48 89 c3 mov %rax,%rbx 1795: 8d 40 ff lea -0x1(%rax),%eax 1798: 3d e8 03 00 00 cmp $0x3e8,%eax 179d: 77 26 ja 17c5 <secret_phase+0x4b> 179f: 89 de mov %ebx,%esi 17a1: 48 8d 3d 68 3a 00 00 lea 0x3a68(%rip),%rdi # 5210 <n1> 17a8: e8 90 ff ff ff callq 173d <fun7> 17ad: 83 f8 04 cmp $0x4,%eax 17b0: 75 1a jne 17cc <secret_phase+0x52> 17b2: 48 8d 3d f7 19 00 00 lea 0x19f7(%rip),%rdi # 31b0 <array.3195+0x10> 17b9: e8 a2 f8 ff ff callq 1060 <puts@plt> 17be: e8 5d 03 00 00 callq 1b20 <phase_defused> 17c3: 5b pop %rbx 17c4: c3 retq 17c5: e8 ab 01 00 00 callq 1975 <explode_bomb> 17ca: eb d3 jmp 179f <secret_phase+0x25> 17cc: e8 a4 01 00 00 callq 1975 <explode_bomb> 17d1: eb df jmp 17b2 <secret_phase+0x38> ``` ``` 000000000000173d <fun7>: 173d: 48 85 ff test %rdi,%rdi 1740: 74 32 je 1774 <fun7+0x37> 1742: 48 83 ec 08 sub $0x8,%rsp 1746: 8b 17 mov (%rdi),%edx 1748: 39 f2 cmp %esi,%edx 174a: 7f 0c jg 1758 <fun7+0x1b> 174c: b8 00 00 00 00 mov $0x0,%eax 1751: 75 12 jne 1765 <fun7+0x28> 1753: 48 83 c4 08 add $0x8,%rsp 1757: c3 retq 1758: 48 8b 7f 08 mov 0x8(%rdi),%rdi 175c: e8 dc ff ff ff callq 173d <fun7> 1761: 01 c0 add %eax,%eax 1763: eb ee jmp 1753 <fun7+0x16> 1765: 48 8b 7f 10 mov 0x10(%rdi),%rdi 1769: e8 cf ff ff ff callq 173d <fun7> 176e: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax 1772: eb df jmp 1753 <fun7+0x16> 1774: b8 ff ff ff ff mov $0xffffffff,%eax 1779: c3 retq ``` Znów będę szczery, nie chciało mi się za bardzo siedzieć i nad tym myśleć, dlatego po jednym prześledzeniu działania przy wejściu `6` (co okazało się być dosyć trafne, gdyż oczekiwany input to jedna liczba całkowita), postanowiłem zrobić kolejny bruteforce na wartościach od 0 do 1000, dosyć szybko okazało się, że szukaną wartością jest 7, co sprawiło że cała bomba została pomyślnie rozbrojona. ## Easter egg Po próbie zakończenia programu skrótem `Ctrl + C` zostaniemy zapytani, czy myślimy, że zatrzymamy bombę właśnie tym skrótem. Jeżeli wpiszemy `yes`, to wypisane zostanie `Well...`, a następnie w nieskończonej pętli będzie wypisywało się `y` od nowej linii. Gdy wpiszemy coś innego (np. `no`), wypisane zostanie tylko `Well...OK. :-)` i program zakończy swoje działanie.

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully