비트 코인 코어 버그 CVE-2018–17144 : 분석

비트 코인 세계는 지난주 0.16.3이 대중에게 공개되었고 모든 사람들이 가능한 한 빨리 업그레이드 할 것을 촉구했을 때 놀랐습니다. 표면상의 이유는 패치가 필요한 0.14-0.16.2에서 발견 된 서비스 거부 (DoS) 벡터가 있기 때문입니다. 나중에 우리는 0.15-0.16.2의 동일한 버그로 인해 인플레이션 가능성이 있음을 발견했습니다.

이 기사에서는 무슨 일이 일어 났는지, 어떤 위험이 있었는지, 어떻게 악용 될 수 있었는지, 어떤 일이 일어날 수 있었는지 명확히하려고합니다.

이중 지출을위한 두 가지 방법

실제 버그에 도달하기 전에 몇 가지 설명이 필요합니다. 이중 지출과 관련된 버그이므로 먼저 이중 지출을 정의해야합니다.

이중 지출은 Alice와 같은 누군가가 동전을 Bob에게 쓰고 같은 동전을 Charlie에게 쓰는 경우입니다. Alice는 본질적으로 두 개의 수표를 작성하려고하는데, 그 중 하나는 반송 될 것임을 알고 있습니다. 물론 우리가 수표를 생각할 때 Alice가 가지고있는 일부 계정이이 두 수표를 작성하여 초과 인출되는 경우가 있습니다. 비슷하지만 비트 코인의 작동 방식은 정확하지 않습니다.

비트 코인은 계정에서 작동하지 않지만 UTXO 또는 사용되지 않은 트랜잭션 출력으로 작동합니다. 거래의 출력에는 본질적으로 주소와 금액이 있습니다. 해당 출력이 사용 된 후에는 다시 사용할 수 없습니다. UTXO는 0.413 BTC 코인과 같이 원하는 금액으로 귀하에게 전송 된 단일 코인이라고 생각하면됩니다.

이중 지출은 단일 코인 (UTXO)이 두 번 지출되는 것을 의미합니다. 일반적으로 이것은 Alice가 한 거래에서 Bob에게 0.413 BTC를 보내고 다른 거래에서 Charlie에게 보내는 것을 의미합니다. 이것이 비트 코인에서 해결되는 방식은 이러한 트랜잭션 중 하나가 블록으로 만들고 실제로 누가 지불을 받는지 결정하는 것입니다. 두 트랜잭션이 어떻게 든 여러 블록으로 들어 오면 후자의 블록은 소프트웨어에 의해 거부됩니다. 두 트랜잭션이 모두 단일 블록으로 들어 오면 해당 블록도 소프트웨어에 의해 거부됩니다. 기본적으로 소프트웨어는 이중 지출을 감지하고 이중 지출이있는 경우 차단을 거부해야합니다.

두 개의 다른 거래에서 동일한 UTXO를 보내는 것이 이중 지출의 유일한 방법은 아닙니다. 동일한 UTXO가 동일한 거래 에 두 번 소비되는 더 병리적인 경우가 있습니다. 이 경우 Alice는 Bob에게 동전 하나를 두 번 보냅니다. 따라서 Alice는 0.413 BTC 코인을 두 번 사용하여 0.826 BTC를 Bob에게 보냅니다. 0.413 BTC에 해당하는 UTXO가 1 개만 전송되므로 이는 분명히 유효한 거래가 아닙니다. 이것은 Alice가 Bob에게 동일한 $ 10 청구서를 두 번 지불하고 Bob이 $ 20를 받았다고 생각하는 것과 같습니다.

버그 정의

지금까지 정의한 내용을 요약하면 두 가지 유형의 이중 지출 시도가 있습니다.

(1)은 비트 코인 코어 소프트웨어에 의해 올바르게 처리됩니다. 여기서 우리가 걱정하는 것은 (2)입니다. 누구나 이와 같이 두 배로 지출하는 트랜잭션을 구성 할 수 있지만 노드가 이러한 종류의 트랜잭션을 받아들이도록하는 것은 또 다른 문제입니다. 트랜잭션을 블록으로 가져 오는 방법에는 두 가지가 있습니다.

