c0mpos3r

[Knight Frontier] BoB 프로젝트 탐구 - DeFi Hacking - Smart Contract 취약점 분석 및 버그클래스 자동 분석 도구 제작 본문

TechDocs | Blog

[Knight Frontier] BoB 프로젝트 탐구 - DeFi Hacking - Smart Contract 취약점 분석 및 버그클래스 자동 분석 도구 제작

음대생 2025. 10. 16. 22:01

주제 선정 이유

블록체인은 불변성이 특징인데, 역설적으로 이게 가장 큰 문제다. 한번 배포된 스마트 컨트랙트는 수정이 거의 불가능하고, 취약점이 발견되면 수억 원의 자산이 순식간에 사라진다. 2022년 Ronin Network 해킹에서 6억 달러 이상이 증발한 사건이나, 최근까지도 계속되는 DeFi 프로토콜 공격들을 보면 이건 단순한 기술적 문제가 아니라 실제 사람들의 돈과 직결된 문제다.

 

더 흥미로운 건 대부분의 취약점이 새로운 게 아니라는 점이다. Reentrancy, Integer Overflow 같은 알려진 패턴들이 계속 반복된다. 이건 자동화로 충분히 막을 수 있다는 뜻이고, 동시에 개발자들이 보안에 대한 체계적인 접근을 하지 못하고 있다는 의미이기도 하다. 전공 수업에서 소프트웨어 보안을 배울 때 이론적으로만 이해했던 취약점들이 실제로 수조 원 규모의 피해를 만들어내는 걸 보면서, 보안이 선택이 아닌 필수라는 걸 절실히 느꼈다.

주제 관련 기반 지식

1. 스마트 컨트랙트와 EVM(Ethereum Virtual Machine)

스마트 컨트랙트는 블록체인 위에서 실행되는 프로그램으로, 특정 조건이 충족되면 자동으로 계약이 이행되는 자율 실행 코드다. 이더리움에서는 주로 Solidity 언어로 작성되며, 한 번 블록체인에 배포되면 코드 수정이 불가능하다는 특징을 가진다. 이러한 불변성은 신뢰를 보장하지만, 동시에 버그가 있을 경우 치명적인 결과를 초래한다.

 

EVM은 이더리움 네트워크의 분산 컴퓨팅 환경으로, 스택 기반의 가상 머신이다. 각 연산마다 가스(Gas)라는 비용이 책정되어 있으며, 이는 네트워크 과부하를 방지하고 무한 루프 같은 악의적 코드 실행을 막는다. EVM의 동작 방식을 이해하는 것이 스마트 컨트랙트 보안의 출발점이다.

  • 스택 기반 아키텍처: EVM은 256비트 워드를 사용하는 스택 머신으로 동작한다. PUSH, POP, ADD 같은 명령어들이 스택을 통해 데이터를 조작하며, 이 과정에서 오버플로우나 언더플로우가 발생할 수 있다.
  • 상태 저장 방식: 컨트랙트의 상태는 Key-Value 형태로 Storage에 저장되며, 각 슬롯은 32바이트를 차지한다. Storage 접근은 매우 비싸기 때문에(SSTORE 연산은 20,000 가스) 최적화가 중요하다.
  • 가스 메커니즘: 모든 연산에는 가스 비용이 있으며, 트랜잭션 실행 시 사용자가 설정한 가스 한도를 초과하면 실행이 중단되고 상태가 롤백된다. 이는 DoS 공격을 방지하지만, 가스 부족으로 인한 의도치 않은 실행 실패도 발생할 수 있다.

2. DeFi(탈중앙화 금융)의 구조와 작동 원리

DeFi는 중개자 없이 블록체인 상에서 금융 서비스를 제공하는 생태계다. 전통 금융은 은행, 증권사 같은 중앙화된 기관이 신뢰를 보증하지만, DeFi는 스마트 컨트랙트 코드 자체가 신뢰의 기반이 된다. 대출, 예금, 거래, 보험 등 거의 모든 금융 서비스가 코드로 구현된다.

 

