Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

XZ Utils 백도어 사건으로 돌아보는 오픈소스 생태계

XZ Utils는 오픈소스 무손실 압축 라이브러리로 압축과 해제에 Lempel–Ziv–Markov chain 알고리즘(LZMA)을 사용하고 있다. 지난 3월 29일 XZ Utils에서 메인테이너가 백도어를 심는 충격적인 사건이 발생했다. 그래서 사건도 사건이지만 이 사건을 통해서 오픈 소스 생태계에 대해서 평소 생각하던 걸 좀 더 정리해 보게 되었다.

XZ Utils

일단 XZ Utils가 뭔지 찾아봤다. 의외로 Chromium 프로젝트에서 가장 자세한 히스토리 파일을 찾을 수 있었다.

2005년 Slackware라는 리눅스 배포판의 포크인 Tukaani 리눅스의 배포를 위한 그룹이라고 생각되는데 정작 Tukaani 리눅스는 나온 적은 없는 것 같다. 이 소규모 그룹의 목표는 리눅스 배포를 700MiB로 압축하는 것이었고 gzip 대신 LZMA가 압축률이 높아서 LZMA로 700MiB로 압축할 수 있게 된다. Slackware는 .tar.gz의 약어인 .tgz 파일로 배포하고 있었는데 LZMA를 쓴 경우에는 .tar.lzma의 약자로 .tlz를 사용하게 되었다.

Tukaani 프로젝트는 멈췄지만, LZMA Utils 개발은 계속 진행되었고 Slackware 기반 일부 배포판에서는 여전히 LZMA를 사용하고 있었다. 이 LZMA Utils에는 lzmash라는 쉘 스크립트와 lzmadec라는 디코더 CLI가 포함되어 있었는데 이는 Lasse Collin이라는 개발자가 작성했다. 개발이 진행되면서 새 포맷을 만들게 되었지만 만드는 데 시간이 꽤 걸리게 되어 기존 .lzma 파일 확장자를 쓸수 없게 되자 .xz 파일 확장자를 쓰기로 하고 2008년 12월에 드디어 릴리스 하게 된다.

새로운 LZMA Utils의 핵심은 liblzma 라이브러리였지만 프로젝트 이름을 LZMA Utuils에서 XZ Utils로 바꾸게 된다. XZ Utils는 압축률이 높았기 때문에 다양한 리눅스 배포판에 포함되기 시작하고 Fedora, Ubuntu, Debian, Red Hat, Kali Linux, OpenSUSE 등 우리가 볼 수 있는 대부분의 배포판에 포함되어 기본 유틸리티로 사용되게 된다.

이렇게 수많은 배포판에 기본 유틸리티로 쓰이는 압축 라이브러리가 되었지만, XZ Utils를 만든 Lasse Collin가 2007년부터 2022년까지 거의 혼자서만 이 프로젝트를 유지보수하는 상황이었다.

XZ Utils의 컨트리뷰션 그래프

이번 백도어 문제로 GitHub에서는 GitHub의 xz 저장소를 비활성화시켰고 지금은 아예 사라진 상태이다. xz의 원본 저장소는 GitHub이라기보다는 git.tukaani.org라고 할 수 있어서 여기서 커밋을 볼 수 있다. git.tukaani.org를 메인으로 쓰다가 몇 년 전부터 GitHub을 같이 이용한 것으로 보이는데 양방향 싱크를 한 것인지 GitHub으로 이사 갔다가 돌아온 것인지는 정확히 알 수가 없다.
GitHub에서 xz 저장소를 비활성화해서 지금은 GitHub에서 저장소를 직접 볼 수가 없어서 인터넷 아카이브에서 찾아볼 수밖에 없었다.

차단된 GitHub의 XZ 저장소

XZ Utils는 24년 1월 26일 기준으로 xz의 안정 버전은 5.4.6이었고 불안정 버전은 5.5.1이었다.

XZ Utils 백도어 취약점

이번 사건은 Andres Freund라는 개발자가 서버의 SSH 접속이 뭔가 느림을 발견하고 이를 추적하면서 XZ 최신 버전에 백도어가 숨겨져 있는 것을 발견하고 이를 openwall의 OSS-Security 메일링 리스트에 리포팅하면서 알려지게 된다. 이 Andres Freund가 올린 리포팅이 그냥 이상하다고만 올린 게 아니라 이상 현상부터 XZ가 원인이었고 여기에 백도어가 심겨 있었으며 XZ에 해당 백도어가 어떻게 들어왔는지까지 다 분석해서 올려서 이후에도 상황 업데이트가계속되지만, 첫 리포팅에서 대부분의 상황이 알려지게 된다.

