Sui.

Пост

Поделитесь своими знаниями.

article banner.
harry phan.
Jun 30, 2025
Статья

Руководство для хакеров по освоению Move CTF 2025 (неделя 1)

В сфере безопасности блокчейна нет лучшей учебной площадки, чем соревнование Capture The Flag (CTF).

Разработчики совершенствуют свои навыки в условиях дружеской конкуренции. Конкурс Move CTF 2025 Week 1 на блокчейне Sui — прекрасный пример, призванный проверить ваше понимание языка Move.

Мы перейдем от настройки среды к анализу защит смарт-контракта, составлению сценария решателя и, наконец, выполнению транзакции, в результате которой будет разыгран желанный приз — CTF {letSmovectF_Week1}.

Независимо от того, являетесь ли вы новичком в Move или опытным исследователем в области безопасности, это пошаговое руководство послужит практическим руководством по совершенствованию ваших навыков. Давайте погрузимся в процесс!

Шаг 1. Разведка — понимание цели

Прежде чем написать хоть одну строчку кода, наша первая задача — понять поле битвы. Задача сосредоточена на одном модуле 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: проверка догадок (головоломка с доказательством работоспособности)

Задание: найдите предположение (вектор байтов, выполняющий роль числительного числа), при котором при сложении предположения и секрета (sha3_256 (guess || secret)) первые два байта полученного хеша совпадали с первыми двумя байтами challenge.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 установлен и настроен для тестовой сети.

# 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

После успешной публикации интерфейс командной строки выведет результаты, включая две важные части информации, которые необходимо сохранить:

Идентификатор пакета: адрес вашего недавно опубликованного контракта. Идентификатор объекта: адрес общего 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 на первой неделе стало невероятным опытом. Это заставило меня выйти за рамки теории и напрямую заняться блокчейном Sui, укрепив ключевые концепции, такие как:

Логика смарт-контрактов. Внимательное чтение и понимание кода Move имеют первостепенное значение.

Криптография на практике: применение хеширования (sha3_256) и понимание манипуляций с байтами.

Механика цепочки: важность специальных форматов сериализации, таких как BCS.

Автоматизация: использование скриптов для управления сложными повторяемыми задачами.

Эта задача свидетельствует о силе практического обучения. Если вы хотите улучшить свои навыки в области разработки и безопасности блокчейна, я настоятельно рекомендую вам приступить к

  • Sui
2
Поделиться
Комментарии
.

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

610Посты1335Ответы
Sui.X.Peera.

Заработай свою долю из 1000 Sui

Зарабатывай очки репутации и получай награды за помощь в развитии сообщества Sui.

Кампания вознагражденийИюль