Sui.

Publication

Partagez vos connaissances.

article banner.
harry phan.
Jun 30, 2025
Article

Guide du hacker pour conquérir Move CTF 2025 (semaine 1)

En matière de sécurité de la blockchain, il n'y a pas de meilleur terrain d'entraînement qu'un défi Capture The Flag (CTF).

Les développeurs développent leurs compétences dans le feu de la compétition amicale. Le défi Move CTF 2025 Week 1 sur la blockchain Sui est un exemple parfait conçu pour tester votre compréhension du langage Move.

Nous passerons de la configuration de l'environnement à l'analyse des défenses du contrat intelligent, en passant par la création d'un script de résolution et enfin l'exécution de la transaction qui révélera le prix tant convoité : CTF {LetsMoVectF_Week1}.

Que vous soyez novice dans Move ou chercheur en sécurité expérimenté, cette présentation vous fournira une feuille de route pratique pour améliorer vos compétences. Allons y plonger !

Étape 1 : Reconnaissance - Comprendre la cible

Avant d'écrire une seule ligne de code, notre premier travail consiste à comprendre le champ de bataille. Le défi est centré sur un seul module Moveweek1::challenge, que nous devons analyser.

public struct Challenge has key {
    id: UID,
    secret: String,
    current_score: u64,
    round_hash: vector<u8>,
    finish: u64,
}

Notre mission, en termes simples, est d'appeler avec succès la get_flagfonction de saisie. Un appel réussi déclenchera une FlagEventdiffusion de notre victoire et du drapeau sur l'ensemble du réseau.

Cependant, la get_flagfonction est protégée par une série de cinq contrôles de validation distincts. Pour réussir, nous devons tous les satisfaire en une seule transaction.

Étape 2 : Déconstruire les défenses - Les cinq obstacles

La get_flagfonction est celle d'une forteresse et ses murs sont faits de assert!déclarations. Éliminons chacun de ces obstacles un par un.

Obstacle 1 : La vérification du score

