Sui.

帖子

分享您的知识。

article banner.
harry phan.
Jun 30, 2025
文章

CTF 2025 征服黑客指南(第 1 周)

在区块链安全方面,没有比夺旗帜(CTF)挑战赛更好的训练场了.

开发人员在友谊竞争的火焰中锻炼自己的技能. Sui区块链上的Move CTF 2025年第一周挑战赛就是一个完美的例子,旨在测试你对Move语言的理解.

我们将从设置环境到分析智能合约的防御,精心设计求解器脚本,最后执行揭示梦寐以求的奖品的交易:CTF {letsMovectf_Week1}.

无论你是 Move 新手还是经验丰富的安全研究人员,本演练都将提供一个实用的路线图来提高你的技能. 让我们潜入吧!

第 1 步:侦察-了解目标

在编写一行代码之前,我们的第一项工作是了解战场. 挑战集中在一个 Move 模块上week1::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 关:分数检查

任务:计算当前 challenge.secret 字符串的 sha3_256 哈希值. 正确的分数是从该哈希的前 4 个字节派生的 u64 数字(使用大端字节顺序).

概念:这是一项基本的加密挑战,旨在确保您可以按照合约的要求正确执行哈希和字节操作.

第 2 关:猜测检查(工作量证明拼图)

任务:找到一个猜测值(一个字节矢量,用作随机数),这样,当你将猜测值和秘密进行哈希处理时(sha3_256(guess || secret)),得到的哈希值的前两个字节与 challenge.round_hash 的前两个字节相匹配.

概念:这是一种经典的工作量证明(PoW)机制. 它无法用数学方法求解;它需要计算工作(“蛮力”)才能找到有效的猜测,证明你已经花费了资源来求解.

障碍 3:hash_input 检查(身份绑定)

任务:提供一个正确组合密钥和你的个人 github_id 的哈希值. 这里的诀窍是必须首先使用二进制规范序列化 (bcs:: to_bytes) 对密钥进行序列化. 这与仅使用其原始字节不同,因为 BCS 会在数据前添加其长度. 最终计算结果是 sha3_256(bcs(机密)|| github_id).

概念:该支票将您的解决方案与您的唯一标识符关联起来,防止其他人简单地重播您的成功交易. BCS 的使用是 Move 中的常见模式,也是需要注意的关键细节.

第 4 和 5 关:种子和 magic_number 检查

任务:这两个参数是相互关联的.

种子按长度(机密)* 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 将输出结果,包括您必须保存的两条关键信息:

包裹编号:您新发布的合同的地址. 对象 ID: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 函数使用随机对象生成新的密钥并更新 Challenge 对象.

我通过再次查询对象,找到新的秘密并重复这个过程来证实了这一点. 我的求解器脚本是可重复使用的,我只需要更新秘密变量,重新运行计算,然后再次执行调用即可第二次和第三次夺取旗帜,从而提升排名.

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

结论:不仅仅是一面旗帜

应对 Move CTF 2025 第 1 周的挑战是一次不可思议的学习经历. 它迫使我超越理论,直接参与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 社区成长而获得奖励。

奖励活动七月