본문으로 건너뛰기
피드

Lean이 '이 프로그램은 안전하다'고 증명했는데, 런타임에서 버그가 나왔다

security 약 6분
vote
0
댓글
북마크

형식 검증 언어 Lean 4의 런타임에서 힙 버퍼 오버플로우가 발견됐다. lean_alloc_sarray 함수에서 정수 오버플로우가 발생해 156바이트짜리 조작된 ZIP 파일로 트리거 가능하며, lean-zip에서도 별도의 DoS 취약점이 확인됐다.

  • 1

    lean_alloc_sarray에서 capacity가 SIZE_MAX에 가까우면 24+n이 정수 오버플로우 → 23바이트만 할당하고 SIZE_MAX 바이트를 읽음

  • 2

    156바이트 조작 ZIP 파일(ZIP64 compressedSize=0xFFFFFFFFFFFFFFFF)로 트리거 가능

  • 3

    Lean 4 v4.31.0-nightly까지 모든 버전 영향

  • 4

    lean-zip의 readExact도 compressedSize 미검증으로 OOM DoS 가능

  • 형식 검증 언어 Lean 4의 런타임 C 코드에서 힙 버퍼 오버플로우가 발견됨
    • 아이러니하게도 Lean은 "이 프로그램이 정확하다"를 수학적으로 증명하는 언어인데, 정작 자기 런타임이 고전적인 C 버그를 갖고 있었음
  • 취약 함수: lean_alloc_sarray
    • ByteArray capacity n에 대해 할당 크기가 24 + n으로 계산됨
    • nSIZE_MAX(2^64 - 1)에 가까우면 24 + n이 정수 오버플로우로 랩어라운드 → 23바이트짜리 버퍼만 할당
    • 호출자는 그 버퍼에 SIZE_MAX 바이트를 읽어들임 → 힙 버퍼 오버플로우
  • 트리거 방법
    • 156바이트짜리 조작된 ZIP 파일 하나면 충분함
    • ZIP64 compressedSize0xFFFFFFFFFFFFFFFF로 세팅
    • IO.FS.Handle.read가 내부적으로 lean_io_prim_handle_readlean_alloc_sarray를 호출하면서 오버플로우 발생
  • 5줄짜리 최소 재현 코드가 공개됨
    def main : IO Unit := do
      IO.FS.writeFile "test.bin" "hello"
      let h ← IO.FS.Handle.mk "test.bin" .read
      let n : USize := (0 : USize) - (1 : USize) -- SIZE_MAX
      let _ ← h.read n -- lean_alloc_sarray에서 오버플로우
  • lean_io_get_random_bytes에서도 동일한 패턴 존재함
  • 영향 범위: Lean 4 전 버전, v4.31.0-nightly-2026-04-11까지
  • 수정 PR이 제출된 상태임

⚠️주의

> 이 버그는 Lean 언어로 작성된 사용자 코드의 문제가 아님. Lean의 런타임 자체(C로 작성된 메모리 할당 레이어)에서 발생하는 정수 오버플로우임. 형식 검증이 커버하는 순수 함수형 레이어와는 별개의 영역이라 증명으로 잡을 수 없었음.

  • lean-zip에서도 별도의 DoS 취약점 발견
    • readExact 함수가 ZIP 헤더의 compressedSize를 검증 없이 h.read에 그대로 전달함
    • 수 엑사바이트를 주장하는 ZIP 파일을 열면 OOM 패닉 발생
    • 시스템 unzip은 헤더 크기를 실제 파일 크기와 대조하는데, lean-zip은 안 함

