TL;DR: 2017년에 심어진 커널 크립토 최적화 코드 한 줄이 로컬 권한 탈취(LPE)로 이어지는 취약점이 터졌다. PoC는 이미 공개됐고, 732바이트짜리 Python 스크립트 하나로 Ubuntu/RHEL/Amazon Linux/SUSE 전부 루트 탈취가 가능하다.
1. 배경과 문제: "계정 비밀번호 백도어, 커널 업데이트는 리스크가 크다."
우리 서버는 OVH 베어메탈 위에서 동작하는 온프레미스 환경이다. 어느 날 모니터링 채널에 CVE 하나가 올라왔다.
CVE-2026-31431, 일명 "Copy Fail" 이며 영향받는 배포판은 Ubuntu/Amazon Linux/RHEL/SUSE 인데 사실상 웬만한 서버에 설치되어 있는 리눅스 전부이다.
문제는 커널 업데이트를 바로 실행하기에는 애매한 상황이었다. 커널 버전이 올라가면 네트워크 관련 툴(ip, nftables 등)의 의존성이 함께 올라가면서 방화벽 규칙 / 라우팅 설정 등 생각하지 못한 부분에서 이슈가 발생할 수 있다. 일부 서비스들의 경우 서비스 특성상 다운타임은 곧 장애로 이어지며 수많은 고객사에도 장애가 발생하기 때문에 커널 버전을 바로 올리기는 부담스러웠다.
그래서 우선 "우리 서버가 영향 범위 안에 들어가는가?" 부터 기도하면서 확인을 해봤다.
2. 트러블슈팅 / 원인: "2017년에 추가된 이슈"
2-1. 취약점 구조
이 취약점의 핵심을 한 줄로 요약하면 'AF_ALG 소켓 + splice() + authencesn = 아무 파일의 페이지 캐시에 4바이트 통제 쓰기' 이다.
구체적으로 설명하자면
- 2015년 : 커널에 algif_aead.c가 추가되면서 AF_ALG 소켓을 통한 AEAD 암호화 인터페이스가 생겼다. 이 시점에서는 req->src(입력)와 req->dst(출력) 스캐터리스트가 분리되어 있었다. splice()로 페이지 캐시 페이지를 넣어도 읽기용 src에만 들어가므로 안전했다.
- 2017년 (커밋 72548b093ee3) : 누군가 성능 최적화 목적으로 in-place 연산을 추가했다. "어차피 같은 데이터 쓰는데 복사 한 번 줄이면 빠르지 않나?" 라는 합리적인 아이디어였다. 그런데 이 최적화가 req->src = req->dst로 세팅하면서 — splice()로 들어온 페이지 캐시 페이지(원래 읽기 전용)가 쓰기 가능한 목적지 스캐터리스트에 체이닝되는 상황이 생겼다.
- authencesn의 스크래치 쓰기: IPsec ESN(Extended Sequence Number)용 래퍼인 authencesn에는 오래된 버그가 있다. 출력 버퍼 끝 경계를 4바이트 넘어서 스크래치 패드로 쓰는 코드다. 원래는 별다른 문제가 없었는데, 복사 한번의 최적화로 인해 이 4바이트가 공격자가 선택한 읽기 가능 파일의 페이지 캐시 내부에 떨어지게 되었다.
- 결론으로 HMAC 검증은 실패해서 recvmsg()는 에러를 리턴하지만, 쓰기는 이미 일어난 뒤다. setuid 바이너리(예: /usr/bin/passwd)의 페이지 캐시를 조작하면 로컬 권한 탈취가 가능하다.

2-2. 영향 범위 확인
Copy Fail 의 영향 범위를 확인하기 위해 배포된 파이썬 스크립트가 있다. 해당 스크립트들 실행해보니 결과는 다음과 같았다.

스크립트에서는 "6.12/6.17/6.18 라인보다 낮아서 트리거가 안 될 수도 있다"는 메세지를 출력해줬지만, 전제 조건(AF_ALG + authencesn 로드 가능)은 충족되어 VULNERABLE 판정이 났다.
해당 커널(6.8.0-53-generic)에는 2017년 in-place 최적화 커밋(72548b093ee3)이 포함되어 있고, algif_aead 모듈이 로드 가능한 상태라는 뜻이다. 아직 패치 커밋(a664bf3d603d)이 백포팅되지 않은 상태인 것이다.
3. 해결책 : 임시 조치
3-1. 임시 조치: algif_aead 모듈 비활성화
커널 업데이트 전에 바로 적용이 가능하고 간단한 방법이다. algif_aead 커널 모듈이 올라오지 못하도록 하는 것이다.
# algif_aead 모듈 블랙리스트 등록
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
# 현재 로드된 모듈 제거 (에러 나도 무시)
rmmod algif_aead 2>/dev/null || true
/bin/false로 install 명령을 덮어쓰면, modprobe algif_aead를 시도해도 실패하게 되며 재부팅을 하더라도 모듈이 올라오지 않는다.

