Parity Multisig Contract

보안 취약점 살펴보기

ICO 해킹사태

블록체인ers 주간발표

발표자 ironpark

용어 알아보기

  1. 패리티 (Parity)
    - 이더리움 클라이언트이자 지갑역할을 하는 소프트웨어
    - 가장 널리 사용되는
    이더리움 클라이언트는 Geth, 지갑은 Mist
    (Mist는 이더리움 네트워크와 연결되기 위하여 Geth 클라이언트를 사용한다)

     
  2. 스마트 컨트렉트 (Smart Contract)
    - 프로그래밍을 통해 만들어진 자동화된 계약
    - 이더리움 기반 ICO의 경우 해당 스마트 컨트렉트에 입금되었을때 해당 컨트렉트에 "프로그래밍 되어진 계약" 에 의해 자동으로 토큰을 발급해 주는 형식

     
  3. 취약점
    - 프로그램 혹은 시스템에서 발견되는 보안적인 헛점

     
  4. ICO (Initial Coin Offering)
    - 개발/마케팅 자금을 확보하기 위해 초기에 크라우드펀딩을 통해 토큰을 나눠주는것
    - IPO와 CrowdFunding 그 중간 어딘가..
  1. 대량의 이더 (약 15만개) 이 해커의 지갑 주소로 탈취된 사건
     
  2. Edgeless, Swarm City, æternity 등의 ICO 지갑이 해킹당함
     
  3. 일반적인 개인 지갑은 피해가 없었음
     
  4. 당시 그리고 지금 이더리움 블록체인 네트워크 자체는 어떠한 보안문제가 발생하지 않았음

ICO 해킹사태

도대체 왜?

WHY??!?

WHY??!?

WHY??!?

대체 해킹이 발생한 이유는 무엇이며.

최초 원인 제공은 누구인가.

원인과 진행

  1. 패리티에서 배포한 Multi-sig Smart Contract 코드에
    보안 취약점이 발견됨
     
  2. 따라서 해당 코드를 사용한 모든 ICO 지갑에 같은 취약점 발생
     
  3. Edgeless, Swarm City, æternity ICO 지갑에서
    15만 이더리움이 탈취됨

     
  4. 문제점을 확인한 WhiteHack 그룹이 같은 문제를 가지고있는 ICO 지갑들을 "같은 취약점을 이용" 하여 자금을 안전한 지갑으로 옮기는데 성공함
    (약37만 이더)

코드 살펴보기


contract Wallet is WalletEvents {
  address _walletLibrary;

  function Wallet(address[] _owners, uint _required, uint _daylimit) {
    bytes4 sig = bytes4(sha3("initWallet(address[],uint256,uint256)"));
    address target = _walletLibrary;
    assembly {
      delegatecall(sub(gas, 10000), target, 0x0, add(argsize, 0x4), 0x0, 0x0)
    }
  }

  function() payable {
    if (msg.value > 0)
      Deposit(msg.sender, msg.value);
    else if (msg.data.length > 0)
      _walletLibrary.delegatecall(msg.data);
  }

  function getOwner(uint ownerIndex) constant returns (address) {
    return address(m_owners[ownerIndex + 1]);
  }

  function hasConfirmed(bytes32 _operation, address _owner) external constant returns (bool) {
    return _walletLibrary.delegatecall(msg.data);
  }

  function isOwner(address _addr) constant returns (bool) {
    return _walletLibrary.delegatecall(msg.data);
  }
}

fallback 함수란
다른 함수에 매칭 되지 않을 때 기본으로 호출되는 함수

walletLibrary에게 권한을 위임 하여 호출한다
이때 호출되는 라이브러리의 함수는
msg.data에 의하여 결정된다.

코드 살펴보기


contract WalletLibrary is WalletEvents {

  function initDaylimit(uint _limit) {
    m_dailyLimit = _limit;
    m_lastDay = today();
  }

  function initMultiowned(address[] _owners, uint _required) {
    m_numOwners = _owners.length + 1;
    m_owners[1] = uint(msg.sender);
    m_ownerIndex[uint(msg.sender)] = 1;
    for (uint i = 0; i < _owners.length; ++i)
    {
      m_owners[2 + i] = uint(_owners[i]);
      m_ownerIndex[uint(_owners[i])] = 2 + i;
    }
    m_required = _required;
  }

  function initWallet(address[] _owners, uint _required, uint _daylimit) {
    initDaylimit(_daylimit);
    initMultiowned(_owners, _required);
  }
}

하루 출금 제한을 바꿀 수 있고

지갑의 주인을 바꿀 수 있다

그런데 말입니다

이 함수가 Public 이라면요?

취약점 패치

함수를 internal 로 바꾸고
컨트렉트의 initialize는 한번만 가능하도록 바꾸기만 했을 뿐인데. 취약점이 패치되었다.

Parity Smart Contrect취약점

By ironpark

Parity Smart Contrect취약점

  • 1,289