Taking a Closer Look at the YIEDL Exploit

5 min read

Learn how Yiedl was exploited, resulting in a loss of assets worth approximately $160,000.

TL;DR#

On April 24, 2024, Yiedl was exploited on the BNB chain due to a smart contract vulnerability, which resulted in a loss of 260 BNB, worth approximately $160,000.

Introduction to YIEDL#

YIEDL is a service that allows users to invest their on-chain assets in a portfolio of crypto-assets generated from crowd-sourced machine-learning forecasts.

Vulnerability Assessment#

The root cause of the exploit is due to insufficient parameter validation.

Steps#

Step 1:

We attempt to analyze one of the attack transactions executed by the exploiter.

Step 2:

The vulnerable and exploited Y-BULL (Yiedl BULL) contract has a redeem function that allows users to exchange a specific number of shares they hold in an asset pool for a certain asset.

/* User Functions */
function redeem(uint256 sharesToRedeem, address receivingAsset, uint256 minTokensToReceive, bytes[] calldata dataList, bool useDiscount) external nonReentrant returns (uint256 tokensToReturn) {
  require(depositableAssets.contains(receivingAsset), "da");
  TxParams memory dp;
  (dp.aum, dp.assets, dp.prices, dp.usdValues) = _getAllocations(0);
  dp.nav = getNav();
  dp.nominalFinalAum = dp.aum - ((dp.nav * sharesToRedeem) / UNIT);
  require(dataList.length == dp.assets.length, "l");
  dp.totalSupply = totalSupply();
  uint256 rcvTokenAccumulator = ((receivingAsset == NATIVE_TOKEN ? address(this).balance : ERC20(receivingAsset).balanceOf(address(this))) * sharesToRedeem) / dp.totalSupply;

  for (uint256 i = 0; i < dp.assets.length; i++) {
    if (dp.assets[i] == receivingAsset) {
      continue;
    }
    uint256 rcvTokenSize = receivingAsset == NATIVE_TOKEN ? address(this).balance : ERC20(receivingAsset).balanceOf(address(this));

    if (dp.assets[i] != NATIVE_TOKEN) {
      ONE_INCH_AGG_ROUTER.functionCall(dataList[i]);
    } else {
      uint256 sizeToSwap = (address(this).balance * sharesToRedeem) / dp.totalSupply;
      ONE_INCH_AGG_ROUTER.functionCallWithValue(dataList[i], sizeToSwap);
    }

    rcvTokenAccumulator += receivingAsset == NATIVE_TOKEN ? address(this).balance - rcvTokenSize : ERC20(receivingAsset).balanceOf(address(this)) - rcvTokenSize;
  }
  _burn(msg.sender, sharesToRedeem);

  uint256 feePortion = (rcvTokenAccumulator * feePercentages[FeeType.REDEEM]) / UNIT;
  dp.feeRecipient = feeRecipient;
  if (useDiscount) {
    (uint256 discountTokensToSpend, uint256 discountMultiplier) = discountPolicy.computeDiscountTokensToSpend(_getUsdValue(receivingAsset, feePortion));
    ERC20(discountPolicy.discountToken()).safeTransferFrom(msg.sender, dp.feeRecipient, discountTokensToSpend);
    feePortion = (feePortion * discountMultiplier) / (10 ** discountPolicy.decimals());
    emit FeeCollected(discountPolicy.discountToken(), discountTokensToSpend);
  }

  tokensToReturn = rcvTokenAccumulator - feePortion;
  require((tokensToReturn) >= minTokensToReceive, "s4");
  if (receivingAsset == NATIVE_TOKEN) {
    payable(msg.sender).sendValue(tokensToReturn);
  } else {
    ERC20(receivingAsset).safeTransfer(msg.sender, tokensToReturn);
  }

  if (feePortion > 0) {
    uint256 feeTokenAmount;
    dp.feeAsset = feeAsset;
    if (receivingAsset == dp.feeAsset) {
      feeTokenAmount = feePortion;
    } else {
      feeTokenAmount = _directSwapForFee(
        feePortion,
        0, // don't hinder redemptions due to low liquidity for the fee conversion.
        receivingAsset,
        dp.feeAsset
      );
    }

    ERC20(dp.feeAsset).safeTransfer(dp.feeRecipient, feeTokenAmount);
    emit FeeCollected(dp.feeAsset, feeTokenAmount);
  }

  require(absSlippage(dp.nav, getNav(), UNIT) <= slippageTolerances[SlippageType.NAV], "s3");
  _postSwapHandler(receivingAsset, dp);

  emit Transaction(false, msg.sender, receivingAsset, tokensToReturn, sharesToRedeem);
}

