Writeups
  • â„šī¸Infos
  • đŸ—“ī¸2021
    • DvCTF (to join DaVinciCode)
      • Crypto
        • Baby RSA
        • Ressaye
        • Unbreakable encryption
      • Forensics
        • Broken Portrait
        • Russian Dolls
        • Sus USB
      • Misc
        • Jus de Flag
        • Welcome
      • OSINT
        • Absolutely Nuts
      • Progra
        • Snoop's Mission
      • Reverse
        • Baby Reverse
        • Basic Cracking
        • Code Pyn
      • Steganography
        • Colorful Code
        • Hurt Your Eyes
        • Orchestra of Flags
        • Tyger
      • Web
        • Have I Been Pwned
        • What's Up ?
  • đŸ—“ī¸2022
    • DvCTF 2022
      • Crypto
        • Cwryptographic Owacle
        • Secure Or Not Secure
        • small weiner
      • Forensics
        • Very Bad Script
      • Misc
        • Data Leak
        • Going postal
        • The Hacker Man
      • OSINT
        • Elon Musk
        • Monkeey
        • Painting Spot
        • Welcome to the DaVinciCTF!
      • Pentest
        • DaVinci's Playlist : Part 1
        • DaVinci's Playlist : Part 2.5
        • DaVinci's Playlist : Part 2
      • Programming
        • Heaven's Gate
        • Sudoku
        • TicTacToe
      • Reverse
        • CryptoVault
        • Mine Game
        • Obfuscated
        • Peripheral Interface Controller XVI
      • Steganography
        • ICMP
        • The Arts of Details
        • Treasure
      • Warmup
        • EBG13
        • FrenchFlag
        • MP3
        • QmFzZTY0
        • RSA
        • Welcome
      • Web
        • CyberStreak v1.0
        • đŸŽĩ
    • picoCTF 2022
      • Challs WU
    • @HackDay - Qualifications
      • Crypto
        • Francis Bacon
        • Francs Maçons
        • Rotate-me!
        • Un message codÊ ?
      • Forensics
        • bad_timing_for_reversing
      • Hardware
        • Cubik'cipher
        • WebSDR
      • Reverse
        • Calling Conventions
        • Memory Investigation
      • Steganography
        • I can make pictures
        • J'ai perdu le flag :(
        • PokÊmons
        • Un coup de maÃŽtre
        • Un logo cachotier
      • Web
        • GIT!
        • Part. 1 - Uploads
        • Part. 2 - Old md5
        • Part. 3 - sudo python
    • 404CTF
      • Crypto
        • Un simple oracle [1/2]
        • Un simple oracle [2/2]
      • Misc
        • Je suis une thÊière
        • Pierre-papier-Hallebarde
        • GoGOLFplex
      • OSINT
        • À l'aube d'un Êchange
        • Collaborateur suspect
        • Equipement dÊsuet
      • Reverse
        • Mot de passe ?
      • Steganography
        • La plume à la main
        • PNG : Un logo obèse [1/4]
        • PNG : Drôles de chimères [2/4]
        • Toujours obèse [3/4]
      • Web
        • FichÊ JS
        • Le braquage
        • Du gÃĸteau
        • En construction !
    • Operation Kernel
      • Crypto
        • Scytale
      • Forensics
        • Research Paper
        • Excel Confidential
      • Reverse
        • CryptoLocker
        • What_If_CryptoLocker
      • Social Engineering
        • Pour vivre secure vivons cachÊ
        • Pour vivre secure vivons cachÊ Part 2
      • Stegano
        • AudioSpectre
        • Datacenter
        • Takazume
      • WEB
        • Research paper blog
        • SQL Project 1
        • SQL Project 2
        • SQL Project 3
        • Tenue de soirÊe requise
  • đŸ—“ī¸2023
    • 404CTF 2023
      • RÊsultats
      • Analyse forensique
        • PÃĒche au livre
        • Le Mystère du roman d'amour
        • Les Mystères du cluster de la Comtesse de SÊgur [1/2]
        • Lettres volatiles
        • Note de bas de page
      • Cloud
        • Le Sot
        • Le Cluster de Madame Bovary
        • Harpagon et le magot
        • Les nuages menaçants 1/3
        • Les nuages menaçants 2/3
      • Cryptanalyse
        • Recette
        • ASCON Marchombre
      • Divers
        • Bienvenue
        • Exemple de connexion à distance
        • Discord
        • À vos plumes !
      • Exploitation de binaires
        • Je veux la lune !
      • Programmation
        • L'Inondation
        • Des mots, des mots, des mots
      • Radio-FrÊquence
        • Navi
        • Avez-vous vu les cascades du hÊrisson ?
        • Le Plombier du cÃĸble
        • Ballistic Missile Submarine
      • Renseignement en sources ouvertes
        • Le Tour de France
        • Les OSINTables [1/3]
        • Un vol ?
        • L'Ãĸme d'un poète et le coeur d'une femme [1/4]
        • L'Ãĸme d'un poète et le coeur d'une femme [2/4]
        • L'Ãĸme d'un poète et le coeur d'une femme [3/4]
        • L'Ãĸme d'un poète et le coeur d'une femme [4/4]
      • RÊtro IngÊnierie
        • Le Divin Crackme
        • L'Inspiration en images
      • SÊcuritÊ MatÊrielle
        • Un courrier suspect
        • Un rÊveil difficile
      • StÊganographie
        • Odobenus Rosmarus
        • L'Œuvre
        • Les FÊlicitations
        • En Profondeur
        • Le Rouge et le vert, avec un soupçon de bleu
      • Web
        • Le Loup et le renard
        • L'AcadÊmie du dÊtail
        • La Vie Française
        • Fuite en 1791
        • L'Épistolaire moderne
        • Chanson d'Inde
      • Web3
        • Art
        • L'Antiquaire, tÃĒte en l'air
  • đŸ—“ī¸2025
    • 404CTF 2025
      • RÊsultats
      • Algorithmique Quantique
        • Machinerie quantique
        • Grover (1/2)
        • Grover (2/2)
      • Analyse forensique
        • USB 51
        • Forensic et Mat [1/2]
        • Apprenti Carver [1/2]
        • Dockerflag
        • Forensic et Mat [2/2]
        • Apprenti Carver [2/2]
        • Tape ton MDP
        • Toortik Triflexation [1/2]
        • Toortik Triflexation [2/2]
      • Cryptanalyse
        • Message lointain
        • Entretien galactique
        • R1R2
        • Saturn Cipher
        • Planètes anormales
        • Spacemark
        • You spin me round
        • DÊrive dans l'espace
        • Lunette cosmico galactique
        • Jupiter Cipher
        • Courbe de Lancement
        • More Space
      • Divers
        • Bienvenue
        • Pix2Num
        • Politique de confidentialitÊ
        • Space Traveller
        • Satellisation
        • Étoile binaire [2/2]
      • Exploitation de binaires
        • Gorfou en danger [1/3]
        • Gorfou en danger [2/3]
        • Gorfou en danger [3/3]
        • Spaaaaaaace
        • KerberINT Space Program
        • 22 bytes pour sauver l'univers
        • Bounty Machine
        • Space Odyssey
        • Solaris
        • Cosmic-Base
        • Kalaxy
        • Bokit
      • Intelligence Artificielle
        • Gorfoustral (1/3)
        • Gorfoustral (2/3)
        • Gorfoustral (3/3)
        • Du tatouage
      • Renseignement en sources ouvertes
        • L'addition est salÊe
        • Une mission inconnue
        • Earth Attack (0/2)
        • Un satellite qui vaut de l'or
        • Un peu de vacances
        • La ville en rose
        • Earth Attack (1/2)
        • La tÃĒte dans les Êtoiles
        • En eaux sombres
        • Earth Attack (2/2)
        • DPOsint
      • RÊaliste
        • The LDAP Chronicles
        • Houston, we have a problem
        • Named Resolve
        • The AD Guardians
        • The GPO Mission
        • Ghost Membership
      • RÊtro-IngÊnierie
        • Cbizarre [1/2]
        • Cbizarre [2/2]
        • Reversconstrictor
        • 3x3cut3_m3
        • Inscription
        • Étoile binaire [1/2]
        • RFC 9452 bis: IP over Rockets with Quality of Service
      • SÊcuritÊ matÊrielle
        • Trop d'IQ
        • Space Radio
        • R16D4
        • Comment est votre tempÊrature ?
        • Code Radiospatial n°1
        • Unidentified Serial Bus [1/2]
        • Unidentified Serial Bus [2/2]
      • SÊcuritÊ Web
        • Cheese Chess
        • Rainbow Rocket
        • Fire Server
        • Sideral Noise
        • Space Fleet Command
