Dynastic Writeup - Cyber Apocalypse 2024
→ 1 Introduction
This writeup covers the Dynastic Crypto challenge from the Hack The Box Cyber Apocalypse 2024 CTF, which was rated as having a ‘very easy’ difficulty. The challenge involved implementing a ‘decryption’ function for a provided Python ‘encryption’ function.
The description of the challenge is shown below.
→ 2 Key Techniques
The key techniques employed in this writeup are:
- Manual Python source code review
- Adapting existing Python source code
→ 3 Artifacts Summary
The downloaded artifact had the following hash:
$ shasum -a256 crypto_dynastic.zip
353327ad9d0191bfc9e2622ff346236d0be7d7870b2195846fee81cfad0f3653 crypto_dynastic.zip
The zip file contained a single Python source code file,
source.py
, and output.txt
:
$ unzip crypto_dynastic.zip
Archive: crypto_dynastic.zip
creating: crypto_dynastic/
inflating: crypto_dynastic/source.py
inflating: crypto_dynastic/output.txt
$ shasum -a256 crypto_dynastic/*
d0e599602c813536965e71233bac5b4272a2a221292c661098b7185a79e26684 crypto_dynastic/output.txt
f2079b4bbf17e3b3518707b2f658b058b38131e7bd3428b90f930d97831f848c crypto_dynastic/source.py
→ 4 Static Analysis
→ 4.1 output.txt
output.txt
contained a single line comment, followed by
a line containing the flag. The flag only contained upper case letters,
’_‘,’?’ and ‘!’ characters.
Make sure you wrap the decrypted text with the HTB flag format :-]
DJF_CTA_SWYH_NPDKK_MBZ_QPHTIGPMZY_KRZSQE?!_ZL_CN_PGLIMCU_YU_KJODME_RYGZXL
→ 4.2 source.py
source.py
contains Python code that ‘encrypts’ the flag
as follows:
- Lines 12-13 loop through each character in the flag
- Lines 14-15 leave the character untouched if it is not an alphabetic character
-
Lines 17-18 transform each character in the flag with the aid of two
functions
-
to_identity_map
converts the character to its integer representation, then returns the offset from0x41
(decimal 65), which corresponds to ‘A’. For example, ‘E’ will become 4. -
from_identity_map
is then called with an offset equal to the index of the current character in the flag. For example, if the ‘E’ in the previous example is the 29th character currently being encrypted,from_identity_map
will be called with4 + 28 == 32
, since string indices start from 0. -
from_identity_map
computesa % 26
(the integer remainder after dividing by 26), before adding it to0x41
and converting the result back to a character. Continuing with the same example,32 % 26
will be 6. Added to0x41
and converted back to a character will becomeG
.
-
from secret import FLAG
from random import randint
def to_identity_map(a):
return ord(a) - 0x41
def from_identity_map(a):
return chr(a % 26 + 0x41)
def encrypt(m):
c = ''
for i in range(len(m)):
ch = m[i]
if not ch.isalpha():
ech = ch
else:
chi = to_identity_map(ch)
ech = from_identity_map(chi + i)
c += ech
return c
with open('output.txt', 'w') as f:
f.write('Make sure you wrap the decrypted text with the HTB flag format :-]\n')
f.write(encrypt(FLAG))
→ 5 Implementing the decoder
decrypt.py
was implemented that does the opposite of
what source.py does
:
-
Line 7: the
encrypt
function has been renamed todecrypt
-
Line 15 reverses the offset, passing
chi - i
tofrom_identity_map
. Notably, this simple change is sufficient to reverse the ‘encryption’ -
Line 19 opens
output.txt
in read mode -
Line 20 ignores the first line in
output.txt
-
Line 21 calls
decrypt
instead ofencrypt
def to_identity_map(a):
return ord(a) - 0x41
def from_identity_map(a):
return chr(a % 26 + 0x41)
def decrypt(m):
c = ''
for i in range(len(m)):
ch = m[i]
if not ch.isalpha():
ech = ch
else:
chi = to_identity_map(ch)
ech = from_identity_map(chi - i)
c += ech
return c
with open('output.txt', 'r') as f:
f.readline()
print(f"HTB{{{decrypt(f.readline())}}}")
→ 6 Obtaining the flag
The script was run and the flag was obtained:
$ python3 decrypt.py
HTB{DID_YOU_KNOW_ABOUT_THE_TRITHEMIUS_CIPHER?!_IT_IS_SIMILAR_TO_CAESAR_CIPHER}
→ 7 Conclusion
The flag was submitted and the challenge was marked as pwned