ThaySan
  • 👋Bienvenue
    • Avant-propos
  • 🚩CTF & Writeups
    • 2025 | EC2
      • Let's Crax
    • 2025 | HackDay
      • 🔑Cryptographie
        • Drunk Christmas
        • Find Eve 1
        • Well hidden message - Standard Code Encryption
      • 🔎Forensic
        • Copperwire Extraction
        • Distracted user
        • I believe you can't fly
      • 🧠Misc
        • Hello Steve
      • 💾Programmation
        • Lonely bot
        • Lonely bot #2
        • Lonely bot #3
        • Useless Animals Sorting
        • Who cares about SSI anyway ?
      • ⚙️Reverse
        • Just dig
        • Rusty_rev
        • The Cogs of Blackmail
      • 🎭Steganographie
        • It says a lot when there is no music
        • Mona LSB
        • Well hidden message - Insignificant blue
      • 🌐Web
        • Super Website Verificator 3000
        • The analytical engine leak
        • The Watchful Gears: Uncover the Secrets Within
        • Your region's finest
    • 2024 | Efrei - CyberNight
      • 🔑Cryptographie
        • Clavier spécial
        • Le futur
        • Securechain 30.0
        • Cascade
        • Shared Flag
        • Weird Algorithm
      • 🧊Minecraft
        • Introduction
        • Non aux Bouquins Trafiqués
        • Redstone Gold Block
      • 💾Programmation
        • Captcha 1.0
        • Intro à la prog
        • Captcha 2.0
      • ⚙️Reverse
        • Reverse the Reverse
        • Find me if you can
        • HuGO Decrypt
        • Kitten eXORcism
        • M30W Vault Tech
        • The Ugandan Labyrinth
      • 🎭Stéganographie
        • Le message
        • bon Le ordre
        • COD FORFLAG
        • Mauvaise note
        • Bruit
        • Un (un ?) drôle de QR code
        • Randonnée Guillerette à Bordeaux
      • 💻Système
        • Marche-pied
        • Escabot
        • régulation des Données et des Normes de Sécurité
      • 🌐Web
        • cybernight.zip
        • Mon champion préféré
        • Co(mpressed)okies
        • Gitty Mistake
        • JWT Kiddo
        • Parseur Farceur
      • L'enquête
        • L'enquête 2/6
        • L'Enquête 1/6
        • Bienvenue, enquêteur
    • 2024 | Star-Hack
      • 🔑Cryptographie
        • César, mais pas César
        • Double ennui
        • Langage secret
        • Quadratique Mystérieuse
        • ReSultAt
        • Sup3r S3cr3t
        • Warmup
      • 🔎Forensic
        • Cache-cache
        • Fichier ZIP protégé par mot de passe
        • HEADER
        • Investigation 1
        • Investigation 2
      • 🧠Misc
        • B4l4d3 Urb41n3
        • Bruhh, c'est quoi ça ?
        • Cut13
        • Pika Pika
      • 😈Pwn
        • Pwn0x01
        • Pwn0x02
        • Pwn0x03
      • ⚙️Reverse
        • Assembly
        • Rev0x00
        • Rev0x01
        • Rev0x02
      • 🌐Web
        • Clone Udemy
        • Flask
        • Guess_The_Passcode
        • PHP
        • Tickets
        • Usine de Cookies
    • 2024 | ECW
      • 🔑Cryptographie
        • Course hipPIN
    • 2024 | CTFREI Intro
      • 🔑Cryptographie
        • AES Intro
        • Aléatoire
        • Game of Luck
        • RSA Intro
        • RSA2
        • RSA3
      • 🔎Forensic
        • Mais qui est le photographe ?
        • Mais où est passé mon flag ?
        • Mémoire 1/4
        • Mémoire 2/4
        • Mémoire 3/4
        • Mémoire 4/4
        • My computer is talking
      • 📚OSINT
        • Avion ✈
        • Geoint
        • Google!
        • Googlint
        • Le pivot
        • Le temps commence maintenant
        • Sacré dossier
        • Socint
      • 💾Programmation
        • Try Me
        • Answer Me
        • Eval Me
        • Time Based
      • 😈Pwn
        • BOF Intro
        • Shop
        • BOF 2
        • BOF win()
      • ⚙️Reverse
        • CrackMe1
        • CrackMe2
        • CrackMe3
        • Hidden...
        • Something changed?
        • ZZZ
      • 🎭Stéganographie
        • Cybernight être comme
        • Joli paysage
        • Petit poisson
        • StegHide 'n' Seek
        • Un canard pas comme les autres
      • 💻Système
        • Bash Jail
        • Bash Jail Revenge
        • BrokenBin
        • GTFO Of Here
        • Pyjail
        • Pyjail Revenge
        • Strange input, right?
      • 🌐Web
        • SQLi
        • POST This Money
        • Give me my Flask PIN
        • Access
        • Render
        • RenderV2
        • Touchy
    • 2024 | DefCamp
      • 🔑Cryptographie
        • conv
        • oracle-srl
        • ctr
      • 🔎Forensic
        • i-got-a-virus
        • Alternating
        • call-me-pliz
      • 🧠Misc
        • pyterm
      • 📱Mobile
        • mobisec
      • 📚OSINT
      • 😈Pwn
      • ⚙️Reverse
      • 🕵️Traque
      • 🌐Web
        • noogle
        • production-bay
    • 2024 | 404CTF
      • 🔑Cryptographie
        • Bébé nageur
        • Le petit bain
        • Poor Random Number Generator [1/2]
        • Plongeon Rapide Super Artistique
        • J'éponge donc j'essuie
        • Poor Random Number Generator [2/2]
        • La Seine
        • J'ai glissé chef !
        • SEA - La face cachée de l'Iceberg
      • 🔎Forensic
        • Le tir aux logs
        • Darts Bank
        • Vaut mieux sécuriser que guérir
        • De bons croissants au beurre
        • Poids Raw vs. Cours Jette [1/3]
      • 🔌Hardware
        • Serial killer
        • Le soulevé de GND
        • Comment est votre modulation ? [1/2]
        • Sea side channel [1/4] - Introduction
        • Comment est votre modulation ? [2/2]
        • Sea side channel [2/4] - Reconnaissance
        • Sea side channel [3/4] - Mais où sont les triggers ?
      • 🤖IA
        • Du poison [1/2]
        • Du poison [2/2]
        • Des portes dérobées
      • 🧠Misc
        • Discord
        • De la friture sur la ligne
        • Bienvenue
        • Revers(ibl)e Engineering [0/2]
      • 📚OSINT
        • Légende
        • Not on my watch
        • Secret Training [1/2]
      • 😈Pwn
        • Pseudoverflow
        • Jean Pile
        • Mordu du 100m
        • Antismash
      • 🐈‍⬛Quantique
        • Des trains superposés
        • De l'écoute, pas très discrète
        • De la multiplicité des problèmes
      • ⚙️Reverse
        • ⭐Échauffement
        • ⭐Intronisation du CHAUSSURE
        • ⭐Bugdroid Fight [1/2]
        • ⭐Revers(ibl)e Engineering [1/2]
        • ⭐Bugdroid Fight [2/2]
        • ⭐Nanocombattants
        • ⭐Revers(ibl)e Engineering [2/2]
        • Le Tableau Noir
      • 🎭Stéganographie
        • ⭐L'absence
        • ⭐Regarder en stéréo
        • ⭐La Barre Fixe
        • ⭐Le grand écart
        • ⭐La chute
      • 🌐Web
        • ⭐Vous êtes en RETARD
        • ⭐Le match du siècle [1/2]
        • ⭐Exploit mag
        • ⭐Le match du siècle [2/2]
        • ⭐LE GORFOU 42
        • ⭐La boutique officielle
    • 2024 | CTFREI - Bordeaux
      • 🔑Cryptographie
        • zzz
      • 📚OSINT
        • Alexis Dumas
        • Back to the bureau
        • Dr Octopus
        • Folie et ambition
        • GeoGuessr
        • Hugo Nelots : prélude
        • La fin ?
        • La fuite Dumas
        • Un réseau suspect
      • 💾Programmation
        • Eval me 1
        • Eval me 2
        • Time Based
      • 💻Système
        • Broken Binary 1
        • Broken Binary 2
        • GTFO of here
        • Pyjail 1
        • Pyjail 2
        • Pyjail 3
        • Pyjail 4
      • 🌐Web
        • Au commencement était le verb
        • Becadmin
        • PHP Juggler
    • 2024 | HTB - Cyber Apocalypse Challenges
      • 🔗Blockchain
        • Lucky Faucet
        • Recovery
        • Russian Roulette
      • 🔑Cryptographie
        • Blunt
        • Dynastic
        • Iced TEA
        • Makeshift
        • Primary Knowledge
      • 🔎Forensic
        • An unusual sighting
        • Data Siege
        • Fake Boost
        • Game Invitation
        • It Has Begun
        • Phreaky
        • Pursue The Tracks
        • Urgent
      • 🔌Hardware
        • BunnyPass
        • Flash-ing Logs
        • Maze
        • Rids
        • The PROM
      • 🧠Misc
        • Character
        • Cubicle Riddle
        • Path of Survival
        • Stop Drop and Roll
        • Unbreakable
        • Were Pickle Phreaks
        • Were Pickle Phreaks Revenge
      • 😈Pwn
        • Delulu
        • Pet Companion
        • Tutorial
        • Writing on the Wall
      • ⚙️Reverse
        • BoxCutter
        • Crushing
        • FollowThePath
        • LootStash
        • MazeOfPower
        • Metagaming
        • PackedAway
        • QuickScan
      • 🌐Web
        • Flag Command
        • KORP Terminal
        • Labyrinth Linguist
        • LockTalk
        • Testimonial
        • TimeKORP
    • 2024 | UNbreakable
      • 🔑Cryptographie
        • start-enc
        • traffic-e
      • 🔎Forensic
        • easy-hide
        • password-manager-is-a-must
      • 🧠Misc
        • rfc-meta
      • 📱Mobile
        • flagen
        • improper-configuration
      • 📡Network
        • wifi-basic
        • wifiland
      • 📚OSINT
        • persistent-reccon
        • safe-password
      • 😈Pwn
        • intro-to-assembly
      • ⚙️Reverse
        • fake-add
      • 🎭Stéganographie
        • secrets-of-winter
      • 🌐Web
        • pygment
        • sided-curl
        • you-can-trust-me
    • 2023 | EFREI - CyberNight
      • 📚OSINT
        • Invest Now !
      • 😈Pwn
        • NSA Call Converter
      • ⚙️Reverse
        • CryptoVirus
        • WebChaussettes
      • 🌐Web
        • DoctoLeak
    • 2023 | Flag4All
      • 🔑Cryptographie
        • Aes IV
        • Crypt my loop
        • Kentucky fried chicken
        • RSA primes
        • Xor
    • 2022 | EFREI - CyberNight
      • 🔑Cryptographie
        • Coupé-décalé
        • ExFILEtration
        • Il s'est baissé ou pas
        • J'ai pas roté
        • Les allemands !
        • RSA Strong Prime generator
      • 🔎Forensic
        • Bomberman 1/2
        • Bomberman 2/2
        • Magic
        • Peu importe le chemin
        • Sniff sniff
        • Souvenir
        • Xray
      • 🔌Hardware
        • Class4
        • Find me 2/3
        • Identify 1/3
        • Yo listen 3/3
      • 🧠Misc
        • Et je tombe tombe tombe
        • Des yeux partout
        • RiGOLe
        • Roomba tricheur
        • Survey
        • Tinder
      • 💾Programmation
        • Repeat
        • Startup
        • Timing
      • ⚙️Reverse
        • Auth 1
        • Auth2
        • Auth3
        • Cryptoroomba
        • Tenet
      • 🎭Stéganographie
        • 50 shades of stephane legar
        • Chess master
        • Deviens champion sers toi de tout ce que tu as appris
        • Drifting in the bits
        • Pyramide
        • Spirale
      • 🌐Web
        • Ah bah c'est du propre
        • Cooking roomba
        • Leaderboard
        • vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
