Case
이더리움의 행방, Parity multi-sig wallet
2017 11 09
  • Facebook
  • Twitter
  • Copy URL

비트코인이 미친 랠리를 하는 요즘, 가상화폐 시장이 들썩이고 있다. 비트코인은 2000년 사토시 나가모토가 개발한 세계 최초의 암호화폐로, 비트코인을 비롯하여 이더리움, 리플, 큐텀 등 다양한 가상화폐가 있다. 가상화폐가 처음 공개되었을 때는 큰 주목을 못 받았지만, 세 번의 상승 물결을 타고, 최근에는 가상화폐 덕에 재미 좀 보는 사람이 여럿 생긴 것 같다.[1] 특히나 가상화폐 시장에서는 1분 동안 이유도 모를 급락과 급증이 자주 보이는데, 이 때문에 1분 사이로 웃는 이들도 있지만, 등에 식은땀도 흘리는 이도 여럿 있으리라. 이처럼 가상화폐 시장에서 1분은 많은 것이 좌우되므로 실시간으로 사고, 팔 수 있는 서비스는 가상화폐 거래소에서 중요한 요소다. 중요한 순간에 팔지 못하고, 사지를 못 한다면 무슨 소용이 있겠는가. 그런 의미로 오늘은 가상 화폐 거래와 관련하여 소름 돋을 만한 사건을 준비해 봤다. 11월 6일, Parity Technologies의 Parity multi-sig wallet에서는 치명적인 버그가 발견되면서, 7월 20일 이후에 배포된 모든 Parity multi-sig wallet이 동결되어 약 2억 8천만 달러 상당의 이더리움(Ethereum, ETH)이 묶이게 되었다.[2][3] 어떻게 된 것인지, 무슨 버그 때문인지, 그 혼돈의 도가니에 대해 알아보도록 하자.

이미지를 불러오는데 실패했습니다.

Parity multi-sig wallet은 Parity Technologies의 가상화폐 지갑으로 Parity Technologies가 호스팅하는 디지털 지갑이다.[4] 즉, Parity multi-sig wallet은 Parity Technologies가 만든 이더리움 클라이언트로, 정확한 검증 및 모듈화로 고성능을 낼 수 있는 이더리움 지갑이다. 다른 가상화폐 지갑과 살짝 다른 점은 Parity multi-sig wallet은 네트워크상에서 자금이 이체되기 전에 여러 사람의 서명이 필요하다는 것이다.[5][6] 이는 하나 이상의 키, 단일 서명 트랜잭션보다 좀 더 복잡한 트랜잭션을 지원하여, 일반적으로 비트코인 소유에 대한 책임을 분담하는 데 사용된다. 따라서, Parity multi-sig wallet을 쓰는 이는 개인 사용자보다 그룹이나 단체 등에서 많이 사용된다.

사건의 시작은 7월 20일, 새 버전의 Parity multi-sig wallet 라이브러리가 배포되면서 시작된다. 배포된 라이브러리 코드에는 일종에 구현 버그가 있었는데, 아무도 모르게 약 100일 동안 잠들어 있다가 devops199라는 사용자가 2017년 11월 6일, 실수로 이 버그를 유발하면서 트리거가 되었다.[7] 당시 그는 라이브러리로 전환된 자신의 지갑을 삭제하였고, 그 과정에서 라이브러리 코드를 삭제함으로 Parity multi-sig wallet으로 오갔던 모든 거래를 사용할 수 없도록 만든 것이다. 이 과정에서 라이브러리 코드가 삭제되면서 라이브러리 논리에 반하게 되고, Parity multi-sig wallet 안에 있는 모든 자금을 동결된 것이다.[8]

