Move CTF Week1 Challenge 技术分析

Move CTF 共学营由 HOH 水分子社区联合 Cyclens 及 Movebit 共同推出。本期共学将于25年6月中旬正式开始,通过4周线上视频录播课程、有奖Task任务以及CTF挑战赛等多种方式,帮助大家快速了解 Web3 领域安全问题、提升在网络安全领域的实战能力。

简介

Move CTF 共学营由 HOH 水分子社区联合 Cyclens 及 Movebit 共同推出。本期共学将于25年6月中旬正式开始,通过4周线上视频录播课程、有奖Task任务以及CTF挑战赛等多种方式,帮助大家快速了解 Web3 领域安全问题、提升在网络安全领域的实战能力。 详细信息请参考:https://platform.cyclens.tech/activity/1

本文分析 Week1 的 Move CTF 挑战,该挑战实现了一个多重验证的智能合约游戏。

挑战概述

模块信息

  • 模块名称: week1::challenge
  • 主要功能: 通过多重验证机制获取CTF flag
  • 核心机制: 工作量证明 + 参数验证

核心数据结构

Challenge 结构体

public struct Challenge has key {
    id: UID,                  // 对象唯一标识符
    secret: String,           // 当前轮次的密钥
    current_score: u64,       // 当前分数
    round_hash: vector<u8>,   // 当前轮次的哈希值
    finish: u64,              // 完成次数/排名计数器
}

FlagEvent 事件结构体

public struct FlagEvent has copy, drop {
    sender: address,          // 发送者地址
    flag: String,             // CTF flag内容
    github_id: String,        // GitHub ID
    success: bool,            // 是否成功
    rank: u64,                // 排名
}

验证机制分析

1. 分数验证 (Score Validation)

验证逻辑:

let secret_hash = sha3_256(*string::as_bytes(&challenge.secret));
let expected_score = (((*vector::borrow(&secret_hash, 0) as u64) << 24) |
                     ((*vector::borrow(&secret_hash, 1) as u64) << 16) |
                     ((*vector::borrow(&secret_hash, 2) as u64) << 8) |
                     (*vector::borrow(&secret_hash, 3) as u64));

计算方式:

  • 对secret进行SHA3-256哈希
  • 取哈希值前4字节,按大端序组合成u64整数
  • 提供的score参数必须与expected_score完全匹配

2. 猜测验证 (Guess Validation)

验证逻辑:

let mut guess_data = guess;
vector::append(&mut guess_data, *string::as_bytes(&challenge.secret));
let random = sha3_256(guess_data);
assert!(compare_hash_prefix(&random, &challenge.round_hash, 2), EINVALID_GUESS_HASH);

工作量证明机制:

  • 将guess与secret拼接后计算SHA3哈希
  • 验证结果哈希的前2字节是否与round_hash匹配
  • 需要暴力破解找到合适的guess值

3. 哈希输入验证 (Hash Input Validation)

验证逻辑:

let mut bcs_input = bcs::to_bytes(&challenge.secret);
vector::append(&mut bcs_input, *string::as_bytes(&github_id));
let expected_hash = sha3_256(bcs_input);
assert!(hash_input == expected_hash, EINVALID_HASH);

计算步骤:

  • 将secret进行BCS编码
  • 与github_id字符串拼接
  • 计算SHA3哈希作为expected_hash

4. 魔数验证 (Magic Number Validation)

验证逻辑:

let expected_magic = challenge.current_score % 1000 + seed;
assert!(magic_number == expected_magic, EINVALID_MAGIC);

计算公式:

  • expected_magic = current_score % 1000 + seed

5. 种子验证 (Seed Validation)

验证逻辑:

let secret_bytes = *string::as_bytes(&challenge.secret);
let secret_len = vector::length(&secret_bytes);
assert!(seed == secret_len * 2, EINVALID_SEED);

计算公式:

  • seed = secret字符串长度 × 2

参数分类

静态参数 (可离线计算)

  • score: 基于secret的SHA3哈希前4字节计算
  • hash_input: secret的BCS编码与github_id拼接的SHA3哈希
  • seed: secret字符串长度的2倍
  • magic_number: (current_score % 1000) + seed

动态参数 (需要从合约状态获取)

  • guess: 需要暴力破解的工作量证明参数
  • 当前合约状态: secret、current_score、round_hash

解题策略

步骤1: 获取合约状态

  • 读取Challenge对象的当前状态
  • 获取secret、current_score、round_hash等关键信息

步骤2: 计算静态参数

# 伪代码示例
secret_hash = sha3_256(secret.encode())
score = int.from_bytes(secret_hash[:4], 'big')
seed = len(secret) * 2
magic_number = (current_score % 1000) + seed

bcs_secret = bcs_encode(secret)
hash_input = sha3_256(bcs_secret + github_id.encode())

步骤3: 暴力破解guess

# 伪代码示例
for guess in range(0, 2**32):
    guess_bytes = guess.to_bytes(4, 'little')
    combined = guess_bytes + secret.encode()
    hash_result = sha3_256(combined)
    if hash_result[:2] == round_hash[:2]:
        return guess_bytes

步骤4: 调用get_flag函数

使用计算出的所有参数调用合约的get_flag函数。

安全机制

工作量证明 (Proof of Work)

  • 通过guess参数的暴力破解增加攻击成本
  • 前缀匹配长度为2字节,平均需要尝试65536次

多重验证

  • 5层独立验证确保参数正确性
  • 每层验证失败都会导致交易回滚

动态更新机制

challenge.secret = getRandomString(rand, ctx);
challenge.round_hash = sha3_256(*string::as_bytes(&challenge.secret));
challenge.current_score = 0;
challenge.finish = challenge.finish + 1;

每次成功获取flag后:

  • 生成新的随机secret
  • 更新round_hash
  • 重置current_score
  • 增加完成计数器

技术要点

Move语言特性

  • 使用share_object创建共享对象
  • 利用Random模块生成随机数
  • 通过event::emit发出事件

密码学应用

  • SHA3-256哈希函数
  • BCS (Binary Canonical Serialization) 编码
  • 字节序处理 (大端序)

错误处理

定义了5个错误常量:

  • EINVALID_GUESS_HASH: 猜测哈希无效
  • EINVALID_HASH: 哈希输入无效
  • EINVALID_MAGIC: 魔数无效
  • EINVALID_SEED: 种子无效
  • EINVALID_SCORE: 分数无效

总结

这个CTF挑战综合考验了:

  1. Move语言理解: 合约结构、函数调用、事件处理
  2. 密码学知识: 哈希函数、编码方式、字节操作
  3. 算法能力: 暴力破解、参数计算
  4. 区块链概念: 共享对象、交易上下文、随机数生成

挑战的核心在于理解各个验证步骤的逻辑,正确计算静态参数,并通过暴力破解找到合适的guess值。成功解题需要对Move语言和区块链开发有深入理解。

  • 原创
  • 学分: 0
  • 分类: Sui
  • 标签:
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
cuidaquan
cuidaquan
江湖只有他的大名,没有他的介绍。