DeFi의 핵심은 '컴포저빌리티(Composability)'다. 마치 레고 블록처럼 서로 다른 프로토콜들을 조합해 새로운 금융 상품을 만들 수 있다. 하지만 이는 양날의 검이다. 한 프로토콜의 취약점이 연결된 다른 프로토콜들로 전파될 수 있기 때문이다.

  • AMM(Automated Market Maker): Uniswap 같은 DEX에서 사용하는 방식으로, 유동성 풀(Liquidity Pool)을 통해 자동으로 가격을 결정한다. x * y = k 공식을 사용하며, 거래가 발생하면 풀의 비율이 변해 가격이 자동 조정된다.
  • 유동성 제공과 이자 농사: 사용자들이 자산을 풀에 예치하면 LP(Liquidity Provider) 토큰을 받고, 거래 수수료의 일부를 보상으로 받는다. 이를 다시 다른 프로토콜에 스테이킹해 추가 수익을 얻는 것을 Yield Farming이라 한다.
  • 담보 기반 대출: MakerDAO, Aave 같은 프로토콜에서는 암호화폐를 담보로 맡기고 스테이블코인이나 다른 자산을 빌릴 수 있다. 담보 비율이 일정 수준 이하로 떨어지면 청산(Liquidation)이 자동 실행된다.

3. 주요 스마트 컨트랙트 취약점 유형

스마트 컨트랙트 취약점은 크게 코드 레벨 버그와 로직 레벨 결함으로 나뉜다. 코드 레벨 버그는 프로그래밍 실수로 발생하며 정적 분석으로 탐지 가능한 경우가 많다. 반면 로직 레벨 결함은 비즈니스 로직 자체의 설계 오류로, 각 함수는 정상 작동하지만 조합했을 때 예상치 못한 결과가 나온다.

가. Reentrancy(재진입) 공격

Reentrancy는 스마트 컨트랙트 역사상 가장 악명 높은 취약점으로, 2016년 The DAO 해킹으로 5천만 달러 이상의 피해를 냈다. 외부 컨트랙트를 호출할 때 제어권이 넘어가는데, 그 사이에 상태가 업데이트되기 전이면 공격자가 같은 함수를 반복 호출할 수 있다.

  • Classic Reentrancy: 출금 함수에서 call.value() 로 이더를 전송한 후 잔액을 업데이트하는 순서 문제. 공격자는 fallback 함수에서 출금 함수를 재귀적으로 호출해 잔액이 차감되기 전에 여러 번 출금한다.
  • Cross-function Reentrancy: 서로 다른 함수 간의 재진입. 함수 A가 외부 호출 후 상태를 업데이트하는데, 그 사이에 공격자가 함수 B를 호출해 아직 업데이트되지 않은 상태를 악용한다.
  • Read-only Reentrancy: 상태를 변경하지 않고 읽기만 하는 함수도 위험할 수 있다. 외부 호출 중에 다른 컨트랙트가 일관성 없는 상태를 읽어 잘못된 결정을 내릴 수 있다.

나. Flash Loan 공격

Flash Loan은 DeFi만의 독특한 메커니즘으로, 담보 없이 대량의 자금을 빌렸다가 같은 트랜잭션 내에서 상환하는 방식이다. 상환하지 못하면 트랜잭션 전체가 롤백되므로 대출자 입장에서는 리스크가 없다. 하지만 공격자는 이를 이용해 순식간에 막대한 자본을 확보하고 시장 조작이나 프로토콜 악용을 시도한다.

  • 가격 Oracle 조작: 단일 DEX의 가격을 참조하는 프로토콜을 대상으로, Flash Loan으로 막대한 물량을 사서 가격을 인위적으로 올린 후 다른 프로토콜에서 그 왜곡된 가격으로 이득을 취한다.
  • 담보 조작 공격: 담보 자산의 가격을 Flash Loan으로 조작해 청산을 피하거나, 반대로 다른 사용자를 억지로 청산시켜 청산 보상을 가져간다.
  • Arbitrage Amplification: 여러 DEX 간 가격 차이를 이용한 차익거래를 Flash Loan으로 증폭시킨다. 개별 프로토콜은 정상이지만 조합하면 경제적 허점이 생긴다.

