LINE Corporation이 2023년 10월 1일부로 LY Corporation이 되었습니다. LY Corporation의 새로운 기술 블로그를 소개합니다. LY Corporation Tech Blog

Blog


SMARTIAN: 데이터 흐름 분석을 활용한 스마트 컨트랙트 퍼징

LINE DEVELOPER DAY 2021에서 김도연 님이 발표하신 SMARTIAN: 데이터 흐름 분석을 활용한 스마트 컨트랙트 퍼징 세션 내용을 옮긴 글입니다.

안녕하세요. 2021년 1월에 LINE에 입사해 Security R&D 팀에서 소프트웨어 보안 연구 및 보안 컨설팅을 담당하고 있는 김도연입니다.

이번 글에서 새로운 이더리움 스마트 컨트랙트 퍼징1(fuzzing) 툴인 SMARTIAN을 소개하려고 합니다. SMARTIAN은 데이터 흐름 분석을 이용한 스마트 컨트랙트 퍼저2(fuzzer)입니다. SMARTIAN은 제 석사 연구의 연장선이며, 연구 논문은 소프트웨어 엔지니어링 업계 최고 수준의 학회인 ASE 2021에 채택됐습니다.

글은 다음과 같은 순서로 진행합니다.

  • 스마트 컨트랙트 보안의 중요성
  • 스마트 컨트랙트에서 버그 감지가 어려운 이유
  • SMARTIAN 소개
  • SMARTIAN 성능 평가

스마트 컨트랙트 보안의 중요성

LINE은 현재 다양한 블록체인 사업을 전개하고 있으며, 블록체인 서비스를 안전하게 유지하기 위해서 dApp의 기본 구성 요소인 스마트 컨트랙트(smart contract)의 보안을 위해 최선을 다하고 있습니다. dApp은 블록체인에서 실행되는 탈중앙화 앱입니다. 그렇다면 스마트 컨트랙트란 무엇일까요? 스마트 컨트랙트는 블록체인에서 실행되는 작은 컴퓨터 프로그램입니다. 지금부터 스마트 컨트랙트가 실제로 어떻게 작동하는지 간단한 예제를 통해서 알아보겠습니다.

혹시 크라우드펀딩(crowdfunding)이라고 들어보셨나요? 크라우드펀딩은 많은 사람에게서 소액의 자금을 모아 아이디어나 프로젝트에 자금을 제공하는 것을 말합니다. 크라우드펀딩에는 일반적으로 세 가지 유형의 역할이 있습니다.

  • 크리에이터(creator): 자금을 조달하려는 아이디어나 프로젝트를 제안하는 사람
  • 투자자(investor): 프로젝트에 투자하고 싶은 사람
  • 크라우드펀딩 플랫폼(crowdfunding platform): 크리에이터와 투자자를 중재하는 플랫폼

스마트 컨트랙트가 어떤 식으로 작동하는지 살펴보기 위해 크라우드펀딩 사례를 한번 살펴보겠습니다. 크리에이터는 제품을 만들기 위해 최소 만 달러가 필요하지만 돈이 없는 상태라고 가정하겠습니다. 자신들을 지원할 수 있는 투자자를 찾아야 하는 상황입니다. 이때 크라우드펀딩 플랫폼을 통해서 투자자로부터 투자를 받을 수 있습니다. 크리에이터는 크라우드펀딩 플랫폼에서 잠재적인 투자자들에게 자신의 제품을 소개합니다. 제품 소개를 본 몇몇 투자자가 흥미를 느껴 투자하기로 결정하고, 크라우드펀딩 플랫폼으로 자금을 이체합니다. 크라우드펀딩 플랫폼은 크리에이터가 원했던 금액까지 투자액이 쌓이기를 기다립니다. 투자자들의 투자액이 만 달러 이상이 되면 크라우드펀딩 플랫폼은 이 모든 돈을 크리에이터에게 이체합니다. 반면 투자자가 없어서 정해진 기한 내에 만 달러가 모이지 않으면 크라우드펀딩 플랫폼은 각 투자자에게 다시 자금을 돌려줍니다.

