Donation
感覺有點不太明白成為winner到底要干啥,但是withdrawDonationsFromTheSuckersWhoFellForIt()函式可以轉走合約中的錢,因此應該就能是winner了,
看了一下WP,原來這個靶場所有題目完成的標志是把錢轉回,
寫了個攻擊合約才發現需要auth,是這個靶場對每一題都有的auth,我想直接互動,但是我不知道為什么remix這里點不了了:

(注:后來發現,是因為題目的那個給的都是小寫,應該有一部分字母是大寫,所以才不行,)
考慮到要與合約直接互動,我又不會web3.js和python的那個,正好想到了這個靶場是給abi的,因此利用這個:
myetherwallet
來互動,直接呼叫withdrawDonationsFromTheSuckersWhoFellForIt函式即可,
Lock Box
考察智能合約的可見性,讀private量,拿web3.js讀一下即可:
const Web3 = require('web3');
var Tx = require('ethereumjs-tx').Transaction;
// rpcURL = "https://rinkeby.infura.io/v3/2ab0c9f096474b2a8b7b60a25ded6c21";
rpcURL = "https://ropsten.infura.io/v3/4b96df939eb84de689c2ceb92b831086";
const web3 = new Web3(rpcURL);
web3.eth.getStorageAt("0xd62038f72ADa7Bb9fB78E86f0aFedDC37927ba9d", "1", function(x,y){console.info(y);})
注意讀的是slot1,因為繼承的CtfFramework合約還有個mapping占據了slot0,
Piggy Bank
函式重寫的時候沒加上onlyOwner的修飾,看一下余額是150000000000000000,直接collectFunds弄回來就可以了,
SI Token Sale
找了一會沒找到有什么利用點:
contract SIToken is StandardToken {
using SafeMath for uint256;
string public name = "SIToken";
string public symbol = "SIT";
uint public decimals = 18;
uint public INITIAL_SUPPLY = 1000 * (10 ** decimals);
constructor() public{
totalSupply_ = INITIAL_SUPPLY;
balances[this] = INITIAL_SUPPLY;
}
}
contract SITokenSale is SIToken, CtfFramework {
uint256 public feeAmount;
uint256 public etherCollection;
address public developer;
constructor(address _ctfLauncher, address _player) public payable
CtfFramework(_ctfLauncher, _player)
{
//minus a small developer fee
feeAmount = 10 szabo;
developer = msg.sender;
purchaseTokens(msg.value);
}
function purchaseTokens(uint256 _value) internal{
require(_value > 0, "Cannot Purchase Zero Tokens");
require(_value < balances[this], "Not Enough Tokens Available");
balances[msg.sender] += _value - feeAmount;
balances[this] -= _value;
balances[developer] += feeAmount;
etherCollection += msg.value;
}
function () payable external ctf{
purchaseTokens(msg.value);
}
// Allow users to refund their tokens for half price ;-)
function refundTokens(uint256 _value) external ctf{
require(_value>0, "Cannot Refund Zero Tokens");
transfer(this, _value);
etherCollection -= _value/2;
msg.sender.transfer(_value/2);
}
function withdrawEther() external ctf{
require(msg.sender == developer, "Unauthorized: Not Developer");
require(balances[this] == 0, "Only Allowed Once Sale is Complete");
msg.sender.transfer(etherCollection);
}
}
很明顯withdrawEther我們沒法用,能用的就只有refundTokens,但是只能把余額的一般提取出來,因此需要想辦法讓我們自己的balanceOf足夠到可以將合約里的前拿出來,
又找了一會,在這里發現了溢位:
balances[msg.sender] += _value - feeAmount;
因此轉過去的value<10即可溢位,使我們的balance無限大,就可以將全部的錢取出了,
記得refundTokens的時候,傳的值是合約余額的2倍,
Secure Bank
這題不會,看了WP才恍然大悟,原來是這樣,
主要就是SecureBank和MembersBank合約的withdraw函式是不同的:
function withdraw(address _user, uint256 _value) public isMember(_user) ctf{
function withdraw(address _user, uint8 _value) public ctf{
_value一個是uint256,另一個是uint8,因此就不算是繼承重寫了,而是2個不同的函式,在wallet里面也能直接看出來有2個withdraw函式:

但是他們都呼叫了super.withdraw,這里都是呼叫SimpleBank的withdraw函式:
//取錢
//但是這個取錢可以任意取別人的,沒有檢測
//后續的子合約應該會加上
function withdraw(address _user, uint256 _value) public ctf{
require(_value<=balances[_user], "Insufficient Balance");
balances[_user] -= _value;
msg.sender.transfer(_value);
}
因此可以任意取任何人的錢,只不過需要這個人是member里面的,注冊一下即可,
去Etherscan能看到創建合約的人的address,0.4ether的余額就在這個人的balance里面:

給這個人注冊一下,然后轉走就可以了,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/279637.html
標籤:區塊鏈