다. Oracle 조작 및 의존성 문제

Oracle은 블록체인 외부의 실세계 데이터를 스마트 컨트랙트에 제공하는 서비스다. 가격 정보, 날씨 데이터, 스포츠 경기 결과 등을 가져온다. 많은 DeFi 프로토콜이 자산 가격을 Oracle에 의존하는데, 이 Oracle이 신뢰할 수 없거나 조작 가능하면 전체 시스템이 위험해진다.

  • 단일 출처 의존: 하나의 DEX나 중앙화 거래소의 가격만 참조하면, 그곳의 가격 조작이 직접 프로토콜에 영향을 준다. Flash Loan으로 일시적으로 가격을 왜곡시킬 수 있다.
  • TWAP (Time-Weighted Average Price): 일정 기간의 평균 가격을 사용해 순간적 조작을 완화한다. 하지만 TWAP 기간이 짧으면 여전히 취약하고, 너무 길면 실시간성이 떨어진다.
  • Chainlink 같은 탈중앙화 Oracle: 여러 노드가 독립적으로 데이터를 수집하고 합의를 통해 최종 값을 결정한다. 단일 실패점을 제거하지만, 구현 비용이 높고 응답 속도가 느릴 수 있다.

라. Access Control 및 권한 관리 오류

스마트 컨트랙트에는 관리자만 호출해야 하는 민감한 함수들이 있다. 컨트랙트 업그레이드, 긴급 정지, 자금 인출 같은 기능이다. 이런 함수들의 접근 제어가 제대로 구현되지 않으면 아무나 호출해 전체 시스템을 장악할 수 있다.

  • Missing Modifier: Solidity의 onlyOwner 같은 modifier를 빼먹으면 누구나 관리자 함수를 호출할 수 있다. 간단한 실수지만 치명적인 결과를 낳는다.
  • Uninitialized Proxy: Proxy 패턴을 사용할 때 initialize 함수가 public이면, 공격자가 먼저 호출해 자신을 owner로 설정할 수 있다. 반드시 배포 직후 즉시 초기화해야 한다.
  • Signature Replay: 서명 기반 인증에서 nonce나 타임스탬프 검증이 없으면, 한 번 사용된 서명을 계속 재사용할 수 있다. EIP-712 표준을 따라 구조화된 서명을 사용해야 한다.

4. 스마트 컨트랙트 분석 기법

가. 정적 분석 (Static Analysis)

코드를 실행하지 않고 소스 코드나 바이트코드를 분석해 잠재적 취약점을 찾는 방법이다. 빠르고 비용이 적게 들지만, 실제 실행 흐름을 고려하지 못해 False Positive가 많을 수 있다.

  • AST(Abstract Syntax Tree) 분석: Solidity 컴파일러가 생성하는 추상 구문 트리를 파싱해 코드 패턴을 찾는다. 예를 들어 외부 호출 후 상태 변경 패턴을 찾아 Reentrancy 가능성을 탐지한다.
  • Dataflow Analysis: 변수의 값이 프로그램 내에서 어떻게 흐르는지 추적한다. 사용자 입력(tainted data)이 적절한 검증 없이 민감한 연산에 사용되는지 확인한다.
  • Control Flow Analysis: 프로그램의 실행 경로를 그래프로 표현하고, 모든 경로에서 불변 조건이 유지되는지 검증한다. 예를 들어 모든 분기에서 접근 제어가 확인되는지 체크한다.

나. 심볼릭 실행 (Symbolic Execution)