A. 채굴자가 거래를 블록에 포함 할 수 있도록 충분한 수수료로 거래를 네트워크에 브로드 캐스트합니다.

B. 거래를 채굴 자로 블록에 포함합니다.

(A)는 트랜잭션을 생성하여 네트워크의 노드에 브로드 캐스팅하는 것 외에는 많은 것을 요구하지 않습니다. (B)는 충분한 작업 증명을 요구합니다. 버그의 경우 (A)는 해당 트랜잭션이 즉시 유효하지 않은 것으로 표시되고 네트워크의 노드에 의해 거부되므로 가능한 공격 벡터가 아닙니다. 거래가 전파되지 않기 때문에 채굴 자의 협력없이 채굴 자의 멤풀에 들어갈 수있는 방법이 없습니다. (B)는 버그가 나타나는 유일한 경우입니다. 즉,이 버그를 악용하려면 작업 증명 또는 충분한 채굴 장비와 전기가 필요합니다.

명확하게 말하면, 이중 지출을 처리해야하는 4 가지 경우가 있습니다.

1A — 동일한 UTXO를 사용하는 여러 mempool 트랜잭션

1B — 동일한 UTXO를 사용하는 다중 블록 트랜잭션

2A — 동일한 UTXO를 여러 번 소비하는 단일 mempool 트랜잭션

2B — 동일한 UTXO를 여러 번 소비하는 단일 블록 트랜잭션

버그에는 두 가지 징후가 있습니다. 0.14.x에는 서비스 거부 취약성이 있고 0.15.x ~ 0.16.2에는 인플레이션 버그가 있습니다. 다음으로 넘어갑니다.

서비스 거부 취약성

이 이야기는 2009 년 Bitcoin 0.1에서 시작됩니다.이 코드는 사례 1B와 2B를 거부하여 합의를 강제합니다 (블록이 이중 지출되지 않는지 확인).

모든 입력이 아직 사용되지 않았는지 확인하는 ‘충돌 확인’댓글을 볼 수 있습니다. “Mark outpoints as used”주석 아래의 코드는 UTXO를 사용한 것으로 표시합니다. UTXO가 두 번 이상 사용되면 오류가 발생합니다.

2011 년에 PR 443이 합병되었습니다. 이 변경은 단일 tx 이중 지출이 mempool을 통해 전송되는 경우를 처리하기위한 것입니다 (위의 사례 2A). 이 Pull Request 주석은 목적을 명확하게합니다 (강조) :

또한 중복 입력이있는 트랜잭션은 블록에 들어 가지 않습니다… 누군가 몇 주 전에 시도했지만 txes는 블록으로 끝나지 않았습니다. 나는 나중에 어딘가에 그들이 블록에 추가되는 것을 막는 수표가 있다고 가정합니다. 이것은 명백히 잘못된 거래가 중계되는 것을 방지하기위한 것입니다.

실제 코드 변경은 위의 ConnectInputs 에있는 “충돌 확인”주석 아래의 코드와 동일하지만 다른 위치에 있습니다. 코드 변경은 CheckTransaction 에 있으며 위의 4 가지 경우 (1A, 1B, 2A, 2B) 모두에 대해 실행됩니다. 결과적으로 Cases 1B 및 2B가 CheckTransaction 에서 한 번, ConnectInputs 에서 한 번, 두 번 확인되므로 이제 블록 이중 지출 합의 코드에 중복성이 있습니다.

2013 년에 PR 2224가 합병되었습니다. 이 변경의 목표는이 PR 의견이 다음과 같이 명확하게 설명하는 것처럼 합의 오류 (예 : 이중 지출)와 시스템 오류 (예 : 디스크 공간 부족)를 구분하는 것이 었습니다.

실행중인 블록 또는 트랜잭션 유효성 검사에 대한 메타 데이터를 저장하는 CValidationState를 도입합니다. 이전에는 혼동되어 디스크 공간이 부족하여 블록이 유효하지 않은 것으로 표시 될 수 있었기 때문에 런타임 오류 (예 : 디스크 공간 부족)가있는 유효성 검사 오류 (예 : 네트워크 규칙 충족 실패)를 구분하는 데 사용됩니다. . 또한 CValidationState는 DoS 수준을 추적하는 역할도 맡습니다 (따라서 트랜잭션 또는 블록 내에 저장할 필요가 없습니다…).