이번 사건을 처음 알린 Andres Freund는 Microsoft의 Principle software engineer이면서 오랫동안 PostgreSQL에 기여한 커미터이기도 하다. 아래에서 anarazel가 Andres Freund다.

PostgreSQL의 Andres Freund 커밋 그래프

이번 공격은 간단히 정리하면 백도어를 여는 악성 코드를 테스트 쪽 코드인 척하고 넣어두고 빌드가 될 때 악성 코드가 tarball에 추가되는 구조로 되어 있고 glibc를 사용하는 amd64 리눅스에만 포함되도록 만들어졌다. Andres Freund의 말에 의하면 glibc와 amd64만 타게팅한 것은 백도어가 들키지 않게 하기 위함으로 추측하고 있다. 모든 시스템에 다 들어가면 들킬 확률도 높아지고 시스템마다 다르면 찾아내기도 더 어려워지니 가장 많은 glibc에 amd64만 목표로 한 것으로 보인다.이번 백도어는 sshd를 이용한 것으로 인증을 우회해서 서버에 접속할 수 있거나 원격 코드를 실행할 수 있을 것으로 보고 있다.

Evan Boehs라는 개발자가 정리한 Everything I Know About the XZ Backdoor에 이번 사건이 잘 정리되어 있다. 물론 수사가 이뤄진 것은 아니라 어느 정도 정황과 추측이 섞여 있지만 이 글에서 거의 대부분의 상황을 알 수 있다고 생각한다. 또한 FAQ on the xz-utils backdoor (CVE-2024-3094)도 참고하면 좋다.

이번 백도어 사건을 정리해 보면 다음과 같다.

  • 2021년 Jia Tan이라는 사람이 JiaT75라는 GtiHub 계정을 만들고 libarchive라는 저장소에 PR을 올린다.(여기도 의심할 필요 있음)
  • xz-utils의 메일링 리스트에 Jia Tan이 패치를 제출한다.(이때는 git.tukaani.org에서 메일로 패치를 받은듯하다..)
  • Jigar Kumar라는 사람이 나타나서 이 패치를 병합해야 한다고 압력을 가한다. 이 Jigar Kumar라는 사람은 누군지 모른다.
  • 이 Jigar Kumar는 Lasse Collin에게 혼자만 작업하니 다른 메인테이터가 필요하다고 압박을 가한다.
  • Dennis Ens라는 사람도 등장해서 같이 압박한다.(이 사람도 누군지 모른다.)
  • Jia Tan(JiaT75)은 xz에 커밋을 또 올리게 되고 이후 메인테이너가 된다.

    • 위의 컨트리뷰터 목록을 보아도 2022년부터 활발하게 기여한 걸 볼 수 있다.
    • 이시점 어느 정도부터 git.tukaani.org와 GitHub의 xz 저장소가 같이 올리게 된다.
  • 2023년이 되면서 Jia Tan(JiaT75)은 완전한 신뢰를 얻게 되고 3월에는 기본 연락처가 Lasse Collin에서 Jia Tan(JiaT75)으로 바뀐다.
  • Jia Tan(JiaT75)이 기존 tukaani.org/xz/로 되어있던 프로젝트 주소를 xz.tukaani.org/xz-utils로 바꾸고 이 주소는 핀란드의 어떤 서버에서 호스팅이 된다.
  • 프로젝트에 백도어를 심는 커밋을 추가하고 5.6.0을 릴리스한다. 의도적으로 모든 tarball에 백도어가 심은 것이 아니라 타게팅한 시스템의 tarball에만 심어졌다.
  • 이 백도어로 인해서 valgrind 에러가 발생하자 백도어는 남겨둔 채 이 에러를 우회한 5.6.1을 릴리스한다.

5.6.0은 2월 24일에 릴리스되고 5.6.1은 3월 9일에 릴리스된다. 5.6.0이 나온 지 한 달이 약간 넘은 상황이기 때문에 이 시점 이후에 xz를 설치하거나 최신 버전으로 업데이트한 경우에만 백도어가 포함된 버전이 설치되었을 것이고 그 이전 시스템은 괜찮은 상황이다. Ubuntu를 기준으로 하더라도 이번 4월에 나올 24.04에 xz 5.6.0이 포함되었다.

