본문으로 건너뛰기
피드

리눅스 커널 15년 묵은 취약점 ‘GhostLock’, 권한 상승과 컨테이너 탈출까지 뚫렸다

security 약 12분
vote
0
댓글
북마크

GhostLock은 2011년 리눅스 2.6.39부터 들어간 커널 취약점으로, 패치 전 주요 배포판 대부분에 영향을 준다. 특별한 커널 설정이나 권한 없이 로컬 사용자가 커널 스택 use-after-free를 이용해 루트 권한 상승과 컨테이너 탈출까지 이어갈 수 있고, 연구팀은 구글 kernelCTF에서 안정도 97% 익스플로잇으로 9만2337달러 보상을 받았다.

  • 1

    GhostLock은 CVE-2026-43499로 등록된 리눅스 커널 stack-use-after-free 취약점임

  • 2

    공격자는 일반 스레딩 시스템콜만으로 해제된 커널 스택 포인터를 잡고, 제한적 포인터 쓰기 primitive를 만든 뒤 제어 흐름 탈취까지 이어감

  • 3

    익스플로잇은 inet6_protos, CPU entry area, DirtyMode를 조합해 루트 권한 상승과 컨테이너 탈출을 달성함

  • 4

    리눅스 7.1에서 수정됐고, 영향받는 배포판은 최신 장기지원 커널로 올리는 게 핵심 대응임

15년 동안 살아남은 커널 버그

  • GhostLock은 리눅스 커널의 stack-use-after-free 취약점이고, CVE-2026-43499로 등록됨

    • 2011년 리눅스 2.6.39에 들어갔고, 리눅스 7.1에서 수정됨
    • 연구팀 설명 기준으로 패치 전 주요 리눅스 배포판이 영향을 받음
    • 특별한 커널 설정이나 권한이 필요 없어서, 로컬 비권한 사용자가 공격 출발점에 설 수 있음
  • 결과만 보면 꽤 세다. 권한 상승, 컨테이너 탈출, 제어 흐름 탈취까지 이어짐

    • 구글 kernelCTF에서 97% 안정도의 익스플로잇으로 인정받음
    • 보상액은 9만2337달러
    • 원격 kernelCTF 환경에서는 약 5초 만에 플래그를 얻었다고 함

⚠️주의

> 이건 “희귀 설정에서만 터지는 연구용 버그” 쪽이 아님. 패치 전 커널에서 일반 시스템콜만으로 출발할 수 있는 로컬 권한 상승 취약점이라, 멀티테넌트 서버나 컨테이너 호스트 입장에서는 꽤 직접적인 위험임.

공격 흐름을 한 줄로 줄이면

  • 핵심은 해제된 커널 스택 포인터를 다시 잡고, 그 자리에 공격자가 원하는 가짜 구조체를 올리는 것임

    • 공격자는 dangling pointer가 rt_mutex_waiter처럼 해석되게 만듦
    • 그다음 커널의 rtmutex 처리 경로가 이 가짜 waiter를 정상 구조체처럼 따라가게 함
    • 커널은 크래시 없이 정상 복귀할 수 있어서, 단순한 서비스 거부가 아니라 안정적인 익스플로잇으로 발전함
  • 익스플로잇 체인은 크게 7단계로 정리됨

    • prefetch로 커널 이미지 슬라이드와 physmap base를 leak함
    • GhostLock으로 waiter 태스크의 pi_blocked_on에 dangling rt_mutex_waiter를 남김
    • PR_SET_MM_MAP으로 같은 커널 스택 프레임을 다시 덮어 가짜 rt_mutex_waiter를 만듦
    • rtmutex rb-tree erase를 이용해 제한적 포인터 쓰기 primitive를 얻음
    • inet6_protos[IPPROTO_UDP]를 CPU entry area 쪽 포인터로 덮음
    • IPv6 UDP loopback 패킷으로 fake handler를 호출해 제어 흐름을 뺏음
    • DirtyMode로 core_pattern 권한 비트를 바꿔 사용자 공간에서 루트 권한 상승을 마무리함
