보안정보
전문화된 보안 관련 자료, 보안 트렌드를 엿볼 수 있는
차세대 통합보안관리 기업 이글루코퍼레이션 보안정보입니다.
데이터 압축 라이브러리 XZ Utils CVE-2024-3094 분석 및 대응방안
2024.06.04
2,308

01. 개요
2024년 3월 29일, Microsoft 보안연구원 안드레스 프런드(Andres Freund)는 GNU/리눅스에서 사용되는 데이터 압축 라이브러리인 ‘XZ Utils’에 백도어가 있다는 사실을 보고하였다. XZ Utils 5.6.0 및 5.6.1버전에서 발견된 백도어는 지아 탄(Jia Tan(계정 : JiaT75))유저가 XZ Utils을 관리하는 깃허브(GitHub)의 투카니 프로젝트(Tukaani Project)에 삽입한 것으로 CVE-2024-3094(CVSS 10.0)라고 명명되었다. 현재는 Tukaani Project에서 5.6.0 및 5.6.1버전은 삭제되고 비활성화되었으나, XZ Utils의 단일 관리자인 라세 콜린(Lasse Collin)은 본인의 홈페이지를 통해서 추후 XZ Utils 5.8.0 버전으로 업그레이드 할 것임을 알렸다.
CVE-2024-3094를 소프트웨어 공급망 공격이라고 부르는 이유는 백도어가 설치된 XZ 5.6.0과 5.6.1 버전이 자체적인 취약점이 아니라는 점이다. Jia Tan(JiaT75) 유저는 XZ Utils의 단일 관리자인 Lasse Collin 과 2022년부터 2년여간의 시간 동안 신뢰를 쌓아 프로젝트 관리 권한의 일부를 위임받았기 때문이다.
백도어가 설치된 XZ 5.6.0 및 5.6.1 버전으로 영향을 받은 리눅스 환경은 최신 버전의 리눅스 버전에서 주로 발생되었다. 일반적으로 리눅스 배포 버전은 신규 기능이 포함된 개발 및 테스트 버전인 최신 버전과 안전성이 검증된 안정화 버전으로 분류해서 배포하게 된다.
추후에 설명하게 될 백도어 동작을 위해서 반드시 필요한 sshd의 libsystemd가 최신 버전에서만 의존성(Dependency)관계에 있기 때문에 취약점의 영향이 되었다. 일반적인 배포 버전에서는 리눅스에서 제공되는 OpenSSH에 경우 해당 의존성이 존재하지 않아서 취약점의 영향을 받지 않게 되는 것이다.
따라서 빠른 시일내에 백도어가 포함되어 있는 XZ Utils 5.6.0 및 5.6.1의 사용여부를 확인 후 제거하거나, 안정화 버전인 5.8.0버전 출시 이전까지는 5.4.6으로 다운그레이드가 필요하다. 본 문서에서는 리눅스 생태계의 보안에 영향을 미치고 있는 XZ Utils 백도어 사건을 유발하는 CVE-2024-3094의 공격방식과 백도어에 대한 분석을 통해 취약점의 영향도와 대응방안을 알아보고자 한다.
02. CVE-2024-3094 취약점 영향받는 버전
1) 취약한 버전 확인 방법
CVE-2024-3094로 영향받는 XZ Utils 버전을 확인하기에 앞서 취약점에 영향받기 위해서는 2가지 조건을 충족해야 한다. 2가지 충족한 경우에는 [표 1]의 점검 방법을 이용하여 취약한 버전인지 확인하면 된다.
① bc(IFUNC의 경우)를 사용하는 배포판을 사용
② xz 또는 liblzma 버전 5.6.0 또는 5.6.1이 설치(xz-utils는 liblzma 라이브러리를 제공)

Alpine Linux (edge branch)에서는 취약점을 조치한 버전인 5.6.1.-r2 버전이더라도 ‘xz --version’의 실행 결과가 5.6.1로 출력되기 때문에 ‘apk list xz’명령어로 확인이 필요하다.

