Move CTF共学:Task1

  • hwen
  • 发布于 9小时前
  • 阅读 114

本文主要介绍Move CTF共学营Week1 Task1的解题思路。第一次尝试CTF挑战,感觉还挺有趣味性,有种在用代码解密的快乐,同时也能精进对Move的理解

前言

参与了HOH社区举办的Move CTF共学,本文主要分享Week1 Task1解题思路

ctf参与平台: https://platform.cyclens.tech/activity/1 Task1代码可见: https://github.com/hoh-zone/lets-ctf/tree/main/src/ctfbook/chapter_1/task1

成功调用get_flag函数即为夺旗成功。每次get_flag被调用后,Challenge.secret都会重新生成。

这次的合约需要自己部署到testnet, 部署后得到

  • package ID 0xf52bc6a6689a664a96d4d21ee14d600d148a2e8ca56547b6585d43421cbd4147
  • challenge ID 0x2b2540a47c79a4782ae24c1a72b941652cf403c83d2095752f4bf37986e9b144

解题思路一

首先想到的是在合约内写一个test function,使用debug::print打印所需要的数值,最后复制到CLI中调用

本次定义的

  • github_id734ba641-cf91-4ffe-820c-ffa1548d823f
  • 链上查询到Challenge.secret为字符串+gtpX_<QUl\%Kt-9zM>1>uC6[y2A
//增加一个反斜杠\转义字符  
let secrect = string::utf8(b"+gtpX_<QUl\\%Kt-9zM>1>uC6[y2A"); 
let github_id = string::utf8(b"734ba641-cf91-4ffe-820c-ffa1548d823f");

除了guess data,其余值的获取都可以通过复制原题代码代入数值

let data = *string::as_bytes(&secret);  

//计算score  
let secret_hash =  sha3_256(data);  
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));  

//计算length,magic_number  
let seed = vector::length(&data) *2 ;  
let magic_number = expected_score % 1000 + seed;  

//计算hash_input  
let mut bcs_input = bcs::to_bytes(&secret);  
vector::append(&mut bcs_input, *string::as_bytes(&github_id)); 
let expected_hash = sha3_256(bcs_input); 

debug::print(&seed);  
debug::print(&magic_number);  
debug::print(&expected_hash);  
debug::print(&expected_score);

打印后得到,

  • score = 1231502107
  • seed = length(data1 * 2) = 56
  • magic number = score % 1000 + seed = 163
  • hash_input = 0x82a70eaefdbf471c17181784e596cbf36060e2006c40a8e4d2e7be3b9bc896be
    • 转化为 vector<u8>[130, 167, 14, 174, 253, 191, 71, 28, 23, 24, 23, 132, 229, 150, 203, 243, 96, 96, 226, 0, 108, 64, 168, 228, 210, 231, 190, 59, 155, 200, 150, 190]

Python 枚举guess_data

由代码可知guess_data需要满足条件sha3_256(guess_data || secret)[0..2] == challenge.round_hash[0..2], 即二者分别被哈希后的前2两个字节必须相同。

打印dataround_hash的值得到相应的值,可知round_hash前2个bytes为0x4967

debug::print(&data)
//0x2b677470585f3c51556c5c254b742d397a4d3e313e7543365b793241

debug::print(&sha3_256(b"+gtpX_<QUl\\%Kt-9zM>1>uC6[y2A"));
//0x49673b1b9d73da90a305e38c7f241a6c4e4fbd9d2a55f9d2575d73b7dc432259

再使用python枚举guess data,代码如下

# secret = *string::as_bytes(&challenge.secret))`
secret = bytes.fromhex("2b677470585f3c51556c5c254b742d397a4d3e313e7543365b793241")

# target round_hash prefix
target_prefix = bytes.fromhex("4967")

def find_valid_guess():

    for i in range(0, 2**16): #遍历次数
        guess = i.to_bytes(4, byteorder='big')  # 设置guess为4字节
        guess_data = guess + secret
        hash_result = hashlib.sha3_256(guess_data).digest()

        if hash_result.startswith(target_prefix):
            print("Found valid guess!")
            print(list(guess))
            return guess

    print("No valid guess found in range.")
    return None

