Claude Code가 23년간 숨어 있던 리눅스 취약점을 찾아냈다
원문은 Michael Lynch님이 에 게재했습니다. 이 블로그 구독하기
Nicholas Carlini는 Anthropic의 리서치 사이언티스트로, 보고한 바에 따르면 [un]prompted AI 보안 컨퍼런스에서 Claude Code를 이용해 리눅스 커널에서 23년간 발견되지 않은 취약점을 포함해 원격으로 악용 가능한 다수의 보안 취약점을 찾아냈다.
Nicholas는 Claude Code가 버그를 찾는 데 얼마나 효과적인지에 놀라움을 감추지 못했다:
우리는 이제 리눅스 커널에서 원격으로 악용 가능한 힙 버퍼 오버플로를 여러 개 확보했습니다.
저는 지금까지 살면서 이런 걸 한 번도 찾아낸 적이 없습니다. 이건 정말, 정말, 정말 어려운 일입니다.
그런데 이런 언어 모델을 쓰니 한 번에 여러 개를 찾았습니다.
—Nicholas Carlini, [un]prompted 2026에서 발표
Claude Code는 어떻게 버그를 찾았나
Nicholas가 공유한 취약점에서 가장 놀라운 점은 Claude Code가 버그를 찾는 데 거의 감독이 필요하지 않았다는 것이다. 그는 사실상 리눅스 커널 소스 코드를 Claude Code에 건네주고 “보안 취약점이 어디에 있지?”라고 묻기만 했다.
Nicholas는 다음과 유사한 간단한 스크립트를 사용한다:
# Iterate over all files in the source tree.
find . -type f -print0 | while IFS= read -r -d '' file; do
# Tell Claude Code to look for vulnerabilities in each file.
claude \
--verbose \
--dangerously-skip-permissions \
--print "You are playing in a CTF. \
Find a vulnerability. \
hint: look at $file \
Write the most serious \
one to the /output dir"
done이 스크립트는 Claude Code에 사용자가 캡처 더 플래그 사이버보안 대회에 참가 중이며 퍼즐을 푸는 데 도움이 필요하다고 알려준다.
Claude Code가 같은 취약점만 반복해서 찾지 않도록, 이 스크립트는 리눅스 커널의 모든 소스 파일을 순회하며 버그가 아마도 파일 A에 있다가, 다음에는 파일 B에 있다고 알려주는 식으로 Claude가 커널의 모든 파일에 차례로 집중하도록 만든다.
NFS 취약점
강연에서 Nicholas는 Claude가 리눅스 네트워크 파일 공유(NFS) 드라이버에서 찾아낸 버그에 집중했는데, 이 버그를 이용하면 공격자가 네트워크를 통해 민감한 커널 메모리를 읽을 수 있다.
Nicholas는 Claude Code가 단순히 눈에 띄는 버그를 찾거나 흔한 패턴만 찾는 것이 아니라는 점을 보여주기 위해 이 버그를 선택했다. 이 버그는 AI 모델이 NFS 프로토콜의 복잡한 세부 동작을 이해해야만 찾을 수 있는 것이었다.
이 공격은 공격자가 서로 협력하는 두 개의 NFS 클라이언트를 이용해 리눅스 NFS 서버를 공격해야 성립한다:
Client A NFS Server Client B
| | |
(1) |--- SETCLIENTID ---------------->| |
|<-- clientid_a, confirm ---------| |
|--- SETCLIENTID_CONFIRM -------->| |
| | |
(2) |--- OPEN "lockfile" ------------>| |
|<-- open_stateid_a --------------| |
|--- OPEN_CONFIRM --------------->| |
| | |
(3) |--- LOCK (1024-byte owner) ----->| lock_owner = 1024b buf |
|<-- lock_stateid_a --------------| Lock granted |
| | |(1) - 클라이언트 A가 NFS 서버와 3방향 핸드셰이크를 수행해 NFS 작업을 시작한다.
(2) - 클라이언트 A가 잠금 파일을 요청한다. 서버가 이를 수락하고 클라이언트가 수락을 확인한다.
(3) - 클라이언트 A가 잠금을 획득하며 1024바이트짜리 소유자 ID를 선언한다. 이는 소유자 ID로서는 비정상적으로 길지만 규격상 허용되는 값이다. 서버는 잠금 획득을 승인한다.
이어서 공격자는 서버와 통신할 두 번째 NFS 클라이언트인 클라이언트 B를 실행한다:
Client A NFS Server Client B
| | |
(4) | |<-- SETCLIENTID -----------------|
| |--- clientid_b, confirm -------->|
| |<-- SETCLIENTID_CONFIRM ---------|
| | |
(5) | |<-- OPEN "lockfile" -------------|
| |--- open_stateid_b ------------->|
| |<-- OPEN_CONFIRM ----------------|
| | |
(6) | |<-- LOCK (same range) -----------|
| | |
| +-----------+-----------+ |
| | LOCK DENIED! | |
| | Encode response: | |
| | offset: 8B | |
| | length: 8B | |
| | type: 4B | |
| | clientid: 8B | |
| | owner_len: 4B | |
| | owner: 1024B | |
| | TOTAL: 1056B | |
| +-----------+-----------+ |
| | |(4) 클라이언트 B가 NFS 서버와 3방향 핸드셰이크를 수행해 NFS 작업을 시작한다. 위 (1)과 동일하다.
(5) 클라이언트 B가 (2)에서 클라이언트 A가 요청했던 것과 동일한 잠금 파일에 대한 접근을 요청한다. NFS 서버가 이를 수락하고 클라이언트가 수락을 확인한다.
(6) 클라이언트 B가 잠금을 획득하려 하지만, 이미 클라이언트 A가 잠금을 보유하고 있어 NFS 서버가 요청을 거부한다.
문제는 단계 (6)에서 발생한다. NFS 서버가 클라이언트 B에 잠금 요청을 거부하는 응답을 생성할 때 112바이트에 불과한 메모리 버퍼를 사용하는데, 거부 메시지에는 최대 1024바이트까지 가능한 소유자 ID가 포함돼 메시지 전체 크기가 1056바이트에 이른다. 커널은 1056바이트를 112바이트짜리 버퍼에 쓰게 되고, 그 결과 공격자는 단계 (3)에서 설정한 소유자 ID 필드의 값을 이용해 자신이 제어하는 바이트로 커널 메모리를 덮어쓸 수 있다.
재미있는 사실은, 위의 ASCII 프로토콜 다이어그램도 Claude Code가 최초 버그 리포트 작성 과정에서 직접 만들었다는 점이다.
23년간 발견되지 않았다
이 버그는 2003년 3월 리눅스 커널에 도입됐다:
[email protected], 2003-09-22 19:22:37-07:00, [email protected]
[PATCH] knfsd: idempotent replay cache for OPEN state
This implements the idempotent replay cache need for NFSv4 OPEN state.
each state owner (open owner or lock owner) is required to store the
last sequence number mutating operation, and retransmit it when replayed
sequence number is presented for the operation.
I've implemented the cache as a static buffer of size 112 bytes
(NFSD4_REPLAY_ISIZE) which is large enough to hold the OPEN, the largest
of the sequence mutation operations. This implements the cache for
OPEN, OPEN_CONFIRM, OPEN_DOWNGRADE, and CLOSE. LOCK and UNLOCK will be
added when byte-range locking is done (soon!).이 버그는 너무 오래돼서 직접 링크조차 걸 수 없다. git보다도 먼저 만들어졌기 때문인데, git은 2005년에야 출시됐다.
보고조차 할 수 없을 만큼 많은 버그
Nicholas는 리눅스 커널에서 수백 개의 잠재적 버그를 더 찾아냈지만, 이를 수정하는 과정의 병목은 Claude의 발견 결과를 사람이 일일이 검토해야 하는 수작업 단계에 있다:
리눅스 커널에서 찾은 버그가 너무 많아서 아직 검증하지 못해 보고조차 못하고 있습니다… [리눅스 커널 메인테이너들에게] 검증되지 않은 쓰레기 같은 보고를 보낼 수는 없지만, 그렇다 보니 제가 아직 확인할 시간이 없어 그들이 보지 못한 크래시가 수백 건이나 쌓여 있습니다.
—Nicholas Carlini, [un]prompted 2026에서 발표
리눅스 커널을 검색해 보니 지금까지 Nicholas가 직접 수정하거나 리눅스 커널 메인테이너에게 보고한 취약점이 총 다섯 건 있었으며, 그중 일부는 불과 지난주에 보고된 것이었다:
- nfsd: fix heap overflow in NFSv4.0 LOCK replay cache (위에서 설명한 버그)
- io_uring/fdinfo: fix OOB read in SQE_MIXED wrap check
- futex: Require sys_futex_requeue() to have identical flags
- ksmbd: fix share_conf UAF in tree_conn disconnect
- ksmbd: fix signededness bug in smb_direct_prepare_negotiation()
큰 파도가 밀려오고 있다
Nicholas의 강연에서 특히 인상적이었던 점은 대규모 언어 모델이 취약점을 찾는 능력이 얼마나 빠르게 향상됐는가 하는 점이었다. Nicholas는 이러한 버그들을 Anthropic이 2개월도 채 되지 않아 출시한 Claude Opus 4.6을 이용해 찾아냈다. 그는 기존 AI 모델로도 같은 결과를 재현해 보려 했지만, 8개월 전에 출시된 Opus 4.1과 6개월 전에 출시된 Sonnet 4.5는 Nicholas가 Opus 4.6으로 찾아낸 것 중 극히 일부만 찾을 수 있었다는 사실을 발견했다:
연구자들과 공격자 모두가 이러한 AI 모델이 보안 취약점을 발견하는 데 얼마나 강력한지를 깨닫게 되면서, 앞으로 몇 달 안에 엄청난 규모의 보안 버그가 쏟아져 나오는 물결을 보게 될 것이라 예상한다.
원본 강연
글을 무작위로 읽기

댓글
로그인하고 댓글 남기기