Допис
Діліться своїми знаннями.
Посібник хакера з підкорення ходу CTF 2025 (тиждень 1)
У безпеці блокчейну немає кращого навчального майданчика, ніж виклик Capture The Flag (CTF).
Розробники підковують свої навички в пожежах дружньої конкуренції. Виклик Move CTF 2025 Week 1 на блокчейні Sui є прекрасним прикладом, призначеним для перевірки вашого розуміння мови Move.
Ми перейдемо від налаштування середовища до аналізу захисту смарт-контракту, створення сценарію вирішувача та, нарешті, виконання транзакції, яка розкриває бажаний приз: CTF {LetsMoveCTF_week1}.
Незалежно від того, чи є ви новачком Move або досвідченим дослідником безпеки, цей посібник надасть практичну дорожню карту для вдосконалення ваших навичок. Давайте зануримося!
Крок 1: Розвідка - Розуміння Targe
Перш ніж писати один рядок коду, наше перше завдання - зрозуміти поле бою. Завдання зосереджено навколо одного модуля Moveweek1::challenge
, який нам потрібно проаналізувати.
public struct Challenge has key {
id: UID,
secret: String,
current_score: u64,
round_hash: vector<u8>,
finish: u64,
}
Наша місія, простіше кажучи, полягає в успішному виклику get_flag
функції входу. Успішний дзвінок спровокуєFlagEvent
, транслюючи нашу перемогу і прапор на всю мережу.
Однак get_flag
функція захищена серією з п'яти різних перевірок перевірки. Щоб досягти успіху, ми повинні задовольнити їх усіх за одну транзакцію.
Крок 2: Деконструювання оборони - П'ять перешкод
get_flag
Функція - фортеця, а її стіни складені з твер assert!
джень. Давайте розберемо кожну з цих перешкод по черзі.
Перешкода 1: Перевірка рахунку
Завдання: Обчисліть хеш sha3_256 поточного рядка challenge.secret. Правильна оцінка - це число u64, отримане з перших 4 байтів цього хешу (з використанням біг-ендіанського порядку байтів).
Концепція: Це основна криптографічна проблема, яка гарантує, що ви можете правильно виконувати хешування та маніпуляції байтами, як того вимагає контракт.
Перешкода 2: Перевірка вгадування (головоломка підтвердження роботи)
Завдання: Знайдіть припущення (байтовий вектор, який діє як nonce) таким чином, щоб при хешуванні вашої здогадки та секрету разом (sha3_256 (вгадати || секрет)), перші два байти отриманого хешу збігаються з першими двома байтами виклику.round_hash.
Концепція: Це класичний механізм Proof-of-Work (PoW). Його неможливо вирішити математично; це вимагає обчислювальних зусиль («груба сила»), щоб знайти достовірну здогадку, доводячи, що ви витратили ресурси на її вирішення.
Перешкода 3: Перевірка hash_input (прив'язка ідентичності)
Завдання: Надати хеш, який правильно поєднує секрет і ваш особистий github_id. Хитрість тут полягає в тому, що секрет спочатку повинен бути серіалізований за допомогою бінарної канонічної серіалізації (bcs: :to_bytes). Це відрізняється від простого використання його необроблених байтів, оскільки BCS доповнює дані своєю довжиною. Остаточний розрахунок - sha3_256 (bcs (секрет) || github_id).
Концепція: Ця перевірка пов'язує ваше рішення з вашим унікальним ідентифікатором, не даючи іншим просто повторювати вашу успішну транзакцію. Використання BCS є загальним шаблоном у Move та ключовою деталлю, яку слід помітити.
Перешкода 4 і 5: Перевірка насіння та магічного числа
Завдання: Ці два параметри пов'язані між собою.
насіння розраховується як довжина (секрет) * 2.
magic_number обчислюється як (оцінка% 1000) + насіння.
Концепція: Це логічні головоломки, які перевіряють вашу здатність уважно читати код Move та повторювати його прості арифметичні операції.
Крок 3: Налаштування набору інструментів - середовище та розгортання
Зрозумівши теорію, настав час забруднити руки.
По-перше, переконайтеся, що ваш Sui CLI встановлено та налаштовано для тест-мережі.
# 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
Далі побудуйте та публікуйте контракт Move в тестовій мережі Sui. Це скомпілює код і розгорне його, створюючи початковий спільний Challenge
об'єкт, з яким нам потрібно взаємодіяти.
# Build the project
sui move build
# Publish the contract to the testnet
sui client publish --gas-budget 100000000
Після успішної публікації CLI виведе результати, включаючи дві важливі відомості, які ви повинні зберегти:
Ідентифікатор пакету: адреса вашого нещодавно опублікованого контракту.
Ідентифікатор об'єкта: Адреса спіль Challenge
ного об'єкта, створеного init
функцією.
Крок 4: Підробка ключів - створення розв'язувача Python
Тепер нам потрібно обчислити правильні аргументи для переходуget_flag
. Робити це вручну нудно, тому ми напишемо сценарій Python для його автоматизації. Цей скрипт читає початковийsecret
, «LetsMoveCTF_Week1", і обчислює всі п'ять необхідних параметрів.
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}")
Крок 5: Пограбування - виклик get_flag та захоплення призу З розрахованими нашими параметрами ми будемо використовувати інший сценарій Python для побудови та виконання кінцевої команди виклику клієнта sui. Це автоматизує виснажливий процес форматування аргументів для командного рядка.
call_get_flag.py (короткий зміст)
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)
Після запуску цього скрипта транзакція надсилається. Якщо всі наші параметри правильні, на виході буде показано Status: Success і, головне, випущений flagEvent:
"ParsedJSON": {
"flag": "CTF{Letsmovectf_week1}",
"github_id": "qiaopengjun5162",
"rank": "1",
"success": true
}
Успіх! Прапор захоплений.
Добре розроблений CTF не закінчується після одного вирішення. Після нашого успішного виклику функція get_flag використовує об'єкт Random для створення нового секрету та оновлює об'єкт Challenge.
Я підтвердив це, знову запитавши об'єкт, знайшовши новий секрет і повторивши процес. Мої сценарії вирішувачів можна було використовувати повторно - мені просто потрібно було оновити секретну змінну, повторно запустити обчислення та виконати виклик знову, щоб захопити прапор вдруге та втретє, піднявшись у ряди.
https://suiscan.xyz/testnet/tx/AzJywLk8zv1Fx5Pc8p4ZrZwFZQ9hmTbtvweo14MVn8fZ
Висновок: Більше, ніж просто прапор
Вирішення виклику Move CTF 2025 Week 1 було неймовірним навчальним досвідом. Це змусило мене вийти за рамки теорії та безпосередньо взаємодіяти з блокчейном Sui, підсилюючи ключові концепції, такі як:
Розумна логіка контракту: уважно читати та розуміти код переміщення є першорядним.
Криптографія на практиці: Застосування хешування (sha3_256) та розуміння маніпулювання байтами.
Механіка ланцюга: важливість конкретних форматів серіалізації, таких як BCS.
Автоматизація: Використання скриптів для управління складними, повторюваними завданнями.
Цей виклик є свідченням сили практичного навчання. Якщо ви хочете розвинути свої навички у розробці та безпеці блокчейну, я настійно рекомендую вам перейти до
- Sui
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.
Зароби свою частку з 1000 Sui
Заробляй бали репутації та отримуй винагороди за допомогу в розвитку спільноти Sui.

- ... SUIBigSneh+1396
- ... SUISuiLover+1333
- ... SUI0xduckmove+1207
- ... SUIThorfin+1202
- ... SUIOwen+970
- ... SUIharry phan+847
- ... SUItheking+742
- Чому BCS вимагає точного порядку полів для десеріалізації, коли структури Move мають названі поля?53
- Помилки перевірки кількох джерел» у публікаціях модуля Sui Move - автоматичне вирішення помилок43
- Невдала операція Sui: об'єкти, зарезервовані для іншої транзакції25
- Як обмеження здібностей взаємодіють з динамічними полями в гетерогенних колекціях?05