여기서 스마트 컨트랙트가 등장합니다. 앞서 말씀드렸듯 스마트 컨트랙트는 블록체인에서 실행되는 컴퓨터 프로그램입니다. 우리는 스마트 컨트랙트로 크라우드펀딩 플랫폼을 대체할 수 있습니다. 즉, 스마트 컨트랙트를 이용하면 크리에이터가 투자를 받기 원할 때 크라우드펀딩 플랫폼으로 갈 필요가 없다는 의미입니다. 대신 크라우드펀딩 플랫폼과 동일하게 작동하는 스마트 컨트랙트를 블록체인에 배포한 뒤 투자가 충분히 들어올 때까지 기다리면 됩니다.

그런데 스마트 컨트랙트는 개발 과정에서 버그가 발생할 수 있습니다. 스마트 컨트랙트에 문제가 있다면 어떤 일이 일어날지 상상해 보겠습니다.

만약 투자가 충분히 들어오면 투자금을 크리에이터에게 전송하는 것이 정상적인 플로우입니다. 그런데 만약 투자금을 크리에이터에게 전송할 때, 크리에이터의 계좌를 바꿀 수 있다면 어떻게 될까요? 이런 문제는 공격자가 쉽게 크리에이터의 계좌를 변경할 수 있다는 점 때문에 발생합니다. 공격자는 악의적으로 크리에이터의 계좌를 자신의 계좌로 바꾼 후, 모든 투자금을 크리에이터가 아닌 공격자에게 이체할 수 있습니다. 실제로 이와 같은 스마트 컨트랙트의 버그를 악용하는 사례가 많이 발생하고 있습니다. 이런 문제는 때에 따라 수백만 달러에 달하는 디지털 자산을 처리하는 스마트 컨트랙트에 치명적인 문제를 초래할 수 있습니다. 이와 같은 불상사를 방지하려면 블록체인에 배포하기 전에 스마트 컨트랙트의 취약점을 찾아내는 것이 매우 중요합니다. 이에 스마트 컨트랙트에서 자동으로 버그를 찾는 연구가 큰 관심을 받게 되었습니다.

스마트 컨트랙트에서 버그 감지가 어려운 이유

스마트 컨트랙트의 버그를 찾는 툴은 아래와 같이 여러 가지가 있고, 이를 세 가지 유형으로 나눌 수 있습니다. 정적 분석기(static analyzer)와 심볼릭 실행기(symbolic executor), 그리고 퍼저입니다.

  • 정적 분석기: MadMax, Remix, SASC, Security, Slither, SmartCheck, Vandal, VeriSmart, Zeus
  • 심볼릭 실행기: Maian, Manticore, Mythril, Osiris, Oyente, sCompile, teEther
  • 퍼저: sFuzz, ILF, Harvey, Echidna, ContractFuzzer, Reguard, ContraMaster

그 중에서도 저희는 퍼저를 집중적으로 살펴볼 예정인데요. 그렇다면 퍼저란 무엇일까요? 먼저 퍼즈(fuzz)는 대상 프로그램에서 사용할 임의의 문자열을 생성하는 것입니다. 퍼징은 프로그램에 예상치 않은 데이터를 무작위로 입력하고 프로그램을 실행하며 테스트하는 것입니다. 퍼저는 대상 프로그램을 퍼징해서 버그를 찾는 툴입니다.