실제 관련 코드 변경은 다음과 같습니다.

지금까지 ConnectInputs 는 여러 메소드로 모듈화되었으며이 함수는 이중 지출을 확인하는 기능이되었습니다. 여기서 중요한 변화는 한때 오류 assert 로 변경되었다는 것입니다.

assert 는 C ++에서 무엇을합니까? 프로그램을 완전히 중단합니다. 프로그래머가 여기서 프로그램을 중지하려는 이유는 무엇입니까? 여기가 Pull Request의 목적이있는 곳입니다. 여기에 그 당시의 관련 코드 스 니펫이 있습니다.

이전과 같이 Case 1B 및 2B를 처리합니다. 함수 이름은 ConnectInputs 에서 ConnectBlock 으로 변경되었지만 Cases 1B 및 2B 검사의 중복성은 PR 443에서 유지되었습니다. 이미 살펴본 것처럼 UpdateCoins 는 두 번째 이중 지출 확인을 수행합니다. CheckBlock CheckTransaction 을 호출하여 첫 ​​번째 이중 지출 확인을 수행합니다.


같은 것을 두 번째로 확인하기 때문에 UpdateCoins 의 이중 지출 확인이 실패하는 유일한 방법은 일종의 UTXO 데이터베이스 또는 메모리 손상이있는 경우입니다. 실제로 이것이 assert 로 변경된 이유 인 것 같습니다. 우리는 이미 CheckTransaction 을 통해 CheckBlock UpdateCoins 전에 확인하는 것처럼 거래가 이중 지출되지 않는다는 것을 알고 있습니다. 따라서 PR 2224는 UpdateCoins 에서이 상태에 도달하는 것이 합의 오류가 아닌 시스템 오류 여야한다고 올바르게 추측했습니다. 이 경우 추가 데이터 손상을 방지하기 위해 올바른 방법은 프로그램을 중지하는 것입니다.

2017 년 PR 9049는 Bitcoin 0.14의 일부로 도입되었습니다. Segwit이 블록을 더 크게 만들려고했기 때문에 이것은 블록 유효성 검사 시간을 단축하기위한 많은 변경 사항 중 하나였습니다. 코드 변경은 매우 작았습니다.

여기에서 부울 fCheckDuplicateInputs 가 추가되어 블록 검사 속도를 높일 수 있습니다. 아래에서 볼 수 있듯이 이것은 중복 검사로 여겨졌습니다. 불행히도 UpdateCoins 의 코드는 PR 2224에서 시스템 손상 검사 로 변경되었으며 합의 검사가 아닙니다. 0.14.0까지 코드는 더 많이 모듈화되었으며 assert 는 약간 다르게 보입니다.

한때 중복 확인이었던 것이 이제는 블록 수준의 단일 TX 이중 지출 (Case 2B)을 담당하고 프로그램을 중지합니다. 이것은 여전히 ​​기술적으로 프로그램을 중단함으로써 합의 규칙을 매우 나쁘게 시행합니다.

PR 9049는 어떻게 통과 되었습니까? Greg Maxwell이 저를 IRC의이 채팅에 추천했습니다.

TL; DR, 개발자는 PR 9049를 논의 할 때 PR 2224를 고려하지 않고 PR 443의 다른 곳에서 블록 수준 단일 TX 이중 지출 (케이스 2B)이 확인되고 있다고 생각하는 경향이있었습니다. 이로 인해 개발자는 PR 9049를 자세히 보지 않았습니다.

요약 :

이것은 버그를 유발 한 이벤트의 이상한 합류라고 말할 수 있습니다.

DoS 취약성의 심각도

이것은 Core 0.14.x 소프트웨어가 이상하게 충분한 블록이 주어지면 충돌 할 수 있음을 의미합니다. 코드가있는 위치로 인해 충돌을 일으키기 위해 공격자는 다음을 수행해야합니다.