Propulsé par GitBook
Sur cette page
  • Challenge
  • Solution
  • Connaître la taille du flag
  • Début du flag
  • Fonction de chiffrement
  • Déchiffrement

Cet article vous a-t-il été utile ?

  1. CTF & Writeups
  2. 2025 | EC2

Let's Crax

Précédent2025 | EC2Suivant2025 | HackDay

Dernière mise à jour il y a 1 mois

Cet article vous a-t-il été utile ?

Flag: flag{Th1s_Py7h0n_VM_h4s_n0_s3cr3t5_f0r_m3}

Challenge

Description


Aucune description

Solution

Commençons par quelques modifications pour automatiser nos essais. Terminé les print, on s'en cogne donc on commente :

180:    elif syscall_id == 0x4:
181:        # Display byte from memory
182:        self.add_pc(2)
183:        # print(chr(self.get_byte_from_mem(self.registers[2])), end="")
184:        return 1

Pareil pour l'input, on va passer le flag à tester directement lors de la création de la VM et remplacer la ligne de l'input par le flag en question :


20: class VM:
21:
22:    def __init__(self, flag: str) -> None:
23:        self.flag = flag

# [...] reste du code

185:        elif syscall_id == 0x5:
186:            # Read stdin to memory
187:            self.add_pc(2)
188:            # data = input()
189:            data = self.flag
190:            data_byte_array = bytearray(data.encode())