algif_aead 을 막으면 기존의 서비스에 문제가 생기지 않을까라는 생각이 들어 확인해봤지만, dm-crypt, LUKS, IPsec, TLS, SSH, OpenSSL/GnuTLS 와 같이 많이 사용되는 것들은 커널 내부 crypto API를 직접 사용하고 AF_ALG 소켓을 경유하지 않는다. AF_ALG는 유저스페이스에서 커널 암호화 기능을 직접 사용하는 특수한 케이스에서만 필요하다.
3-2. 컨테이너 / 멀티 테넌트 환경 추가 조치
컨테이너를 운용 중이라면 seccomp 정책으로 AF_ALG 소켓 생성 자체를 틀어막는 게 더 깔끔할 수 있다.
{
"defaultAction": "SCMP_ACT_ALLOW",
"syscalls": [
{
"names": ["socket"],
"action": "SCMP_ACT_ERRNO",
"args": [
{
"index": 0,
"value": 38,
"op": "SCMP_CMP_EQ"
}
]
}
]
}
3-3. 영구 해결: 커널 패치
임시 조치는 말 그대로 임시다. 정식 해결은 업스트림 픽스가 포함된 커널 패키지로 업데이트하는 것이다.
픽스 커밋: a664bf3d603d — algif_aead.c의 in-place 최적화를 되돌리고, 소스/목적지 스캐터리스트를 완전히 분리하여 페이지 캐시 페이지가 쓰기 가능한 목적지로 체이닝되는 경로를 원천 차단한다.
# Ubuntu / Debian 계열
sudo apt update && sudo apt upgrade linux-image-$(uname -r)
# RHEL / CentOS / Amazon Linux 계열
sudo yum update kernel
# 또는
sudo dnf update kernel
업데이트 후 재부팅 필수이다. 커널은 디스크에 반영만 해선 안 되고 실제로 부팅해서 올려야 한다. 당연한 얘기지만 가끔 재부팅 안 하고 "업데이트를 했는데 왜 적용이 안될까" 하는 경우도 있다.
3-4. 취약 여부 재검증
조치 후 검출 스크립트를 다시 돌려서 algif_aead 로드 불가 확인 또는 패치 커밋 반영 여부를 검증한다.
# 모듈 비활성화 확인
modprobe algif_aead 2>&1
# 아래 이미지처럼 출력이 된다면 문제가 없는거다.
# 또는 modinfo로 아예 없는지 확인
modinfo algif_aead

4. 마지막 요약
항목 내용
| CVE | CVE-2026-31431 "Copy Fail" |
| 심각도 | CVSS 7.8 (HIGH) — 로컬 권한 탈취(LPE) |
| 원인 | 2017년 algif_aead in-place 최적화로 읽기 전용 페이지 캐시가 쓰기 가능 스캐터리스트에 체이닝됨 |
| 영향 범위 | 2017년 이후 대부분의 리눅스 배포판 (Ubuntu / RHEL / SUSE / Amazon Linux) |
| PoC | 공개됨 (732바이트 Python, 루트 획득) |
| 임시 조치 | algif_aead 모듈 블랙리스트 (/etc/modprobe.d/disable-algif.conf) |
| 영구 해결 | 커널 업데이트 (픽스 커밋: a664bf3d603d) |
- 알고 있어야 할 것: 732바이트 Python PoC로 로컬 루트 가능, 2017년부터 지금까지 사실상 모든 리눅스가 영향 받음
- 지금 당장 할 것:
- echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
- rmmod algif_aead 2>/dev/null || true
- 앞으로 해야 할 것: 커널 패치 + 재부팅
참고 자료
'실무 경험 > 실무 개발 & 협업' 카테고리의 다른 글
| IDC 베어메탈 + Docker Swarm 복합 장애 살려내기 (0) | 2026.04.14 |
|---|---|
| [블록체인] - 솔라나 메인넷 노드, RPC 트러블슈팅 (0) | 2026.04.01 |
| [트러블슈팅] - 유지보수가 중단된 클라이언트와의 TLS 핸드셰이크 (0) | 2026.02.02 |
| 휴먼에러를 방지하는 방법 1 - git add -p(git add partial (or patch) (0) | 2025.04.24 |
| [블록체인] - Integer overflow 와 underflow (0) | 2025.04.21 |