그렇다면 그는 어떻게 라이브러리로 자신의 Parity multi-sig wallet을 전환할 수 있었을까. 거래를 하면 배포되는 0x863df6bfa4469f3ead0be8f9f2aae51c91a907b4 주소에는 소유자가 초기화되지 않은 취약점이 있었다. 거래는 라이브러리이지만, 이더리움의 경우 계좌, 라이브러리 및 거래간에 실제 구분이 ​​없었으므로 이를 일반 Parity multi-sig wallet으로 전환할 수 있었다.[9] 이는 두 개의 거래에서 발생했는데 첫 번째 거래에서 라이브러리를 소유하고, 두 번째 거래에서는 7월 20일 이후에 만들어진 모든 Parity multi-sig wallet에서 사용된 라이브러리를 죽였다.

이 과정을 좀 더 자세히 이야기하면, 앞서 얘기한 것처럼 7월 19일에 initWallet () 함수를 사용하여 패리티 라이브러리의 소유자를 자신으로 초기화했다. 이렇게 해서 라이브러리에 소유자를 직접 지정하면, 사용자는 라이브러리를 일반 Parity multi-sig wallet으로 변환 할 수 있게 되는 것이다.[10]

// throw unless the contract is not yet initialized.
modifier only_uninitialized { if (m_numOwners > 0) throw; _; }

 // constructor - just pass on the owner array to the multiowned and
 // the limit to daylimit
function initWallet(address[] _owners, uint _required, uint _daylimit) only_uninitialized {
    initDaylimit(_daylimit);
    initMultiowned(_owners, _required);
}

이 후, 라이브러리의 소유자로 사용자를 초기화 한 후, 사용자는 kill () 루틴을 호출하면 이 타사 라이브러리에 종속된 모든 지갑을 마비시킬 수 있다. 이러한 버그는 7월 20일 이후에 생성 된 모든 지갑에 영향을 미치며, 그 영향권 안에 있는 지갑은 더 이상이 라이브러리를 사용할 수 없기 때문에 Parity multi-sig wallet을 사용하는 모든 사용자의 거래가 동결된 것이다.[11]

// kills the contract sending everything to `_to`.
function kill(address _to) onlymanyowners(sha3(msg.data)) external {
    suicide(_to);
 }

정리하면, Parity multi-sig wallet 라이브러리에 있는 initWallet() 함수를 호출하여 해당 라이브러리를 소유할 수 있고, 여기서 Kill()을 호출하여 라이브러리에 의존하고 있는 모든 지갑에 있는 이더리움이 동결된 것이다. 본래 이처럼 동결되는 기능은 특정 상황에서만 사용할 수 있도록 보호되어야 했지만, 버그로 인해 동결되는 상황이 완전하게 무방비로 되었기 때문에 이를 이용해 사용자가 기존 지갑의 소유권과 사용 매개 변수를 임의로 재설정 할 수 있었던 것이다.[12]

devops199에 따르면 그의 Parity multi-sig wallet은 ‘0x863df6bfa4469f3ead0be8f9f2aae51c91a907b4’ 주소에 있는 라이브러리를 사용하고 있으며, 그는 이를 Github에 올려놨다. 또한, 이 버그를 통해, ‘0x863df6bfa4469f3ead0be8f9f3ead0be8f9f2aae51c91a907b4’ 계약의 소유자를 자기 자신으로 수정하는 등 악용 가능성에 대해 언급했으며, 이 같은 버그를 찾은 것에 대해 우연히 발견했다고 얘기했다.[13][14] 이에 대해 Parity multi-sig wallet의 개발자인 토마스즈 드뤼에가는 그가 이더리움의 거래를 중지하려고 일부러 그런 것은 아니라고 판단되며, 이더리움을 빼돌리려 하다가 성공하지 못한 것으로 보인다고 설명했다.[15]

현재, 앞서 말한 것처럼 7월 20일 이후에 업데이트된 Parity multi-sig wallet은 동결되어 이더리움을 전송하거나 지출하는 것과 같은 거래는 불가능하다. 또한, 이 같은 사건으로 얼마나 많은 사용자의 지갑이 영향을 받았는지 불분명하며, 비공식적인 통계에 따르면 그 규모가 적어도 2억 8천 달러 가치의 이더리움이 동결된 것으로 보인다.[16]

