Ta objava vsebuje primere rešitev nalog iz kategorije obratni inženiring na tekmovanju SICEH CTF 2016, ki je potekalo v okviru konference Infosek 2016.

1. Napačno geslo

Program kličemo na način ./re1 <zastavica> ter nam sporoči ali je zastavica, ki smo jo vnesli, pravilna. Z ogledom strojne kode lahko vidimo, da program preveri, ali je argument dolg natanko 0x15 znakov, ali prvi del ustreza besedilu ISCTF{, ali srednji del ustreza besedilu dv4kr47_r0t_13 ter ali se konča s } (local_8h je naslov zastavice, ki smo jo vnesli):

|      |    0x00400644      488b45f8       mov rax, qword [rbp - local_8h]
|      |    0x00400648      4889c7         mov rdi, rax
|      |    0x0040064b      e870feffff     call sym.imp.strlen
|      |    0x00400650      4883f815       cmp rax, 0x15
|      |,=< 0x00400654      740c           je 0x400662
|      ||   0x00400656      b800000000     mov eax, 0
|      ||   0x0040065b      e88bffffff     call sym.failure
|     ,===< 0x00400660      eb7d           jmp 0x4006df
|     |||   ; JMP XREF from 0x00400654 (sym.main)
|     ||`-> 0x00400662      488b45f8       mov rax, qword [rbp - local_8h]
|     ||    0x00400666      ba06000000     mov edx, 6
|     ||    0x0040066b      bebb074000     mov esi, str.ISCTF_         ; "ISCTF{" @ 0x4007bb
|     ||    0x00400670      4889c7         mov rdi, rax
|     ||    0x00400673      e828feffff     call sym.imp.strncmp
|     ||    0x00400678      85c0           test eax, eax
|     ||,=< 0x0040067a      740c           je 0x400688
|     |||   0x0040067c      b800000000     mov eax, 0
|     |||   0x00400681      e865ffffff     call sym.failure
|    ,====< 0x00400686      eb57           jmp 0x4006df
|    ||||   ; JMP XREF from 0x0040067a (sym.main)
|    |||`-> 0x00400688      488b45f8       mov rax, qword [rbp - local_8h]
|    |||    0x0040068c      4883c006       add rax, 6
|    |||    0x00400690      ba0e000000     mov edx, 0xe
|    |||    0x00400695      bec2074000     mov esi, str.dv4kr47_r0t_13 ; "dv4kr47_r0t_13" @ 0x4007c2
|    |||    0x0040069a      4889c7         mov rdi, rax
|    |||    0x0040069d      e8fefdffff     call sym.imp.strncmp
|    |||    0x004006a2      85c0           test eax, eax
|    |||,=< 0x004006a4      740c           je 0x4006b2
|    ||||   0x004006a6      b800000000     mov eax, 0
|    ||||   0x004006ab      e83bffffff     call sym.failure
|   ,=====< 0x004006b0      eb2d           jmp 0x4006df
|   |||||   ; JMP XREF from 0x004006a4 (sym.main)
|   ||||`-> 0x004006b2      488b45f8       mov rax, qword [rbp - local_8h]
|   ||||    0x004006b6      4883c014       add rax, 0x14
|   ||||    0x004006ba      0fb610         movzx edx, byte [rax]
|   ||||    0x004006bd      b8d1074000     mov eax, 0x4007d1
|   ||||    0x004006c2      0fb600         movzx eax, byte [rax]
|   ||||    0x004006c5      38c2           cmp dl, al
|   ||||,=< 0x004006c7      740c           je 0x4006d5
|   |||||   0x004006c9      b800000000     mov eax, 0
|   |||||   0x004006ce      e818ffffff     call sym.failure
|  ,======< 0x004006d3      eb0a           jmp 0x4006df
|  ||||||   ; JMP XREF from 0x004006c7 (sym.main)
|  |||||`-> 0x004006d5      b800000000     mov eax, 0
|  |||||    0x004006da      e8f7feffff     call sym.success

Zastavico lahko verjetno pravilno uganete tudi s uporabo strings:

> strings re1
...
ISCTF{
dv4kr47_r0t_13
...

2. Osnovnošolska matematika

Naloga je po načinu uporabe podobna prejšnji, program poženemo s ./re2 <zastavica> in nam pove, ali je naša zastavica pravilna. Proces preverjanja zastavica pa je nekoliko kompleksnejši, zato uporaba strings ne zadošča. V funkciji main je vsak znak srednjega dela naše zastavice (med { in }) spremenjen, nato pa je rezultat primerjan z besedilom ISCTF{zbxuxn_tm_sp_zolo}. Znaki srednjega dela zastavice so nadomeščeni z vrednostjo, ki je vrne funkcija rotx. Ta funkcija je klicana z i-tim znakom zastavice, i-tim številom zaporedja, ki za rešitev naloge ni relevantno in i-jem (local_18h je spremenljivka, uporabljena za napredovanje zanke, local_20h je dolžina srednjega dela zastavice, local_40h je naslov stednjega dela zastavice, local_30h pa je naslov zaporedja):

|     ||`-> 0x00400811      c745e8000000.  mov dword [rbp - local_18h], 0
|     ||,=< 0x00400818      eb40           jmp 0x40085a
|    .----> 0x0040081a      8b45e8         mov eax, dword [rbp - local_18h]
|    ||||   0x0040081d      4863d0         movsxd rdx, eax
|    ||||   0x00400820      488b45c0       mov rax, qword [rbp - local_40h]
|    ||||   0x00400824      488d1c02       lea rbx, qword [rdx + rax]
|    ||||   0x00400828      488b45d0       mov rax, qword [rbp - local_30h]
|    ||||   0x0040082c      8b55e8         mov edx, dword [rbp - local_18h]
|    ||||   0x0040082f      4863d2         movsxd rdx, edx
|    ||||   0x00400832      8b0c90         mov ecx, dword [rax + rdx*4]
|    ||||   0x00400835      8b45e8         mov eax, dword [rbp - local_18h]
|    ||||   0x00400838      4863d0         movsxd rdx, eax
|    ||||   0x0040083b      488b45c0       mov rax, qword [rbp - local_40h]
|    ||||   0x0040083f      4801d0         add rax, rdx
|    ||||   0x00400842      0fb600         movzx eax, byte [rax]
|    ||||   0x00400845      0fbec0         movsx eax, al
|    ||||   0x00400848      8b55e8         mov edx, dword [rbp - local_18h]
|    ||||   0x0040084b      89ce           mov esi, ecx
|    ||||   0x0040084d      89c7           mov edi, eax
|    ||||   0x0040084f      e8f0fdffff     call sym.rotx
|    ||||   0x00400854      8803           mov byte [rbx], al
|    ||||   0x00400856      8345e801       add dword [rbp - local_18h], 1
|    ||||   ; JMP XREF from 0x00400818 (sym.main)
|    |||`-> 0x0040085a      8b45e8         mov eax, dword [rbp - local_18h]
|    |||    0x0040085d      3b45e0         cmp eax, dword [rbp - local_20h]
|    `====< 0x00400860      7cb8           jl 0x40081a

Funkcija rotx vsakemu znaku prišteje i, če je to mogoče ne da bi vrednost znaka presegla 'z' (local_4h je znak, ki ga funkcija spreminja, local_ch pa je i):

|           0x00400679      807dfc60       cmp byte [rbp - local_4h], 0x60 ; [0x60:1]=248 ; '`'
|       ,=< 0x0040067d      7e39           jle 0x4006b8
|       |   0x0040067f      807dfc7a       cmp byte [rbp - local_4h], 0x7a ; [0x7a:1]=0 ; 'z'
|      ,==< 0x00400683      7f33           jg 0x4006b8
|      ||   0x00400685      8b45f4         mov eax, dword [rbp - local_ch]
|      ||   0x00400688      89c2           mov edx, eax
|      ||   0x0040068a      0fb645fc       movzx eax, byte [rbp - local_4h]
|      ||   0x0040068e      01d0           add eax, edx
|      ||   0x00400690      8845fc         mov byte [rbp - local_4h], al
|      ||   0x00400693      807dfc7a       cmp byte [rbp - local_4h], 0x7a ; [0x7a:1]=0 ; 'z'
|     ,===< 0x00400697      7e0c           jle 0x4006a5
|     |||   0x00400699      0fb645fc       movzx eax, byte [rbp - local_4h]
|     |||   0x0040069d      8b55f4         mov edx, dword [rbp - local_ch]
|     |||   0x004006a0      29d0           sub eax, edx
|     |||   0x004006a2      8845fc         mov byte [rbp - local_4h], al
|     `---> 0x004006a5      0fbe45fc       movsx eax, byte [rbp - local_4h]
...
|      ||   0x004006b5      8845fc         mov byte [rbp - local_4h], al
|      ``-> 0x004006b8      0fb645fc       movzx eax, byte [rbp - local_4h]

Zdaj ko poznamo algoritem, ga lahko implementiramo v obratni smeri in izračunamo zastavico. Primer rešitve v Python-u:

flag = "zbxuxn_tm_sp_zolo"
solution = []

for i in range(len(flag)):
    char = ord(flag[i])
    if (char >= ord('a') and char <= ord('z') and char - i >= ord('a')):
        solution.append(char - i) 
    else:
        solution.append(char)

print("ISCTF{" + "".join(map(lambda x: chr(x), solution)) + "}")
// ISCTF{zavrti_me_se_malo}

Član zmagovalne ekipe Hekerski Sindikat je predlagal enostavnejšo rešitev. Če uporabimo program ltrace, ki spremlja klice funkcij dinamičnih knjižnjic, lahko vidimo primerjavo naše spremenjene zastavice s ciljnim besedilom in rešimo nalogo znak po znak:

> ltrace ./re2 "ISCTF{aaaaaaaaaaaaaaaaa}"
strlen("ISCTF{aaaaaaaaaaaaaaaaa}")                                = 24
strcmp("ISCTF{abcdefghijklmnopq}", "ISCTF{zbxuxn_tm_sp_zolo}")    = -25
puts("Zastavica je napa\304\215na!"Zastavica je napačna!
)                                                                 = 23
+++ exited (status 1) +++

3. Passage

Rešitev naloge smo poslali v uničenje!

4. Prijava iz varnega sistema

Rešitev naloge zahteva daljši opis, ki bo morda dodan v prihodnosti.