퍼저는 세 개의 카테고리로 분류할 수 있습니다. 블랙 박스(black-box)와 화이트 박스(white-box), 그리고 그레이 박스(grey-box) 퍼저입니다. 블랙 박스는 대상 프로그램의 내부를 볼 수 없습니다. 프로그램의 입출력 작동만 관찰합니다. 화이트 박스 퍼저는 블랙 박스 퍼저와 반대라고 생각하면 됩니다. 대상 프로그램의 내부를 전부 관찰할 수 있고 프로그램 실행 시 수집된 정보를 분석해서 테스트 케이스를 생성할 수 있습니다. 종종 동적 계측(dynamic instrumentation)이나 SMT 솔버(satisfiability modulo theories solver)를 사용하기 때문에 일반적으로 블랙 박스 퍼저보다 비용(cost)이 훨씬 높습니다. 그레이 박스 퍼저는 블랙 박스 퍼저와 화이트 박스 퍼저의 중간 정도라고 생각하면 됩니다. 프로그램 내부의 정보를 어느 정도 모을 수 있지만 화이트 박스 퍼저와는 달리 많은 비용이 발생하지는 않습니다. 프로그램을 간단히 분석하거나 코드 커버리지(code coverage)와 같은 동적 정보를 수집합니다. 때로는 속도를 높이고 더 많은 입력을 테스트할 수 있도록 불완전한 정보에 의존하기도 합니다.

현재 발표된 스마트 컨트랙트의 취약점을 찾아주는 퍼저에는 여러 가지 문제가 있어서 사용성이 좋지 않습니다.

  • 버그가 트리거된 위치를 알려주지 않음
  • 테스트 케이스를 저장하지 않기 때문에 어떤 툴이 더 나은지 정량적으로 비교하기가 어려움
  • 오픈소스가 아님
  • 스마트 컨트랙트에서 꼭 탐지해야 할 버그들을 감지하지 못함

퍼저가 스마트 컨트랙트에서 버그를 찾기 위해 넘어야 할 중요한 기술 과제가 하나 더 있습니다. 바이너리 프로그램을 위한 전통적인 퍼저는 일반적으로 코드 커버리지를 피드백으로 사용하지만, 스마트 컨트랙트에는 바이너리 프로그램과는 사뭇 다른 '영구 상태(persistent state, 이하 상태)'라는 특성이 있는데요. 코드 커버리지가 변하지 않더라도 영구 상태가 바뀌면 버그가 발생할 수 있는 상태에 가까워질 수 있습니다. 때문에 코드 커버리지만 피드백으로 사용하면 버그를 찾는 것이 어렵습니다. 그렇다면 어떻게 상태가 변하는지 알 수 있을까요? 그 전에 트랜잭션이 무엇인지 알아야 할 필요가 있습니다. 트랜잭션(transaction)은 스마트 컨트랙트를 실행하는 입력값입니다. 트랜잭션을 이용해서 스마트 컨트랙트에 정의 되어 있는 함수를 실행할 수 있습니다. 만약 여러 개의 함수를 순서대로 실행하고 싶다면, 순서가 있는 여러 개의 트랜잭션(a sequence of transactions, 이하 트랜잭션 시퀀스)을 스마트 컨트랙트로 보내면 됩니다. 이때 트랜잭션이 스마트 컨트랙트에 도착하면 함수가 실행될 텐데요. 이 과정에서 상태가 바뀔 수 있습니다. 그래서 1) 상태를 바꾸는 함수가 실행되고, 2) 변한 상태를 이용하는 함수가 실행되는 트랜잭션 시퀀스를 찾아야 합니다. 현재 스마트 컨트랙트를 위한 퍼저는 트랜잭션을 무작위로 변경하거나 기계 학습을 이용해서 처리합니다. 하지만 이들 모두가 결정론적이지 않기 때문에(non-deterministic) 버그를 트리거하는 트랜잭션 시퀀스를 만들기가 어렵습니다.

앞서 말씀드린 크라우드펀딩 사례를 살펴보겠습니다. 참여자에는 세 가지 유형이 있다고 말씀드렸습니다. 크리에이터와 투자자, 크라우드펀딩 플랫폼인데요. 그중 크라우드펀딩 플랫폼을 스마트 컨트랙트로 대체하는 것이 바로 아래 코드입니다.

