Skip to content
On this page

挑战高楼!揭秘智能合约的“电梯难题”

你有没有想过,在数字世界的摩天大楼里,一部看起来平平无奇的智能合约“电梯”,竟然暗藏玄机,让你止步不前?今天,我们就来揭开这场名为“Elevator”的CTF挑战的面纱,看看如何巧妙地“乘坐”这部不听话的电梯,抵达顶层!

故事的开端:一部“不守承诺”的电梯

我们面前的“Elevator”合约,负责控制一栋大楼的电梯。它有两个重要的状态变量:top(布尔值,表示是否在顶层)和floor(无符号整数,表示当前楼层)。

它的核心功能是 goTo(uint256 _floor) 函数。乍一看,这似乎很简单,输入想去的楼层,电梯就带你去。然而,这里有一个关键的限制:

solidity
Building building = Building(msg.sender); // 电梯认为调用者就是“大楼”

if (!building.isLastFloor(_floor)) { // 只有当目标楼层不是最后一层时,才更新楼层
    floor = _floor;
    top = building.isLastFloor(floor);
}

问题就出在这里! goTo 函数在更新楼层之前,会调用一个名为 isLastFloor 的函数来判断目标楼层是否是“最后一层”。但它期望的调用者(msg.sender)是“大楼”(Building 接口的实现者)。这意味着,只有当电梯以为自己正在被“大楼”调用,并且“大楼”告诉它“你请求的楼层不是最后一层”时,它才会执行楼层更新。

智能的漏洞:Solidity 的“不完美承诺”

Solidity 的一个特性是,它在接口调用时,会尝试将调用者(msg.sender)强制转换为指定的接口类型。在这里,Elevator 合约直接将 msg.sender 转换成了 Building 接口。

想象一下,如果你自己扮演“大楼”的角色,并且有能力控制 isLastFloor 函数的返回值,会发生什么?

破解之道:反客为主,重塑逻辑

CTF 题目提供了一个绝妙的解决方案——Hack.sol 合约。这个合约的设计思路是:

  1. 模拟“大楼”: Hack 合约实现了 Building 接口,并提供了一个 isLastFloor 函数。
  2. 控制“最后一层”的判断: Hack 合约的 isLastFloor 函数非常狡猾。它有一个计数器 ct
    • 第一次被调用时(也就是 Elevator 合约的 goTo 函数第一次检查 isLastFloor 时),ct 为 1,isLastFloor 返回 false(因为 ct > 1false)。
    • 第二次被调用时,ct 变为 2,isLastFloor 返回 true(因为 ct > 1true)。
  3. 诱导 Elevator Hack 合约的 runGoTo 函数调用 target.goTo(9999999)
    • 此时,msg.senderHack 合约。
    • Elevator 合约将 Hack 合约的地址强制转换为 Building 接口,并调用 HackisLastFloor 函数。
    • 第一次调用 isLastFloor,返回 falseElevator 内部逻辑判断 !building.isLastFloor(_floor)true,所以会执行 floor = _floor;,将楼层设置为 9999999
    • 紧接着,Elevator 合约会再次调用 building.isLastFloor(floor) 来更新 top 状态。这次,Hack 合约的 isLastFloor 函数会被第二次调用,ct 已经大于 1,所以返回 true
    • Elevator 合约最终将 top 设置为 true

至此,我们成功地“欺骗”了 Elevator 合约,让它认为自己已经达到了顶层,即使我们并没有真正访问一个“最后一层”的逻辑。

测试验证:代码中的“电梯运行记录”

98_test_elevator.ts 文件展示了如何用代码来验证这个攻击。它首先部署了一个 Hack 合约,并传入了 Elevator 合约的地址。然后,调用 hack.runGoTo()。最终,它会检查 Elevator 合约的 top 状态是否被成功地修改为了 true,以及 floor 是否更新为 9999999

结论:智能合约的安全,需要对细节的深刻理解

“Elevator”这个CTF题目,巧妙地利用了Solidity在接口调用和类型转换方面的一些特性。它告诉我们,在编写智能合约时,必须对 msg.sender 的行为、接口调用的预期以及逻辑的每一个细节都有清晰的认识。一个小小的“不守承诺”,就可能成为攻击者突破防线的关键。

所以,下次当你遇到一个看起来“死活不让你上去”的智能合约时,不妨想想,它是不是也藏着这样一个“不守承诺”的电梯呢?

Built with AiAda