Heartbleed (CVE-2014–0160)

쑤욱가앗·2025년 9월 30일

Vulnerability

목록 보기
3/6

Heartbleed는 암호화 통신에 널리 사용되는 오픈소스 라이브러리인 OpenSSL에서 발견된 치명적인 취약점이다. 이 취약점은 OpenSSL의 Heartbeat 확장 모듈에 존재하며, 공격자가 서버 메모리에 저장된 민감한 정보를 무단으로 탈취할 수 있도록 허용한다. 마치 심장(Heart)에서 피가 새어 나오는(Bleed) 것처럼 서버의 중요 정보가 유출된다는 의미에서 Heartbleed라는 이름이 붙었다.

이 취약점은 OpenSSL 1.0.1 버전부터 1.0.1f 버전까지 영향을 미쳤으며, 해당 버전을 사용하는 웹 서버뿐만 아니라 이메일, VPN 등 다양한 서비스가 공격에 노출되었다. 가장 큰 문제는 공격이 발생해도 로그가 남지 않아 피해 사실조차 인지하기 어렵다는 점이다.

Heartbleed 취약점 원인

Heartbleed 취약점의 핵심 원인은 경계 검사(Bounds Check)의 부재이다.

OpenSSL의 확장 규격 중 하나인 Heartbeat는 클라이언트와 서버 간의 연결이 활성화 상태인지 확인하기 위해 주기적으로 간단한 메시지를 주고받는 기능이다.

정상적인 통신 과정은 다음과 같다.
1. 클라이언트는 특정 길이의 데이터(Payload)와 그 길이를 담은 요청 메시지를 서버로 보낸다.
2. 서버는 요청받은 길이만큼의 데이터를 그대로 클라이언트에게 다시 보내 응답한다.

그 결함의 핵심은 서버가 클라이언트가 제시한 데이터의 길이를 전혀 검증하지 않는다는 점이다. 이는 가장 기본적인 보안 원칙인 입력값 검증(Input Validation), 더 구체적으로는 경계 검사(Bounds Check) 로직이 코드 상에서 완전히 누락된 것이다.

공격 시나리오

  1. 공격자는 실제 보낸 데이터의 길이보다 훨씬 큰 값을 길이 필드에 담아 Heartbeat 요청을 보낸다. 예를 들어, 1바이트의 데이터만 보내면서 길이는 65535바이트(64KB)로 조작하여 요청한다.
  2. 취약한 서버는 이 길이 값을 검증하지 않고, 공격자가 요청한 65535바이트만큼의 데이터를 자신의 메모리에서 읽어온다.
  3. 서버는 공격자로부터 받은 1바이트 데이터 뒤에, 자신의 메모리에서 읽어 들인 65534바이트의 데이터를 덧붙여 공격자에게 응답으로 전송한다.

이 과정에서 공격자는 서버 메모리에 저장되어 있던 민감한 정보를 획득하게 된다. 여기에는 SSL 개인 키, 세션 쿠키, 사용자 계정 정보(ID, 비밀번호), 그리고 암호화된 통신 내용까지 포함될 수 있다. 공격자는 이 과정을 반복하여 서버 메모리의 더 많은 영역을 탈취할 수 있다.

Heartbleed 실습

실습을 위해 사전 구축된 취약한 환경을 제공하는 Vulnhub의 Docker 이미지를 사용한다.

먼저 vulhub/openssl/CVE-2014–0160으로 이동하여 아래 명령어로 Docker 컨테이너를 실행한다. 이 컨테이너가 우리의 공격 대상이 된다.

sudo docker-compose up -d

실행된 컨테이너의 IP 주소를 확인해야 공격을 수행할 수 있다. 아래 명령어를 통해 공격 대상의 정확한 IP 주소를 확인한다.

sudo docker-compose ps

sudo docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' cve-2014-0160-nginx-1

이제 공격자 역할을 할 Kali Linux와 공격 대상 서버가 모두 준비되었다. 확인된 IP 주소를 <타겟 IP 주소>로 사용한다.

위에서 확인한 IP 주소를 <타겟 IP 주소>로 사용한다.

Kali Linux의 대표적인 모의 해킹 프레임워크인 Metasploit을 사용하여 Heartbleed 취약점을 확인하고 서버 메모리 정보를 탈취한다.

먼저 msfconsole을 실행하고, Heartbleed 스캐너 모듈을 찾아 공격에 필요한 옵션을 설정한다.

msfconsole
search heartbleed
use auxiliary/scanner/ssl/openssl_heartbleed
show options

RHOSTS 옵션을 앞에서 확인한 Docker 컨테이너의 IP 주소로 설정하고, verbose 옵션을 true로 설정하여 공격 과정의 상세한 로그를 확인한다.

set RHOSTS 172.18.0.2

set verbose true

공격을 실행하기 전, Wireshark를 실행하여 실제 네트워크에서 어떤 데이터가 오고 가는지 직접 확인한다.

sudo wireshark 명령어로 Wireshark를 실행한다. 네트워크 인터페이스는 반드시 Docker 컨테이너와 동일한 네트워크 대역을 사용하는 것을 선택해야 패킷을 정상적으로 캡처할 수 있다.

Metasploit 콘솔에서 run 명령어를 입력하여 공격을 시작한다. Wireshark 화면에는 TCP 3-way handshaking 과정 이후, 비정상적인 Heartbeat 요청 패킷이 전송되는 것이 즉시 나타난다.

이로 인해, 메모리에 있는 65535 bytes가 노출되었음을 볼 수 있다.

Metasploit의 실행 결과와 Wireshark로 캡처한 패킷을 통해 Heartbleed의 동작 원리를 명확하게 확인할 수 있다.

Wireshark로 캡처한 ‘Heartbeat Request’ 패킷을 분석해 보면, 자신의 페이로드(Payload) 길이가 65535바이트라고 주장하는 것을 볼 수 있다. 하지만 실제로는 아무런 데이터도 보내지 않았거나 아주 작은 크기의 데이터를 전송했다.

취약한 서버는 이 거짓된 길이 값을 그대로 신뢰하여 자신의 메모리에서 65535바이트만큼의 데이터를 읽어 공격자에게 전송하려고 시도한다.

Wireshark에서 서버가 보낸 응답 패킷을 확인하면, 실제로 서버 메모리에 저장되어 있던 데이터가 대량으로 전송된 것을 볼 수 있다.

한 가지 흥미로운 점은 공격자는 65535바이트를 요청했지만, 서버의 응답 패킷은 약 16381바이트 정도의 데이터를 담고 있다는 것이다. 이는 TLS 프로토콜의 규격상 하나의 레코드(전송 단위)에 담을 수 있는 데이터의 최대 크기가 16384바이트(16KB)로 제한되어 있기 때문이다. 서버는 공격자의 요청을 모두 이행하기 위해 65535바이트를 메모리에서 읽었지만, 데이터를 보낼 때는 TLS 프로토콜 규칙에 따라 보낼 수 있는 최대 크기로 잘라서 보낸 것이다. 공격자는 이러한 요청을 반복하여 서버의 더 많은 메모리 영역을 계속해서 탈취할 수 있다.

profile
Incident Response

0개의 댓글