그러므로 이번 사건은 Andres Freund가 아주 빨리 발견했기 때문에 수많은 시스템이 취약점에 노출되기 전에 잡아낸 것이고 아마 조용히 많은 Linux 시스템이 이 버전으로 업데이트되기를 기다렸다가 뭔가 하려고 하지 않았을까 생각할 수 있다.

이 취약점은 CVE-2024-3094 할당받았고 가장 높은 심각도를 판정받았다. 처음 취약점이 공개되었을 때 상황 파악이 완전히 되지 않아서 Jia Tan 뿐 아니라 Lasse Collin의 깃헙 계정도 정지되었지만 지금은 다 풀린 상태이다.

Lasse Collin은 Tukanni 프로젝트에 이번 백도어 사건에 대한 공식 페이지를 만들고 홈페이지도 xz.tukaani.org를 차단하고 tukaani.org/xz/로 되돌리는 작업을 하고 있다. 아직도 이번 경위에 대해서 조사하고 있는 것으로 보고 이후 정리해서 깨끗한 XZ Utils 5.8.0을 릴리스 하겠다고 발표했다.

오픈소스 생태계의 상황

기존에도 공급망 공격(Supply Chain Attack)은 종종 있었다. 공급망 공격은 사람들이 신뢰하는 레지스트리를 다른 곳으로 속이거나 공급망을 해킹하는 등 다양한 방법을 통해서 할 수 있지만 이번 공격은 사회공학을 통했다는 점에서 다른 부분이 있고 많은 사람이 충격을 받았다.

그도 그럴 것이 앞의 커밋 그래프를 보면 Jia Tan이라는 사람 혹은 그룹은 이 백도어를 위해서 2년 가까이 XZ Utils에 커밋을 하면서 신뢰를 쌓았고 이 사건이 벌어지기 전까지 XZ Utils를 유지보수하면서 지탱한 것도 사실이다. 이번 사건이 발생했을 때 많은 사람이 "어떻게 리뷰를 통과하고 악성코드가 코드에 들어왔지?"라는 의문을 가졌지만, 메인테이너가 직접 넣은 코드였고 메인테이너가 단둘뿐이었기 때문이다.

이번 공격 자체도 충격적이지만 비슷한 일이 반복적으로 발생하는데 상황이 나아지진 않는다고 느끼고 있다. 이전에도 비슷한 사건이 있었다.

  • 2018년에는 Node.js의 event-stream를 이용한 공급망 공격이 있었다. 2011년에 event-stream을 만든 Dominic Tarr는 당시 npm에만 400여 개의 모듈을 가지고 있었고 더 이상 관리되지 않던 event-stream에 자신이 기여하겠다고 접근해서 저장소 권한과 모듈 배포 권한을 획득한 뒤 이 안에 악성코드를 심어서 배포했다.
  • 2024년에는 브라우저 간 동작 차이를 메꿔주는 polyfill.js를 편하게 사용하도록 polyfill.io라는 서비스가 Funnull이라는 회사에 넘어가게 되면서 최초에 polyfill.io를 만들었던 사람이 공급망 공격이 우려되니 즉시 사용을 중단하라고 경고했다.

polyfill.io는 약간 다른 부분이 있긴 하지만 event-stream을 포함해서 이번 사건도 오픈소스 메인테이너 부족이 근본적인 원인이 아닌가 하는 생각이 든다. 메인테이너가 10명, 20명이었다면 Jia Tan이 저렇게 메인테이너로 쉽게 들어오지도 못했을 것이고 들어왔어도 악성코드를 맘대로 커밋하지 못했을 것이다. 그렇게 보면 이런 문제 혹은 품질의 문제도 포함해서 근본적인 원인은 오픈소스 생태계의 메인테이너들이 처한 환경이 그리 좋지 않다는 데 있다고 생각한다.

xkcd에 Dependency라는 다음과 같은 만화가 있다.

xkcd의 Dependency

수많은 의존성을 가진 오픈소스를 사용하고 있지만 일반적으로 개발자가 직접 사용하는 유명한 프로젝트나 모던한 프로젝트에만 관심을 두지, 그 뒤에 있는 많은 프로젝트에는 관심을 가지지 않는다. 이번 XZ Utils와 마찬가지로 xkcd에서는 그중 어떤 의존성은 한 명의 메인테이너에게 완전히 의존하고 있어서 그 사람이 지치거나 더는 작업을 할 수 없게 되었을 때 전체 의존성이 깨질 수 있음을 지적한 것이다.