코드를 살펴보겠습니다. Open, Funds, Creator는 영구 상태 변수입니다. 크리에이터가 크라우드펀딩을 OpenCrowdFunding 함수를 호출해서 오픈하면 Invest 함수가 정상적으로 실행될 수 있으므로 투자가 가능합니다. Funds 변수가 만 달러 이상인 경우 모든 돈을 Creator 변수에 저장된 크리에이터 주소로 이체하고 크라우드펀딩을 종료합니다.

이때 SendAllFundsToCreator 함수에 액세스 제어(access control) 버그가 있다고 가정해 보겠습니다. 녹색으로 강조한 msg.senderSendAllFundsToCreator 함수를 호출하는 트랜잭션을 보낸 사람입니다. transfer 함수는 Fundsmsg.sender에게 이체할 수 있습니다.

CloseCrowdFunding은 누구나 호출할 수 있고, SendAllFundsToCreator 함수의 msg.senderCloseCrowdFunding 함수를 호출한 사람과 같기 때문에 아무나 가능합니다. 그래서 CloseCrowdFunding 함수를 호출한 사람이 크리에이터가 아닌 공격자라면 모아진 투자금을 공격자에게 이체할 수 있습니다.

그렇다면 어떻게 버그를 패치할 수 있을까요? 한 가지 해결책은 SendAllFundsToCreator 함수가 실행되기 전에 아래와 같이 트랜잭션을 보낸 사람을 확인하는 코드를 삽입하는 것입니다. require는 조건이 거짓이면 더 이상 코드를 실행시키지 않습니다. 따라서 크리에이터만 transfer 함수를 실행한 뒤 Open 변수를 false로 만들 수 있습니다.

패치하기 전에 버그를 트리거하기 위해서는 트랜잭션 시퀀스가 차례대로 OpenCrowdFunding 함수, Invest 함수, CloseCrowdFunding 함수를 호출해야 합니다. 이때, OpenCrowdFunding 함수를 호출하는 트랜잭션을 보내는 사람은 Creator 변수에 저장된 크리에이터의 주소여야 합니다. Funds 변수가 만 달러 이상이 되기 위해서 Invest 함수는 최소 한 번 이상 실행돼야 합니다. Invest 함수는 크라우드펀딩 기능이 오픈된 상태에서만 실행할 수 있습니다. 사소해 보일지도 모르겠습니다만, 스마트 컨트랙트에서 버그를 찾는 대부분의 툴은 이와 같은 순서나 누가 트랜잭션을 보냈는지에 대해 신경 쓰지 않기 때문에 버그를 찾기가 어렵습니다.

정리하자면, 위 예시의 스마트 컨트랙트에서 버그를 찾으려면 아래 세 가지 요소를 '잘' 찾아야 합니다.

  • 트랜잭션 순서(transaction order): OpenCrowdFunding 함수 → Invest 함수 → CloseCrowdFunding 함수
  • 함수의 인수(function argument): 최소 만 달러 이상인 Invest 함수의 value 변수
  • 트랜잭션을 보내는 사람(transaction sender): 크라우드펀딩을 열기 위해 크리에이터가 직접 OpenCrowdFunding 함수를 호출해야 함

SMARTIAN: 이더리움 스마트 컨트랙트 퍼저

우리는 이더리움 스마트 컨트랙트에서 버그를 똑똑하게 찾기 위해 SMARTIAN이라는 이더리움 스마트 컨트랙트 전용 그레이 박스 퍼저를 구현했습니다. SMARTIAN은 버그가 발생한 위치를 쉽게 파악할 수 있고, 스마트 컨트랙트에서 발견되는 다양한 버그를 감지할 수 있으며, 오픈소스입니다. 그리고 정적, 동적 데이터 흐름을 분석해 트랜잭션 순서와 함수의 인수, 발신자를 체계적으로 찾을 수 있어서 다른 퍼저들보다 더 빠르고 정확하게 버그를 감지할 수 있습니다. 여기서 데이터 흐름이란 영구 상태 변수가 어디서 정의되고 어디서 사용되는지를 나타내는 정보입니다.

