Paulos Yibelo, jailer 없이 실행한 Firecracker의 vCPU 스레드 제어 시연
PWN Research의 Paulos Yibelo는 CVE-2026-99999로 얻은 호스트 메모리 접근을 Firecracker v1.16.1의 활성 vCPU 스레드 제어로 연결했다고 보고했습니다. 게스트의 직렬 포트 쓰기를 계기로 Firecracker가 stderr에 8바이트 표식을 출력하게 했으며, 실험은 jailer 없이 root로 직접 실행한 설정에서 이뤄졌습니다.

PWN Research의 Paulos Yibelo는 PwnEscape 후속 글에서 Linux 취약점 CVE-2026-99999로 확보한 호스트 메모리 접근을 이용해 Firecracker microVM의 호스트 프로세스에서 활성 vCPU 스레드가 KVM_RUN에서 복귀할 때 실행할 코드와 인수를 바꿨다고 보고했습니다. 앞선 글은 자체 KVM 시험 환경에서 이 메모리 접근을 선택적 커널 메모리 쓰기와 호스트 root 권한 코드 실행까지 확장한 사례를 다뤘습니다. 이번 글은 그 접근을 Firecracker v1.16.1의 실행 흐름 제어로 연결했습니다.
앞선 글에서 설명한 취약점은 호스트 Linux 네트워킹 경로에서 발생합니다. 게스트가 전달한 체크섬 오프로드 메타데이터는 커널이 체크섬을 나중에 계산하면서 쓸 위치를 지정합니다. IPv4 패킷을 먼저 파싱한 뒤 체크섬 계산이 헤더를 덮어쓰면, 후속 조각화 처리는 변경된 IPv4 헤더 길이 필드를 기준으로 동작합니다. 연구진의 사례에서는 조각화가 패킷의 논리적 데이터 범위를 넘은 호스트 메모리를 IPv4 옵션으로 취급해 네트워크로 내보냈습니다. Linux 커널 수정 커밋은 체크섬을 완료하기 전에 체크섬 시작 위치가 IPv4 헤더 끝보다 앞서지 않는지 확인하도록 했습니다.
Firecracker는 microVM 하나마다 호스트 프로세스 하나를 두고, vCPU마다 KVM_RUN을 수행하는 스레드를 둡니다. vCPU 스레드는 게스트를 실행하기 위해 KVM에 들어갔다가 사용자 공간 처리가 필요해 KVM_RUN에서 나오면 Firecracker 코드로 복귀합니다. 이때 커널은 pt_regs에 사용자 레지스터 상태를 저장합니다. 여기에는 복귀할 명령 위치와 스택 포인터가 들어 있어, 호스트 메모리 접근으로 저장 상태를 바꾸면 다음 복귀 때 실행할 코드와 전달할 인수를 바꿀 수 있습니다.
연구진은 게스트에서 제어할 수 있는 페이지에 고유 표식(nonce)을 기록하고, 게스트 물리 주소에서 호스트 물리 주소로 이어지는 EPT 변환을 찾아 해당 페이지를 호스트 메모리에서 식별했습니다. 이어 그 페이지를 매핑한 호스트 주소 공간을 역추적하고, 알려진 바이트 패턴을 대조해 Firecracker 바이너리와 적재 위치를 확인했습니다. 마지막으로 시스템 호출이 활성 ioctl인지, 요청이 KVM_RUN인지, 복귀 명령 위치와 파일 디스크립터, 스택 포인터가 해당 프로세스와 맞는지 대조해 현재 VM의 vCPU 스레드에 속한 pt_regs 프레임을 골랐습니다. 복귀 주소 하나만 일치하는 오래된 스택 내용을 후보에서 제외하기 위해 여러 조건을 확인했다고 연구진은 설명했습니다.
연구진이 구성한 동작은 Firecracker 프로세스의 stderr에 표식을 쓰는 것이었습니다. 저장된 복귀 위치를 Firecracker의 write(2) 래퍼로 바꾸고, 인수로 stderr의 파일 디스크립터 2와 프로세스 스택에 둔 문자열 주소, 길이 8을 설정했습니다. 스택에는 호출이 끝난 뒤 원래 KVM_RUN 복귀 지점으로 이어질 임시 경로도 배치했습니다. write가 8을 반환하면 성공한 KVM_RUN이 돌려주는 0과 달라지므로, 연구진은 복귀 경로에 반환값을 0으로 바꾸는 명령을 넣었습니다.
게스트가 직렬 포트에 한 바이트를 쓰자 vCPU 스레드가 KVM_RUN에서 빠져나왔고, 커널은 수정된 레지스터 상태를 복원했습니다. Firecracker는 지정된 문자열을 stderr에 쓴 뒤 원래 복귀 경로로 돌아갔습니다. 호스트 캡처에는 표식과 줄바꿈을 포함해 8바이트가 기록됐습니다. Firecracker 프로세스는 계속 실행됐고 게스트의 SSH 연결도 응답했으며, 연구진은 실행 뒤 임시로 바꾼 스택 내용도 복구했다고 보고했습니다.
실험 대상은 x86-64의 Firecracker v1.16.1, 호스트 커널 7.0.0-1011-aws, 게스트 커널 6.18.44+였습니다. 연구진은 Firecracker를 systemd-run 아래 root로 직접 실행했고 jailer는 사용하지 않았습니다. 따라서 시연에서 선택한 호출은 root로 실행한 Firecracker 프로세스의 권한으로 수행됐습니다. Firecracker 설계 문서는 seccomp 필터가 기본 적용된다고 설명하며, 권한 강등과 cgroup·namespace·chroot 설정에는 jailer를 권고합니다. 연구진은 VMM을 장악한 뒤 이용할 수 있는 권한과 자원이 배포 설정에 따라 달라진다고 밝혔습니다. 다른 호출로 확장하려면 해당 프로세스의 메모리 매핑과 시스템 호출 정책에 맞는 코드와 인수를 골라야 한다고도 설명했습니다.