[IMAGE: https://steemitimages.com/DQmRBLYuKKdB5kPnHcwB2ZBLgLtkQGaATS7cR4kjsjBFiSC/hacked_4.png]
이더 15만개는 어떻게 털렸을까?
시간이 좀 지난 이슈이고 일단락 된듯하지만 다시한번 알아보고
ICO 지갑이 탈탈 털린 이유를 본격적으로 알아보자 제발 납득좀가게 알아보자.
예상독자 : 이더리움 스마트 컨트렉에 관심있는 프로그래머 , 이더리움에 관심있는 일반인, 해킹에 피해를 입은 당사자.
용어 알아보기
- 패리티 (Parity)
- 이더리움 클라이언트이자 지갑역할을 하는 소프트웨어
- 가장 널리 사용되는 이더리움 클라이언트는 Geth, 지갑은 Mist
(Mist는 이더리움 네트워크와 연결되기 위하여 Geth 클라이언트를 사용한다) - 스마트 컨트렉트 (Smart Contract)
- 프로그래밍을 통해 만들어진 자동화된 계약
- 이더리움 기반 ICO의 경우 해당 스마트 컨트렉트에 입금되었을때 해당 컨트렉트에 "프로그래밍 되어진 계약" 에 의해 자동으로 토큰을 발급해 주는 형식 - 취약점
- 프로그램 혹은 시스템에서 발견되는 보안적인 헛점 - ICO (Initial Coin Offering)
- 개발/마케팅 자금을 확보하기 위해 초기에 크라우드펀딩을 통해 토큰을 나눠주는것
- IPO와 CrowdFunding 그 중간 어딘가..
사건 요약
"대량의 이더 (약 15만개) 가 해커의 지갑 주소로 탈취된 사건"
- Edgeless, Swarm City, æternity 등의 ICO 지갑이 해킹당함
- 일반적인 개인 지갑은 피해가 없었음
- 당시 그리고 지금 이더리움 블록체인 네트워크 자체는 보안문제가 발생하지 않았음
코드 살펴보기
[IMAGE: https://steemitimages.com/DQmZKaXN7BpEHfr3fS8roAepyi7X3NkVG3F9rEexvtFds67/Jackie-Chan-WTF-Meme.png]
도대체 왜 이런일이 일어나 우리에게 시련을주시고 혼란을 일으키는 것인가.
이것을 알기위해 스마트 컨트렉 코드를 살펴볼 것 입니다.
본 포스팅에 필요한 부분만을 요약하고 잘라내었기 때문에 전체 소스코드는 아닙니다.
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);
}
}
.
[IMAGE: https://steemitimages.com/DQmR9r5ufJ5ErvBGmBUbhWcWA3XX3F7xoTvFAMZGv9nnKgb/swrdc.jpg]
이것만 보았는데 도 불구하고 아무래도 프로그래밍에 대한 지식이 전무하거나 영어 울렁증이 심하다면 혼란스러울 수 있다. 그러니까 아주 ~~아작~~.. 아니 조각 조각을 내어 엑기스만 살펴보자
function() payable 이 함수는 fallback 함수이다 fallback 함수는 컨트렉이 호출되었을때 해당 컨트렉에 매칭 되는 명령(함수) 가 없을때 기본적으로 호출되는 함수를 말하는데.
여기서 프로그래밍에 대한 지식이 없는 분들을 위하여 첨언을 하자면 함수는 입력을 받아 결과를 계산, 실행 하는것을 말한다. 프로그램은 수많은 함수들의 집합이라고 볼 수 있다.
function() payable 함수는 내부에서_walletLibrary.delegatecall(msg.data); 을 호출 (실행) 하는데 간단히 말하자면 "스마트 컨트렉 코드에 매칭되는 함수가 없으면 walletLibrary 에서 매칭되는 함수를 찾아서 호출한다." 라는 코드입니다. 그리고 이것 자체로는 문제가 없습니다. 하지만 문제가 있으니까 털렷겠죠?
계속해서 walletLibrary 를 살펴봅시다.
contract WalletLibrary is WalletEvents {
function initDaylimit(uint _limit) {
m_dailyLimit = _limit;
m_lastDay = today();
}
function initMultiowned(address[] _owners, uint _required) {
...
}
function initWallet(address[] _owners, uint _required, uint _daylimit) {
initDaylimit(_daylimit);
initMultiowned(_owners, _required);
}
}
initWallet initDaylimit initMultiowned 3가지 함수가 보이는데요 함수명만 번역해도 대략적인 기능을 유추해 볼 수 있습니다.
- initWallet : 지갑을 초기화 한다
- initDaylimit : 하루 출금제한 설정
- initMultiowned : 지갑의 권한을 가지는 주인을 설정한다.
네 이 함수가 public으로 되어있었습니다. 외부에서 접근이 가능했다 라는것이죠. 여기서 말하는 외부는 라이브러리 밖 즉 라이브러리를 사용하는 스마트 컨트렉을 말합니다. 그런데 이 스마트 컨트렉이 function() payable 함수를 walletLibrary 와 연결해놓았죠?
그렇습니다. 컨트렉의 주인이 아닌 사람도 누구나! 아무나! initWallet 을 호출 할 수 있는 상태였습니다. 즉 주인을 바꿔버릴 수 있었던거죠
취약점 패치
취약점 패치는 정말 간단하게 되었습니다. 이함수를 internal 즉 내부 에서만 접근할 수 있게 바꿔 버리고 initWallet 함수는 only uninitialized 즉 컨트렉이 초기화 되어 있지 않은 상태에서만 호출이 가능하도록 변경 되었습니다.
생각해볼 부분
- Dao 해킹사태와는 무엇이 다른가.
- 이런일이 더이상 안 일어 나도록 하기위해서는 어떤 조치가 필요할 까.
본 포스팅은 얼만전에 발표했던 자료를 재 구성, 보충 한 것 입니다.
아래에서 슬라이드를 보실 수 있습니다.
https://slides.com/ironpark/parity-smart-contrect
저는.
프로그래밍, 인공지능, 보안, 암호화폐에 관심이 많습니다.
다양한 글을 생산하고 있으니 관심있으시면 팔로우 부탁드립니다 :)
또한 본 포스팅이 도움이 되셨다면 Vote! 다른 사람에게도 보여주고 싶다면 ReSteem! 을 해주세요
글쓴이에게 많은 도움이 됩니다.
이전글 보러가기 > 암호화폐 트레이딩 플랫폼 CoinEX 개발일지.1