아래는 SMARTIAN의 아키텍처입니다. SMARTIAN은 크게 세 부분으로 구성됩니다.

  • 정보 수집(information gathering)
  • 테스트 케이스 풀 초기화(test case pool initialization)
  • 퍼징(fuzzing)

여기서 테스트 케이스와 트랜잭션 시퀀스와 시드(seed)는 동일한 개념입니다.

자, 그러면 작동 과정을 하나씩 살펴보겠습니다. 제일 먼저 스마트 컨트랙트의 소스 코드를 컴파일하면 EVM(Ethereum Virtual Machine) 바이트코드가 됩니다. 여기서 EVM은 스마트 컨트랙트를 실행할 수 있는 환경입니다.

SMARTIAN은 EVM 바이트코드를 입력으로 받습니다.

그리고 정적 분석을 사용해 정보를 수집합니다. 정적 분석은 스마트 컨트랙트를 실행하기 전에 진행하는 분석으로, 스마트 컨트랙트 영구 상태 변수의 데이터 흐름, 트랜잭션을 누가 보냈는지와 같은 정보를 수집합니다.

이렇게 수집한 정보를 테스트 케이스 풀 초기화 단계로 보냅니다.

SMARTIAN은 수집한 정보를 바탕으로 테스트 케이스 풀을 만듭니다.

생성된 테스트 케이스 풀 안에 있는 테스트 케이스를 활용해 버그를 찾아야 하는데 아직 스마트 컨트랙트를 실행하기 전이므로 이 테스트 케이스가 실제로 버그를 찾을 수 있는지는 확신할 수 없습니다. 따라서 이 테스트 케이스를 사용해 스마트 컨트랙트를 실행해야 합니다. 퍼징 단계는 테스트 케이스를 직접 실행하기 위해 기본값(default value)으로 초기화된 테스트 케이스들을 입력으로 받습니다.

퍼징 단계에서는 테스트 케이스들을 실행합니다.

대상 프로그램을 테스트하는 동안 SMARTIAN은 동적 분석을 수행합니다. 트랜잭션에서 어떤 영구 상태가 정의(define)되고 사용(use)되고 있는지와 같은 정보를 수집합니다. 새로운 상태 변화를 발견하거나 버그를 찾으면 이 테스트 케이스를 추후에 재사용합니다.

요약해 보겠습니다. 첫째는 정보 수집입니다. 유용한 데이터 흐름을 수집하기 위해 정적 분석을 실행합니다. 함수에서 어떤 상태 변수를 정의하고 사용하는지와 발신자와 관련된 정보도 수집합니다. 두 번째는 테스트 케이스 풀 초기화입니다. 수집한 정보에 기반해 어떤 시퀀스가 버그를 트리거할 확률이 높은지 예측해서 만든 뒤 각 함수의 인수를 기본값으로 설정합니다. 마지막으로 퍼징 단계입니다. 동적 분석을 통해 새로운 데이터 흐름을 발견하면 이를 이용해서 버그를 트리거할 수 있는 실제 값(concrete value)을 찾습니다. 또한 자체 버그 오라클3을 이용해 다양한 버그를 감지할 수 있습니다.

이 과정이 꽤 복잡하죠? 앞서 나온 크라우드펀딩을 예시로 살펴보겠습니다.

크라우드펀딩의 정보를 수집하는 단계에서 SMARTIAN은 Open, Funds 그리고 Creator라는 세 가지 상태 변수가 있다는 것을 파악하고, OpenCrowdFunding, Invest, CloseCrowdFunding이라는 세 가지 함수도 파악합니다. 또한 Open 변수는 OpenCrowdFunding 함수에 정의돼 있고 Invest 함수에서 사용한다는 것과, FundsInvest 함수에 정의돼 있고 이는 CloseCrowdFunding 함수에서 사용한다는 것을 파악합니다. Opentrue이면 OpenCrowdFunding 함수의 발신자는 크리에이터여야 한다는 것 역시 파악합니다. SMARTIAN은 이러한 사실을 테스트 케이스 풀 초기화 단계로 보냅니다.