공급망 공격은 아니었지만 2014년 4월 OpenSSL에서 메모리에 저장된 정보를 빼갈 수 있는 Heartbleed라는 취약점이 발견되었다. 이때 취약점과 별개로 오픈소스 생태계는 이래서 믿을 수 없다거나 어떻게 이런 버그를 모를 수 있냐 하는 얘기도 있었지만, 전 세계에서 OpenSSL에 의존하지 않는 곳이 없다시피 하지만 실패로 펀딩을 제대로 받지 못하고 풀타임 직원이 1명뿐임이 밝혀졌다. 그리고 OpenSSL에 십여 년 동안 기여하던 사람들이 이때 펀딩이 들어오면서 처음 뒤셀도르프에서 오프라인으로 만날 수 있게 되었다는 얘기에 놀라기도 했다.(이때 이분들은 온라인으로만 서로 작업하다가 15년 만에 처음 만나게 되었다.)

이런 사건들을 보면 우리 생태계가 소수의 선의에 얼마나 기대어 있는가를 다시한번 생각하게 했다. 여기서 우리 생태계라고 한 것은 오픈소스 생태계뿐만 아니라 그 위에 쌓아 올린 수많은 IT 시스템도 마찬가지이기 때문이다. 비슷한 일로 수많은 웹사이트에서 polyfill 라이브러리를 사용하는 core-js의 메인테이너가 생활비조차 마련하지 못한 상황이 알려져서 아주 안타깝기도 했다. 이 글을 보고 이후에는 core-js에 소액을 기부하고 있다.

최근 Redis의 라이센스 변경 이슈를 포함해서 몇 년 전에 Elastic의 라이센스 변경에 관한 글도 썼고 비슷한 상황에서 다른 선택을 한 Grafana Labs에 대한 생각도 적었었다. 물론 큰 이슈이지만 기본적으로 회사이기도 하고 거대기업과의 이권이 달린 일이기에 주목을 훨씬 많이 받는다는 면에서 앞에서 얘기한 모던하거나 직접 사용하는 프로젝트에만 관심을 가지는 것과 크게 다르진 않다고 생각한다. 물론 이 부분도 클라우드의 발전과 이어지기 때문에 중요한 부분이고 관심을 가지고 고민해야 할 부분이라고 생각한다.

그럼에도 잊지 않아야 할 것은 기업이 운영하는 오픈소스 외에도 개인 메인테이너나 소수가 운영하는 수많은 오픈소스 프로젝트라는 큰 축이 오픈소스 생태계를 지지하고 있다는 점이다. 의존성까지 고려한다면 이러한 소수의 오픈소스 프로젝트들이 생태계를 지지하는 중심이라고 생각한다. 그런데도 수년이 지나도록 이러한 환경을 개선되지 않고 있다.

이번 XZ Utils 백도어 사건을 운 좋게 막은 것은 다행이지만 이번 일을 통해 오픈소스 생태계가 계속 유지될 수 있게 하는 방법을 고민하는 계기가 되었으면 하고 바라고 있다. 지금 상태로는 지속 가능하지 않아 보여서 걱정이 많다.

꽤 오랫동안 생각해 봤지만, 명확한 해결책은 잘 떠오르지 않는다.(그럴 일이라면 이미 해결되었겠지...) 사람마다 생각이 다르겠지만 나는 지금보다 오픈소스 생태계에 기부금의 규모가 훨씬 커져야 한다고 생각한다. 개인이나 회사나 결국 오픈소스 생태계에 기여하는 메인테이너들의 헌신과 선의에 기대서 많은 이득을 취하고 있는데(꼭 돈을 번다기보다 개발 속도나 안정성 등에서...) 그에 비해 다시 생태계에 내놓는 것은 너무 부족하다고 생각한다(물론 나도 포함이다). 어떻게 개인 메인테이너들에게 분배하고 어떻게 해야 공평하냐 같은 많은 문제가 있긴 하지만 지금의 펀딩 혹은 기부금의 액수가 10배, 100배 커진다면 어느 정도의 문제는 해소되지 않을까 생각한다. 물론 돈이 몰리면 그로 인한 문제도 발생하겠지만 그건 또 그때 해결하면 되고 첫 발걸음으로는 오픈소스 생태계의 들어가는 돈의 규모가 더 커져야 한다는 것이 요즘 내 생각이다.

2024/04/06 20:14 2024/04/06 20:14