sequenceDiagram
    participant 공격자
    participant 커널스택
    participant 락처리
    participant IPv6테이블
    participant 사용자공간
    공격자->>커널스택: 해제된 waiter 포인터 유지
    공격자->>커널스택: PR_SET_MM_MAP으로 가짜 waiter 배치
    락처리->>커널스택: rt_mutex_waiter로 해석
    락처리->>IPv6테이블: inet6_protos 포인터 덮기
    공격자->>IPv6테이블: loopback UDP로 handler 호출
    IPv6테이블->>사용자공간: DirtyMode 이후 루트 권한 상승

스택 재사용이 제일 맛있는 부분

  • dangling object는 waiter 자신의 커널 스택에 있던 rt_mutex_waiter임

    • 공격자는 그 정확한 스택 프레임 위에 다시 제어 가능한 바이트를 올려야 함
    • 글에서는 prctl(PR_SET_MM, PR_SET_MM_MAP, ...) 경로를 사용함
    • prctl_set_mm_map() 안에서 user_auxv[AT_VECTOR_SIZE]라는 고정 크기 스택 버퍼가 만들어지고, 이 버퍼가 해제된 waiter와 비슷한 스택 깊이에 놓임
  • 공격자는 auxv 내용을 조작해서 가짜 waiter 필드들을 맞춰 넣음

    • tree는 rb-tree erase가 원하는 child pointer를 root로 올리도록 구성함
    • task는 안전한 역참조를 위해 &init_task로 둠
    • lock은 쓰기 목표인 &inet6_protos[IPPROTO_UDP] - 8로 맞춤
    • wake_state는 0으로 설정함
  • race window를 넓히는 디테일도 있다. memfd와 fallocate(PUNCH_HOLE)을 같이 씀

    • auxv를 페이지 경계에 걸치게 배치함
    • 형제 스레드가 trailing page에 구멍을 내면서 copy_from_user 시간을 늘림
    • 그 사이 다른 CPU에서 sched_setattr()를 호출해 PI chain walk를 태움
    • 연구팀은 단일 코어 CPU에서도 exploitable할 것으로 본다고 적음

“임의 쓰기”가 아니라 제한적인 한 방

  • GhostLock이 바로 완전한 arbitrary write를 주는 건 아님. 실제 primitive는 꽤 빡빡한 제한이 있음

    • rt_mutex_dequeue()의 rb-tree erase를 이용해 단일 child pointer를 root slot에 쓰는 구조임
    • 결과적으로 *(uint64_t *)target = W0_BASE 같은 제한적 포인터 쓰기에 가까움
    • target 앞 qword는 unlocked spinlock처럼 보여야 해서 low 4 bytes가 0이어야 함
    • target 뒤쪽 값들도 커널이 엉뚱한 waiter나 owner를 따라가지 않게 안전해야 함
  • 그래서 연구팀은 inet6_protos[IPPROTO_UDP]를 골랐음

    • 쓰기 가능한 커널 데이터 영역에서 주변 레이아웃 조건이 잘 맞는 포인터 테이블을 찾은 것
    • 트리거도 편함. 비권한 사용자가 loopback IPv6 UDP 패킷을 보내면 됨
    • 덮은 뒤에는 커널이 CPU entry area에 있는 가짜 inet6_protocol을 진짜처럼 보고 handler를 호출함

중요

> 익스플로잇의 포인트는 “완전한 임의 쓰기 없이도 충분하다”는 데 있음. 제한적인 포인터 쓰기 한 번을 inet6_protos와 CPU entry area에 연결해서, 결국 프로그램 카운터 제어까지 끌고 감.

