sec3团队在2022年Aptos CTF MOVEment比赛中获得第一名

  • Sec3dev
  • 发布于 2022-12-24 15:34
  • 阅读 29

sec3团队在2022年Aptos CTF MOVEment比赛中获得第一名,展示了团队对Move语言的理解及其在安全领域的应用。文章描述了5个挑战及其解决方案,涉及的内容包括智能合约漏洞分析和应对策略,体现了团队的技术实力。

我们非常兴奋地宣布,我们的 sec3 团队 “Super Rookies” 在 Aptos Capture The Flag 竞争中获得了第一名 MOVEment with Aptos Dec 2022。在四个挑战中,除了完整性检查,我们获得了两个首血 (第一个玩家解决了一个挑战) 和两个次血 (第二个玩家解决了一个挑战),最终排名第一。

这次比赛非常有趣,让我们有机会展示我们对 Move 语言的理解以及我们如何帮助保护它们。在这篇博文中,我们将简要讨论挑战和我们的解决方案。有关漏洞和可能的修复等详细信息,请参考 我们团队的总结


挑战 1:checkin

挑战信息

目标合同

挑战 1 是一个完整性检查,让玩家熟悉使用 aptos-cli 与私有 Aptos 链进行通信,合约已在该链上部署。合约中有一个 get_flag 函数,一旦调用将会触发一个 Flag 事件。

解决方案

在初始化一个账户并通过 aptos-cli 调用 get_flag 函数后,我们可以提交交易哈希。服务器将检查此交易是否触发了 Flag 事件。如果是,服务器将返回该标识。

挑战 2:hello move

挑战信息

目标合同

挑战 2 是一个简单的挑战,让玩家熟悉 Move 语言。合约有五个函数: init_challengehashdiscrete_logaddpow 以及 get_flag

init_challenge 函数用于通过发送一个包含 5 个成员的 Challenge 对象来初始化挑战,该对象的成员包括 balance = 10q1 = falseq2 = falseq3 = false 和事件处理程序。

q1q2q3 这三个字段指示此挑战中 3 个子问题的解决状态,这些状态将在 get_flag 函数中检查。

子问题 q1:hash

如果我们调用 hash 函数并提供一个满足 len(guess)==4 && keccak256(guess+"move")=="d9ad5396ce1ed307e8fb2a90de7fd01d888c02950ef6852fbc2191d2baf58e79"guess: vector<u8>,那么字段 q1 将被设置为 true。这可以通过编写一个简单的脚本来暴力破解所有可能的猜测来解决,答案是 good

子问题 q2:discrete_log

为了将 q2 设置为 true,我们需要提供一个满足 pow(10549609011087404693, guess, 18446744073709551616) == 18164541542389285005guess: u128,这是一道经典的离散对数问题。我们可以在 sage 中用 discrete_log(18164541542389285005,Mod(10549609011087404693,18446744073709551616)) 来解决这个问题,答案是 3123592912467026955

子问题 q3:add

与其他已检查的算术实现类似,Move 语言中的 Shl 和 Shr 操作 如果移位量大于或等于操作数的位宽将抛出 ARITHMETIC_ERROR,这是 CPU 级别的未定义行为。而且,如果发生溢出,Shl 操作不会引发 ARITHMETIC_ERROR。因此,我们可以将当前余额 10 向左移位超过 8 位(例如,每次左移两次并移动 5 位)将余额设置为 0

挑战 3:swap empty

挑战信息

目标合同

此目标合同实现了一个非常简单的交换协议,允许用户在两个代币 Coin1Coin2 之间进行交换。用户可以调用函数 get_coin 来获得 5 Coin15 Coin2 的空投。函数 swap_12swap_21 可用于在 Coin1Coin2 之间进行交换。最后,函数 get_flag 检查保留账户中 Coin1Coin2 的数量是否为 0

漏洞

漏洞在于 get_amouts_out 函数的设计。它根据储备中 Coin1Coin2 的比例计算交换金额,这显然是不安全的。考虑以下 PoC:

  • 攻击者从空投中获得 5 Coin15 Coin2

用户: 5 Coin15 Coin2

储备: 50 Coin150 Coin2

  • 攻击者将 5 Coin2 兑换为 5 * 50 / 50 = 5 Coin1

用户: 10 Coin10 Coin2

储备: 45 Coin155 Coin2

  • 攻击者将 10 Coin1 兑换为 10 * 55 / 45 = 12 Coin2

用户: 0 Coin112 Coin2

储备: 55 Coin143 Coin2

  • 攻击者将 12 Coin2 兑换为 12 * 55 / 43 = 15 Coin1

用户: 15 Coin10 Coin2

储备: 40 Coin155 Coin2

通过重复这个过程,恶意用户可以几乎耗尽储备账户中的所有代币。

挑战 4:simple swap

挑战信息

目标合同

这个合同实现了一个类似于 Uniswap v2 的代币交换程序,允许用户在 TestUSDCSimpleCoin 之间进行交换,收取 0.25 的费用和 0.1 的奖励。在初始化过程中,管理员添加了 10^10 TestUSDC10^10 SimpleCoin 到池中。get_flag 函数将检查用户是否至少有 10^10 SimpleCoin。如果是,用户将获得该标识。

漏洞

该合约中有两个漏洞。

  • 第一个漏洞是,用户通过空投可以索取的代币数量没有限制。攻击者可以索取大量代币,然后将其兑换为其他代币以耗尽储备池。
  • 第二个漏洞是 swap_exact_x_to_y_directswap_exact_y_to_x_direct 函数被错误地暴露给公众。攻击者可以调用此函数在不支付费用的情况下进行代币交换。

结合这两个漏洞,攻击者可以首先索取大量 TestUSDC,然后每次将等于当前储备池的 TestUSDC 交换为 SimpleCoin,从而在获得 0.1 奖励的同时耗尽一半的储备池。在 n 次重复后,储备池中的 SimpleCoin 数量将为 (10^10)/(2^n) ​。

挑战 5:move lock v2

挑战信息

目标合同

该合约使用多项式生成一个数字,其系数由用脚本哈希和多个伪随机数加密的字符串生成。如果用户猜测正确的数字,将会触发标识事件。显然,几乎不可能猜测正确的数字,因为可能的猜测数量为 2^128

漏洞

漏洞在于伪随机数是通过以秒为单位的时间戳和一个计数器生成的。计数器初始化为 0,每次生成随机数时增加 1。因此,时间戳和计数器都是可预测的。攻击者可以直接重用目标合同中的大部分代码来生成相同的多项式和正确的数字。因为字符串是通过对脚本哈希和常量进行 XOR 加密的,我们需要通过脚本调用漏洞合约。

  • 原文链接: sec3.dev/blog/we-won-the...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Sec3dev
Sec3dev
https://www.sec3.dev/