Summary
Mar-21-2023 01:39:47 PM +UTC, the attacker(0xb189943) created many new contracts, which gained ASKACR tokens from the ASKACR contract itself. Finally the attacker gained 28,633 BSC-USD.
Attacker
https://bscscan.com/address/0xb1899430b21f646b1b298a3f0c0707ea4047c53e
Attacking Contract
https://bscscan.com/address/0x559a352d205d5df7cd8021891ab9c680f7f278e2
Attacked Contract
https://bscscan.com/address/0x5ae4b2f92f03717f3bdfe3b440d14d2f212d3745
Transaction
https://bscscan.com/tx/0xc20fa4953ff394bb806a57cafe71d1163973c0e5a47bb8dad1703a518b15ea3b
Steps
1. The attacker(0xb189943) flash-loaned 160000000000000000000000 BSC-USD to the attacking contract(0x559a352), then the attacking contract performed the following steps;
2. Swapped 80000000000000000000000 BSC-USD for 7602113503899446077512 ASKACR(0x5ae4b2f92f03717f3bdfe3b440d14d2f212d3745);
3. Added liquidity with 80000000000000000000000 BSC-USD and 4602113503899446077512 ASKACR and gained 11030872800726050506746 Cake-LP token;
4. Transferred 0 ASKACR tokens to itself;
5. Created a new contract(0xbd9669) and made the new contract approve a great allowance to the attacking contract for the Cake-LP token;
6. Transferred 11020872800726050506746 Cake-LP token to the new contract(0xbd9669);
7. Made the new contract(0xbd9669) transfer 0 ASKACR token to itself;
8. Repeated step d to step f;
9. Transferred 11020872800726050506746 Cake-LP to each new contract and withdrew the ASKACR token from each new contract to the attacking contract.
10. Transferred 11020872800726050506746 Cake-LP to itself and removed the liquidity;
11. Swapped ASKACR tokens to the BSC-USD tokens;
12. Paid the flash-loan token and transferred the 28633086898865610595739 BSC-USD to 0xb189943.
Root Cause
The root cause is the way to compute the share. The share will be added to the corresponding account's balance. However, the way to compute the share mainly depends on the amount of LP tokens. Note that the _lpBalances[from] is only the number of the LP tokens in the previous transfer.
| Solidity |
| function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { |
| _inviter(from, to); |
| _lpShare(from, to); |
| } |
| function _lpShare(address from, address to) internal { |
| address addressThis = address(this); |
| uint256 fromShare = computeLpShare(from); |
| uint256 toShare = computeLpShare(to); |
| ... |
| if(toShare > 0){ |
| _balances[addressThis] = _balances[addressThis] - toShare; |
| _balances[to] = toShare + _balances[to]; |
| emit Transfer(addressThis, to, toShare); |
| } |
| _allShares[from] = _shares; |
| _allShares[to] = _shares; |
| } |
| function computeLpShare(address from) public view returns (uint256){ |
| uint256 lpBalanceFrom = _pair.balanceOf(from); |
| lpBalanceFrom = lpBalanceFrom > _lpBalances[from]? _lpBalances[from]: lpBalanceFrom; |
| if(lpBalanceFrom <= 0){ |
| return 0; |
| } |
| uint256 share = (_shares - _allShares[from]) * lpBalanceFrom; |
| return share / (10 ** 18); |
| } |
In the _afterTokenTransfer function, users' balance of the Cake-LP will be stored in the _lpBalances mapping:
| Solidity |
| function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual { |
| _lpBalances[from] = _pair.balanceOf(from); |
| _lpBalances[to] = _pair.balanceOf(to); |
| } |
The hacker created many new contracts and transferred LP tokens to the new contracts.

Then, the hacker made the new contract and transferred 0 ASKACR tokens to the new contract itself to make _lpBalances[New_Contract] 11020872800726050506746.

So, due to the share calculation rule in the computeLpShare function, in the next transfer, the new contract gained some shares into balance.
Finally, the new contract transferred all the tokens to the attacker and the attacker gained the profit.

Fund Loss
28,633 BSC-USD
PoC
https://github.com/MetaTrustLabs/SmartContractAttackPoC/blob/main/test/ASKACR/ASKACRTest.sol
Twitter: https://twitter.com/MetatrustLabs
Website: https://metatrust.io/
All Comments