DUCTF{king_of_the_olympian_gods_and_god_of_the_sky}CV
This challenge is in the reverse engineering category. As such, this requires us to reverse engineer a binary program, reason about its execution, determine how to extract the secret, and then finally actually extract it.
Because this is a beginner challenge, the first thing we're going to use is strings(1).
$ strings zeus
/lib64/ld-linux-x86-64.so.2
0FQr
__cxa_finalize
__libc_start_main
strcmp
puts
printf
libc.so.6
GLIBC_2.2.5
GLIBC_2.34
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
PTE1
u+UH
4*9'
Vl\Q
nT\S
To Zeus Maimaktes, Zeus who comes when the north wind blows, we offer our praise, we make you welcome!
Maimaktes1337
-invocation
Zeus responds to your invocation!
His reply: %s
The northern winds are silent...
;*3$"
GCC: (Debian 13.2.0-24) 13.2.0
Scrt1.o
__abi_tag
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.0
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
main.c
__FRAME_END__
_DYNAMIC
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_start_main@GLIBC_2.34
_ITM_deregisterTMCloneTable
puts@GLIBC_2.2.5
_edata
_fini
printf@GLIBC_2.2.5
__data_start
strcmp@GLIBC_2.2.5
__gmon_start__
__dso_handle
_IO_stdin_used
_end
__bss_start
main
__TMC_END__
_ITM_registerTMCloneTable
__cxa_finalize@GLIBC_2.2.5
_init
.symtab
.strtab
.shstrtab
.interp
.note.gnu.property
.note.gnu.build-id
.note.ABI-tag
.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
.got.plt
.data
.bss
.comment
There are some immediately obvious suspects here. Namely,
To Zeus Maimaktes, Zeus who comes when the north wind blows, we offer our praise, we make you welcome!Maimaktes1337-invocationZeus responds to your invocation!His reply: %sThe northern winds are silent...The next step is to view the zeus disassembly directly. Firstly, we should check that there's no silliness occurring with the ELF sections with readelf(1).
$ readelf -l zeus
Elf file type is DYN (Shared object file)
Entry point 0x1070
There are 13 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000002d8 0x00000000000002d8 R 0x8
INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000688 0x0000000000000688 R 0x1000
LOAD 0x0000000000001000 0x0000000000001000 0x0000000000001000
0x000000000000034d 0x000000000000034d R E 0x1000
LOAD 0x0000000000002000 0x0000000000002000 0x0000000000002000
0x00000000000001ec 0x00000000000001ec R 0x1000
LOAD 0x0000000000002dd0 0x0000000000003dd0 0x0000000000003dd0
0x0000000000000258 0x0000000000000260 RW 0x1000
DYNAMIC 0x0000000000002de0 0x0000000000003de0 0x0000000000003de0
0x00000000000001e0 0x00000000000001e0 RW 0x8
NOTE 0x0000000000000338 0x0000000000000338 0x0000000000000338
0x0000000000000020 0x0000000000000020 R 0x8
NOTE 0x0000000000000358 0x0000000000000358 0x0000000000000358
0x0000000000000044 0x0000000000000044 R 0x4
GNU_PROPERTY 0x0000000000000338 0x0000000000000338 0x0000000000000338
0x0000000000000020 0x0000000000000020 R 0x8
GNU_EH_FRAME 0x00000000000020ec 0x00000000000020ec 0x00000000000020ec
0x0000000000000034 0x0000000000000034 R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x0000000000002dd0 0x0000000000003dd0 0x0000000000003dd0
0x0000000000000230 0x0000000000000230 R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
03 .init .plt .plt.got .text .fini
04 .rodata .eh_frame_hdr .eh_frame
05 .init_array .fini_array .dynamic .got .got.plt .data .bss
06 .dynamic
07 .note.gnu.property
08 .note.gnu.build-id .note.ABI-tag
09 .note.gnu.property
10 .eh_frame_hdr
11
12 .init_array .fini_array .dynamic .got
Now for the actual disassembly:
$ objdump -d -j .text zeus
zeus: file format elf64-x86-64
Disassembly of section .text:
0000000000001070 <_start>:
1070: 31 ed xor %ebp,%ebp
1072: 49 89 d1 mov %rdx,%r9
1075: 5e pop %rsi
1076: 48 89 e2 mov %rsp,%rdx
1079: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
107d: 50 push %rax
107e: 54 push %rsp
107f: 45 31 c0 xor %r8d,%r8d
1082: 31 c9 xor %ecx,%ecx
1084: 48 8d 3d 3d 01 00 00 lea 0x13d(%rip),%rdi # 11c8 <main>
108b: ff 15 2f 2f 00 00 callq *0x2f2f(%rip) # 3fc0 <__libc_start_main@GLIBC_2.34>
1091: f4 hlt
1092: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
1099: 00 00 00
109c: 0f 1f 40 00 nopl 0x0(%rax)
00000000000010a0 <deregister_tm_clones>:
10a0: 48 8d 3d 81 2f 00 00 lea 0x2f81(%rip),%rdi # 4028 <__TMC_END__>
10a7: 48 8d 05 7a 2f 00 00 lea 0x2f7a(%rip),%rax # 4028 <__TMC_END__>
10ae: 48 39 f8 cmp %rdi,%rax
10b1: 74 15 je 10c8 <deregister_tm_clones+0x28>
10b3: 48 8b 05 0e 2f 00 00 mov 0x2f0e(%rip),%rax # 3fc8 <_ITM_deregisterTMCloneTable@Base>
10ba: 48 85 c0 test %rax,%rax
10bd: 74 09 je 10c8 <deregister_tm_clones+0x28>
10bf: ff e0 jmpq *%rax
10c1: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
10c8: c3 retq
10c9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
00000000000010d0 <register_tm_clones>:
10d0: 48 8d 3d 51 2f 00 00 lea 0x2f51(%rip),%rdi # 4028 <__TMC_END__>
10d7: 48 8d 35 4a 2f 00 00 lea 0x2f4a(%rip),%rsi # 4028 <__TMC_END__>
10de: 48 29 fe sub %rdi,%rsi
10e1: 48 89 f0 mov %rsi,%rax
10e4: 48 c1 ee 3f shr $0x3f,%rsi
10e8: 48 c1 f8 03 sar $0x3,%rax
10ec: 48 01 c6 add %rax,%rsi
10ef: 48 d1 fe sar %rsi
10f2: 74 14 je 1108 <register_tm_clones+0x38>
10f4: 48 8b 05 dd 2e 00 00 mov 0x2edd(%rip),%rax # 3fd8 <_ITM_registerTMCloneTable@Base>
10fb: 48 85 c0 test %rax,%rax
10fe: 74 08 je 1108 <register_tm_clones+0x38>
1100: ff e0 jmpq *%rax
1102: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
1108: c3 retq
1109: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
0000000000001110 <__do_global_dtors_aux>:
1110: f3 0f 1e fa endbr64
1114: 80 3d 0d 2f 00 00 00 cmpb $0x0,0x2f0d(%rip) # 4028 <__TMC_END__>
111b: 75 2b jne 1148 <__do_global_dtors_aux+0x38>
111d: 55 push %rbp
111e: 48 83 3d ba 2e 00 00 cmpq $0x0,0x2eba(%rip) # 3fe0 <__cxa_finalize@GLIBC_2.2.5>
1125: 00
1126: 48 89 e5 mov %rsp,%rbp
1129: 74 0c je 1137 <__do_global_dtors_aux+0x27>
112b: 48 8b 3d ee 2e 00 00 mov 0x2eee(%rip),%rdi # 4020 <__dso_handle>
1132: e8 29 ff ff ff callq 1060 <__cxa_finalize@plt>
1137: e8 64 ff ff ff callq 10a0 <deregister_tm_clones>
113c: c6 05 e5 2e 00 00 01 movb $0x1,0x2ee5(%rip) # 4028 <__TMC_END__>
1143: 5d pop %rbp
1144: c3 retq
1145: 0f 1f 00 nopl (%rax)
1148: c3 retq
1149: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
0000000000001150 <frame_dummy>:
1150: f3 0f 1e fa endbr64
1154: e9 77 ff ff ff jmpq 10d0 <register_tm_clones>
0000000000001159 <xor>:
1159: 55 push %rbp
115a: 48 89 e5 mov %rsp,%rbp
115d: 48 89 7d d8 mov %rdi,-0x28(%rbp)
1161: 48 89 75 d0 mov %rsi,-0x30(%rbp)
1165: 48 c7 45 f0 33 00 00 movq $0x33,-0x10(%rbp)
116c: 00
116d: 48 c7 45 e8 0d 00 00 movq $0xd,-0x18(%rbp)
1174: 00
1175: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp)
117c: 00
117d: eb 3b jmp 11ba <xor+0x61>
117f: 48 8b 55 d8 mov -0x28(%rbp),%rdx
1183: 48 8b 45 f8 mov -0x8(%rbp),%rax
1187: 48 01 d0 add %rdx,%rax
118a: 0f b6 30 movzbl (%rax),%esi
118d: 48 8b 45 f8 mov -0x8(%rbp),%rax
1191: ba 00 00 00 00 mov $0x0,%edx
1196: 48 f7 75 e8 divq -0x18(%rbp)
119a: 48 8b 45 d0 mov -0x30(%rbp),%rax
119e: 48 01 d0 add %rdx,%rax
11a1: 0f b6 08 movzbl (%rax),%ecx
11a4: 48 8b 55 d8 mov -0x28(%rbp),%rdx
11a8: 48 8b 45 f8 mov -0x8(%rbp),%rax
11ac: 48 01 d0 add %rdx,%rax
11af: 31 ce xor %ecx,%esi
11b1: 89 f2 mov %esi,%edx
11b3: 88 10 mov %dl,(%rax)
11b5: 48 83 45 f8 01 addq $0x1,-0x8(%rbp)
11ba: 48 8b 45 f8 mov -0x8(%rbp),%rax
11be: 48 3b 45 f0 cmp -0x10(%rbp),%rax
11c2: 72 bb jb 117f <xor+0x26>
11c4: 90 nop
11c5: 90 nop
11c6: 5d pop %rbp
11c7: c3 retq
00000000000011c8 <main>:
11c8: 55 push %rbp
11c9: 48 89 e5 mov %rsp,%rbp
11cc: 48 81 ec a0 00 00 00 sub $0xa0,%rsp
11d3: 89 bd 6c ff ff ff mov %edi,-0x94(%rbp)
11d9: 48 89 b5 60 ff ff ff mov %rsi,-0xa0(%rbp)
11e0: 48 8d 05 21 0e 00 00 lea 0xe21(%rip),%rax # 2008 <_IO_stdin_used+0x8>
11e7: 48 89 45 f8 mov %rax,-0x8(%rbp)
11eb: 48 8d 05 7d 0e 00 00 lea 0xe7d(%rip),%rax # 206f <_IO_stdin_used+0x6f>
11f2: 48 89 45 f0 mov %rax,-0x10(%rbp)
11f6: 48 b8 09 34 2a 39 27 movabs $0xc1f1027392a3409,%rax
11fd: 10 1f 0c
1200: 48 ba 1d 56 6c 5c 51 movabs $0x11512515c6c561d,%rdx
1207: 12 15 01
120a: 48 89 45 b0 mov %rax,-0x50(%rbp)
120e: 48 89 55 b8 mov %rdx,-0x48(%rbp)
1212: 48 b8 08 3e 04 18 1c movabs $0x5a411e1c18043e08,%rax
1219: 1e 41 5a
121c: 48 ba 52 59 12 06 06 movabs $0x3412090606125952,%rdx
1223: 09 12 34
1226: 48 89 45 c0 mov %rax,-0x40(%rbp)
122a: 48 89 55 c8 mov %rdx,-0x38(%rbp)
122e: 48 b8 15 0b 17 6e 54 movabs $0x12535c546e170b15,%rax
1235: 5c 53 12
1238: 48 ba 0e 0f 32 15 03 movabs $0x3a110315320f0e,%rdx
123f: 11 3a 00
1242: 48 89 45 d0 mov %rax,-0x30(%rbp)
1246: 48 89 55 d8 mov %rdx,-0x28(%rbp)
124a: c7 45 df 00 5a 4a 4e movl $0x4e4a5a00,-0x21(%rbp)
1251: 83 bd 6c ff ff ff 03 cmpl $0x3,-0x94(%rbp)
1258: 0f 85 ce 00 00 00 jne 132c <main+0x164>
125e: 48 8b 85 60 ff ff ff mov -0xa0(%rbp),%rax
1265: 48 83 c0 08 add $0x8,%rax
1269: 48 8b 00 mov (%rax),%rax
126c: 48 8d 15 0a 0e 00 00 lea 0xe0a(%rip),%rdx # 207d <_IO_stdin_used+0x7d>
1273: 48 89 d6 mov %rdx,%rsi
1276: 48 89 c7 mov %rax,%rdi
1279: e8 d2 fd ff ff callq 1050 <strcmp@plt>
127e: 85 c0 test %eax,%eax
1280: 0f 85 a6 00 00 00 jne 132c <main+0x164>
1286: 48 8b 85 60 ff ff ff mov -0xa0(%rbp),%rax
128d: 48 83 c0 10 add $0x10,%rax
1291: 48 8b 00 mov (%rax),%rax
1294: 48 8b 55 f8 mov -0x8(%rbp),%rdx
1298: 48 89 d6 mov %rdx,%rsi
129b: 48 89 c7 mov %rax,%rdi
129e: e8 ad fd ff ff callq 1050 <strcmp@plt>
12a3: 85 c0 test %eax,%eax
12a5: 0f 85 81 00 00 00 jne 132c <main+0x164>
12ab: 48 8d 05 de 0d 00 00 lea 0xdde(%rip),%rax # 2090 <_IO_stdin_used+0x90>
12b2: 48 89 c7 mov %rax,%rdi
12b5: e8 76 fd ff ff callq 1030 <puts@plt>
12ba: 48 8b 45 b0 mov -0x50(%rbp),%rax
12be: 48 8b 55 b8 mov -0x48(%rbp),%rdx
12c2: 48 89 85 70 ff ff ff mov %rax,-0x90(%rbp)
12c9: 48 89 95 78 ff ff ff mov %rdx,-0x88(%rbp)
12d0: 48 8b 45 c0 mov -0x40(%rbp),%rax
12d4: 48 8b 55 c8 mov -0x38(%rbp),%rdx
12d8: 48 89 45 80 mov %rax,-0x80(%rbp)
12dc: 48 89 55 88 mov %rdx,-0x78(%rbp)
12e0: 48 8b 45 d0 mov -0x30(%rbp),%rax
12e4: 48 8b 55 d8 mov -0x28(%rbp),%rdx
12e8: 48 89 45 90 mov %rax,-0x70(%rbp)
12ec: 48 89 55 98 mov %rdx,-0x68(%rbp)
12f0: 8b 45 df mov -0x21(%rbp),%eax
12f3: 89 45 9f mov %eax,-0x61(%rbp)
12f6: 48 8b 55 f0 mov -0x10(%rbp),%rdx
12fa: 48 8d 85 70 ff ff ff lea -0x90(%rbp),%rax
1301: 48 89 d6 mov %rdx,%rsi
1304: 48 89 c7 mov %rax,%rdi
1307: e8 4d fe ff ff callq 1159 <xor>
130c: 48 8d 85 70 ff ff ff lea -0x90(%rbp),%rax
1313: 48 89 c6 mov %rax,%rsi
1316: 48 8d 05 95 0d 00 00 lea 0xd95(%rip),%rax # 20b2 <_IO_stdin_used+0xb2>
131d: 48 89 c7 mov %rax,%rdi
1320: b8 00 00 00 00 mov $0x0,%eax
1325: e8 16 fd ff ff callq 1040 <printf@plt>
132a: eb 0f jmp 133b <main+0x173>
132c: 48 8d 05 95 0d 00 00 lea 0xd95(%rip),%rax # 20c8 <_IO_stdin_used+0xc8>
1333: 48 89 c7 mov %rax,%rdi
1336: e8 f5 fc ff ff callq 1030 <puts@plt>
133b: b8 00 00 00 00 mov $0x0,%eax
1340: c9 leaveq
1341: c3 retq
Now time for the mighty radare2.
$ r2 -e bin.relocs.apply=true -A zeus
INFO: Analyze all flags starting with sym. and entry0 (aa)
INFO: Analyze imports (af@@@i)
INFO: Analyze entrypoint (af@ entry0)
INFO: Analyze symbols (af@@@s)
INFO: Analyze all functions arguments/locals (afva@@@F)
INFO: Analyze function calls (aac)
INFO: Analyze len bytes of instructions for references (aar)
INFO: Finding and parsing C++ vtables (avrr)
INFO: Analyzing methods (af @@ method.*)
INFO: Recovering local variables (afva@@@F)
INFO: Type matching analysis for all functions (aaft)
INFO: Propagate noreturn information (aanr)
INFO: Use -AA or aaaa to perform additional experimental analysis
-- This is an unacceptable million year dungeon.
[0x00001070]> afl
0x00001030 1 6 sym.imp.puts
0x00001040 1 6 sym.imp.printf
0x00001050 1 6 sym.imp.strcmp
0x00001060 1 6 sym.imp.__cxa_finalize
0x00001070 1 34 entry0
0x000010a0 4 34 sym.deregister_tm_clones
0x000010d0 4 51 sym.register_tm_clones
0x00001110 5 54 entry.fini0
0x00001150 1 9 entry.init0
0x00001344 1 9 sym._fini
0x00001159 4 111 sym.xor
0x000011c8 6 378 main
0x00001000 3 23 sym._init
[0x00001070]> s sym.main
[0x000011c8]> v
This will enter us into radare2's visual mode interface.

As we can see, there are two calls to strcmp(3). The first one compares argv[1] with the string "-invocation" and the second one compares argv[2] against some other string; likely our answer. This corresponds to the following invocation:
$ ./zeus -invocation <MAGIC_STRING>
If we trace the value of the parameters to the second strcmp call, we can see that rsi takes on a value computed earlier in main by the first lea instruction. This instruction computes the address of a string in the program's .rodata section, namely: "To Zeus Maimaktes, Zeus who comes when the north wind blows, we offer our praise, we make you welcome!". This leaves us with the final invocation:
$ ./zeus -invocation "To Zeus Maimaktes, Zeus who comes when the north wind blows, we offer our praise, we make you welcome!"
Let's execute the program inside a container.
$ docker run --rm -it -v "$PWD":/work -w /work ubuntu:22.04 bash
root@b96233869153:/work# ./zeus -invocation "To Zeus Maimaktes, Zeus who comes when the north wind blows, we offer our praise, we make you welcome!"
Zeus responds to your invocation!
His reply: DUCTF{king_of_the_olympian_gods_and_god_of_the_sky}AU