기술 맥락

  • 왜 형식 검증 언어에서 이런 버그가 나올 수 있냐면, Lean 4의 증명이 커버하는 범위를 생각해 봐야 해요
    • Lean이 증명하는 건 순수 함수형 레이어에서의 정확성이에요. "이 함수는 이런 입력에 대해 이런 출력을 보장한다" 같은 명제를 수학적으로 증명하는 거죠
    • 그런데 실제 실행은 C로 작성된 런타임이 담당하거든요. lean_alloc_sarray 같은 메모리 할당 함수는 그 증명 범위 밖이에요
  • 정수 오버플로우의 메커니즘을 좀 더 자세히 보면요
    • 64비트 시스템에서 size_t는 최대 2^64 - 1까지 표현해요
    • sizeof(lean_sarray_object)가 24바이트이고, 여기에 capacity를 더하는데요
    • capacitySIZE_MAX(= 2^64 - 1)이면 24 + (2^64 - 1) = 23이 돼요 (모듈러 연산)
    • 결과적으로 23바이트만 malloc하고, fread에는 SIZE_MAX를 넘기는 거예요
  • ZIP64 포맷을 이용한 트리거가 영리한 게, ZIP64 확장 필드는 compressedSize를 64비트로 표현할 수 있어서 0xFFFFFFFFFFFFFFFF를 합법적인 ZIP 구조 안에 넣을 수 있거든요
    • 실제 파일은 156바이트밖에 안 되지만, 헤더가 "이 엔트리의 압축 크기는 18 엑사바이트"라고 주장하는 거예요
  • 이 사례가 보안 커뮤니티에서 주목받는 이유는, 형식 검증의 한계를 구체적으로 보여주기 때문이에요
    • 증명은 모델 안에서만 유효하고, 모델 바깥의 구현(FFI, 런타임, OS 인터페이스)은 별도로 검증해야 한다는 교훈이에요

형식 검증이 증명하는 건 '명세 안에서의 정확성'이지, 런타임 C 코드의 안전성까지 보장하지 않는다는 것을 보여주는 사례다.

댓글

댓글

댓글을 불러오는 중...

security

엘에이 경찰, 사생활 침해 논란 끝에 플록 번호판 감시 계약 종료

엘에이 경찰이 번호판 인식 카메라 업체 플록 세이프티와의 3년 계약을 연장하지 않기로 했어. 시민권, 프라이버시, 데이터 보관과 공유 문제를 해결하지 못했다는 게 핵심 이유야. 플록은 미국 전역에 최소 8만 대 카메라망을 깔아 경찰과 연방기관이 차량을 추적할 수 있게 해왔고, 오탐·보안 사고·이민 단속 악용 의혹까지 겹치며 압박이 커졌어.

security

크로미움 148부터 Math.tanh 한 번으로 운영체제 지문이 새는 문제

크로미움 148 이후 V8이 Math.tanh 계산을 자체 구현 대신 운영체제의 수학 라이브러리에 맡기면서, 같은 입력값도 리눅스·맥·윈도우에서 마지막 비트가 달라지는 지문 신호가 생겼다. 이 차이는 User-Agent로 맥이라고 주장하면서 리눅스 수학 결과를 내는 식의 위장을 바로 들키게 만든다. CSS 삼각함수와 웹 오디오까지 보면 브라우저 수학 경로가 꽤 복잡하게 갈라지고, 제대로 흉내 내려면 실제 운영체제 라이브러리의 비트 단위 동작까지 맞춰야 한다.

security

출입통제도 클라우드 구독제로 간다…제로트러스트·AI 분석이 승부처

기업 출입보안이 사업장별 서버를 두는 방식에서 클라우드 기반 서비스형 출입통제(ACaaS)로 옮겨가고 있다. 시장은 2026년 17억8000만 달러에서 2030년 31억9000만 달러로 커질 전망이고, 제로트러스트·모바일 인증·AI 출입 분석·스마트빌딩 통합이 핵심 경쟁 포인트로 꼽힌다.

security

AWS·구글 클라우드, 양자컴퓨터 대비해 암호 체계 갈아엎는 중

AWS와 구글 클라우드가 양자컴퓨터 시대를 대비해 기존 공개키 암호와 양자내성암호를 함께 쓰는 하이브리드 전환을 시작했다. 핵심 배경은 지금 훔친 암호문을 나중에 양자컴퓨터로 푸는 ‘선수집·후해독’ 공격이고, 국내도 통신·금융·국방 등 5개 분야에 45억원을 투입해 실증에 들어간다.

security

보안 점검 맡긴 AI 에이전트가 악성코드를 직접 실행할 수 있다는 경고

AI 보안 에이전트가 저장소를 검사하다가 README 같은 문서에 숨은 프롬프트 인젝션에 속아 악성 바이너리를 실행할 수 있다는 연구가 나왔다. 클로드 코드와 코덱스의 자동 모드처럼 승인 없이 명령을 수행하는 구성에서 문제가 재현됐고, 여러 모델과 공급업체를 가로질러 같은 패턴이 통했다는 점이 핵심이다.