CPU entry area와 DirtyMode로 짧게 끝내기

  • CPU entry area는 이 공격에서 작지만 고정 주소에 가까운 작업대 역할을 함

    • 제어 가능한 메모리를 알려진 direct-map 주소에 둘 수 있음
    • 크기는 약 120바이트라 넉넉하진 않음
    • 그래도 가짜 inet6_protocol, JOP/pivot slot, 최종 ROP stack을 같이 담는 식으로 사용함
  • 구글 lts-6.12.80 타깃에서는 깔끔한 단일 stack pivot gadget을 못 찾아 한 단계를 더 거침

    • 먼저 CEA 주소를 rbp에 올림
    • 이후 mov rsp, rbp; pop rbp; ret 형태로 스택을 피벗함
    • ret2usr나 /proc/%P/fd/x 전체 overwrite 경로는 gadget이 10 qword쯤 필요해서 너무 길었다고 함
  • 그래서 마지막은 DirtyMode를 선택함. 짧고 현실적임

    • coredump_sysctls[1].mode에 쓰기 가능한 비트를 세움
    • 그러면 /proc/sys/kernel/core_pattern이 world-writable이 됨
    • 비권한 프로세스가 core_pattern에 |/proc/%P/fd/666 %P를 쓰고 helper를 크래시시켜, 커널이 공격자 바이너리를 root로 실행하게 만듦

패치와 완화책

  • 패치의 핵심은 waiter->task를 믿고 읽지 않게 바꾼 것임

    • 호출자가 owning task를 직접 넘기도록 수정함
    • self-blocking path에서는 current를, proxy lock rollback에서는 proxied task를 넘김
    • pi_blocked_on은 여전히 해당 waiter를 가리킬 때만 clear되도록 guard를 둠
  • RANDOMIZE_KSTACK_OFFSET은 스택 재사용 단계를 흔들 수 있음

    • 이 공격은 해제된 waiter frame과 이후 user_auxv frame이 결정적으로 겹치는 데 의존함
    • RANDOMIZE_KSTACK_OFFSET이 켜지면 대략 1/32, 즉 5비트 stack-offset guess 문제가 됨
    • kernelCTF 제출 대상 두 개는 기본값으로 꺼져 있었고, mitigation target은 켜져 있어서 이 경로를 쓰지 않았다고 함
  • STATIC_USERMODE_HELPER는 이 글의 DirtyMode 경로를 막는 데 도움이 됨

    • 다만 연구팀은 같은 아이디어가 다른 /proc/sys knob에도 일반화될 수 있다고 봄
    • 조건은 ctl_table::mode가 접근 권한을 막고, 해당 테이블이 예측 가능한 writable kernel data에 있어야 한다는 것

타임라인도 빠르게 보자

  • 연구팀은 2026년 4월 18일 [email protected]에 버그와 초안 패치를 보냄
    • 4월 20일 다른 패치로 수정됨
    • 5월 4일 fix v1이 backport됨
    • 6월 30일 구글이 kernelCTF 제출을 인정함
    • 7월 7일 기술 글이 공개됨

기술 맥락

  • 이 취약점에서 중요한 선택은 “해제된 스택 객체를 다시 덮을 수 있느냐”였어요. 커널 힙 UAF처럼 slab을 뿌리는 게 아니라, 같은 태스크의 커널 스택에서 비슷한 깊이의 로컬 버퍼를 찾아야 했거든요. 그래서 PR_SET_MM_MAP의 user_auxv 버퍼가 공격 체인의 핵심 발판이 됐어요.

  • inet6_protos[IPPROTO_UDP]를 고른 이유도 단순히 함수 포인터가 있어서가 아니에요. GhostLock이 주는 쓰기는 조건이 빡센 한 번짜리 포인터 쓰기에 가깝기 때문에, 목표 주소 앞뒤 qword가 rtmutex 경로의 검사를 버틸 수 있어야 했어요. IPv6 UDP 테이블은 그 레이아웃과 트리거 편의성이 같이 맞아떨어진 케이스예요.

  • CPU entry area를 쓴 건 공간보다 주소 예측 가능성이 더 중요했기 때문이에요. 약 120바이트밖에 안 되는 작은 창에 가짜 inet6_protocol, 피벗 슬롯, ROP 스택을 욱여넣은 건 kernelCTF에서 빠르고 안정적으로 플래그를 따기 위한 선택이었어요.

  • DirtyMode는 긴 커널 ROP를 피하려는 마무리 전략이에요. 커널 안에서 모든 일을 끝내려면 gadget도 많이 필요하고 실패 지점도 늘어나요. 대신 sysctl mode 비트 하나를 바꿔 사용자 공간에서 core_pattern을 조작하면, 짧은 커널 체인으로 루트 권한 상승을 완성할 수 있어요.