Maintenant, on est prêt...

Connaître la taille du flag

On va modifier le fichier vm.py. Pour ça, on ajoute dans run() la variable instruction_count au début, et dans sa boucle while, on va incrémenter cette variable. Enfin, on la retourne en fin de fonction.

Elle nous permet de compter le nombre d'instructions jouées, et donc de savoir si on a provoqué une modification en fonction de notre input.

  def run(self, entry_point: int) -> None:
        instructions_count = 0
        self.jmp(entry_point)
        while True:
            instructions_count += 1
            if self.registers[self.pc] == 0xBADC0DE:
# [...] Reste du code 

On va lancer la vm avec plein de flags de tailles différentes :

def start():
    program = open('program.bin', "rb").read()
    for i in range(45):
        vm = VM("a" * i)
        entry_point = vm.load_code(program)
        n = vm.run(entry_point)
        print(i, n)

# 40 1032
# 41 1032
# 42 1044   <-- Lezgoooo
# 43 1032
# 44 1032

Avec un flag de 42 caractères, on fait plus d'instructions. Donc, on comprend qu'il y avait une condition sur la taille du flag et qu'on l'a validée avec 42 caractères.

Début du flag

On va réutiliser le même principe en espérant que le binaire vérifie caractère par caractère le flag. Donc, on va tester tous les caractères possibles à la première position et voir s'il y a quelque chose qui change :