여러 관계자는 이 같은 사건을 이더리움의 플랫폼 문제라기보다 개별 기업의 실수에 의한 것이라는 인식이 더 크게 보고 있으며[17][18], Parity Technologies는 이에 대해 이에 대한 악용 사례를 최소화하기 위해 최선을 다하고 있다고 밝혔다.[19] 개발자들은 이 버그를 일찍이 발견하지 못한 그 원인으로 Parity multi-sig wallet을 구현하는 데 있어 많은 양의 복잡성 때문이라고 얘기했다. 따라서 그들은 Parity Wallet의 Multi-sig 디자인을 다시 고찰할 것을 언급하며, UI가 이전보다 일반적이고 가벼운 플랫폼으로 재구성될 것이며, 모듈이 잘 격리되어 있게 할 것이라고 했다. 그리고 이와 같은 일이 다시 발생하지 않도록 기본 접근 권한을 ‘공용’이 아닌 ‘개인’으로 변경하고, 명시적으로 접근할 수 있는 수정을 불가하도록 하고 제한이 없는 함수를 구현하지 않을 것이라고 덧붙였다. 마지막으로 그들은 이와 같은 일이 번복되지 않기 위해 Parity는 버그 현상금 프로그램을 마련하여 더욱 안전한 거래가 이루어질 수 있도록 의사를 밝혔다.[20]

한편으론, 이에 대한 해답으로 동결된 이더리움을 다시 움직이기 위해선 버그에 의해 날아간 라이브러리 컨트랙을 하드포크를 통해서 복구하는 방법밖에는 없을 것이라는 분석이 나오기도 했다.[21] 하드포크란 기본 이더리움 프로토콜을 변경하여 시스템을 개선하기 위해 새로운 규칙을 만드는 것으로, 프로토콜 변경은 특정 블록 번호에서 활성화된다. 따라서 하드포크를 하면 모든 이더리움 클라이언트는 업그레이드가 필요한데, 그렇지 않으면 이전 규칙에 따라 호환되지 않는 체인에서 멈추게 되기 때문이다.[22] 만약, 하드포크를 하지 않을 경우, 업데이트되지 않은 이더리움 클라이언트를 사용하는 이는 포크가 발생하면 사전 포크 블록체인에 동기화된다. 따라서 주 네트워크에 대한 재생 방지 기능이 없으면 이전 규칙에 따라 호환되지 않는 체인에 갇히게 된다. 또한, 이전 클라이언트는 트랜잭션을 생성할 수는 있지만, 해당 트랜잭션의 결과를 볼 수는 없다.[23] 따라서, 현재 사태에서 가장 최선의 방안은 하이포크라는 말이 있기도 하다.  

결과적으로 Parity Technologies가 만든 Parity multi-sig wallet은 취약한 소스 구현으로 오랜 시간 배포되면서 버그는 방치되었었다. 이 때문에 이를 사용하는 많은 사용자가 현재 거래를 하지 못하고, 손가락만 빠는 상황이 되어버렸다. 아마도 이 때문에 그들은 꽤 많은 고객을 잃을 수도 있지 않을까 생각한다. 만약, Parity Technologies 개발자 팀이 코드를 검토하였다면 이와 같은 최악의 상황은 피했을지도 모른다. 아니면, 그들에게 조금이나마 보안에 대해 검토를 했다면 문제는 더 커지지 않았을지도 모른다. 하지만 그들은 타사의 라이브러리에 의존하는 Parity multi-sig wallet을 만들었고, 전 세계적으로 사용되었다는 점에서도 논쟁의 여지가 있다. 아무튼, 이 사건을 계기로 Parity Technologies뿐만 아니라 모두가 더 나은 네트워크와 더 나은 애플리케이션을 구축하는 방법에 대해 배울 수 있기를 바랄 뿐이다.

유성경 yuopboy@grayhash.com