| jmcph4 |

DownUnderCTF 2025 Solutions

Beginner

Zeus

Challenge

Answer

DUCTF{king_of_the_olympian_gods_and_god_of_the_sky}CV

Solution

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,

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