得到guess data = [0, 0, 76, 231]

提交

使用sui client调用函数

sui client call --package 0xf52bc6a6689a664a96d4d21ee14d600d148a2e8ca56547b6585d43421cbd4147 --module challenge --function get_flag --args 1231502107 "[0, 0, 76, 231]"  "[130, 167, 14, 174, 253, 191, 71, 28, 23, 24, 23, 132, 229, 150, 203, 243, 96, 96, 226, 0, 108, 64, 168, 228, 210, 231, 190, 59, 155, 200, 150, 190]" 734ba641-cf91-4ffe-820c-ffa1548d823f 163 56 0x2b2540a47c79a4782ae24c1a72b941652cf403c83d2095752f4bf37986e9b144 0x8

返回如下信息表示成功 image.png 填入表中得到真正的flag,再返回提交即可

image.png

解题思路二

看教程里使用合约去调用challenge,二者本质上差不多。用这种方式再了写一次

使用sui move new solv_test新建合约,Move.toml中导入原题合约

[dependencies]  
week1 = {local = "../week1"}

解题合约函数代码如下,思路是一样的,复制原题中的代码,代入参数

//packageID: 0x76dd3cabc1be65c1fd8037c528e38288c29b438e763abe4dff9e80b068975da3  
public entry fun solve_get_flag(  
    secret : String,  
    github_id : String,  
    guess: vector<u8>,  
    challenge: &mut Challenge,   
rand: &Random,   
ctx: &mut TxContext  
){  

    //score  
    let secret_hash = sha3_256(*string::as_bytes(&secret));  
    let 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));  

    //hash_input  
    let mut bcs_input = bcs::to_bytes(&secret);  
    vector::append(&mut bcs_input, *string::as_bytes(&github_id));  
    let hash_input = sha3_256(bcs_input);  

    //seed
    let secret_bytes = *string::as_bytes(&secret);  
    let seed = vector::length(&secret_bytes) * 2;  

    //magic_number  
    let magic_number = score % 1000 + seed;  

    challenge::get_flag(  
        score,  
        guess,  
        hash_input,  
        github_id,  
        magic_number,  
        seed,  
        challenge,  
        rand,  
        ctx,  
    );}

部署后得到packageID 0x76dd3cabc1be65c1fd8037c528e38288c29b438e763abe4dff9e80b068975da3


在链上查询目前的challenge.secret

image.png

以及challenge.round_hash的前2个bytes image.png

在python中将两个值转化为bytes,同样遍历求guess data的值


secret_str = "P%z8_ZP%:*\@adr9Gwe"
secret = secret_str.encode('utf-8')

# target round_hash prefix
target_prefix = bytes([26,217])

def find_valid_guess():
    for i in range(0, 2**24): #遍历次数可调整
        guess = i.to_bytes(4, byteorder='big')  # 设置guess为4字节
        guess_data = guess + secret
        hash_result = hashlib.sha3_256(guess_data).digest()

        if hash_result.startswith(target_prefix):
            print("Found valid guess!")     
            print(list(guess))
            return guess

    print("No valid guess found in range.")
    return None

得到guess = [0,3,173,31]


sui cli中调用,填入当前的challenge.secret以及github_id,此时没有模拟环境了,我自己将id设置为test_id

sui client call --package 0x76dd3cabc1be65c1fd8037c528e38288c29b438e763abe4dff9e80b068975da3 --module solv_test --function solve_get_flag --args "P%z8_ZP%:*\@adr9Gwe" "test_id"  "[0,3,173,31]" 0x2b2540a47c79a4782ae24c1a72b941652cf403c83d2095752f4bf37986e9b144 0x8

返回结果,调用成功

image.png

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

0 条评论

请先 登录 后评论
hwen
hwen
0x04cc...e629
区块链入门中,正在学习Move合约开发,持续发布学习笔记