flawopen.com/Teardowns/cve-2014-0160-heartbleed
CVE-2014-0160: OpenSSL Heartbleed 메모리 유출
CVE-2014-0160은 OpenSSL이 레코드에 없는 페이로드 길이를 신뢰할 때 TLS 또는 DTLS 피어가 Heartbeat 레코드 뒤에서 최대 64KiB를 읽게 했습니다. 업스트림 수정은 페이로드를 파싱하고 되돌려 보내기 전에 레코드를 검증합니다.[1], [2]
몇 단어만 적힌 카드를 받은 직원이 훨씬 긴 복사본을 만들라는 라벨을 믿는 상황을 떠올려 보십시오. 카드 끝에서 멈추지 않고 공동 트레이에 이어지는 글까지 복사합니다. Heartbleed는 OpenSSL이 수신한 레코드 경계를 넘어 읽게 했으며, 노출되는 바이트는 프로세스 메모리 내용에 따라 달랐습니다.[1], [3]
핵심 개념 및 용어
TLS/DTLS Heartbeat (RFC 6520)- TLS 또는 DTLS의 연결 유지 메시지입니다. 요청에는 피어가 그대로 돌려보내는 페이로드와 프로토콜에서 요구하는 패딩이 포함됩니다.[3]
payload_length- Heartbeat 페이로드 크기를 나타내는 16비트 필드입니다. 메시지 유형, 길이 필드, 최소 패딩 뒤에 수신 레코드 안에 들어가야 합니다.[1], [3]
버퍼 오버리드 (CWE-126)- 의도한 소스 버퍼의 끝을 넘어 읽는 것입니다. Heartbleed 응답은 메모리 내용에 따라 프로세스 메모리를 최대 64KiB까지 노출할 수 있었습니다.[5]
프레임워크 매핑
- 이 가이드에서 설명하는 약점의 CWE 참조: CWE-126
- CISA KEV — 추가일 2022-05-04 — CVE-2014-0160
근본 원인 분석 (Root Cause)
tls1_process_heartbeat()와 dtls1_process_heartbeat()는 Heartbeat 메시지의 16비트 페이로드 길이를 읽고 응답 경로에서 이를 memcpy()에 전달했지만, s->s3->rrec.length 안에 해당 페이로드 바이트가 실제로 있는지 확인하지 않았습니다. 피어는 TLS 또는 DTLS 레코드가 담은 것보다 더 긴 길이를 선언할 수 있었습니다. 그러면 OpenSSL이 수신 레코드 뒤의 바이트까지 되돌려 보내 최대 64KiB의 프로세스 메모리를 노출할 수 있었습니다. 내용은 메모리 상태에 따라 달라 특정 키, 비밀번호 또는 쿠키가 반드시 포함되지는 않습니다. 업스트림 커밋 96db902는 먼저 유형, 길이 필드, 최소 패딩을 담기에 너무 짧은 레코드를 거부한 뒤 1 + 2 + payload + 16을 수신 레코드 길이와 비교합니다. 또한 SSL3_RT_MAX_PLAIN_LENGTH로 응답을 제한하고 계산한 write_length를 사용합니다. TLS와 DTLS 핸들러 모두에 같은 검사가 적용되었습니다.[1], [2], [3], [4]
단계별 공격 실행 흐름
소스 코드 비교: 취약한 구현 vs 보안 패치
이 코드는 OpenSSL 업스트림 변경에서 발췌한 것으로 단독 실행 프로그램이 아닙니다. 취약 코드는 고정 헤더와 최소 패딩이 있는지 확인하기 전에 필드를 파싱한 다음 피어가 선언한 페이로드 길이를 복사합니다. 수정은 파싱 전에 레코드 최소 길이를 검사하고, 선언된 페이로드를 수신 레코드와 대조하며, 응답 길이를 제한합니다. OpenSSL은 tls1_process_heartbeat()와 dtls1_process_heartbeat()에 대응하는 변경을 적용했습니다.[2], [1]
소스 코드 발췌: ssl/t1_lib.c
/* 수정 전 tls1_process_heartbeat()의 일부입니다. */
hbtype = *p++;
n2s(p, payload);
pl = p;
/* TLS1_HB_REQUEST 응답 경로에서: */
memcpy(bp, pl, payload);
r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT,
buffer, 3 + payload + padding);
/* 타입, 길이, 최소 패딩을 담기에 너무 짧은 레코드는 거부합니다. */
if (1 + 2 + 16 > s->s3->rrec.length)
return 0;
hbtype = *p++;
n2s(p, payload);
if (1 + 2 + payload + 16 > s->s3->rrec.length)
return 0;
pl = p;
/* TLS1_HB_REQUEST 응답 경로에서: */
unsigned int write_length = 1 + 2 + payload + padding;
if (write_length > SSL3_RT_MAX_PLAIN_LENGTH)
return 0;
buffer = OPENSSL_malloc(write_length);
memcpy(bp, pl, payload);
r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, write_length);
사고 타임라인
엔지니어링 및 시스템 보안 강화 체크리스트
- ✓수정이 포함된 공급업체 지원 OpenSSL 릴리스로 업그레이드하세요. 업스트림은 1.0.1g와 1.0.2-beta2에서 수정했습니다. 표시 버전만 보지 말고 배포판 백포트를 확인하세요.[1], [2]
- ✓노출되었을 수 있는 엔드포인트의 TLS 개인 키와 인증서를 교체하고, 유출 가능성이 있으면 기존 인증서를 폐기하세요. 신뢰할 수 없는 Heartbeat를 처리한 클라이언트도 포함합니다.[6]
- ✓취약한 서비스를 패치한 뒤 프로세스 메모리에 있었을 가능성이 있는 자격 증명을 교체하세요. 사용자 비밀번호는 서비스 담당자가 수정 완료를 확인한 후에만 변경하세요.[6], [8]
- ✓TLS 및 DTLS 핸들러를 레코드 경계에서 테스트하세요. 고정 헤더 부족, 수신 바이트를 초과하는 페이로드 길이, 최소 패딩을 갖춘 유효 요청을 포함합니다.[2], [3]
- ✓Heartbeat가 필요 없고 호환성이 허용하면 OpenSSL 권고의 대체 완화책인
-DOPENSSL_NO_HEARTBEATS로 다시 빌드하세요.[1]
출처
- OpenSSL Security Advisory — TLS heartbeat read overrun (CVE-2014-0160)
- OpenSSL upstream fix — commit 96db902
- RFC 6520 — TLS and DTLS Heartbeat Extension
- NVD — CVE-2014-0160
- MITRE CWE-126 — Buffer Over-read
- Codenomicon / Heartbleed.com — The Heartbleed Bug
- CVE Program — CVE-2014-0160
- CISA — “Heartbleed” OpenSSL Vulnerability