(1)과 (3)은 그다지 비싸지 않습니다. (2) 충분한 작업 증명이있는 블록을 생성하는 데 필요한 해시 전력의 양은 유효한 블록을 찾는 것과 동일한 양의 에너지 / 채굴 장비를 필요로하므로 최소 12.5 BTC의 비용입니다.

게임 이론 관점에서 네트워크 분할이 그다지 좋지 않다고 생각하는 경우이 취약점을 악용 할 인센티브는 매우 낮습니다. 기껏해야 공격자는 12.5 BTC의 비용으로 전체 노드의 좁은 조각을 제거합니다. 일부 노드를 마음대로 충돌시킬 수있는 것보다 훨씬 더 많은 것을 필요로하는 분할 된 네트워크에서 이익을 얻을 가능성은 희박하므로 공격자가 공격 비용을 쉽게 회수 할 수 없으므로 얻을 것이 많지 않습니다.

이것이 유일한 취약점이라면 공격자는 많은 사람들에게 불편을 줄 수 있지만 이러한 노드는 단순히 재부팅하여 불량 블록을 제공하는 노드가 아닌 다른 노드에 연결할 수 있기 때문에 지속적인 불편은 없습니다. 체인이 길어지면이 불량 블록 공격은 완전히 이빨을 잃게됩니다. 공격자가 블록 당 12.5 BTC의 비용으로 블록을 계속 생성하여 네트워크의 0.14.x 노드에 공급하지 않는 한 공격은 어느 정도 거기서 끝날 것입니다.

즉, 취약성은 확실히 존재하지만 DoS에 대한 경제적 인센티브는 매우 낮았습니다.

인플레이션 버그

0.15.0부터 UTXO를 더 빠르게 조회하고 저장하는 기능이 도입되어 다음 버그 반복이 도입되었습니다. 단일 트랜잭션 이중 지출이있는 블록이 들어 왔을 때 충돌하는 대신 소프트웨어는 블록이 유효한 것으로 간주했습니다.

이것은 0.14 노드를 충돌시키는 병리 적 트랜잭션 (동일한 UTXO가 동일한 트랜잭션 또는 위의 2B에서 여러 번 사용됨)이 이제 0.15 노드에서 유효한 것으로 간주되어 본질적으로 BTC를 생성한다는 것을 의미합니다.

방법은 다음과 같습니다. 0.15에 도입 된 PR 10195는 많은 것을 포괄하지만 UTXO가 저장되는 방식이보다 효율적으로 조회 할 수 있도록 변경되었다는 것이 주요 요점입니다. 그 결과 이전의 UpdateCoins 함수에 대한 변경 사항을 포함하여 많은 변경 사항이있었습니다.

assert (false) 주변의 코드가 어떻게 완전히 제거되었는지 확인하세요. 이를인지 한 PR 10537도 0.15.0에서 코드를 변경하여 어설 션이 다시 반환되었습니다.

어설 션이 실패하는 조건은 이제 다음과 같은 inputs.SpendCoin 에 따라 다릅니다.

본질적으로 SpendCoin 이 false를 반환하는 유일한 방법은 코인이 UTXO 세트에 존재하지 않는 경우입니다. 그러나 보시다시피 코인은 DIRTY 가 아니라 FRESH 이어야합니다. 이것은 명백한 용어는 아니지만 고맙게도 핵심 개발자 Andrew Chow가 설명합니다.

이제 문제는 UTXO가 언제 FRESH 로 표시됩니까? UTXO 데이터베이스에 추가 될 때 FRESH 로 표시됩니다. 그러나 UTXO 데이터베이스는 여전히 메모리에만 있습니다 (캐시로). 디스크에 저장 될 때 메모리의 항목은 더 이상 FRESH 로 표시되지 않습니다. 이러한 디스크 저장은 모든 블록 이후에 발생합니다 (다른 시간과 마찬가지로 중요하지 않음).

FRESH 코인은 메모리 풀에 들어간 코인입니다. 공격하는 채굴자는 UpdateCoins 의 해당 assert 문을 통해 노드를 충돌시킬 수 있습니다. 그러나 더 나쁜 것은 코인이 DIRTY (본질적으로 디스크에서 읽음)이면 인플레이션을 유발할 수 있습니다.