def start():
    program = open('program.bin', "rb").read()
  
    CHARSET = string.ascii_letters + string.digits + string.punctuation
    flag_size = 42
    base_flag = ''
    for c in CHARSET:
        flag = base_flag + c + 'a' * (flag_size - len(base_flag) - 1)
        vm = VM(flag)
        entry_point = vm.load_code(program)
        n = vm.run(entry_point)
        print(c, n)

# a 1044
# b 1044
# c 1044
# d 1044
# e 1044
# f 1048
# g 1044
# h 1044

Avec f il y a plus d'instructions jouées, comme si on avait passé une condition de plus. Si on continue en gardant le f au début et en testant le 2nd caractère, on obtient

j 1048
k 1048
l 1056
m 1048
n 1048

Le second caractère est l. Si on continue comme ça, on obtient le début flag{. Malheureusement, plus rien ensuite. En réfléchissant un peu, on se doute que le dernier caractère est }. Et ça tombe bien, ça augmente beaucoup nos instructions :

def start():
    program = open('program.bin', "rb").read()
    
    CHARSET = string.ascii_letters + string.digits + string.punctuation
    flag = 'flag{' + 'a' * 36 + '}'
    vm = VM(flag)
    entry_point = vm.load_code(program)
    n = vm.run(entry_point)
    print(n)
# 1354

Fonction de chiffrement

Ce qui se trouve à l'intérieur du flag est chiffré et vérifié. On peut le voir en ajoutant des lignes dans la fonction enc().

Un petit tour sur ChatGPT avec le bout de code en question nous apprend qu'il s'agit possiblement d'une variante de Tiny Encryption Algorithm et que c'est donc réversible !

Cette fonction est appelée une fois qu'on a trouvé le début et la fin du flag justement. On va donc afficher les variables qui la concerne et qui nous intéressent :

  • k : la clé de chiffrement

  • y et z : 4 caractères de notre input en clair au début et chiffrés à la fin

    def enc(self, reg1: int, reg2: int,  reg3: int) -> None:
# [...] reste du code

        print('BEFORE ENCRYPTION:')
        print(f'k: {k}')
        print(f'y: {y.value} -> {y.value.to_bytes(4, 'little')}')
        print(f'z: {z.value} -> {z.value.to_bytes(4, 'little')}')

        sum = c_uint32(0)
        delta = 0x9e3779b9
        n = 32

        while(n>0):
            sum.value += delta & 0xffffffff
            y.value += ( z.value << 4 ) + k[0] ^ z.value + sum.value ^ ( z.value >> 5 ) + k[1] & 0xffffffff
            z.value += ( y.value << 4 ) + k[2] ^ y.value + sum.value ^ ( y.value >> 5 ) + k[3] & 0xffffffff
            n -= 1
            
        print('AFTER ENCRYPTION:')
        print(f'y: {y.value} -> {y.value.to_bytes(4, 'little')}')
        print(f'z: {z.value} -> {z.value.to_bytes(4, 'little')}')