Powered by GitBook
On this page

Was this helpful?

  1. 2025
  2. 404CTF 2025
  3. RÊtro-IngÊnierie

Reversconstrictor

PreviousCbizarre [2/2]Next3x3cut3_m3

Last updated 1 day ago

Was this helpful?

CatÊgorie: RÊtro-IngÊnierie - DifficultÊ: Facile

Description:

Solution:

Nous avons à disposition un binaire dont nous ne connaissons pas le contenu. En regardant le titre du challenge, nous avons une petite idÊe de ce qu'il peut cacher mais nous allons faire du repÊrage :

Bon cela nous apporte quelques infos, mais nous allons surtout nous focus sur la partie "python" qui est l'objectif pour lequel le titre rÊfÊrence (boa constrictor / python...).

Et maintenant nous avons de nouveaux fichiers, dont un .pyc qui nous intÊresse beaucoup :

À partir de maintenant, il s'agit d'un simple reverse de .pyc, comme dans chaque CTF. Nous allons donc procÊder Êtape par Êtape en commençant par dÊcompiler le .pyc :

Nous obtenons ce code python en clair, c'est merveilleux :

import tkinter as tk
import importlib.util as importlib
import os
import sys

def import_module():
    module_path = os.path.join(sys._MEIPASS, 'modules/encrypt_key.cpython-39.pyc')
    spec = importlib.util.spec_from_file_location('nom_module', module_path)
    mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    return mod