수집한 정보를 바탕으로 SMARTIAN은 아래와 같은 테스트 케이스를 구성합니다. 그리고 함수의 인자를 기본값인 0으로 설정합니다.

SMARTIAN은 이 테스트 케이스로 대상 스마트 컨트랙트에 대한 퍼징 테스트를 수행합니다. 정보 수집 단계에서 OpenCrowdFunding 함수를 호출한 사람이 크리에이터가 아니면 Open 변수가 true가 될 수 없다는 것을 알았기에 OpenCrowdFunding 함수를 호출한 사람을 크리에이터로 설정합니다.

하지만 Funds 변수가 0이므로 CloseCrowdFunding 함수 쪽 흐름으로 진입할 수 없어서 버그를 찾지 못합니다. Invest 함수의 인수는 0이 아니어야 합니다.

비록 버그는 발견하지 못했지만 이 트랜잭션 시퀀스를 실행하면서 동적 분석을 통해 정의-사용 체인(define-use chain)을 두 가지 찾았습니다.

따라서 이 테스트 케이스를 높은 확률로 버그를 찾을 수 있는 좋은 테스트 케이스로 판단하고 다시 실행합니다. 다시 퍼징(re-fuzzing)하는 단계에서 SMARTIAN은 Invest 함수의 인수를 만 달러로 설정하고 트랜잭션 시퀀스를 실행하며, 결국 CloseCrowdFunding 함수에서 버그를 찾습니다.

SMARTIAN 평가하기

여기까지 SMARTIAN의 구조와 작동 방식을 말씀드렸습니다. 그런데 과연 SMARTIAN이 다른 툴보다 성능이 좋을까요? 함께 평가 결과를 살펴보겠습니다. 우선 평가에 사용한 환경은 다음과 같습니다(논문에서 더 자세한 정보를 확인하실 수 있습니다).

비교 대상으로는 퍼저 두 개와 심볼릭 실행기 두 개를 선택했습니다. 최고 수준의 학회에서 발표된 좋은 성능을 내는 오픈소스 퍼저를 선별해서 ILF와 sFuzz를 선택했습니다. 심볼릭 실행기를 선택할 때도 비슷한 기준을 적용했고, 다양한 버그 클래스를 지원하는 Mythril과 Manticore를 선택했습니다. 사실 비교 대상을 선정하는 과정에서 많은 어려움이 있었는데요. 자세한 내용은 논문에서 확인하실 수 있습니다.

아래 표는 우리가 사용한 벤치마크를 요약한 것입니다.

B1은 정수 버그(integer bug)를 찾는 정적 분석기인 Verismart의 논문에서 사용된 벤치마크입니다. 알려진 취약점을 가지고 있는 스마트 컨트랙트를 모은 데이터 셋이고 각각은 전부 CVE를 받은 상태입니다. B2는 SmartBugs에 있는 스마트 컨트랙트들의 일부로 B1보다 더 많은 버그를 포함하고 있지만 토이 스마트 컨트랙트(toy smart contract, 테스트하기 위해 간단히 만든 컨트랙트)도 많이 포함돼 있습니다. B3에는 이더리움의 스마트 컨트랙트 코드와 통계를 제공하는 온라인 플랫폼인 Etherscan에서 얻은 대중적이고 복잡한 스마트 컨트랙트 500개가 포함돼 있습니다. 대중성의 척도는 얼마나 사용자들이 많이 이용했는지, 즉 트랜잭션이 얼마나 많은지입니다. 복잡함의 척도는 스마트 컨트랙트 바이트 코드의 크기입니다. 우리는 3만 건 이상의 트랜잭션이 있는 스마트 컨트랙트를 다운로드해서 우리가 사용한 컴파일러 버전으로 컴파일되지 않는 스마트 컨트랙트를 걸러낸 뒤, 남은 스마트 컨트랙트를 바이트코드 크기 기준으로 정렬해서 바이트코드 크기가 큰 스마트 컨트랙트 500개를 선택했습니다.