2) 취약점에 영향 받는 운영체제 및 버전
취약점에 영향받는 버전을 확인했다면 [표 2]를 참고하여 운영 중인 OS가 취약점에 영향을 받는지 확인해 볼 수 있다. 안정화 버전 보다 개발이나 테스트 버전에서 주로 영향이 있었으며 환경 별 상세 버전 확인이 필요하다면 다음 링크(https://repology.org/project/xz/versions)를 참조하면 된다.

[표 3] 은 CVE-2024-3094 취약점에 영향받지 않는 OS로써 마이그레이션 전에 제거 등으로 영향을 받지 않는 것이므로 만약, 해당 운영체제에서 취약한 버전에 XZ 및 liblzma가 운영 중에 있다면 영향받지 않는 버전으로 다운그레이드 할 것을 권고한다.

03. 취약점 타임라인
‘XZ Utils’ 5.6.0 및 5.6.1에 백도어 악성코드를 삽입한 Jia Tan(JiaT75)은 Tukaani Project 관리자 권한을 획득하기 위해 XZ Utils 단일 관리자인 Lasse Collin과 신뢰를 쌓아갔다. Jia Tan(JiaT75)은 Tukaani Project은 XZ Utils 이외에도 다수의 프로젝트에 코드를 Commit 하면서 오픈소스 기여도를 증명하기도 했다. 이러한 신뢰관계를 토대로 단독 유지 관리 담당자인 Lasse Collins와 함께 프로젝트를 수행하게 됐고 버그 보고 이메일(xz@tukaani.org) 또한 Jia Tan에게도 리디렉션 되도록 변경되어 취약점과 관련한 보고 내용을 모니터링할 수 있게 되었다.
백도어 발견 이후 Lasse Collin 은 Jia Tan 을 xz@takaani.org 메일링에서 제외했고 DNS name(CNAME)에서 xz.tukaani.org를 제외했음을 알렸으며, 이후 업데이트 버전은 5.8.0 대로 점프하여 릴리즈 할 것임을 발표하였다.
1) 2021년 활동 내역
Jia Tan(JiaT75)는 2021년 GitHub에 최초로 계정을 생성한 후 546개의 커밋을 완료하여 여러 프로젝트에 기여하기 시작했는데, 그중 가장 의심스러운 커밋은 libarchive에 생성한 이력이 있다.
(출처: https://github.com/libarchive/libarchive/pull/1609)

2) 2022년 활동 내역
2022년 2월 6일 JiaT75가 XZ 저장소에 첫 번째로 LZMA 및 LZMA2 인코더에 인수 유효성 검사를 추가하는 기능이 내재된 Commit을 제출했다.
(출처 : https://git.tukaani.org/?p=xz.git;a=commitdiff;h=6468f7e41a8e9c611e4ba8d34e2175c5dacdbeb4)

2022년 5월 19일 데니스 엔스(Dennis Ens)는 XZ 업데이트 진행 계획을 문의했고 6월 7일 지가 쿠마르(Jigar Kumar)가 관리자에 관리 부재로 XZ 업데이트는 더 이상 없을 것이라 답변했으나 6월 8일 XZ Utils 관리자 Lasse Collin 은 흥미가 없어진 것은 아니며 앞으로 Jia Tan(JiaT75)과 함께 프로젝트를 수행할 것임과 그가 미래에 큰 역할을 수행할 것이라 해명했다. 이것으로 보아 Jia Tan과 관리자에 신뢰 관계가 형성된 것을 알 수 있다.
(출처: https://www.mail-archive.com/xz-devel@tukaani.org/msg00567.html)

2022년 11월 30일 XZ Utils의 창시자이자 단독 유지 관리 담당자인 Lasse Collins는 버그 보고 이메일을 자신과 Jia Tan에게 리디렉션하는 별칭으로 변경했다.
(출처: https://git.tukaani.org/?p=xz.git;a=commitdiff;h=764955e2d4f2a5e8d6d6fec63af694f799e050e7)

3) 2023년 활동 내역
2023년 1월 11일 XZ Utils의 관리자인 Lasse Collins가 최종 버전인 5.4.1을 출시했다.
(출처: https://git.tukaani.org/?p=xz.git;a=commitdiff;h=18b845e69752c975dfeda418ec00eda22605c2ee)

2023년 3월 18일 프로젝트를 공통으로 수행하게 된 Jia Tan이 첫 번째 릴리스인 5.4.2를 빌드하고 출시했다.
(출처: https://git.tukaani.org/?p=xz.git;a=commitdiff;h=6ca8046ecbc7a1c81ee08f544bfd1414819fb2e8)

2023년 6월 27~28일에는 XZ Utils에 일련의 변경 사항이 적용되어 공격의 기반이 마련되면서 crc64_fast.c에 대한 ifunc 구현에 대한 지원이 추가됐다. 이 패치는 패키지의 원래 관리자인 Lasse Collin이 도입했으며, Lasse Collin은 이 패치의 또 다른 기여자 Hans Jansen의 이름이 명시되어 있다. 해당 취약점을 최초 발표한 Andres Freund에 따르면 이 ifunc 구현은 아마도 백도어가 작동하는 것으로 보이는 방식 중 하나일 것으로 판단했다.
(출처: https://git.tukaani.org/?p=xz.git&a=search&h=HEAD&st=commit&s=ifunc)

2023년 7월 8일 JiaT75는 XZ 및 기타 여러 OSS 프로젝트에서 퍼지 테스트를 수행하는 프로젝트인 oss-fuzz에서 풀 요청을 열었다. 이 PR은 ifunc 퍼징을 비활성화하여 oss-fuzz가 XZ에서 수행된 악의적인 변경을 찾지 못하도록 하게 위함으로 보고 있다.
(출처: https://github.com/google/oss-fuzz/pull/10667)

4) 2024년 활동 내역
2024년 2월 15일 JiaT75는 .gitignore 파일을 통해 XZ 저장소의 build-to-host.m4에 대한 무시 규칙을 추가했다. 실제 릴리스 번들에 포함될 이 스크립트 파일은 시스템 간의 호환성 검사를 수행하는 정상 파일이지만 패키지 빌드 중에 실행되어 피해자 컴퓨터에서 백도어를 설치하는 악성 M4 매크로 파일로 일부 코드를 변경했다.
(출처: https://git.tukaani.org/?p=xz.git;a=commit;h=4323bc3e0c1e1d2037d5e670a3bf6633e8a3031e)

2024년 2월 23일 JiaT75는 XZ 저장소 두 테스트 파일에 난독화된 바이너리 백도어를 추가했다.
(출처: https://fossies.org/linux/xz/ChangeLog)


2024년 2월 24일 JiaT75는 악성 build-to-host.m4가 포함된 버전 5.6.0을 배포하고 이 단계에서는 악성 페이로드가 완전히 작동했으며 모든 후속 XZ 버전이 손상됐다.
(출처: https://src.fedoraproject.org/rpms/xz/c/de73aff0c7dc3a64f7a15c65c431cd73e96a3b9b?branch=main)

2024년 3월 9일 JiaT75는 백도어 바이너리를 향상된 버전으로 업데이트하고 버전 5.6.1을 배포했다.

2024년 3월 29일 XZ 유틸리티에서 발견된 악성 활동에 대한 자세한 설명이 Andres Freund의 oss-security 메일링 리스트에 게시됐다.
(출처 : https://www.openwall.com/lists/oss-security/2024/03/29/4)

2024년 3월 30일 관리자인 Lasse Collin은 프로젝트 위반에 관해 공식 발표했다. tukaani.org 메인 웹사이트와 git.tukaani.org 레포지토리 그리고 해당 관련 파일들은 본인(Lasse Collin)만 접근 가능하며 Jia Tan은 xz.tukaani.org 하위 도메인을 포함한 GitHub에서 호스팅 되는 항목에만 접근 가능했음을 알렸다. 또한 Jia Tan을 xz@takaani.org 메일링에서 제외했고 DNS name(CNAME)에서 xz.tukaani.org를 제거했음을 알렸으며, 이후 업데이트 버전은 5.8.0 대로 점프하여 릴리즈 할 것 임을 알렸다.
(출처 : https://tukaani.org/xz-backdoor/)
2024년 4월 9일 XZ 관리자인 Lasse Collin은 Github에서 XZ-Utils 레포지토리가 복구되었음을 발표하였다.
(출처 : https://tukaani.org/xz-backdoor/)
04. 취약점 상세 분석

취약점 상세 분석에 앞서 XZ Utils 5.6.0 및 5.6.1버전에서 발생하는 CVE-2024-3094는 xz의 업스트림 타르볼(upstream tarballs)에서 발견됐다.

위의 악성 데이터 2종에 시작점인 build-to-host.m4는 시스템 간 호환성 검사를 담당하는 정상 파일로 5.6.0 및 5.6.1에서 추가된 파일이었으나 JiaT75에 의해 일부 코드가 악성 행위를 수행하도록 변경됐다.

취약점 진행 부분은 세 단계로 나뉘며 각 단계를 Stage0부터 Stage2까지 나눈다. 다음 장에서 진행될 코드 분석에 경우 XZ-Utils 취약 버전 중 5.6.1의 소스코드이며 전체 소스코드 중 주요 구문에 대한 분석을 진행했다.

1) Stage 0 : m4/build-to-host.m4
‘m4/build-to-host.m4’ 파일은 악성 행위에 시작이 되는 파일로써 Stage 1로 진행하기 위한 파일 추출 및 실행을 담당한다. [그림 17]에서 Stage 1 실행 구문인 Line 78이 진행되기 위해 gl_[$1]_config 를 설정하게 되는데 이는 Line 63에서 설정하게 된다. Line 63은 Line 86의 변수 gl_am_configmake 값에 설정된 악성 파일인 tests/files/bad-3-corrupt_lzma2.xz의 경로와 Line 95의 gl_path_map에 설정된 문자 변환 tr 명령어, Line 40에서 설정된 악성파일의 확장자(xz) 값이 저장된다.
이를 정리하면 gl_[$1]_config 는 sed \“r\n” tests/files/bad-3-corrupt_lzma2.xz | tr “\t -_” “ \t_-” | xz -d 2> / dev / null’으로 설정되며, 문자 변환 tr 명령어로 인해 \t(0x09)는 공백(0x20), 공백(0x20)은 \t(0x09)로 교체, -(0x2d)는 (0x5f), (0x5f)는 -(0x2d)로 교체 되고 이 데이터가 압축 해제 되어 실행 됨을 알 수 있다.

2) Stage 1 : bad-3-corrupt_lzma2.xz
Stage1은 Linux 실행환경을 체크하고 데이터를 병합하여 Stage2에 필요한 스크립트 추출 및 실행을 진행하게 된다. [그림 18]에서 Line 3~7은 스크립트 실행 시 실행환경이 Linux인지 확인하는 부분이며 Linux가 아닐 경우 스크립트를 종료한다.
구동 환경이 Linux라면 스크립트가 실행되며 주요 실행 부분은 Line 13으로 head 명령어를 통해 특정 범위의 데이터를 추출하는데 이때, 1024바이트를 무시하고 2048 바이트를 출력하는 과정을 반복 진행함으로써 데이터를 병합하는 과정을 진행한다.
이후 병합 된 데이터를 tail 명령어를 통해 데이터 영역 중 31233 바이트 이후 부분을 출력하게 되며 문자 변환 명령어인 tr을 통해 데이터 변환 작업을 시작한다. 변환 작업이 완료되면 good-large_compressed.lzma 파일이 압축 해제되고 Stage2를 진행하기 위한 스크립트가 실행된다.

3) Stage 2 : good-large_compressed.lzma
Stage 2는 빌드 환경 검사 및 데이터 복호화를 통해 최종 악성 파일인 liblzma_la-crc64-fast.o를 생성한다. 먼저 [그림 19]처럼 스크립트가 진행되면서 최종적으로 실행될 백도어가 정상적으로 동작할 수 있도록 빌드 환경을 체크하게 된다. 대상 OS x86_64 여부와 RSA_public_decrypt 함수의 GOT(Global Offset Table)를 후킹 하기 위한 IFUNC 활성화 여부 등 필요 사항을 확인하게 되며 이상이 있을 경우 스크립트를 종료하게 된다.

빌드 환경 및 IFUNC 활성 여부 등에 특이사항이 없다면 [그림 20] Line 209에서 xz 도구를 통해 good-large_compressed.lzma 압축을 해제하게 되는데 해당 파일은 커스텀 된 RC4 암호화 알고리즘으로 난독화되어 있어 awk 명령어를 통해 복호화 구문을 실행하게 된다. 복호화가 완료될 경우 압축이 해제되며 악성 데이터가 저장된 오브젝트 파일인 ‘liblzma_la-crc64-fast.o’가 생성된다.


빌드 과정에서 Stage 2 완료 후 최종적으로 생성된 liblzma_la-crc64-fast.o 파일은 동적 링킹을 위해 공유 라이브러리 파일인 so 파일을 메모리에 상주시키게 되는데 이 so 파일을 분석해 보면 ifunc resolver에서 호출되는 __get_cpuid에 RSA_public_decrypt 함수의 GOT(Global Offset Table)를 수정하는 코드를 삽입하기 위해 CPUID를 호출하는 부분을 확인할 수 있다. 백도어는 이 과정을 진행하기 위해 IFUNC 활성화 여부를 확인하는 것이다.

이때 so 파일은 실행되는 오브젝트 파일(liblzma_la-crc32-fast.o, liblzma_la-crc64-fast.o)에 따라 lzma_crc32 와 lzma_crc64로 구분하게 되는데 모두 __get_cpuid를 호출하는 것은 동일하나 실제 악성 행위가 수행되는 lzma_crc64의 ifunc resolver 가 __get_cpuid를 호출할 때는 변숫값을 1로 설정하여 백도어 초기화 코드에 진입할 수 있도록 하고 lzma_crc32일 경우에는 변숫값을 증가시켜 백도어 초기화 코드에 진입하지 않도록 한다.

백도어 초기화 코드는 GOT(Global Offset Table)를 수정하기 위해 먼저 하드코딩된 GOT 주소를 찾고 이 정보를 통해 내부 CPUID 포인터를 찾는다. 이후 백도어는 해당 포인터를 GOT를 수정하는 코드로 변경하고 정상적인 CPUID를 호출하는 것처럼 호출하게 된다.

백도어가 호출하는 주요 함수는 [표 7]과 같다. 이는 RSA_public_decrypt 함수의 GOT를 수정하여 서명 검증 및 페이로드 해독을 할 수 있는 공격자의 ED448 공개키를 하드코딩하는데 전송된 서명을 해당 공개키와 대응되는 비밀키로 검증하여 임의의 명령어 수행을 가능하게 하기 위함이다. 그리고 RSA_public_decrypt 함수 호출이 불가할 경우 EVP_PKEY_set1_RSA, RSA_get0_key 함수를 차례로 호출하여 GOT 수정을 시도하게 된다.

06. CVE-2024-3094 취약점 공격 시연
취약점 시연은 백도어 동작 방식을 확인하기 위해 진행했으며 취약한 버전에 XZ-Utils를 강제 설치하여 진행했다.

시연을 위해 취약한 서버 환경을 구축 후 취약 버전인 xz-utils 설치한 후 liblzma.so.5.6.1 파일을 확인한다.

백도어 실행을 위해 악성 파일의 행위를 가장하여 ED448 공개키로 대체하는 코드가 저장된 파일을 통해 liblzma 파일을 변조한다. ED448 공개키의 경우 처음 32 바이트를 Chacha20 암호화 알고리즘에 복호화 키로 사용하여 악성 행위를 해독할 수 있게 한다.
※ 백도어 행위는 sshd의 libsystemd 의존성 때문에 발생하는데 OpenSSH는 일반적으로 liblzma를 로드하지 않지만 일부 배포판에서는 systemd 알림을 지원하기 위해 libsystemd를 로드하게 되고 이로 인해 liblzma 파일이 필요하게 된다. 공격자는 이점을 악용하기 위해 liblzma 파일을 변조하게 된다.


파일 변경 후 공격 서버에서 피해 서버에 SSH 연결 후 계정 목록을 저장하는 명령어를 실행한다.

피해 서버 확인 결과 해당 공격자의 명령어가 실행되어 계정 목록이 저장된 파일이 생성됐음을 확인할 수 있다.

07. 마무리
지금까지 리눅스 데이터 압축 라이브러리 XZ Utils에서 발견된 백도어 CVE-2024-3094 취약점에 대해서 알아보았다. 해당 취약점은 오픈소스인 XZ Utils를 이용한 공급망 공격으로 대규모 보안 사고를 야기할 소지가 있었으나, 다행히 초기에 발견되면서 실제 피해 사례는 확인되지 않고 있다. 다만 XZ Utils 외에도 다수의 오픈소스 프로젝트들이 존재하는 만큼 지금도 XZ Utils 백도어 사태와 같은 보안 위협이 존재하는지 알 수 없는 일이다.
이와 같은 보안 위협을 대비하기 위해서는 [표 8]과 [표 59]의 YARA정보를 토대로 CVE-2024-3094 탐지 정책을 적용해야 한다. 서비스 영향도 등으로 인해 XZ Utils의 삭제 및 다운로드를 할 수 있는 상황이 아니라면 해당 탐지 정책을 통해 임시적으로 CVE-2024-3094를 대응하는 데 도움이 될 것이다.
현재도 다수의 조직에서 오픈소스를 활용하고 있다. 따라서 조직 내에서 운영 중인 오픈소스로 인한 공급망 공격에 대한 다양한 대응 방안을 모색해야 한다. 최근 소프트웨어의 연쇄적인 보안 이슈를 대응하기 위한 방안으로 소프트웨어가 제작되는 모든 구성 요소 및 공급자, 종속성 관계 등을 정의하는 SBOM(Software Bill of Materials) 도입이나 취약한 버전의 오픈소스 버전 사용 여부 검증 등도 좋은 대안이 될 수 있으리라 본다.


08. 참고자료
1.Reported Supply Chain Compromise Affecting XZ Utils Data Compression Library, CVE-2024-3094 : https://www.cisa.gov/news-events/alerts/2024/03/29/reported-supply-chain-compromise-affecting-xz-utils-data-compression-library-cve-2024-3094
2.Urgent security alert for Fedora Linux 40 and Fedora Rawhide users : https://www.redhat.com/en/blog/urgent-security-alert-fedora-41-and-rawhide-users
3.Threat Brief: Vulnerability in XZ Utils Data Compression Library Impacting Multiple Linux Distributions (CVE-2024-3094) : https://unit42.paloaltonetworks.com/threat-brief-xz-utils-cve-2024-3094/
4.Versions for xz : https://repology.org/project/xz/versions
5.CVE-2024-3094 (XZ Backdoor) Detector : https://github.com/jfrog/cve-2024-3094-tools/tree/main/cve-2024-3094-detector
6.CVE-2024-3094 checker : https://github.com/FabioBaroni/CVE-2024-3094-checker/tree/main
7.FAQ on the xz-utils backdoor : https://gist.github.com/thesamesam/223949d5a074ebc3dce9ee78baad9e27
8.backdoor in upstream xz/liblzma leading to ssh server compromise : https://www.openwall.com/lists/oss-security/2024/03/29/4
9.CVE-2024-3094 XZ Backdoor: All you need to know : https://jfrog.com/blog/xz-backdoor-attack-cve-2024-3094-all-you-need-to-know/
10.xz-utils 5.6.1 Changelog : https://fossies.org/diffs/xz/5.4.6_vs_5.6.1/
11.Exploration of the xz backdoor (CVE-2024-3094) : https://github.com/amlweems/xzbot
12.xz/liblzma: Bash-stage Obfuscation Explained : https://gynvael.coldwind.pl/?id=782&lang=en&ref=upstract.com
13.XZ backdoor story – Initial analysis : https://securelist.com/xz-backdoor-story-part-1/112354/
14.The XZ Backdoor issue triggered by one untrusted maintainer: https://medium.com/s2wblog/the-xz-backdoor-issue-triggered-by-one-untrusted-maintainer-2d5e5c1273d0
15.XZ Outbreak(CVE-2024-3094) : https://twitter.com/fr0gger_/status/1774342248437813525