module = import_module()

def xor(a, b):
    return bytes((lambda .0: for x, y in .0:
x ^ y)(zip(a, b)))


def validate_password(password):
    if xor(module.encode_password(password.encode('ascii')), module.encrypt_key(0x6D39D56F8A40A6BBE43A82A53B2C762EA780C21A32C6B3EF765D3A54F3432432F3E6D39D56F8A40A6BBE43A82A53B2C762EA780C21A32C6B3EF765D3A54F3432432F3E)) == b'\xe9J\x1aB\xe2\xc5\xf3S\'\xd6>\n$\x94\x1a\x07\'F\xc6\xa1\x07\xb7\xcc\xec\xe1\x84\xec\xac\xe4\xd64\x8f\xc3\x12\x04\x16$n\x15\xec\xe1\xaee5\xc7\xecOX"\x98EO\x1f2\xb4\x15\xc4\xed\xf4\xcd$\xd3\xd3u\xc2\xf8\xc6\xae\x06\x08\xcd\xff\xe0(\xe9\xb0\xe7\xde6\x90\xcc\xfd\x02}%\x1a\x1a\xc9#\x10\xc2\x86\x06\x08\xcd\xfe&\xb8K\x0f)\x9a\xb6\xb9\x02\x17\xa0\xd8\xe4]\x98\xf5*\x154<\x06\x875\xbd\x05@\xe6\x88\xe3&6%\xcc\x18\x06\\%\xa4\x1a7!\xfe\xc3\xae\x06\x08\xcd\xff\xe2\x18\xe2x\xe0\x927x\r\xfa\xa6\xbd\xe67\x97\xf7\xe5)f\x94\xc8\xbdv\r\xef\x12\x1bZ\xe8e\xf3S\'\xd6>\n"8\x1be\x9c\xdf\xe8\x9b\x06\xb7\x0b3V\x1f\xedN\x87\xbbI!C>8z%\xc0\xeaM\xb5\xd1p\xd1\x0f|A\xd7B\x03\xc54\xd5T\xb9\xfd\x88;\xbf\x10\x81L\x90L\x0b\xff\xed\xe1\xe5dQ\xc4\x17\xd5\xafUl\xec':
        label.config('Mot de passe correct !', **('text',))
    else:
        label.config('Mot de passe incorrect !', **('text',))

root = tk.Tk()
root.title('RÃĒve en Python')
root.geometry('300x200')
label = tk.Label(root, 'Entrez le mot de passe :', **('text',))
label.pack(10, **('pady',))
entry_password = tk.Entry(root, 20, **('width',))
entry_password.pack(5, **('pady',))
validate_button = tk.Button(root, 'Valider', (lambda : validate_password(entry_password.get())), **('text', 'command'))
validate_button.pack(5, **('pady',))
root.mainloop()

À ce que nous pouvons voir à la ligne 7, il fait appel à un autre fichier : modules/encrypt_key.cpython-39.pyc

