Summary
Message received cross-chain would revert due to improper encoding/decoding.
Vulnerability Details
Users can teleport there tokens by burning on one chain then minting on the other chain using layerzero,
The issue is the encoded payload uses abi.encodePacked
to encode it while on the recieving it uses abi.decode()
to decode the payload, This is wrong as abi.encodePacked
cannot be decoded using abi.decode()
.
https://github.com/Cyfrin/2024-07-templegold/blob/main/protocol/contracts/templegold/TempleTeleporter.sol#L52
function teleport(
uint32 dstEid,
address to,
uint256 amount,
bytes calldata options
) external payable override returns(MessagingReceipt memory receipt) {
if (amount == 0) { revert CommonEventsAndErrors.ExpectedNonZero(); }
if (to == address(0)) { revert CommonEventsAndErrors.InvalidAddress(); }
bytes memory _payload = abi.encodePacked(to.addressToBytes32(), amount);
temple.burnFrom(msg.sender, amount);
emit TempleTeleported(dstEid, msg.sender, to, amount);
receipt = _lzSend(dstEid, _payload, options, MessagingFee(msg.value, 0), payable(msg.sender));
}
function _lzReceive(
Origin calldata ,
bytes32 ,
bytes calldata _payload,
address ,
bytes calldata
) internal override {
(address _recipient, uint256 _amount) = abi.decode(_payload, (address, uint256));
temple.mint(_recipient, _amount);
}
https://github.com/Cyfrin/2024-07-templegold/blob/main/protocol/contracts/templegold/TempleTeleporter.sol#L107
This would result in a revert and brick the layerzero integration and users would not be able to recieving their burnt token.
Proof of Concept: A simple test with chisel:
➜ address to = address(1);
➜ uint256 amount = uint256(350);
➜ bytes memory _payload = abi.encodePacked(to, amount);
➜ (address addr, uint256 amountdecoded) = abi.decode(_payload, (address, uint256));
Traces:
[804] 0xBd770416a3345F91E4B34576cb804a576fa48EB1::run()
└─ ← [Revert] EvmError: Revert
➜ _payload = abi.encode(to, amount);
➜ (address addr, uint256 amountdecoded) = abi.decode(_payload, (address, uint256));
➜ addr
Type: address
└ Data: 0x0000000000000000000000000000000000000001
Impact
Token burnt through teleport()
would not be minted on the recieving chain resulting in loss of funds to the user.
Complete DoS of layerzero integration.
Tools Used
Manual Review
Recommendations
Use abi.encode()
in encoding payload or use assembly in parsing the payload on the recieving end.