2026년 11월 4일 Debian과 Ubuntu가 APT 취약점 CVE-2026-109518을 수정했다. HTTP 미러로 가는 트래픽을 가로챌 수 있는 공격자가 서명 검증이 끝난 패키지를 다른 파일로 바꿀 수 있다. 패키지는 root로 설치되므로 결과는 root 권한 코드 실행이다. Ubuntu 22.04 이상은 기본 설정 그대로 영향을 받는다.
이 글에서는 취약점이 생기는 조건과 수정 버전을 정리한다. 설치된 버전 확인, Acquire::Retries 우회 설정, HTTPS 전환은 직접 실행해 확인한다. 실행 환경은 Ubuntu 24.04 테스트 호스트와 podman 컨테이너다.
취약점 요약
| 항목 | 내용 |
|---|---|
| CVE | CVE-2026-109518 (Ubuntu USN-8996-1, Debian DSA-6607-1) |
| 발견자 | 맥스 저스티츠(Max Justicz) |
| 심각도 | Ubuntu 우선순위 High, CVSS 4.0 기준 7.7 |
| 공격 조건 | HTTP 트래픽 가로채기, 리디렉션 추종, 다운로드 재시도 |
| 영향 받는 도구 | apt, apt-get, aptitude, 그래픽 패키지 관리자 등 APT HTTP 백엔드를 쓰는 모든 도구 |
| 영향 없음 | snap 패키지 설치, FTP 소스 |
동작 원리
APT 개발자 줄리안 안드레스 클로데(Julian Andres Klode)의 공지에 따르면 공격은 세 단계로 진행된다.
- 공격자가 HTTP 리디렉션으로 서로 다른 두 패키지 다운로드를 같은 URI로 만든다. APT는 두 다운로드를 하나로 합친다.
- 공격자가 일시적인 HTTP 서버 오류를 돌려줘서 APT가 다운로드를 재시도하게 한다.
- 재시도한 다운로드가 기존 하드 링크를 덮어쓴다. 그래서 검증이 끝난 파일이 공격자의 파일로 바뀐다.
수정 패치는 다운로드 대상 파일을 배타적으로 연다. 부분 다운로드 내용을 복사하기 전에 기존 파일을 먼저 unlink해서 하드 링크를 통한 덮어쓰기를 막는다.
수정 버전
| 릴리스 | 수정된 apt 버전 | 비고 |
|---|---|---|
| 26.10 | 3.3.3ubuntu0.1 | |
| 26.04 LTS | 3.2.1ubuntu0.1 | |
| 24.04 LTS | 2.8.4ubuntu0.1 | |
| 22.04 LTS | 2.4.15ubuntu0.1 | |
| 20.04 LTS | 2.0.12+esm1 | Ubuntu Pro 필요 |
| 18.04 LTS | 1.6.19+esm1 | Ubuntu Pro 필요 |
| 16.04 LTS | 1.2.36+esm1 | Ubuntu Pro Legacy 애드온 필요 |
| Debian 13 | 3.0.4 | DSA-6607-1 |
설치된 버전 확인
릴리스 코드명별 수정 버전과 설치된 버전을 dpkg --compare-versions로 비교하는 스크립트다. 수정 전이면 종료 코드 1을 돌려주므로 여러 서버를 점검할 때 쓸 수 있다.
#!/bin/bash
# CVE-2026-109518(USN-8996-1) 수정 버전과 설치된 apt 버전을 비교한다
. /etc/os-release
case "$VERSION_CODENAME" in
stonking) fixed=3.3.3ubuntu0.1 ;;
resolute) fixed=3.2.1ubuntu0.1 ;;
noble) fixed=2.8.4ubuntu0.1 ;;
jammy) fixed=2.4.15ubuntu0.1 ;;
focal) fixed=2.0.12+esm1 ;;
*) echo "$VERSION_CODENAME: 표에 없음"; exit 2 ;;
esac
inst=$(dpkg-query -W -f='${Version}' apt)
retries=$(eval "$(apt-config shell R Acquire::Retries)"; echo "${R:-default}")
if dpkg --compare-versions "$inst" ge "$fixed"; then st=OK; else st=VULNERABLE; fi
printf "%s apt=%s fixed=%s retries=%s -> %s\n" "$VERSION_CODENAME" "$inst" "$fixed" "$retries" "$st"
[ "$st" = OK ]24.04 컨테이너에서 apt를 GA 버전(2.7.14build2)으로 내려 검사한 뒤, 보안 업데이트만 설치했다.
apt-get install -y --allow-downgrades apt=2.7.14build2 libapt-pkg6.0t64=2.7.14build2
bash apt_fixcheck.sh; echo rc=$?
apt list --installed "?source-package(^apt$)" 2>/dev/null
apt-get install -y -o Acquire::Retries=0 --only-upgrade "?source-package(^apt$)" \
| grep -E "upgraded|Unpacking"
bash apt_fixcheck.sh; echo rc=$?noble apt=2.7.14build2 fixed=2.8.4ubuntu0.1 retries=default -> VULNERABLE
rc=1
Listing...
apt/noble,now 2.7.14build2 amd64 [installed,upgradable to: 2.8.4ubuntu0.1]
libapt-pkg6.0t64/noble,now 2.7.14build2 amd64 [installed,upgradable to: 2.8.4ubuntu0.1]
The following packages will be upgraded:
2 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.
Unpacking libapt-pkg6.0t64:amd64 (2.8.4ubuntu0.1) over (2.7.14build2) ...
Unpacking apt (2.8.4ubuntu0.1) over (2.7.14build2) ...
noble apt=2.8.4ubuntu0.1 fixed=2.8.4ubuntu0.1 retries=default -> OK
rc=0
unattended-upgrades가 켜진 서버라면 이미 수정됐을 가능성이 높다. 언제 설치됐는지는 history.log에서 확인한다.
$ zgrep -h -B4 -A1 " apt:amd64 (" /var/log/apt/history.log* | head -6
End-Date: 2026-11-05 06:33:08
Start-Date: 2026-11-05 06:33:11
Commandline: /usr/bin/unattended-upgrade
Upgrade: apt:amd64 (2.7.14build2, 2.8.4ubuntu0.1), libapt-pkg6.0t64:amd64 (2.7.14build2, 2.8.4ubuntu0.1), apt-utils:amd64 (2.7.14build2, 2.8.4ubuntu0.1)
End-Date: 2026-11-05 06:33:18
테스트 호스트는 공지 다음 날 자동으로 수정 버전을 받았다. 업데이트 내역을 추적하는 방법은 Ubuntu APT 패키지 업데이트 내역 추적하기에 정리했다.
Acquire::Retries 우회 설정
APT 2.3.2부터 Acquire::Retries의 기본값은 3이다. 기본값이라 apt-config dump에는 나오지 않는다.
$ apt-config dump | grep -i retries || echo "(no Acquire::Retries line)"
(no Acquire::Retries line)
응답하지 않는 미러를 지정해 재시도 동작을 비교한다.
echo "deb http://127.0.0.1:8099/ubuntu noble main" > /tmp/dead.list
OPTS="-o Dir::Etc::sourcelist=/tmp/dead.list -o Dir::Etc::sourceparts=-"
time (apt-get update $OPTS 2>&1 | grep -E "Err:|Ign:")
time (apt-get update -o Acquire::Retries=0 $OPTS 2>&1 | grep -E "Err:|Ign:")Ign:1 http://127.0.0.1:8099/ubuntu noble InRelease
Ign:1 http://127.0.0.1:8099/ubuntu noble InRelease
Ign:1 http://127.0.0.1:8099/ubuntu noble InRelease
Err:1 http://127.0.0.1:8099/ubuntu noble InRelease
real 0m7.064s
user 0m0.017s
sys 0m0.046s
Err:1 http://127.0.0.1:8099/ubuntu noble InRelease
real 0m0.052s
user 0m0.014s
sys 0m0.039s
기본값에서는 1초, 2초, 4초 간격으로 세 번 재시도한다. 0이면 첫 실패에서 바로 끝난다. Ubuntu는 보안 업데이트를 설치하는 동안만 이 값을 0으로 두라고 안내한다.
sudo apt update && sudo apt install -o Acquire::Retries=0 --only-upgrade '?source-package(^apt$)'HTTPS로 전환하기
공격자가 HTTP 트래픽을 조작해야 하므로 HTTPS 소스는 이 공격을 막는다. Ubuntu 블로그가 안내한 sed 명령을 그대로 실행하면 24.04 컨테이너에서는 실패한다.
dpkg -s ca-certificates | head -1
sed -Ei 's!http://((([a-z]+\.)?archive|security|ports)\.ubuntu\.com)!https://\1!' \
/etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources
grep ^URIs /etc/apt/sources.list.d/ubuntu.sources
apt-get update 2>&1 | grep -A1 -m1 "^Err"dpkg-query: package 'ca-certificates' is not installed and no information is available
sed: can't read /etc/apt/sources.list.d/*.list: No such file or directory
URIs: https://archive.ubuntu.com/ubuntu/
URIs: https://security.ubuntu.com/ubuntu/
Err:1 https://security.ubuntu.com/ubuntu noble-security InRelease
Certificate verification failed: The certificate is NOT trusted. The certificate issuer is unknown. Could not handshake: Error in the certificate verification. [IP: 185.125.190.82 443]
최소 이미지에는 ca-certificates가 없어서 APT가 서버 인증서를 검증할 수 없다. 순서를 바꿔 HTTP 상태에서 ca-certificates부터 설치한다.
- HTTP 소스 상태에서
ca-certificates를 설치한다. 이때도-o Acquire::Retries=0을 붙인다. - 위
sed명령으로 소스를 HTTPS로 바꾼다. apt-get update로 확인한다.
ca-certificates 20260816ubuntu0.24.04.2
Hit:1 https://archive.ubuntu.com/ubuntu noble InRelease
Hit:2 https://security.ubuntu.com/ubuntu noble-security InRelease
Hit:3 https://archive.ubuntu.com/ubuntu noble-updates InRelease
Hit:4 https://archive.ubuntu.com/ubuntu noble-backports InRelease
주의사항
Acquire::Retries=0을 영구 설정으로 남기지 말 것. 수정 버전을 설치한 뒤에는 재시도가 다시 필요하다. 네트워크가 불안정한 환경에서는 재시도가 없으면 업데이트가 쉽게 실패한다.- 커뮤니티 미러를 쓴다면 HTTPS 지원 여부를 먼저 확인할 것. Ubuntu는 일부 미러가 HTTPS를 지원하지 않는다고 밝혔다.
- 오래된 컨테이너 이미지와 골든 이미지를 다시 빌드할 것. 캐시된 이미지에는 수정 전 apt가 남아 있다. 빌드 단계에서 위 검사 스크립트를 돌리면 걸러낼 수 있다.
sed의can't read메시지는 무시해도 된다. 24.04부터 기본 소스는 deb822 형식(ubuntu.sources)이라*.list파일이 없다. 나머지 파일은 정상적으로 바뀐다.- 20.04 이하는 Ubuntu Pro를 붙인 뒤 업데이트할 것. 수정 버전이 ESM 저장소에만 있다. 등록 방법은 Ubuntu Pro 무료 등록과 ESM 활용법을 참고한다.
마무리
이 취약점은 서명 검증을 통과한 뒤에 파일을 바꾼다. 그래서 “APT는 서명을 검사하므로 HTTP여도 안전하다”는 전제가 깨졌다. 수정 버전 설치가 우선이고, HTTPS 전환은 다음 취약점을 대비한 추가 방어선이다.