[LeHack] - Singularity
·3 mins·
0
·
0
·
CTF
Crypto
LeHack
Table of Contents
LeHack2025 - This article is part of a series.
Part 3: This Article
Description #
We are given the following Python script, which retrieves the :
import base64
def banner():
BANNER = """CgogICAgICAgICAgICAgICAgICAuYW5kQUhIQWJubi4KICAgICAgICAgICAgICAgLmFBSEhIQUFV
VUFBSEhIQW4uCiAgICAgICAgICAgICAgZEhQXn4iICAgICAgICAifl5USGIuCiAgICAgICAgLiAg
IC5BSEYgICAgICAgICAgICAgICAgWUhBLiAgIC4KICAgICAgICB8ICAuQUhIYi4gICAgICAgICAg
ICAgIC5kSEhBLiAgfAogICAgICAgIHwgIEhIQVVBQUhBYm4gICAgICBhZEFIQUFVQUhBICB8CiAg
ICAgICAgSSAgSEZ+Il9fX19fICAgICAgICBfX19fIF1ISEggIEkgICAgCiAgICAgICBISEkgSEFQ
SyIifl5ZVUhiICBkQUhISEhISEhISEggSUhICiAgICAgICBISEkgSEhIRCZndDsgLmFuZEhIICBI
SFVVUF5+WUhISEggSUhIICAgICAgIFdlbGNvbWUgYmFjayB0byB0aGUgc2luZ3VsYXJpdHkgIQog
ICAgICAgWVVJIF1ISFAgICAgICJ+WSAgUH4iICAgICBUSEhbIElVUAogICAgICAgICIgIGBISyAg
ICAgICAgICAgICAgICAgICBdSEgnICAiICAgICAgICAgICAgICAgQ2FuIHlvdSBmaW5kIG15IHBh
c3N3b3JkID8KICAgICAgICAgICAgVEhBbi4gIC5kLmFBQW4uYi4gIC5kSEhQCiAgICAgICAgICAg
IF1ISEhIQUFVUCIgfn4gIllVQUFISEhIWwogICAgICAgICAgICBgSEhQXn4iICAuYW5ubi4gICJ+
XllISCcKICAgICAgICAgICAgIFlIYiAgICB+IiAiIiAifiAgICBkSEYKICAgICAgICAgICAgICAi
WUFiLi5hYmRISGJuZGJuZEFQIgogICAgICAgICAgICAgICBUSEhBQWIuICAuYWRBSEhGCiAgICAg
ICAgICAgICAgICAiVUhISEhISEhISEhVIgogICAgICAgICAgICAgICAgICBdSEhVVUhISEhISFsK
ICAgICAgICAgICAgICAgIC5hZEhIYiAiSEhISEhibi4KICAgICAgICAgLi5hbmRBQUhISEhISGIu
QUhISEhISEhBQWJubi4uCiAgICAubmRBQUhISEhISFVVSEhISEhISEhISFVQXn4ifl5ZVUhISEFB
Ym4uCiAgICAgICJ+XllVSEhQIiAgICJ+XllVSEhVUCIgICAgICAgICJeWVVQXiIKICAgICAgICAg
ICAiIiAgICAgICAgICJ+fiIK"""
print(base64.b64decode(BANNER).decode())
def check_password(password):
singularity = lambda t: (ord(t[1])+t[0])^0x42 == bytes.fromhex(
base64.b64decode('MDExMjMyN2IzNDdiMzgxODI1MjA3OGMyMjkxMTNmYzYzYzM3MzMzZDNiMTljMDE1MWQ=').decode()
)[t[0]]
return all(map(singularity, enumerate(password)))
def main():
banner()
password = input("Enter the password> ")
if check_password(password):
print("You can validate with leHACK{{{}}}".format(password))
else:
print("Error: Wrong password")
if __name__ == '__main__':
main()
Analysis #
- The first part of the script displays ASCII art (although very pretty, it’s useless for solving the challenge).
- Next, the script asks us to enter a password which will be given to the
check_password
function.- If the password is not the one expected, the script returns the message ‘Error: Wrong password’.
- If the password is valid, the script returns the message ‘You can validate with leHACK{}’.
Our goal is to find the password verified by the
check_password
function, as this is the flag!
Let’s take a closer look at the check_password
function:
- It’s an anonymous function (represented by the word
lambda
) taking a tuple :- t[0] → the index of the character in the password
- t[1] → the character at this position
- This function performs a mathematical operation for each character in the password:
- It retrieves the character’s ASCII code (
ord(t[1])
) - Adds its position (
+ t[0]
) - And XOR the result with 0x42 (= 66 in decimal)
- It retrieves the character’s ASCII code (
- Finally, this function compares the result with an obfuscated string
- This string is encoded in base64, decoded to give a result in hexadecimal, and then transformed into a byte list.
- The byte list gives :
[1, 18, 50, 123, 52, 123, 56, 24, 37, 32, 120, 194, 41, 17, 63, 198, 60, 55, 51, 61, 59, 25, 192, 21, 29]
Solving #
The expected password is in this string. To find it, we can use the logic of the function :
(ord(char) + i) ^ 0x42 == valeur_attendue[i]
char
is the character at position i in the password, expected_value
is the byte listAnd reverse it:
ord(char) = (valeur_attendue[i] ^ 0x42) - i
With a Python script that performs this action for all the bytes in the list and displays the final result, we obtain :
import base64
# Step 1: Decode the string to obtain the byte list
encoded = 'MDExMjMyN2IzNDdiMzgxODI1MjA3OGMyMjkxMTNmYzYzYzM3MzMzZDNiMTljMDE1MWQ='
hex_string = base64.b64decode(encoded).decode()
target_bytes = bytes.fromhex(hex_string)
# Step 2: Invert the formula to find the password
# We have : (ord(c) + i) ^ 0x42 == target_bytes[i]
# Which becomes: ord(c) = (target_bytes[i] ^ 0x42) - i
password_chars = []
for i, val in enumerate(target_bytes):
c = (val ^ 0x42) - i
password_chars.append(chr(c))
password = ''.join(password_chars)
# Step 3: Display password
print(password)
The result is : COn6r4tS_Y0u_Found_leFl@G
🚩 Flag : leHACK{COn6r4tS_Y0u_Found_leFl@G}
LeHack2025 - This article is part of a series.
Part 3: This Article