슬로우 미스트: Lendf.Me 도난 전 과정 분석 및 방어 제안
慢雾科技
2020-04-19 09:23
本文约2480字,阅读全文需要约10分钟
SlowMist의 자금세탁방지(AML) 시스템에 대한 예비 통계 분석에 따르면 Lendf.Me가 공격을 받은 누적 손실액은 약 24,696,616달러입니다.

편집자 주: 이 기사의 출처는슬로우 미스트 기술(ID: SlowMist)편집자 주: 이 기사의 출처는

슬로우 미스트 기술(ID: SlowMist)

, Odaily의 승인을 받아 재인쇄되었습니다.

WETH: 55159.02134,
WBTC: 9.01152,
CHAI: 77930.93433,
HBTC: 320.27714,
HUSD: 432162.90569,
BUSD: 480787.88767,
PAX: 587014.60367,
TUSD: 459794.38763,
USDC: 698916.40348,
USDT: 7180525.08156,
USDx: 510868.16067,
imBTC: 291.3471

SlowMist Technology의 AML(Anti-Money Laundering) 시스템에 대한 예비 통계 분석에 따르면 Lendf.Me가 공격을 받은 누적 손실액은 약 24,696,616달러이며, 구체적인 도난 통화 및 금액은 다음과 같습니다.

자세한 분석 과정은 다음과 같습니다.

공격 세부 정보

보조 제목

공격 세부 정보

이번에 Lendf.Me를 공격한 공격자의 주소는 0xa9bf70a420d364e923c74448d9d817d3f2a77822이며, 공격자는 컨트랙트 0x538359785a8d5ab1a741a0ba94f26a800759d91d를 배포하여 Lendf.Me를 공격했습니다.

Etherscan에서 공격자의 트랜잭션 중 하나 보기: https://etherscan.io/tx/0xae7d664bdfcc54220df4f18d339005c6faf6e62c9ca79c56387bc0389274363b

우리는 공격자가 처음 0.00021593 imBTC를 입금했지만 Lendf.Me에서 0.00043188 imBTC를 성공적으로 인출했으며 인출 금액은 입금 금액의 거의 두 배에 달했습니다. 그렇다면 공격자는 짧은 거래에서 어떻게 두 배의 잔액을 얻었습니까? 이를 위해서는 트랜잭션의 각 작업을 심층적으로 분석하여 무슨 일이 일어났는지 확인해야 합니다.

bloxy.info에서 트랜잭션을 보면 전체 트랜잭션 프로세스를 알 수 있습니다.

그 직후, supply() 함수의 두 번째 호출 중에 공격자는 자신의 계약에서 Lendf.Me의 withdraw() 함수에 대한 호출을 시작하고 최종적으로 현금을 인출합니다.

여기에서 우리는 Lendf.Me가 transferFrom을 통해 사용자의 tokensToSend() 후크 함수를 호출할 때 transferFrom 함수에서 공격자의 withdraw() 호출이 발생함을 쉽게 찾을 수 있습니다. 분명히 공격자는 supply() 함수를 통해 Lendf.Me 계약에 재진입하여 재진입 공격을 일으켰습니다. 공격의 구체적인 세부 사항은 무엇입니까? 다음으로 Lendf.Me의 계약 코드를 살펴보겠습니다.

보조 제목

코드 분석

일련의 처리 후 Lendf.Me의 supply() 함수는 doTransferIn 함수를 호출하여 사용자가 제공한 통화를 계약에 입금한 다음 시장 변수의 일부 정보를 할당합니다. 방금 언급한 공격 과정을 돌이켜보면, 공격자는 1590행 이후 두 번째 supply() 함수, 즉 두 번째 supply() 함수에서 재진입을 통해 현금을 인출하기 위해 withdraw() 함수를 호출했지만 동작은 되지 않을 것이다. 인출() 전에 실행되고, 1590행 이후의 코드는 인출()이 실행된 후에도 계속 실행됩니다. 여기에서의 작업은 공격자의 출금 가능한 잔액을 증가시킵니다.

supply() 함수를 자세히 분석해 보겠습니다.

위의 그림에 따르면 supply() 함수의 끝에서 시장과 사용자의 잔액이 업데이트되는 것을 볼 수 있습니다. 다음과 같이 localResults.userSupplyCurrent에 저장됩니다.

localResults 변수에 값을 할당하면 사용자의 이체 정보가 먼저 이 변수에 임시로 저장되고 이때 공격자는 withdraw() 함수를 실행하게 됩니다.

여기에는 두 가지 핵심 사항이 있습니다.

1. 함수 시작 시 계약은 먼저 스토리지 시장 및 supplyBalance 변수를 가져옵니다.

정상적인 출금 로직에 따르면,withdraw() 단독 실행시 정상적으로 사용자 잔고가 차감되어 갱신되나, 공격자가 supply()에 withdraw()를 내장하고 있기 때문에,withdrawal()함수에서 사용자 잔고가 갱신된 후 balance(supplyBalance) 다음 supply() 함수에서 실행할 코드, 즉 1590행 이후에 사용자의 balance가 다시 갱신되며 갱신에 사용된 값은 이전의 시작 부분에 저장됩니다. supply() 함수 localResults에 있는 사용자의 원래 예치금에 공격자가 처음으로 supply() 함수 예치금을 호출한 값을 더한 값입니다.

이와 같은 조작으로 출금 후 사용자의 잔고가 차감되더라도 사용자가 출금 금액을 다시 차감하지 않은 경우 다음 supply() 함수의 로직이 값을 덮어쓰게 되어 공격자가 출금 조작을 하게 되지만 잔액을 공제하는 대신 잔액이 증가했습니다. 이러한 방식으로 공격자는 Lendf.Me가 비워질 때까지 기하급수적으로 현금을 인출할 수 있습니다.

여러 계약이 연결된 경우 다자간 계약의 코드 보안 및 비즈니스 보안도 확인하고 다양한 비즈니스 시나리오의 조합에 따른 보안 문제를 충분히 고려해야 합니다.

  • 다음과 같은 주요 비즈니스 운영 방법에 잠금 메커니즘을 추가합니다. OpenZeppelin의 ReentrancyGuard

  • 컨트랙트 작성 시 이 컨트랙트의 변수를 먼저 변경한 후 외부 호출을 하는 방식으로 작성

  • 프로젝트가 시작되기 전에 우수한 제3자 보안 팀을 초대하여 포괄적인 보안 감사를 수행하여 잠재적인 보안 문제를 최대한 발견합니다.

  • 여러 계약이 연결된 경우 다자간 계약의 코드 보안 및 비즈니스 보안도 확인하고 다양한 비즈니스 시나리오의 조합에 따른 보안 문제를 충분히 고려해야 합니다.

  • 계약은 "블랙 스완" 이벤트가 발생할 때 시간 손실을 감지하고 중지할 수 있도록 가능한 한 일시 중지 스위치를 설정해야 합니다.

  • 보안은 역동적이며 각 프로젝트 당사자는 적시에 자체 프로젝트와 관련될 수 있는 위협 인텔리전스를 캡처하고 잠재적인 보안 위험을 신속하게 조사해야 합니다.

계약은 "블랙 스완" 이벤트가 발생할 때 시간 손실을 감지하고 중지할 수 있도록 가능한 한 일시 중지 스위치를 설정해야 합니다.

OpenZeppelin ReentrancyGuard

慢雾科技
作者文库