Nous allons donc procÊder de la mÃĒme manière pour rÊcupÊrer son code :

Voici le code complet :

def encrypt_key(key):
    for _ in range(100):
        key <<= 1
        key ^= 28822426245224264980979321341345830828356797782055329828562090481380116178932605047916536097759912367507574811007140506795012665313071649493970094581868771201400995139374360577815608383329090103210656811239441222567030843263175788045939510447941542030750571932256144094323129497438168350642218592361235189388565721332503735143045072480576796605508643464856724395849208355789353984327745285879034330837484467961665782705864897713128496005106869640456653659559683849265346017315593794571762231394086134713064707220190583043994656101899455622598958597972721263137718293457676368185324168958757297967087684
        key >>= 1
        key &= 109051226663159329753852712655361641732299866997884252194334358336942491585415479875295813282055589726130083576518139892456534344478282750316593419244506314188673419372046405908627553201165095804542555714314672295089748281211620003277814236498206175511101163526217782040005646393337007890354251307329101818031816904956050245603083420859836404091717206011901780489732016582515541865280619889684277395118340072030441380240101696073919110415984233261149866579378832210321108153068228794726382510988474475602148132965289631295957683363624794221017463029077341994983080187012597951461555452400067297865364263
        key -= 30192244264443276570339417266820821425000308120852003855173657187210512774975257998930431381307567916542287355804911140923844613245045835307895499468937998079600051550088167870781968330783540846793847843565906160661919016260958589152016311435717470936180510788226717267994601294202007594965057260235235670775632982187962998589201876115127904069810375748935472032501147620317590198256980636488859805187975959355302150868894406858968080766062052395340075809777559133433991365763567236747759028423915038949095093046477455353960143902941004723715753803085977215629377804159634990715729987578541999707000127
        key ^= 28822426245224264980979321341345830828356797782055329828562090481380116178932605047916536097759912367507574811007140506795012665313071649493970094581868771201400995139374360577815608383329090103210656811239441222567030843263175788045939510447941542030750571932256144094323129497438168350642218592361235189388565721332503735143045072480576796605508643464856724395849208355789353984327745285879034330837484467961665782705864897713128496005106869640456653659559683849265346017315593794571762231394086134713064707220190583043994656101899455622598958597972721263137718293457676368185324168958757297967087684
        key <<= 1
        key += 4324354
        key >>= 1
    key = abs(key)
    encrypted_bytes = key.to_bytes((key.bit_length() + 7) // 8, byteorder='big')
    return encrypted_bytes

def encode_password(password):
    a = b''
    x_list = [110, -34, -230]
    for i in range(len(password)):
        b = password[i] // 11 + 11
        c = password[i] % 11
        d = b + c
        e = b * c
        r = []
        for i in range(3):
            x = x_list[i]
            y = x ** 2 - d * x + e
            assert y > 0 and y < 65536 and (y not in r)
            r.append(y)
        else:
            for i in range(3):
                a += bytes.fromhex(f'{r[i] // 256:02x}')
                a += bytes.fromhex(f'{r[i] % 256:02x}')
    else:
        return a

Nous avons donc toutes les pièces en main pour dÊchiffrer tout cela. Pour faire ça automatiquement, nous allons crÊer un script Python (pour rester dans l'ambiance) :

# ---------------------------------------------------------------------------
# 1)  Constantes du challenge
# ---------------------------------------------------------------------------

TARGET = bytes.fromhex(
    "e94a1a42e2c5f35327d63e0a24941a072746c6a107b7ccece184ecace4d6348f"
    "c3120416246e15ece1ae6535c7ec4f582298454f1f32b415c4edf4cd24d3d375"
    "c2f8c6ae0608cdffe028e9b0e7de3690ccfd027d251a1ac92310c2860608cdfe"
    "26b84b0f299ab6b90217a0d8e45d98f52a15343c068735bd0540e688e3263625"
    "cc18065c25a41a3721fec3ae0608cdffe218e278e09237780dfaa6bde63797f7"
    "e5296694c8bd760def121b5ae865f35327d63e0a22381b659cdfe89b06b70b33"
    "561fed4e87bb4921433e387a25c0ea4db5d170d10f7c41d74203c534d554b9fd"
    "883bbf10814c904c0bffede1e56451c417d5af556cec"
)

CST = int(
    "6D39D56F8A40A6BBE43A82A53B2C762EA780C21A32C6B3EF765D3A54F3432432F3E"
    "6D39D56F8A40A6BBE43A82A53B2C762EA780C21A32C6B3EF765D3A54F3432432F3E",
    16
)

# ---------------------------------------------------------------------------
# 2)  encrypt_key ― repris mot-pour-mot du .pyc
# ---------------------------------------------------------------------------

def encrypt_key(key: int) -> bytes:
    for _ in range(100):
        key <<= 1
        key ^= 0x40440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044440440444044404440440440440440444044440440444044
        key >>= 1
        key &= 0xF3271ADF3271ADF3F3271ADF3271ADF3F3271ADF3271ADF3F3271ADF3271ADF3F3271ADF3271ADF33271ADF3F3271ADF3271ADF3F3271ADFF3271ADF3271ADF3F3271ADF3271ADF3F3271ADF3271ADF3F3271ADF3271ADF3F3271ADF3271ADF33271ADF3F3271ADF3271ADF3F3271ADFF3271ADF3271ADF3F3271ADF3271ADF3F3271ADF3271ADF3F3271ADF3271ADF3F3271ADF3271ADF33271ADF3F3271ADF3271ADF3F3271ADFF3271ADF3271ADF3F3271ADF3271ADF3F3271ADF3271ADF3F3271ADF3271ADF3F3271ADF3271ADF33271ADF3F3271ADF3271ADF3F3271ADF1ADFF3271ADF1ADFADF3F3271ADF1ADFF3271ADF1ADFADF3F327
        key -= 0x4351EAC5DB5A0D3F31513511EAC5DB5A0D3F3521EAC5DB5A0D3F3151EAC5DB5A0D3F2143EAC5DB5AEAC5DB5A0D3F3151EAC5DB5A0D3F31514351EAC5DB5A0D3F31513511EAC5DB5A0D3F3521EAC5DB5A0D3F3151EAC5DB5A0D3F2143EAC5DB5AEAC5DB5A0D3F3151EAC5DB5A0D3F31514351EAC5DB5A0D3F31513511EAC5DB5A0D3F3521EAC5DB5A0D3F3151EAC5DB5A0D3F2143EAC5DB5AEAC5DB5A0D3F3151EAC5DB5A0D3F31514351EAC5DB5A0D3F31513511EAC5DB5A0D3F3521EAC5DB5A0D3F3151EAC5DB5A0D3F2143EAC5DB5AEAC5DB5A0D3F3151EAC5DB5A0D3F315131510D3F31513151DB5A0D3F315131510D3F31513151DB5A0D3F
        key ^= 0x40440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044044044044044404404404404404440440440440440444044440440444044404440440440440440444044440440444044
        key <<= 1
        key += 4324354
        key >>= 1
    key = abs(key)
    return key.to_bytes((key.bit_length() + 7) // 8, "big")

# ---------------------------------------------------------------------------
# 3) encode_byte (une lettre -> 6 octets)  et table inverse
# ---------------------------------------------------------------------------

X = [110, -34, -230]

def encode_byte(p: int) -> bytes:
    b, c = p // 11 + 11, p % 11
    d, e = b + c, b * c
    r = [x * x - d * x + e for x in X]        # trois entiers 16 bits
    out = bytearray()
    for y in r:
        out += y.to_bytes(2, "big")
    return bytes(out)

# table “6 octets  →  caractère”
DEC = {encode_byte(p): p for p in range(256)}

# ---------------------------------------------------------------------------
# 4)  DÊcodage :  TARGET  ⊕  encrypt_key(CST)  →  mot de passe
# ---------------------------------------------------------------------------

enc_key  = encrypt_key(CST)
encoded  = bytes(t ^ k for t, k in zip(TARGET, enc_key))

password = "".join(
    chr(DEC[encoded[i : i + 6]])            # 6 octets = 1 caractère
    for i in range(0, len(encoded), 6)
)

print(password)
🚩FLAG

404CTF{D0_y0U_L0v3_Pyth02?1_l0v3_pYt60n!}

Pour aller plus loin, nous allons utiliser un outil nommÊ afin de rÊcupÊrer les sources contenues dans le binaire :

Alors ici ça n'a pas fonctionnÊ comme prÊcÊdemment, et c'est assez Êtrange... Mais pour rÊparer ça, j'ai utilisÊ un qui l'a fait sans souci.

đŸ—“ī¸
pyinstxtractor
service en ligne
16MB
chall