아래 그래프는 첫 번째 평가 결과를 나타낸 것입니다. 우리는 SMARTIAN에서 정적 분석과 동적 분석이 얼마나 버그를 찾는데 효과적인지 살펴봤고, 각각의 경우에 비용이 얼마나 추가가 되는지 측정했습니다. 실험에 사용한 데이터는 B1입니다. B1은 이전에 알려진 버그가 포함되어 있기 때문입니다. B2가 아닌 B1을 사용한 이유는 B2는 일부 컨트랙트가 토이 컨트랙트이기 때문입니다. 비록 명령어 커버리지(instruction coverage)가 1%만 증가하기는 했지만 정적 분석과 동적 분석 모두에서 최상의 결과를 보여주고 있습니다. 또한 동적 분석을 적용하면 오버헤드가 얼마나 발생하는지도 평가했고, 2.7%만 증가한 것을 확인했습니다.

다음은 B1의 하위 집합에서 버그를 얼마나 잘 발견하는지 최신 툴과 비교한 결과입니다. 일부 툴은 B1의 몇몇 스마트 컨트랙트를 테스팅하는 것이 불가능했기 때문에 모든 툴이 작동하는 B1의 하위 집합으로 비교했습니다. ILF는 정수 버그를 찾지 못해서 제외했습니다. SMARTIAN이 다른 툴보다 훨씬 많은 CVE를 발견한 것을 확인할 수 있습니다.

다음은 최신 툴과 B1의 하위 집합을 대상으로 코드 커버리지를 비교한 것입니다. SMARTIAN의 커버리지가 다른 툴보다 높은 것을 확인할 수 있습니다.

다음은 B2에서 최신 툴과 버그 찾기를 비교한 결과입니다. 역시 SMARTIAN이 다른 툴보다 많은 버그를 발견한 것을 확인할 수 있습니다. 여기서 놀라운 점은 SMARTIAN이 발견한 모든 버그는 실제 버그(true positive, TP)였다는 것입니다. 반면 다른 툴에서는 가짜 버그(false positive, FP, 버그라고 알람이 나왔지만 실제 버그는 아닌 것)가 많이 나왔습니다.

다음은 B2에서 커버리지를 비교한 결과입니다. SMARTIAN의 커버리지가 높다는 것을 알 수 있습니다.

다음은 대중적이고 복잡한 500개의 스마트 컨트랙트 데이터 셋인 B3에서 SMARTIAN이 발견한 버그 결과 표입니다. 어떤 것이 진짜 버그이고 어떤 것이 가짜 버그인지 확인했습니다. SMARTIAN은 진짜 버그 211개와 가짜 버그 8개를 발견했습니다. 대부분의 버그 패턴이 B1에 있는 버그들과 유사했는데요. 이를 통해 많은 개발자가 취약한 코드를 복사 붙여넣기 하고 있다는 것을 알 수 있습니다. 또한 가짜 버그 8개는 버그 오라클의 불완전함 때문이었습니다.

마치며

우리는 스마트 컨트랙트를 안전하게 사용할 수 있도록 만들기 위해 정적 및 동적 데이터 흐름 분석을 활용한 그레이 박스 퍼저인 SMARTIAN을 구현했습니다. 우리가 구현한 SMARTIAN은 다른 최신 툴과 비교해 더 나은 결과를 보여줬습니다. 앞서도 말씀드렸지만 이번 글을 읽으면서 SMARTIAN 연구에 관심이 생기셨다면 논문도 읽어보시고 GitHub도 방문해 보시기 바랍니다(이 연구가 의미있는 연구라고 생각되면 스타를 클릭해주세요 🙂). 이곳에서 벤치마크 결과도 확인하실 수 있습니다. 참고로 이 연구는 제가 석사 과정을 진행할 때 시작한 연구이기 때문에 모든 코드는 제가 있던 연구실에 공유됐습니다.

긴 글 읽어주셔서 감사합니다. 아래에서 발표 영상을 확인하실 수 있습니다.