따라서 핵심 소프트웨어를 0.15.0에서 0.16.2로 속여서 공급을 부 풀리는 이상하고 잘못된 블록을 받아 들일 수 있습니다.

인플레이션 취약점의 심각도

이 공격의 경제성은 공격자가 잠재적으로 허공에서 BTC를 생성 할 수 있기 때문에 서비스 거부 사례보다 훨씬 더 나은 것 같습니다. 공격을 실행하려면 여전히 채굴 장비가 필요하지만 인플레이션 가능성이있어 가치가있을 수 있습니다.

이 버그를 사용하는 비트 코인에 대한 순진한 공격은 다음과 같습니다.

일어난 상황은 다음과 같습니다.

모든 채굴자가 비트 코인 코어 0.15 이상을 실행 중일 수 있습니다.이 경우 취약하지 않은 클라이언트는 단순히 중단되었을 것입니다. 채굴자가 다른 작업을 수행했을 수도 있습니다.이 경우 블록을 발견하자마자 체인 포크가 발생했을 것입니다.

이러한 불규칙성으로 인해 네트워크의 사람들은 곧이를 추적했을 것이며 아마도 일부 개발자에게 경고했고 핵심 개발자가이를 수정했을 것입니다. 포크가 있었다면 그 시점에서 올바른 체인 인 사회적 합의가 논의되기 시작하고 예상치 못한 인플레이션을 일으키는 체인이 손실되었을 가능성이 있습니다. 지체가 있었다면 공격자를 처벌하기 위해 자발적으로 롤백했을 가능성이 높습니다.

공격자에게는 +50 BTC가 아니라 -12.5 BTC 일 가능성이 훨씬 높습니다. 공격자가 더 많은 금액 (예 : 200 BTC)을 두 배로 지출하면 공격이 훨씬 더 노골적이기 때문에 인플레이션 블록이 남아있을 가능성이 훨씬 적습니다.

따라서 공격자의 관점에서 볼 때 이는 그다지 좋은 투자 수익이 아닙니다.

공격자가 이익을 얻을 수있는 또 다른 방법은 BTC를 매도 한 다음 공격을 실행하는 것입니다. 특히 위기가 신속하고 단호하게 처리된다면 BTC 가격이 하락할 것이라는 보장이 없기 때문에 이것 역시 위험합니다. 또한 대부분의 거래소에서 마진을 제공하는 AML / KYC를 감안할 때 공격자가 매우 짧은 순서로 독싱을 당할 가능성이 있습니다.

공격자는 상당한 금전적 위험뿐만 아니라 물리적 위험도 가지고 있습니다. ROI는 실제로 존재하지 않으며 경제적 관점에서 이익을 얻을 수있는 쉬운 방법이 아닙니다.

그러나 국가 수준의 행위자는 이것을 비트 코인 사람들을 놀라게하는 방법으로 사용할 수있었습니다.ROI는 더 추상적이므로 이론적으로 이것은 국가 수준의 행위자의 목적을 달성했을 수 있습니다.

결론

확실히 이것은 매우 심각한 버그였습니다. 그리고 Awemany와의 차이점에도 불구하고이 사람이 책임감있게 공개하기로 결정한 것에 감사합니다. 즉, 악용에 대한 경제 게임 이론을 고려할 때 버그가 그와 같은 사람들이 만든 것처럼 거의 심각하지 않다고 생각합니다.

버그가 발견되기 전에 악의적 인 사람들에게 알려 졌다고하더라도 경제적 인 측면이 타당하지 않기 때문에 공격자가 악용하기로 선택하지 않을 가능성이 높습니다. 확실히 기술적 인 부분은 수정되고 더 나아 져야하지만,이 익스플로잇이 실제로 유용 할 사람들 그룹은 정말 작습니다 (기본적으로 비트 코인을 파괴하려는 국가 수준의 행위자).

비트 코인 코어에 대한 교훈은 많습니다.

과거에 버그가 있었지만 앞으로도 버그가있을 것입니다. 지금 중요한 것은 이러한 강의를 배우고 통합하는 것입니다.