본문으로 이동

ERC-4626 첫 입금 인플레이션 공격: 반올림으로 지분이 사라지는 방식

직접 기부가 빈 ERC-4626 금고의 환율을 조작해 예치자의 지분을 0으로 내림하는 방식과 구현자 및 사용자가 위험을 줄이는 방법을 알아봅니다.

업데이트

교육 목적의 정보이며 투자 조언이 아닙니다. 투자로 인해 손실이 발생할 수 있습니다.

직접 답변

첫 입금 인플레이션 공격은 비어 있거나 거의 비어 있는 ERC-4626 금고를 노립니다. 공격자는 아주 적은 양의 자산을 먼저 예치해 첫 지분을 받은 다음, 기초 자산을 금고로 직접 전송합니다. 이 기부는 totalSupply()를 늘리지 않고 totalAssets()를 늘려 기존 각 지분의 가치를 높입니다.

피해자의 예치금이 조작된 환율로 변환되면 정수 나눗셈으로 발행 지분이 아주 적거나 제로로 내림될 수 있습니다. 피해자의 자산은 금고에 남아 있지만, 유통 지분을 보유한 공격자는 부풀려진 청구권을 상환할 수 있습니다. 이는 환율 조작과 슬리피지 문제이며 ERC-4626 인터페이스 자체의 결함은 아닙니다.

작동 방식

수수료나 보호용 오프셋이 없는 단순한 금고에서 예치로 발행되는 지분은 대략 assets * totalSupply / totalAssets입니다. ERC-4626은 주어진 자산 금액의 지분을 계산할 때 금고에 유리하도록 내림하도록 요구합니다. 정상적인 환율에서는 반올림 손실이 작지만, 지분 가격이 부풀려지면 한 지분보다 가치가 낮은 예치금이 반올림으로 100% 손실될 수 있습니다.

공격 성립 여부는 구현 세부 사항에 달려 있습니다. 특히 totalAssets()가 금고의 토큰 잔액을 읽는 경우, ERC-20을 직접 전송하면 지분을 발행하지 않고도 금고가 계산하는 자산이 늘어날 수 있습니다. 또한 공격자는 지분 공급량이 매우 적을 때 피해자보다 먼저 거래를 실행해야 합니다. 다른 회계 방식이나 명시적 방어를 사용하는 금고는 같은 방식으로 취약하지 않을 수 있습니다.

예시

취약한 빈 금고가 1:1 환율로 시작한다고 가정합니다. 공격자는 자산 1단위를 예치해 지분 1개를 받은 뒤 999단위를 직접 기부합니다. 이제 지분 1개가 자산 1,000단위의 가치를 나타냅니다. 피해자가 999단위를 예치하면 단순 계산은 정수 반올림 후 999 * 1 / 1,000 = 0 지분입니다.

그 결과 금고에는 자산 1,999단위가 있지만 존재하는 지분은 공격자의 1개뿐입니다. 예치가 제로 지분 결과를 허용하고 수수료나 다른 제약이 없다면 공격자는 해당 지분을 상환해 1,999단위 전부를 가져갈 수 있습니다. 여기에는 최초 예치 1단위, 기부 999단위, 피해자 예치 999단위가 포함됩니다. 거래 비용을 제외한 공격자의 총이익은 피해자의 999단위입니다.

위험과 방어

구현자는 의미 있는 초기 유동성을 공급하고, 초기 지분을 소각하거나 잠그고, 제로가 아닌 지분 출력을 강제하거나, 가상 자산과 가상 지분을 사용하는 환율 설계를 적용해 위험을 줄일 수 있습니다. OpenZeppelin 구현은 가상 수량을 추가하고 decimals offset으로 추가 지분 정밀도를 지원합니다. 문서화된 모델에서는 가상 지분이 기부의 일부를 흡수해 조작을 수익성 없게 만들거나 비용을 크게 높입니다. 각 방어에는 전제가 있으므로 직접 전송, 반올림 경계, 수수료, 손실 및 비정상적인 토큰 동작을 대상으로 시험해야 합니다.

사용자와 통합자는 previewDeposit()을 보장된 최소값이 아니라 견적으로 취급해야 합니다. 허용 가능한 최소 지분 수를 강제하고 그 하한에 못 미치면 되돌리는 함수나 라우터를 통해 예치하세요. 새로 생성되었거나 지분 공급이 적은 금고에 예치하기 전 totalAssets(), totalSupply(), 구현의 변환 공식, 원치 않는 토큰 전송이 회계에 영향을 주는지를 확인하세요. 프런트엔드 견적이 유리해도 실행 순서가 바뀔 수 있는 거래를 보호하지는 못합니다.

흔한 오해

  • 오해 1: ERC-4626 자체가 안전한 환율을 보장한다. 표준은 공통 인터페이스와 반올림 동작을 정의할 뿐 모든 구현을 환율 조작으로부터 보호하지는 않습니다.

  • 오해 2: deposit() 직전에 previewDeposit()을 호출하면 그 결과가 보장된다. 호출 사이 또는 실행 전에 온체인 상태가 바뀔 수 있습니다. 예치 경로에는 강제 가능한 최소 지분 한도가 필요합니다.

  • 오해 3: 제로 지분 예치만 거부하면 공격이 사라진다. 가장 극단적인 결과는 막지만 공격자는 여전히 예치자가 소량의 지분만 받게 해 큰 반올림 손실을 일으킬 수 있습니다. 방어는 단순히 제로가 아닌 결과를 요구하는 데 그치지 말고 허용 가능한 슬리피지를 제한해야 합니다.

관련 주제

출처

탐색

위키 검색...