구체적인 값 대신 심볼릭 변수를 사용해 프로그램을 실행하고, 가능한 모든 실행 경로를 탐색하는 기법이다. 특정 조건을 만족하는 입력값을 찾아낼 수 있어, 개발자가 예상하지 못한 edge case를 발견하는 데 효과적이다.

  • 경로 제약 수집: 각 분기문마다 조건을 심볼릭 표현식으로 기록한다. 예를 들어 if (x > 10) 을 만나면 한 경로는 x > 10, 다른 경로는 x <= 10 제약을 갖는다.
  • SMT Solver 활용: Z3 같은 SMT(Satisfiability Modulo Theories) Solver를 사용해 제약 조건을 만족하는 구체적인 값을 찾는다. "잔액이 음수가 될 수 있는가?" 같은 질문에 답한다.
  • 경로 폭발 문제: 복잡한 프로그램은 가능한 경로가 지수적으로 증가해 분석 시간이 기하급수적으로 늘어난다. 휴리스틱을 사용해 중요한 경로 우선 탐색하거나, 일정 깊이 이상은 포기하는 전략이 필요하다.

다. 퍼징 (Fuzzing)

무작위 또는 변형된 입력을 계속 생성해서 프로그램에 주입하고, 비정상 동작이나 크래시를 관찰하는 기법이다. 스마트 컨트랙트에서는 함수 호출 시퀀스를 무작위로 생성해 불변 조건(invariant) 위반을 찾는다.

  • Property-based Testing: "컨트랙트의 총 잔액은 항상 개별 사용자 잔액의 합과 같아야 한다" 같은 불변 조건을 정의한다. Fuzzer가 이를 위반하는 입력 시퀀스를 찾으면 버그를 발견한 것이다.
  • Mutation-based Fuzzing: 정상적인 트랜잭션을 기반으로 값을 조금씩 변형시킨다. 예를 들어 금액을 0으로, 최댓값으로, 음수로 바꿔보거나, 주소를 zero address로 바꿔본다.
  • Coverage-guided Fuzzing: 코드 커버리지를 추적해 새로운 경로를 발견하는 입력에 더 높은 우선순위를 부여한다. AFL(American Fuzzy Lop) 같은 도구가 이 방식을 사용한다.

 

프로젝트 진행 과정 예상

이 프로젝트를 진행한다면 가장 먼저 실제 해킹 사례를 체계적으로 분석하는 것부터 시작할 것이다. The DAO, bZx, Cream Finance 같은 유명 사건들의 사후 분석 보고서(Post-mortem)를 읽고, 실제 취약한 코드를 직접 분석해본다. 각 사건에서 어떤 취약점이 어떻게 악용되었는지, 공격자의 트랜잭션을 Etherscan에서 추적하면서 공격 흐름을 재구성한다.

 

다음으로 버그 클래스 분류 체계를 만든다. OWASP나 SWC Registry를 참고하되, 실제 해킹 사례에서 반복적으로 나타나는 패턴을 중심으로 재분류한다. 단순히 "Reentrancy"로 묶지 않고 Classic, Cross-function, Read-only로 세분화하듯이, 각 취약점의 변종들을 구체적으로 정의한다.

 

분석 도구 개발 단계에서는 정적 분석을 중심으로 하고 필요시 Symbolic Execution이나 Fuzzing을 보조 수단으로 사용한다. Solidity AST를 파싱하는 라이브러리를 활용해 코드 패턴을 탐지하는 룰 엔진을 만든다. 

  1. 외부 호출(call, transfer) 탐지
  2. 그 이후에 상태 변경(SSTORE) 발생 확인
  3. ReentrancyGuard 같은 방어 메커니즘 존재 여부 체크
  4. 발견 시 경고 레벨 결정 (High/Medium/Low)

False Positive를 줄이기 위해 실제 취약한 컨트랙트와 안전한 컨트랙트로 구성된 테스트셋을 만들어 정확도를 측정한다. 도구가 놓친 취약점(False Negative)과 잘못 경고한 경우(False Positive)를 분석해 규칙을 계속 개선한다.

 