Step 3:

The dataList parameter is used to make external calls to control asset exchange with information relating to transactions or other routing details. Due to a lack of validation in this parameter, the attacker was able to inject payloads that led to unintentioned interactions with the router contracts, leading to unauthorized asset transfers.

Step 4:

The attacker repeatedly invoked a call to this redeem function, passing the `sharesToRedeem` parameter as zero.

undefined

Step 5:

This function iterates through the list of native assets that are authorized or whitelisted by the contract. If the asset is not inside this scope, it will parse the `dataList` parameter and make an external call to the associated function in the 1inch router contract to carry out the asset exchange.

Step 6:

As a result of this unverified parameter, the attacker was able to inject malicious payloads to carry out an arbitrary token exchange. This allowed the attacker to repeadetly redeem tokens without holding any redemption shares and trigerred the token exchange operations, thereby profiting from these trades.

Aftermath#

The team acknowledged the occurrence of the exploit and stated that their new BSC vault was exploited. As viewed in this transaction, this exploited vault was deployed roughly 17 hours before the incident took place.

According to them, the vulnerability in the BNB integration smart contract allowed the attacker to repeatedly redeem small amounts of assets using a custom malicious payload. The reported loss of assets amounts to roughly $300,000. The attacker had transferred approximately 260.53 BNB worth roughly $158,402 to this address, which, at the time of this writing, had already started to launder these stolen assets to Tornado Cash.

Solution#

To address the vulnerability in the YIEDL smart contract, a multi-faceted approach to enhancing security is essential. Initially, the most critical step is to patch the current vulnerability by rigorously validating the `dataList` parameter. This can be done by incorporating logic that ensures each entry in `dataList` conforms to expected types and formats, and verifying that the length of `dataList` matches the number of required operations per the contract's logic. It is also vital to sanitize inputs by stripping out or rejecting any entries that contain unexpected or potentially malicious data. This could involve whitelisting pre-approved data to ensure only safe and expected entries are processed.

Monitoring and alert systems are crucial for the early detection of unusual activity. Setting up real-time monitoring on critical functions and using off-chain analytics to alert if transactions deviate from normal patterns can help with quick detection and response to suspicious activities. Enhanced logging mechanisms should capture detailed transaction information, with regular audits of these logs to identify and mitigate suspicious activities promptly.

For long-term security, regular security audits conducted by reputable firms are indispensable. These audits should include a comprehensive review of the smart contracts and their interactions with external systems. Implementing the recommendations from these audits quickly is crucial for maintaining a robust security posture. 

Even with robust security measures in place, completely eliminating the risk of vulnerability exploitation remains unfeasible. In such circumstances, the role of Neptune Mutual becomes essential. Had the team associated with the Yiedl protocol established a dedicated cover pool at our marketplace, the financial impact from incidents like this would have been significantly reduced. Neptune Mutual is adept at offering coverage for losses stemming from smart contract vulnerabilities, using parametric policies tailor-made for these unique risks.

Working with Neptune Mutual streamlines the recovery process for users by diminishing the need for extensive proof of loss documentation. Once an incident is verified and resolved through our comprehensive incident resolution protocol, our priority shifts to quickly providing compensation and financial aid to those affected. This method ensures swift support for users impacted by such security incidents.

Our marketplace is available on a variety of major blockchain platforms, such as EthereumArbitrum, and the BNB chain, offering broad support to a wide spectrum of DeFi users. This broad coverage enhances our capability to protect against smart contract vulnerabilities, thereby boosting the overall security of our extensive clientele.

Reference Source BlockSec

By

Tags