Basic Information:
· The attacker’s address was 0x48c94305bddfd80c6f4076963866d968cac27d79
· The attacking contract’s address was 0x887716168fc8c1a2933f97ea3858a94c9e229201
· The malicious strategy contract’s address was 0x13b81fa9c0873a74c49a85bd8149c1c20bf9d18c
· The malicious strategy contract was used by the attacker in this attack.
The Attacking Process:
Step 1: the attacker deployed the contract 0x887716168fc8c1a2933f97ea3858a94c9e229201. This deployment transaction was https://bscscan.com/tx/0xf0a833371d843130601dca50553a203e2a07940ec531592cbd3c48003ace34bd and it happened at Oct-27–2021 01:47:34 PM +UTC
Step 2: BXH’s admin granted the contract with GOVERNANCE_ROLE, i.e., the contract had all the privileges which only Governance had. This transaction was https://bscscan.com/tx/0x992c4b9e5cb5c42fbe35403e1e85034fa42beb5bebb3bfa930d1e6dca37742cf
and it happened at Oct-29–2021 08:19:00 AM +UTC
Step 3: the attacker deployed the malicious strategy contract 0x13b81fa9c0873a74c49a85bd8149c1c20bf9d18c. The deployment transaction was :https://bscscan.com/tx/0x6119e86085440083b8e8b6f5435cbc6480df7fde541c8028d013dce7245720a5
and it happened on Oct-30–2021 03:15:45 AM +UTC
Step 4: the attacker called 0x887716168fc8c1a2933f97ea3858a94c9e229201 to initiate an attack. The transaction was :
https://bscscan.com/tx/0x6466cad9ad300054f0d560db5619a299f67883ad51b6aeafad3061d09674ac84
. With this transaction, the attacking contract 0x887716168fc8c1a2933f97ea3858a94c9e229201 called the govEarnbyStrategyAddress function defined in BXH’sControllerHub contract 0x83dae57c46985c3a2346e8a3c6991ca908f8b06b and supplied the input parameter with the attacking contract’s address listed in step 3.
The govEarnbyStrategyAddress function’s implementation is as follows:
function govEarnbyStrategyAddress(address stategyAddress) public onlyGovernance {
IStrategy _strategy = IStrategy(stategyAddress);
address[] memory tokenStrategyNeed= _strategy.want();
uint256[] memory balanceStrategyNeed=new uint256[](tokenStrategyNeed.length);
//Balance of the vault
for(uint ii=0;ii<tokenStrategyNeed.length;ii++){
balanceStrategyNeed[ii]=VaultPool(vault).available(tokenStrategyNeed[ii]);
IERC20(tokenStrategyNeed[ii]).safeTransferFrom(vault, stategyAddress, balanceStrategyNeed[ii]);
}
_strategy.deposit();
}
modifier onlyGovernance() {
require(
hasRole(GOVERNANCE_ROLE, _msgSender()),
'Caller is not governance'
);
_;
}
From the above code, we can see that only a GOVERNANCE_ROLE can call this function. The attacker obtained this privilege in step 2 and successfully called this function.
Here is a detailed trace of the transactions:
Subsequently, the ControllerHub contract called the “want()” function in the malicious strategy contract and took away all the tokens one by one.
A normal operation would execute the “deposit ()” function in a normal strategy contract to do investment with the tokens. However, in this case the strategy contract was a malicious one, therefore it didn’t do investment and just kept the tokens in the malicious strategy contract instead.
Eventually, the attacker took away all the exploited tokens.