Beginner FriendlyFoundryDeFiOracle
100 EXP
View results
Submission Details
Severity: high
Invalid

[H-2] Oracle Manipulation Due to Mismatched Decimals

Summary

In OracleUpgradeable.sol:20, there is a critical vulnerability where an attacker may use a custom contract with manipulated token decimals to interact with the getPriceInWeth function. This function is intended to provide the price of a token in terms of WETH (Wrapped Ether), which is crucial for calculating the value of collateral in the LendingProtocol. The discrepancy arises when the attacker's token reports incorrect decimal information, leading the protocol to overestimate the value of the provided collateral.

Vulnerability Details

USDC has 6 decimals for example.
So when someone would provide usdc as collateral, he could borrow way more funds as his actual collateral is due to the mismatch in decimals with custom erc20 tokens.

Vulnerable function:

function getPriceInWeth(address token) public view returns (uint256) {
// @audit-issue [H-2] The attacker's contract uses the decimal discrepancy to mislead the LendingProtocol about the value of the collateral, allowing the attacker to borrow more funds than the collateral supports.
return ITSwapPool(swapPoolOfToken).getPriceOfOnePoolTokenInWeth();
}

POC:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// Mockup of the collateral token contract with 6 decimals
contract CollateralToken {
string public constant name = "Collateral Token";
string public constant symbol = "COL";
uint8 public constant decimals = 6;
uint256 public totalSupply = 1000000 * (10**uint256(decimals)); // 1 million tokens
mapping(address => uint256) public balanceOf;
constructor() {
balanceOf[msg.sender] = totalSupply; // Assign all tokens to the contract deployer for the PoC
}
function transfer(address _to, uint256 _value) public returns (bool success) {
require(balanceOf[msg.sender] >= _value);
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
return true;
}
// Other ERC20 functions would go here (approve, transferFrom, etc.)
}
// Mockup of the loan token contract with 18 decimals
contract LoanToken {
string public constant name = "Loan Token";
string public constant symbol = "LOAN";
uint8 public constant decimals = 18;
uint256 public totalSupply = 1000000 * (10**uint256(decimals));
mapping(address => uint256) public balanceOf;
constructor() {
balanceOf[msg.sender] = totalSupply; // Assign all tokens to the contract deployer for the PoC
}
function transfer(address _to, uint256 _value) public returns (bool success) {
require(balanceOf[msg.sender] >= _value);
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
return true;
}
// Other ERC20 functions would go here (approve, transferFrom, etc.)
}
// A simplified version of the lending protocol smart contract
contract LendingProtocol {
mapping(address => uint256) public collateralBalance;
LoanToken public loanToken;
CollateralToken public collateralToken;
uint256 public loanToValueRatio = 50; // In this PoC, you can borrow up to 50% of your collateral's value
constructor(address _loanToken, address _collateralToken) {
loanToken = LoanToken(_loanToken);
collateralToken = CollateralToken(_collateralToken);
}
// A user deposits collateral and borrows loan tokens against it
function depositAndBorrow(uint256 _collateralAmount) public {
collateralToken.transfer(address(this), _collateralAmount);
collateralBalance[msg.sender] += _collateralAmount;
// Incorrectly valuing the collateral based on hardcoded 18 decimals
uint256 loanAmount = _collateralAmount * loanToValueRatio;
// In reality, loanAmount should be adjusted by token.decimals()
loanToken.transfer(msg.sender, loanAmount);
}
// A user repays their loan and redeems their collateral
function repayAndRedeem(uint256 _repayAmount, uint256 _collateralAmount) public {
loanToken.transferFrom(msg.sender, address(this), _repayAmount);
require(collateralBalance[msg.sender] >= _collateralAmount, "Not enough collateral");
collateralBalance[msg.sender] -= _collateralAmount;
collateralToken.transfer(msg.sender, _collateralAmount);
}
}

Impact

  1. Loss of funds for the protocol

  2. Liquidation of liquidity pools

  3. Huge gains for the hacker if the protocol has a high tvl

Tools Used

  1. Manual Review

  2. Vs Code

Recommendations

Use a offchain oracle provider like chainlink to provide token details or token prices to ensure these kind of oracle attacks can not happen

Updates

Lead Judging Commences

0xnevi Lead Judge
over 1 year ago
0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Admin Input/call validation

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.