Parity Multisig Contract
보안 취약점 살펴보기
ICO 해킹사태
블록체인ers 주간발표
발표자 ironpark
용어 알아보기
-
패리티 (Parity)
- 이더리움 클라이언트이자 지갑역할을 하는 소프트웨어
- 가장 널리 사용되는 이더리움 클라이언트는 Geth, 지갑은 Mist
(Mist는 이더리움 네트워크와 연결되기 위하여 Geth 클라이언트를 사용한다)
-
스마트 컨트렉트 (Smart Contract)
- 프로그래밍을 통해 만들어진 자동화된 계약
- 이더리움 기반 ICO의 경우 해당 스마트 컨트렉트에 입금되었을때 해당 컨트렉트에 "프로그래밍 되어진 계약" 에 의해 자동으로 토큰을 발급해 주는 형식
-
취약점
- 프로그램 혹은 시스템에서 발견되는 보안적인 헛점
- ICO (Initial Coin Offering)
- 개발/마케팅 자금을 확보하기 위해 초기에 크라우드펀딩을 통해 토큰을 나눠주는것
- IPO와 CrowdFunding 그 중간 어딘가..
- 대량의 이더 (약 15만개) 이 해커의 지갑 주소로 탈취된 사건
-
Edgeless, Swarm City, æternity 등의 ICO 지갑이 해킹당함
-
일반적인 개인 지갑은 피해가 없었음
- 당시 그리고 지금 이더리움 블록체인 네트워크 자체는 어떠한 보안문제가 발생하지 않았음
ICO 해킹사태
도대체 왜?
WHY??!?
WHY??!?
WHY??!?
대체 해킹이 발생한 이유는 무엇이며.
최초 원인 제공은 누구인가.
원인과 진행
- 패리티에서 배포한 Multi-sig Smart Contract 코드에
보안 취약점이 발견됨
- 따라서 해당 코드를 사용한 모든 ICO 지갑에 같은 취약점 발생
-
Edgeless, Swarm City, æternity ICO 지갑에서
15만 이더리움이 탈취됨
- 문제점을 확인한 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,350