NOW Briefing
Acquire::Retries=0 옵션을 함께 적용해야 합니다.
APT 다운로드 재개 과정의 패키지 서명 검증 우회 취약점 (CVE-2026-109518)
■ 개요
APT는 Debian과 Ubuntu 계열 배포판이 패키지를 내려받고 서명을 검증한 뒤 설치하는 표준 패키지 관리자입니다. 2026년 11월 4일 Debian은 보안 권고 DSA-6607-1을, Canonical은 USN-8996-1을 동시에 공개하며 APT의 HTTP 다운로드 처리에서 발견된 취약점 CVE-2026-109518을 알렸습니다. 발견자는 보안 연구자 Max Justicz입니다. 벤더 설명에 따르면 원인은 APT가 HTTP 리다이렉트로 같은 주소가 된 두 개의 패키지 다운로드를 하나로 합치고, 중단된 다운로드를 다시 이어받을 때 기존 파일을 안전하지 않은 방식으로 다룬다는 두 가지입니다.
악용 조건은 경로상 공격자(APT 클라이언트와 저장소 서버 사이의 HTTP 통신을 조작할 수 있는 위치의 공격자)입니다. 악성 미러나 프록시 운영도 이 위치에 해당합니다. Canonical 설명 기준으로 저장소 접속이 평문 HTTP이고 다운로드 재시도 기능이 켜져 있어야 하며, 재시도는 Ubuntu 22.04 LTS 이상과 Debian 12 이상에서 기본값입니다. 조건이 맞으면 서명 검증을 통과한 .deb 파일의 내용이 설치 직전에 공격자가 지정한 데이터로 바뀌고, 그 패키지가 설치되면 공격자가 root 권한으로 임의 코드를 실행할 수 있습니다. 사용자 인증이나 로컬 계정은 필요하지 않지만, 대상 시스템이 패키지를 내려받는 시점을 공격자가 가로채야 합니다.
공격 표면은 운영체제 업데이트 경로 자체입니다. Canonical은 이 취약점의 심각도를 High로 분류했고, Ubuntu 14.04 LTS부터 26.10까지 8개 릴리스에 패치를 배포했습니다. 다만 20.04 LTS 이하 릴리스의 패치는 Ubuntu Pro 구독의 확장 보안 유지(ESM) 채널로만 제공되며, 16.04 LTS와 14.04 LTS는 ESM에 Legacy 애드온까지 필요합니다. 현재까지 공개된 정보에서 실제 공격에 악용된 사례는 확인되지 않았습니다.
■ 요약
| 항목 | 내용 |
|---|---|
| CVE ID | CVE-2026-109518 (HTTP 다운로드 재개 시 하드링크 처리 오류) |
| CVSS 점수 | CVSS v4.0 7.7 |
| 취약점 유형 | 하드링크 처리 오류, 패키지 서명 검증 우회 |
| 영향/위험 | • 서명 검증을 통과한 패키지 파일의 내용이 검증 이후 교체 가능 • 교체된 패키지 설치로 root 권한 임의 코드 실행 가능 • 악용에 HTTP 통신 조작 위치와 다운로드 재시도 활성화 필요 |
| 취약 버전 | • Debian 13(trixie) apt 3.0.3 이하 • Debian 12(bookworm) apt 2.6.1 이하 • Ubuntu 14.04 LTS~26.10의 패치 이전 apt • 기본 설정만으로 조건이 충족되는 범위는 재시도가 기본값인 APT 2.3.2 이상(구버전도 설정 시 해당) |
| 패치 버전 | • Debian: trixie 3.0.4, bookworm 2.6.2, forky 3.3.6, unstable 3.3.7 • Ubuntu 26.10: 3.3.3ubuntu0.1 • Ubuntu 26.04 LTS: 3.2.1ubuntu0.1 • Ubuntu 24.04 LTS: 2.8.4ubuntu0.1 • Ubuntu 22.04 LTS: 2.4.15ubuntu0.1 • Ubuntu 20.04·18.04 LTS: ESM 채널 제공(Ubuntu Pro 필요) • Ubuntu 16.04·14.04 LTS: ESM + Legacy 애드온 필요 |
■ 패키지 교체가 가능한 이유
APT는 같은 주소를 가리키는 다운로드 작업을 중복으로 처리하지 않고 하나로 병합하며, 디스크에서는 두 경로를 하드링크(같은 파일 데이터를 가리키는 둘 이상의 경로)로 연결합니다. 공격자가 HTTP 리다이렉트로 서로 다른 두 패키지 다운로드를 같은 주소로 유도하면 이 병합이 발생합니다. 이후 공격자가 일시적인 서버 오류를 반환해 APT가 다운로드를 재시도·재개하도록 만들면, APT는 이미 받아둔 파일을 열어 이어 씁니다.
이 재개 단계에서 APT는 기존 파일을 배타적으로 열지 않았습니다. 해당 경로가 이미 검증을 마친 패키지 파일과 하드링크로 연결돼 있으면, 공격자가 보낸 데이터가 그 검증 완료 파일의 내용을 그대로 덮어쓰게 됩니다. 서명 검증은 교체 이전 데이터로 이미 끝난 상태이므로, 설치 단계에서는 바뀐 내용이 그대로 처리됩니다. 재시도 동작은 설정 키 Acquire::Retries로 제어되며, APT 2.3.2부터 기본으로 활성화됐습니다. 그 이전 릴리스라도 운영 스크립트에서 이 값을 지정했다면 같은 조건에 놓입니다.
⚠️ WARN
공개된 PoC 코드는 확인되지 않았습니다. 다만 공격 조건이 평문 HTTP 저장소와 기본 설정 수준의 재시도 동작이므로, 사내 미러나 캐싱 프록시를 HTTP로 운용하는 환경은 노출 범위를 먼저 확인해야 합니다.
■ 패치로 달라진 동작
APT 저장소의 수정 커밋(5af16a8a)은 HTTP 다운로드 메서드 소스인 methods/http.cc에서 응답 헤더 처리 함수 HttpMethod::DealWithHeaders()의 파일 열기 분기를 교체했습니다. 아래는 그 커밋 diff 중 해당 분기 부분입니다.
@@ -1004,8 +1004,24 @@ BaseHttpMethod::DealWithHeadersResult HttpMethod::DealWithHeaders(FetchResult &R
auto ret = BaseHttpMethod::DealWithHeaders(Res, Req);
if (ret != BaseHttpMethod::FILE_IS_OPEN)
return ret;
- if (Req.File.Open(Queue->DestFile, FileFd::WriteAny) == false)
+
+ // If we are resuming, we first need to rescue the data we already have
+ FileFd partial;
+ if (Req.StartPos > 0 && FileExists(Queue->DestFile))
+ {
+ if (not partial.Open(Queue->DestFile, FileFd::ReadOnly))
+ return ERROR_NOT_FROM_SERVER;
+ }
+ // Open the file exclusively to avoid injection attacks by links
+ if (Req.File.Open(Queue->DestFile, FileFd::WriteAny | FileFd::Exclusive) == false)
return ERROR_NOT_FROM_SERVER;
+ if (partial.IsOpen())
+ {
+ // The exclusive open unlinked the old file; copy its content
+ // into the new one and rewind for hashing.
+ if (not CopyFile(partial, Req.File) || not partial.Close() || not Req.File.Seek(0))
+ return ERROR_NOT_FROM_SERVER;
+ }
FailFile = Queue->DestFile;
수정 전에는 대상 파일을 일반 쓰기 모드로 열어 기존 경로의 데이터를 그대로 이어 썼습니다. 수정 후에는 재개 상황일 때 기존 파일을 읽기 전용으로 먼저 확보하고, 대상 파일은 FileFd::Exclusive(기존 경로를 따라가지 않고 새 파일을 배타적으로 만드는 열기 옵션)로 다시 생성합니다. 배타적 열기가 기존 경로의 연결을 끊기 때문에, 이미 받아둔 데이터는 새 파일로 복사한 뒤 해시 계산을 위해 처음으로 되돌립니다.
같은 커밋은 패치 적용 메서드 methods/rred.cc와 압축 처리 메서드 methods/store.cc의 파일 생성 옵션도 FileFd::Empty에서 배타적 열기로 바꿨습니다. 하드링크·심볼릭 링크 대상에 다운로드해도 원본 파일이 변경되지 않는지 확인하는 통합 테스트(test/integration/test-apt-download-onto-hardlink)도 추가했습니다. 커밋 메시지도 하드링크인 기존 파일을 열어 수정하면 의도하지 않은 파일이 변경될 수 있다고 원인을 설명합니다.
■ 탐지 및 점검
• 설치된 버전을 dpkg-query -W -f='${Package} ${Version}\n' apt로 확인하고 릴리스별 패치 버전과 대조합니다.
• apt-config dump | grep -iE '^Acquire::Retries'로 재시도 설정의 실제 적용값을 확인해 노출 여부를 판단합니다. 값이 출력되지 않으면 명시적 설정이 없다는 의미이므로 해당 apt 버전의 기본값(2.3.2 이상은 재시도 활성화)을 기준으로 판단합니다.
• /etc/apt/sources.list와 /etc/apt/sources.list.d/ 아래 항목에서 http://로 시작하는 저장소 주소를 찾아 평문 통신 대상을 목록화합니다.
• 컨테이너 베이스 이미지와 CI 파이프라인에서 패키지를 설치하는 단계를 점검합니다. 이미지 빌드 시점의 apt 버전과 저장소 주소가 호스트 설정과 다를 수 있습니다.
• /var/log/apt/history.log, /var/log/apt/term.log, /var/log/dpkg.log에서 의도하지 않은 패키지 설치와 다운로드 재시도 기록을 확인합니다. HTTP 프록시가 URL 단위로 로그를 수집하는 환경이라면 .deb 요청의 리다이렉트와 서버 오류가 반복된 기록을 함께 봅니다.
✅ CHECK
평문 HTTP라는 이유만으로 방화벽이나 NetFlow 로그에서 패키지 내용 교체를 확인할 수 있는 것은 아닙니다. 요청·응답 본문 수준의 확인에는 프록시 본문 로깅이나 전체 패킷 캡처가 필요합니다.
■ 대응 방안
• 릴리스별 패치 버전으로 apt를 업그레이드합니다. Canonical은 업그레이드 자체가 공격 대상이 되지 않도록 sudo apt update && sudo apt upgrade -o Acquire::Retries=0처럼 재시도를 끈 상태로 적용하라고 안내하며, 이 임시 설정이 경로상 공격자와 악성 미러의 이 취약점 악용을 막는다고 설명합니다.
• 즉시 업그레이드가 어려운 시스템은 apt.conf에 Acquire::Retries 0;을 추가해 임시로 재시도를 비활성화하고, 패치 적용 후 원래 설정으로 되돌립니다.
• 저장소 주소를 http://에서 https://로 전환해 통신 경로 조작 난이도를 높입니다. 다만 Canonical은 일부 커뮤니티·국가별 미러가 HTTPS를 지원하지 않는다고 밝혔으므로 전환 전에 미러의 지원 여부를 확인해야 합니다.
• 자동 업데이트를 쓰는 시스템도 적용 완료를 직접 확인합니다. Canonical은 자동 업데이트 도구 unattended-upgrades가 동작하는 Ubuntu 16.04 LTS 이상에서 24시간 내 자동 적용을 안내하지만, 자동 업데이트를 끈 서버와 골든 이미지는 수동 대상입니다.
• Ubuntu 20.04 LTS 이하를 운영한다면 패치가 ESM 채널로만 제공되므로 Ubuntu Pro 적용 여부(16.04 LTS·14.04 LTS는 Legacy 애드온 포함)를 확인하거나 지원 릴리스로 업그레이드합니다.
💡 TIP
패치 적용 후에는 취약 버전 apt가 포함된 컨테이너 베이스 이미지와 머신 이미지를 재빌드해야 합니다. 호스트만 업그레이드하면 이미지에 포함된 취약 버전 apt가 빌드·배포 단계에서 계속 사용됩니다.
[참고 자료]
• oss-security — CVE-2026-109518: RCE in apt(1) (DSA 6607-1)
• Debian 보안 권고 DSA-6607-1 (apt)
• Debian 보안 추적기 — CVE-2026-109518
• Ubuntu 보안 공지 USN-8996-1 (apt)
• Ubuntu 보안 페이지 — CVE-2026-109518
• Canonical 블로그 — APT 취약점 수정 안내
• APT 수정 커밋 5af16a8ad0f155233dfb10b7c92ad1903112ef79 (methods/http.cc 외)