Ensuite, on sait qu'elles sont forcément comparés avec le flag, donc on va également afficher avec quoi elles le sont. Pour ça, direction la fonction cmp_regs() :

def cmp_regs(self, reg1: int, reg2: int) -> None:
    # 0x47
    print(self.registers[reg1], self.registers[reg2])

Maintenant, si on lance, on va avoir le résultat de notre input chiffré avec ce à quoi il devrait ressembler. Ici j'utilise le flag flag{abcdefghijklmnopqrstuvwxyzABCDEFGHIJ} :

0 0
0 0
BEFORE ENCRYPTION:
k: [3385206627, 632509235, 1634953960, 3929412302]
y: 1684234849 -> b'abcd'
z: 1751606885 -> b'efgh'
AFTER ENCRYPTION:
y: 2026883528 -> b'\xc8\xc9\xcfx'
z: 3029057199 -> b'\xaf\xbe\x8b\xb4'
2026883528 943156865
10 0
9 0

2026883528 c'est le début du flag chiffré 943156865 c'est le résultat du chiffrement qu'il faudrait

On va donc mettre à jour manuellement y pour éviter que ça quitte et pouvoir voir la prochaine comparaison. De cette façon, on sera capable de récupérer tous les y et z attendus !

J'ajoute la variable encryption_counter dans VM :

class VM:

    def __init__(self, flag: str) -> None:
        self.flag = flag
        self.encryption_counter = 0

Et ensuite, on va compléter notre tableau avec les valeurs attendues :

        compared_values = [
            (943156865, 0),
            (0, 0),
            (0, 0),
            (0, 0),
            (0, 0)
        ]
        y.value = compared_values[self.encryption_counter][0]
        z.value = compared_values[self.encryption_counter][1]
        self.encryption_counter += 1

On voit bien la prochaine comparaison 140430192 :

AFTER ENCRYPTION:
y: 2026883528 -> b'\xc8\xc9\xcfx'
z: 3029057199 -> b'\xaf\xbe\x8b\xb4'
943156865 943156865
0 140430192

Il suffit maintenant de compléter notre tableau au fur et à mesure pour obtenir finalement :

compared_values = [
    (943156865, 140430192),
    (2530532487, 129893444),
    (261106022, 2629986848),
    (3679519246, 3532129935),
    (794422906, 4144136265)
]

Déchiffrement

On a tout ce qu'il nous faut. De mon côté, j'ai demandé à ChatGPT de me faire la fonction de déchiffrement, mais elle est très largement faisable à la main étant donné que l'algo de chiffrement est simple.

from ctypes import c_uint32

def decrypt(y: int, z: int, k: tuple[int, int, int, int]):
    y = c_uint32(y)
    z = c_uint32(z)
    n = 32
    delta = 0x9e3779b9
    sum = c_uint32(delta * n)
    while n > 0:
        z.value -= ((y.value << 4) + k[2]) ^ (y.value + sum.value) ^ ((y.value >> 5) + k[3])
        y.value -= ((z.value << 4) + k[0]) ^ (z.value + sum.value) ^ ((z.value >> 5) + k[1])
        sum.value -= delta
        n -= 1
    return y.value.to_bytes(4, 'little'), z.value.to_bytes(4, 'little')


k = [3385206627, 632509235, 1634953960, 3929412302]
compared_values = [
    (943156865, 140430192),
    (2530532487, 129893444),
    (261106022, 2629986848),
    (3679519246, 3532129935),
    (794422906, 4144136265)
]

flag = b''
for values in compared_values:
  d = decrypt(values[0], values[1], k)
  flag += d[0] + d[1]
print(flag.decode())

# Th1s_Py7h0n_VM_h4s_n0_s3cr3t5_f0r_m3

Finalement, on peut relancer la vraie VM avec le programme en testant notre flag : flag{Th1s_Py7h0n_VM_h4s_n0_s3cr3t5_f0r_m3}

$ python3 vm.py program.bin
Ahoy ! Welcome aboard, matey! I've lost the password to the digital whisky reserve. Help me find it, and I'll be grateful!

Enter the password: flag{Th1s_Py7h0n_VM_h4s_n0_s3cr3t5_f0r_m3}
Good job !
🚩
7KB
letscrax.zip
archive