La tâche : calculer le hachage sha3_256 de la chaîne challenge.secret actuelle. Le score correct est un nombre u64 dérivé des 4 premiers octets de ce hachage (en utilisant l'ordre des octets big-endian).

Le concept : Il s'agit d'un défi cryptographique de base visant à vous assurer que vous pouvez effectuer correctement le hachage et la manipulation des octets, comme l'exige le contrat.

Hurdle 2 : The Guess Check (un casse-tête de preuve de travail)

La tâche : trouver une supposition (un vecteur d'octets, qui agit comme un nonce) de telle sorte que lorsque vous hachez votre supposition et le secret ensemble (sha3_256 (guess || secret)), les deux premiers octets du hachage obtenu correspondent aux deux premiers octets du challenge .round_hash.

Le concept : Il s'agit d'un mécanisme classique de preuve de travail (PoW). Il ne peut pas être résolu mathématiquement ; il faut un effort de calcul (« force brute ») pour trouver une estimation valide, prouvant que vous avez dépensé des ressources pour le résoudre.

Obstacle 3 : La vérification hash_input (liaison d'identité)

La tâche : Fournissez un hachage qui combine correctement le secret et votre identifiant github_id personnel. L'astuce consiste à sérialiser le secret à l'aide de la sérialisation canonique binaire (bcs : :to_bytes). Cela diffère de la simple utilisation de ses octets bruts, car BCS ajoute aux données leur longueur au début. Le calcul final est sha3_256 (bcs (secret) || github_id).

Le concept : Cette vérification relie votre solution à votre identifiant unique, empêchant ainsi les autres utilisateurs de simplement rejouer votre transaction réussie. L'utilisation de BCS est un modèle courant dans Move et un détail clé à noter.

Obstacles 4 et 5 : La vérification de la graine et du numéro magique

La tâche : ces deux paramètres sont liés.

la graine est calculée comme longueur (secrète) * 2.

magic_number est calculé comme (score % 1000) + graine.

Le concept : Il s'agit d'énigmes logiques qui testent votre capacité à lire attentivement le code Move et à reproduire ses opérations arithmétiques simples.

Étape 3 : Configuration de votre boîte à outils - Environnement et déploiement

Une fois la théorie comprise, il est temps de se salir les mains.

Tout d'abord, assurez-vous que votre interface de ligne de commande Sui est installée et configurée pour le réseau de test.

# Check your Sui version
sui --version
> sui 1.50.1-homebrew

# Check your active environment
sui client envs
> testnet

# Check your active address and gas balance
sui client active-address
sui client gas

Ensuite, créez et publiez le contrat Move sur le réseau de test Sui. Cela compilera le code et le déploiera, créant ainsi l'Challengeobjet partagé initial avec lequel nous devons interagir.

# Build the project
sui move build

# Publish the contract to the testnet
sui client publish --gas-budget 100000000

Une fois la publication réussie, l'interface de ligne de commande affiche les résultats, y compris deux informations essentielles que vous devez enregistrer :

Numéro du package : adresse de votre nouveau contrat publié. ID de l'objet : adresse de l'Challengeobjet partagé créé par la initfonction.

Étape 4 : Forger les clés - Création du solveur Python

Maintenant, nous devons calculer les bons arguments auxquels passerget_flag. Faire cela manuellement est fastidieux, nous allons donc écrire un script Python pour l'automatiser. Ce script lit l'initiale secret« LetsMoVectf_Week1 » et calcule les cinq paramètres requis.

import hashlib

# --- Configuration ---
github_id = b"qiaopengjun5162"
secret = b"Letsmovectf_week1"

# --- 1. Calculate Score ---
hash_bytes = hashlib.sha3_256(secret).digest()
score = int.from_bytes(hash_bytes[:4], 'big')
print(f"✅ Score: {score}")

# --- 2. Solve Proof-of-Work for Guess ---
target_prefix = hash_bytes[:2]
found_guess = None
for i in range(1000000): # Brute-force loop
    guess_candidate = f"guess{i}".encode()
    combined_data = guess_candidate + secret
    random_hash = hashlib.sha3_256(combined_data).digest()
    if random_hash[:2] == target_prefix:
        found_guess = guess_candidate
        print(f"✅ Guess Found: {found_guess.decode()}")
        print(f"   (as hex): {found_guess.hex()}")
        break

# --- 3. Calculate Hash Input (with BCS) ---
# BCS serialization for a string prepends its length as a ULEB128 integer.
# For short strings, this is just a single byte representing the length.
bcs_encoded_secret = bytes([len(secret)]) + secret
bcs_input_data = bcs_encoded_secret + github_id
hash_input = hashlib.sha3_256(bcs_input_data).digest()
print(f"✅ Hash Input (hex): {hash_input.hex()}")

# --- 4 & 5. Calculate Seed and Magic Number ---
secret_len = len(secret)
seed = secret_len * 2
magic_number = (score % 1000) + seed
print(f"✅ Seed: {seed}")
print(f"✅ Magic Number: {magic_number}")

Étape 5 : The Heist - Appelez get_flag et remportez le prix Une fois nos paramètres calculés, nous utiliserons un autre script Python pour créer et exécuter la dernière commande d'appel client sui. Cela automatise le processus fastidieux de formatage des arguments de la ligne de commande.

call_get_flag.py (résumé)

import subprocess

# --- Configuration (using values from previous script) ---
package_id = "0x804c92e4eef709b83f135d6cc667005ce35d7eccd49384570cbd7b1b40e32434"
challenge_id = "0xd28bc35560711a8b6ca93e2bf8e353fa6e17c15cbc426c48ece1ade9d83ce5ee"
random_id = "0x8"     # Default Random object on Sui
gas_budget = "10000000"

# --- Calculated Parameters ---
score = 1478524421
guess = [103, 117, 101, 115, 115, 55, 54, 57, 48, 56] # b'guess76908'
hash_input = [...] # The full byte array from the solver
github_id = "qiaopengjun5162"
magic_number = 455
seed = 34

# --- Construct and Execute the Sui CLI Command ---
command = [
    "sui", "client", "call",
    "--package", package_id,
    "--module", "challenge",
    "--function", "get_flag",
    "--args",
    str(score), str(guess), str(hash_input), f'"{github_id}"',
    str(magic_number), str(seed), challenge_id, random_id,
    "--gas-budget", gas_budget
]

# Execute the command and print the output
result = subprocess.run(command, capture_output=True, text=True, check=True)
print(result.stdout)

Lors de l'exécution de ce script, la transaction est envoyée. Si tous nos paramètres sont corrects, la sortie affichera Status : Success et, surtout, le FlagEvent émis :

"ParsedJSON": {
  "flag": "CTF{Letsmovectf_week1}",
  "github_id": "qiaopengjun5162",
  "rank": "1",
  "success": true
}

Succès ! Le drapeau est capturé.

Un CTF bien conçu ne s'arrête pas après une résolution. Une fois notre appel réussi, la fonction get_flag utilise l'objet Random pour générer un nouveau secret et met à jour l'objet Challenge.

Je l'ai confirmé en interrogeant à nouveau l'objet, en trouvant un nouveau secret et en répétant le processus. Les scripts de mon solveur étaient réutilisables. Il me suffisait de mettre à jour la variable secrète, de relancer le calcul et d'exécuter à nouveau l'appel pour capturer le drapeau une deuxième et une troisième fois et gravir les échelons.

https://suiscan.xyz/testnet/tx/AzJywLk8zv1Fx5Pc8p4ZrZwFZQ9hmTbtvweo14MVn8fZ

Conclusion : bien plus qu'un drapeau

Relever le défi de la semaine 1 de Move CTF 2025 a été une expérience d'apprentissage incroyable. Cela m'a obligée à aller au-delà de la théorie et à m'engager directement dans la blockchain Sui, renforçant ainsi des concepts clés tels que :

Logique des contrats intelligents : il est primordial de lire et de comprendre attentivement le code Move.

La cryptographie en pratique : appliquer le hachage (sha3_256) et comprendre la manipulation des octets.

Mécanique en chaîne : importance de formats de sérialisation spécifiques tels que BCS.

Automatisation : utilisation de scripts pour gérer des tâches complexes et répétables.

Ce défi témoigne de la puissance de l'apprentissage pratique. Si vous souhaitez développer vos compétences en matière de développement et de sécurité de la blockchain, je vous encourage vivement à vous lancer dans le

  • Sui
2
Partager
Commentaires
.

Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.

610Publications1335Réponses
Sui.X.Peera.

Gagne ta part de 1000 Sui

Gagne des points de réputation et obtiens des récompenses pour avoir aidé la communauté Sui à se développer.

Campagne de RécompensesJuillet