Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory is corrupted when remove asset from token reserve #422

Open
code423n4 opened this issue Aug 30, 2023 · 3 comments
Open

Memory is corrupted when remove asset from token reserve #422

code423n4 opened this issue Aug 30, 2023 · 3 comments
Labels
bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue duplicate-33 edited-by-warden grade-a QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax sufficient quality report This report is of sufficient quality

Comments

@code423n4
Copy link
Contributor

code423n4 commented Aug 30, 2023

Lines of code

https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/core/RdpxV2Core.sol#L287

Vulnerability details

Impact

Impact of memory corruption will appear in case of address update of reserve tokens RDPX/WETH/DPXETH.
I.e. when admin

  1. removes old implementation tokens, for example RDPX and DPXETH via removeAssetFromtokenReserves()
  2. sets new implementation of RDPX and DPXETH via addAssetTotokenReserves()

After these actions protocol is completely bricked.

Proof of Concept

Corrupted memory layout is hard to illustrate in Solidity, I provide PoC for this.

Please add this function to RdpxV2Core.sol:

  function getReserveAssetSymbol(uint256 index) external view returns (string memory symbol) {
    return reserveAsset[index].tokenSymbol;
  }

Add this test to tests/rdpxV2-core/Admin.t.sol. And run forge test --match-test testCorruptedMemory -vvv

  function testCorruptedMemory() public {
    // remove old implementation
    rdpxV2Core.removeAssetFromtokenReserves("WETH");
    rdpxV2Core.removeAssetFromtokenReserves("RDPX");

    // add new implementation
    rdpxV2Core.addAssetTotokenReserves(
      0x1f9090aaE28b8a3dCeaDf281B0F12828e676c326, // random address
      "WETH"
    );
    rdpxV2Core.addAssetTotokenReserves(
      0x2e08451B79a01Cda253811E45719CeB42640c20d, // random address
      "RDPX"
    );

    // print to console current indexes of tokens
    uint256 a1 = rdpxV2Core.reservesIndex("RDPX");
    uint256 a2 = rdpxV2Core.reservesIndex("WETH");
    uint256 a3 = rdpxV2Core.reservesIndex("DPXETH");
    console.log(a1);
    console.log(a2);
    console.log(a3);
    console.log("-----------------");

    // print to console current order of tokens in `reserveAsset`
    string memory tokenSymbol0 = rdpxV2Core.getReserveAssetSymbol(0);
    string memory tokenSymbol1 = rdpxV2Core.getReserveAssetSymbol(1);
    string memory tokenSymbol2 = rdpxV2Core.getReserveAssetSymbol(2);
    string memory tokenSymbol3 = rdpxV2Core.getReserveAssetSymbol(3);
    console.log(tokenSymbol0);
    console.log(tokenSymbol1);
    console.log(tokenSymbol2);
    console.log(tokenSymbol3);
    console.log("-----------------");

    // print to console current array `reserveTokens`
    string memory b1 = rdpxV2Core.reserveTokens(0);
    string memory b2 = rdpxV2Core.reserveTokens(1);
    string memory b3 = rdpxV2Core.reserveTokens(2);
    console.log(b1);
    console.log(b2);
    console.log(b3);

    // As you can see, `reserveTokens` contains duplicates ["RDPX", "WETH", "RDPX"];

    // Also pointers from `reservesIndex` incorrectly point to `reserveAsset` array
    // For example "WETH" and "DPXETH" point to the same asset WETH
  }

Tools Used

Manual Review

Recommended Mitigation Steps

Current implementation always pops last element of array reserveTokens.

Swap element you want to remove with the last element before pop() like you do with reserveAsset:

    // update the index of reserveAsset with the last element
    reserveAsset[index] = reserveAsset[reserveAsset.length - 1];

    // remove the last element
    reserveAsset.pop();

Assessed type

Error

@code423n4 code423n4 added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working labels Aug 30, 2023
code423n4 added a commit that referenced this issue Aug 30, 2023
@c4-pre-sort
Copy link

bytes032 marked the issue as duplicate of #33

@c4-pre-sort
Copy link

bytes032 marked the issue as sufficient quality report

@c4-pre-sort c4-pre-sort added the sufficient quality report This report is of sufficient quality label Sep 11, 2023
@c4-judge c4-judge added downgraded by judge Judge downgraded the risk level of this issue QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax and removed 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value labels Oct 15, 2023
@c4-judge
Copy link
Contributor

GalloDaSballo changed the severity to QA (Quality Assurance)

@T1MOH593 T1MOH593 mentioned this issue Oct 23, 2023
@C4-Staff C4-Staff reopened this Oct 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue duplicate-33 edited-by-warden grade-a QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax sufficient quality report This report is of sufficient quality
Projects
None yet
Development

No branches or pull requests

5 participants