이 글이 무서운 건 ‘복잡한 커널 버그’라서가 아니라, 기본 설정에서 15년 동안 살아남은 취약점이 아주 현실적인 공격 체인으로 정리됐다는 점임. 컨테이너 격리를 커널 보안과 별개로 생각하면 안 된다는 얘기를 꽤 세게 해주는 사례다.

댓글

댓글

댓글을 불러오는 중...

security

크로미움 148부터 Math.tanh 한 번으로 운영체제 지문이 새는 문제

크로미움 148 이후 V8이 Math.tanh 계산을 자체 구현 대신 운영체제의 수학 라이브러리에 맡기면서, 같은 입력값도 리눅스·맥·윈도우에서 마지막 비트가 달라지는 지문 신호가 생겼다. 이 차이는 User-Agent로 맥이라고 주장하면서 리눅스 수학 결과를 내는 식의 위장을 바로 들키게 만든다. CSS 삼각함수와 웹 오디오까지 보면 브라우저 수학 경로가 꽤 복잡하게 갈라지고, 제대로 흉내 내려면 실제 운영체제 라이브러리의 비트 단위 동작까지 맞춰야 한다.

security

출입통제도 클라우드 구독제로 간다…제로트러스트·AI 분석이 승부처

기업 출입보안이 사업장별 서버를 두는 방식에서 클라우드 기반 서비스형 출입통제(ACaaS)로 옮겨가고 있다. 시장은 2026년 17억8000만 달러에서 2030년 31억9000만 달러로 커질 전망이고, 제로트러스트·모바일 인증·AI 출입 분석·스마트빌딩 통합이 핵심 경쟁 포인트로 꼽힌다.

security

AWS·구글 클라우드, 양자컴퓨터 대비해 암호 체계 갈아엎는 중

AWS와 구글 클라우드가 양자컴퓨터 시대를 대비해 기존 공개키 암호와 양자내성암호를 함께 쓰는 하이브리드 전환을 시작했다. 핵심 배경은 지금 훔친 암호문을 나중에 양자컴퓨터로 푸는 ‘선수집·후해독’ 공격이고, 국내도 통신·금융·국방 등 5개 분야에 45억원을 투입해 실증에 들어간다.

security

보안 점검 맡긴 AI 에이전트가 악성코드를 직접 실행할 수 있다는 경고

AI 보안 에이전트가 저장소를 검사하다가 README 같은 문서에 숨은 프롬프트 인젝션에 속아 악성 바이너리를 실행할 수 있다는 연구가 나왔다. 클로드 코드와 코덱스의 자동 모드처럼 승인 없이 명령을 수행하는 구성에서 문제가 재현됐고, 여러 모델과 공급업체를 가로질러 같은 패턴이 통했다는 점이 핵심이다.

security

KT, AI·클라우드 시대 보안 자문위 띄웠다…제로트러스트와 침해 대응 정조준

KT가 AI와 클라우드 전환에 맞춰 정보보호 자문위원회를 출범했다. 외부 전문가들이 AI 기반 공격, 생성형 AI 악용, 제로트러스트, 클라우드 보안, 침해사고 대응, 컴플라이언스까지 전사 보안 전략을 자문하는 구조다.