최종 결과물은 CLI 도구와 웹 UI를 모두 제공한다. 개발자가 배포 전에 로컬에서 빠르게 체크할 수 있도록 CLI를 만들고, 팀 차원에서 정기적으로 전체 코드베이스를 스캔할 수 있도록 CI/CD 통합도 지원한다. 리포트에는 발견된 취약점의 위치, 심각도, 공격 시나리오, 그리고 구체적인 수정 방법을 포함한다.

 

예상 시행착오

가장 큰 어려움은 False Positive와 False Negative의 균형을 맞추는 것일 것이다. 너무 엄격한 규칙은 안전한 코드도 위험하다고 판단해 개발자가 도구를 신뢰하지 않게 만든다. 반대로 너무 관대하면 실제 취약점을 놓쳐 심각한 사고로 이어질 수 있다. 특히 Solidity는 버전마다 특성이 달라서, 0.8.0 이전에는 필수였던 SafeMath가 그 이후는 불필요한 것처럼, 버전별 맥락을 이해해야 정확한 분석이 가능하다.

 

또한 복잡한 DeFi 로직의 경제적 취약점은 정적 분석으로 탐지하기 극도로 어렵다. 코드 자체는 완벽해도 여러 프로토콜을 조합했을 때 생기는 예상치 못한 인센티브 구조나, Flash Loan을 통한 원자적 공격 같은 건 사람의 경제학적 이해가 필요하다. 자동화 도구의 한계를 인정하고, "이 도구는 명백한 코드 버그를 잡는 것이고, 비즈니스 로직 검증은 여전히 사람의 몫"이라는 걸 명확히 해야 한다.

 

주제 조사 후 느낀 점

이 주제를 파면 팔수록 블록체인 보안은 단순히 버그를 찾는 게 아니라 경제학, 게임 이론, 암호학이 복합된 영역임을 깨달았다. 특히 인상 깊었던 건 많은 취약점이 기술적 복잡성보다 개발자의 안전하지 않은 가정에서 비롯된다는 점이다. "이 함수는 관리자만 호출할 것이다", "사용자는 합리적인 값만 입력할 것이다" 같은 암묵적 가정들이 공격자에게 악용된다.

 

제로 트러스트 원칙이 스마트 컨트랙트에서 얼마나 중요한지 체감했다. 아무것도 믿지 말고, 모든 입력을 검증하고, 모든 외부 호출을 의심하고, 최악의 시나리오를 가정해야 한다. 전통적인 개발은 "이게 잘못될 리 없어"라는 낙관에서 출발하지만, 블록체인 개발은 "이게 어떻게 악용될 수 있을까"라는 편집증에서 출발해야 한다.

 

또한 자동화 도구의 명확한 한계를 이해하게 되었다. 아무리 정교한 정적 분석도 비즈니스 로직의 경제적 결함은 찾아내지 못한다. 도구는 개발자를 돕는 보조 수단이지 대체재가 될 수 없다. 하지만 반복되는 단순 실수들을 자동으로 잡아줌으로써 개발자가 더 복잡한 문제에 집중할 수 있게 해준다는 점에서 가치가 크다.

 

https://scs.owasp.org/sctop10/

 

OWASP Smart Contract Top 10 - OWASP Smart Contract Security

OWASP Smart Contract Top 10 GitHub Repo OWASP Project Page The OWASP Smart Contract Top 10 is a standard awareness document that aims to provide Web3 developers and security teams with insights into the top 10 vulnerabilities found in smart contracts. Awar

scs.owasp.org

 

https://consensysdiligence.github.io/smart-contract-best-practices/attacks/reentrancy/

 

Reentrancy - Ethereum Smart Contract Best Practices

Reentrancy Tip Thank you for visiting the Smart Contract Security Best Practices. Please note that this resource is no longer actively maintained. Instead, we recommend visiting the Smart Contract Security Field Guide. The Field Guide is regularly updated

consensysdiligence.github.io

 

https://swcregistry.io/

 

Smart Contract Weakness Classification (SWC)

Please note, this content is no longer actively maintained. The content of the SWC registry has not been thoroughly updated since 2020. It is known to be incomplete and may contain errors as well as crucial omissions. For currently maintained guidance on k

swcregistry.io