Votre mission : trouver le mot de passe qui affiche le flag.

We have an ELF and we have to find the flag.

Exploit

First of all, let’s check a few things on the binary:

magnussen@funcMyLife:~/tartetatin$ ./TarteTatin test

magnussen@funcMyLife:~/tartetatin$ strings TarteTatin
/lib64/ld-linux-x86-64.so.2
~NzzA.
Lf\R
libc.so.6
puts
__stack_chk_fail
stdin
fgets
memcmp
__cxa_finalize
__libc_start_main
GLIBC_2.4
GLIBC_2.2.5
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
%z	 
=a	 
AWAVI
AUATL
[]A\A]A^A_
;*3$"
Vdkk
cnmd
ek`f
EBRBz72e30320b000/51c//2cc/102be713c55e66/`/ad02/4d1702e04cc654/2`80c|
NzTfdvs4Q4ttx1seGCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.7698
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
tarteTatin.c
__FRAME_END__
__init_array_end
_DYNAMIC
__init_array_start
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
_ITM_deregisterTMCloneTable
transform
puts@@GLIBC_2.2.5
stdin@@GLIBC_2.2.5
_edata
__stack_chk_fail@@GLIBC_2.4
__libc_start_main@@GLIBC_2.2.5
memcmp@@GLIBC_2.2.5
fgets@@GLIBC_2.2.5
__data_start
__gmon_start__
__dso_handle
_IO_stdin_used
__libc_csu_init
__bss_start
main
flag_enc
__TMC_END__
_ITM_registerTMCloneTable
__cxa_finalize@@GLIBC_2.2.5
pass_enc
.symtab
.strtab
.shstrtab
.interp
.note.ABI-tag
.note.gnu.build-id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.dynamic
.data
.bss
.comment

Ok, so no response from the program after the execution, there’s some interesting strings, but we don’t know how they’re generated, let’s check the binary.

magnussen@funcMyLife:~/tartetatin$ radare2 -d Tartetatin
Process with PID 673 started...
= attach 673 673
bin.baddr 0x559d5cbc5000
Using 0x559d5cbc5000
asm.bits 64
[0x7ff5fdea0090]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
= attach 673 673
673
[0x7ff5fdea0090]> s main
[0x559d5cbc57a4]> pdf
            ;-- main:
/ (fcn) main 145
|   main ();
|           ; var int local_30h @ rbp-0x30
|           ; var int local_8h @ rbp-0x8
|              ; DATA XREF from 0x559d5cbc568d (entry0)
|           0x559d5cbc57a4      55             push rbp
|           0x559d5cbc57a5      4889e5         mov rbp, rsp
|           0x559d5cbc57a8      4883ec30       sub rsp, 0x30           ; '0'
|           0x559d5cbc57ac      64488b042528.  mov rax, qword fs:[0x28] ; [0x28:8]=-1 ; '(' ; 40
|           0x559d5cbc57b5      488945f8       mov qword [local_8h], rax
|           0x559d5cbc57b9      31c0           xor eax, eax
|           0x559d5cbc57bb      488b15ce0820.  mov rdx, qword [obj.stdin] ; loc.stdin ; [0x559d5cdc6090:8]=0
|           0x559d5cbc57c2      488d45d0       lea rax, qword [local_30h]
|           0x559d5cbc57c6      be20000000     mov esi, 0x20           ; 32
|           0x559d5cbc57cb      4889c7         mov rdi, rax
|           0x559d5cbc57ce      e87dfeffff     call sym.imp.fgets      ; char *fgets(char *s, int size, FILE *stream)
|           0x559d5cbc57d3      488d45d0       lea rax, qword [local_30h]
|           0x559d5cbc57d7      4889c7         mov rdi, rax
|           0x559d5cbc57da      e89bffffff     call sym.transform
|           0x559d5cbc57df      488d45d0       lea rax, qword [local_30h]
|           0x559d5cbc57e3      ba10000000     mov edx, 0x10           ; 16
|           0x559d5cbc57e8      488d35910820.  lea rsi, qword str.NzTfdvs4Q4ttx1se ; obj.pass_enc ; 0x559d5cdc6080 ; "NzTfdvs4Q4ttx1se"
|           0x559d5cbc57ef      4889c7         mov rdi, rax
|           0x559d5cbc57f2      e849feffff     call sym.imp.memcmp     ; int memcmp(const void *s1, const void *s2, size_t n)
|           0x559d5cbc57f7      85c0           test eax, eax
|       ,=< 0x559d5cbc57f9      751f           jne 0x559d5cbc581a
|       |   0x559d5cbc57fb      488d3d1e0820.  lea rdi, qword str.Vdkk ; obj.flag_enc ; 0x559d5cdc6020 ; "Vdkk\x1fcnmd \x1fSgd\x1fek`f\x1fhr9\x1fEBRBz72e30320b000/51c//2cc/102be713c55e66/`/ad02/4d1702e04cc654/2`80c|"
|       |   0x559d5cbc5802      e873ffffff     call sym.transform
|       |   0x559d5cbc5807      488d3d120820.  lea rdi, qword str.Vdkk ; obj.flag_enc ; 0x559d5cdc6020 ; "Vdkk\x1fcnmd \x1fSgd\x1fek`f\x1fhr9\x1fEBRBz72e30320b000/51c//2cc/102be713c55e66/`/ad02/4d1702e04cc654/2`80c|"
|       |   0x559d5cbc580e      e80dfeffff     call sym.imp.puts       ; int puts(const char *s)
|       |   0x559d5cbc5813      b801000000     mov eax, 1
|      ,==< 0x559d5cbc5818      eb05           jmp 0x559d5cbc581f
|      |`-> 0x559d5cbc581a      b800000000     mov eax, 0
|      |       ; JMP XREF from 0x559d5cbc5818 (main)
|      `--> 0x559d5cbc581f      488b4df8       mov rcx, qword [local_8h]
|           0x559d5cbc5823      6448330c2528.  xor rcx, qword fs:[0x28]
|       ,=< 0x559d5cbc582c      7405           je 0x559d5cbc5833
|       |   0x559d5cbc582e      e8fdfdffff     call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|       `-> 0x559d5cbc5833      c9             leave
\           0x559d5cbc5834      c3             ret

So there’s two interesting objects: obj.pass_enc & obj.flag_enc, and a function called transform.

So basically, the program takes an input, transforms it and compares it with pass_enc, if they matches, it transforms the flag_enc string and prints it.

Let’s see what the transform function does.

[0x559d5cbc57a4]> s sym.transform
[0x559d5cbc577a]> pdf
/ (fcn) sym.transform 42
|   sym.transform ();
|           ; var int local_8h @ rbp-0x8
|              ; CALL XREF from 0x559d5cbc57da (main)
|              ; CALL XREF from 0x559d5cbc5802 (main)
|           0x559d5cbc577a      55             push rbp
|           0x559d5cbc577b      4889e5         mov rbp, rsp
|           0x559d5cbc577e      48897df8       mov qword [local_8h], rdi
|       .-> 0x559d5cbc5782      488b45f8       mov rax, qword [local_8h]
|       :   0x559d5cbc5786      488d5001       lea rdx, qword [rax + 1] ; 1
|       :   0x559d5cbc578a      488955f8       mov qword [local_8h], rdx
|       :   0x559d5cbc578e      0fb610         movzx edx, byte [rax]
|       :   0x559d5cbc5791      83c201         add edx, 1
|       :   0x559d5cbc5794      8810           mov byte [rax], dl
|       :   0x559d5cbc5796      488b45f8       mov rax, qword [local_8h]
|       :   0x559d5cbc579a      0fb600         movzx eax, byte [rax]
|       :   0x559d5cbc579d      84c0           test al, al
|       `=< 0x559d5cbc579f      75e1           jne 0x559d5cbc5782
|           0x559d5cbc57a1      90             nop
|           0x559d5cbc57a2      5d             pop rbp
\           0x559d5cbc57a3      c3             ret

Ok, so it’s pretty simple, the function takes a string and for each character it adds one to the ASCII value, it’s a simple ROT1.

Let’s take our two objects and decrypt them.

#!/usr/bin/python3
# coding: utf-8

password = b"NzTfdvs4Q4ttx1se"
flag = b'Vdkk\x1fcnmd \x1fSgd\x1fek`f\x1fhr9\x1fEBRBz72e30320b000/51c//2cc/102be713c55e66/`/ad02/4d1702e04cc654/2`80c|'

clear_password = ''
clear_flag = ''

for value in password:
    clear_password += chr(value - 1)

for value in flag:
    clear_flag += chr(value + 1)

print("Password: {}".format(clear_password))
print("Flag: {}".format(clear_flag))

Our password was already transformed, so we have to decrypt it, but our flag wasn’t transform, so we have to transform it to find the plain flag.

So we subtract 1 to each character in the pass and we add 1 to each character in our flag.

magnussen@funcMyLife:~/tartetatin$ ./exploit.py
Password: MySecur3P3ssw0rd
Flag: Well done! The flag is: FCSC{83f41431c111062d003dd0213cf824d66f770a0be1305e2813f15dd76503a91d}

This was a nice introduction to the reverse challenges.

Thanks to the FCSC team, this was an awesome CTF, I’ve learned a lot and had a lot of fun. Congratulation for the organization, see you next year!