HeartBleed 지용빈
목차 1) 개요 -------------------------------------------------- 2) HTTPS & SSL---------------------------------------- 3) HeartBleed 란?--------------------------------------- 4) HeartBleed 의원리 ---------------------------------- 5) 소스코드 --------------------------------------------- 6) 실습 -------------------------------------------------- 7) 대응방안 --------------------------------------------- 2
1. 개요 이문서는 2014년 4월에발표된 CVE-2014-0160 통칭 'HeartBleed' 취약점에대한실습과원리에대해서술한문서로서이해를돕기위해 PPT와같이제작되었습니다. 사실영어문서찾다가지쳐서필자가만듬. HeartBleed 취약점을웹에서점검할수있도록 https://filippo.io/heartbleed/ 에서취약점점검을할수있습니다. 또한 http://heartbleed.com/ 에서별도로정보를제공하고있습니다. 2. HTTPS & SSL 일반적인 HTTP 는 80번포트를이용하여통신을하게됩니다. 그러나 HTTP 는암호화가되어있지않기때문에보안에있어서는좀더취약합니다. 그래서보안이좀더요구되는인터넷뱅킹같은업무를할때는 HTTPS 가사용됩니다. HTTPS 란일반적인 HTTP 통신을 SSL이란암호화프로토콜로암호화한것입니다. SSL(Secure Socket Layer) 중에서가장널리쓰이는것은 OpenSSL이란암호화방식으로오픈소스환경에서개발되었습니다. SSL의정식적인이름은 TLS(Transport Layer Security) 로서 Server와 Client 사이의통신보안을위한프로토콜로서개발되었습니다. 3. HeartBleed 란? HeartBleed 란이름이붙은이유는이취약점이 OpenSSL의 TLS/DTLS HeartBeat Extension 코드에서문제가발생하였는데처음 HeartBleed 를발표한회사인 Codenomicon 에서피를흘리는하트모양의이미지를처음으로사용해서입니다. HeartBleed 는 OpenSSL 1.0.1 ~ 1.0.1f 그리고 1.0.2-beta1 버전에서발견된취약점으로 OpenSSL에서 TLS/DTLS 구현이미숙한점을이용한것으로 HeartBeat 프로토콜의패킷조작만으로 Sever의메모리에서최대 64kb의민감한정보를누출시킬수있습니다. 현재취약한버전을탑재한운영체제의목록입니다. Debian Wheezy (stable), OpenSSL 1.0.1e-2+deb7u4 Ubuntu 12.04.4 LTS, OpenSSL 1.0.1-4ubuntu5.11 CentOS 6.5, OpenSSL 1.0.1e-15 Fedora 18, OpenSSL 1.0.1e-4 OpenBSD 5.3 (OpenSSL 1.0.1c 10 May 2012) & 5.4 (OpenSSL 1.0.1c 10 May 2012) FreeBSD 10.0 - OpenSSL 1.0.1e 11 Feb 2013 NetBSD 5.0.2 (OpenSSL 1.0.1e) OpenSUSE 12.2 (OpenSSL 1.0.1c) 3
4. HeartBleed 의원리 HeartBleed 취약점은 TLS extension Library 인 HeartBeat 프로토콜에서발견되었습니다. HeartBeat 프로토콜은 Server와 Client의연결을유지하기위해일정신호를주고받는 OpenSSL 확장프로토콜입니다. 이렇게 Client가 HeartBeat Request 를 Server 에날리게되면 Server는 Client에게 HeartBeat Response 를날리게됩니다. 이 HeartBeat 프로토콜의 Packet 을뜯어보면이렇게 4가지구조를이루고있습니다. 4
먼저 Type은날아온패킷이 Response 인지 Request 인지를판단하는정보가들어있습니다. payload_length 에는 payload 의길이값이들어있고 payload 에는가변적인길이의문자열이들어가게됩니다. padding 에는 16Byte 의랜덤문자열이들어가게됩니다. 그리고이렇게날아온 Request 와 Response 패킷은 payload_length 와 payload 의값과길이가같아야지만이서로살아있다고판단하고연결을유지하게됩니다. 이게 HeartBeat 프로토콜의기본적인원리입니다. HearBeat Request 의데이터구조체입니다. 5. Source Code 문제가된 HeartBeat 프로토콜의핵심코드입니다. 설명을위하여빨간색으로주석을달아놓았습니다. #ifndef OPENSSL_NO_HEARTBEATS int tls1_process_heartbeat(ssl *s). unsigned char *p = &s->s3->rrec.data[0], *pl; unsigned short hbtype; unsigned int payload; unsigned int padding = 16; /* Use minimum padding */ /* Read type and payload length first * HeartBeatRequest 구조체선언 5
hbtype = *p++; n2s(p, payload); Request 패킷의데이터에서 payload의길이만큼저장 pl = p; if (s->msg_callback) s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT, &s->s3->rrec.data[0], s->s3->rrec.length, s, s->msg_callback_arg); if (hbtype == TLS1_HB_REQUEST) unsigned char *buffer, *bp; int r; /* Allocate memory for the response, size is 1 bytes * message type, plus 2 bytes payload length, plus * payload, plus padding */ buffer = OPENSSL_malloc(1 + 2 + payload + padding); bp = buffer; /* Enter response type, length and copy payload */ *bp++ = TLS1_HB_RESPONSE; Response 패킷의크기만큼메모리를확보합니다. s2n(payload, bp); memcpy(bp, pl, payload); 이때 memcpy라는함수가문제를일으켰습니다. 바로 payload 의실제크기를비교하지않는다는점입니다. 만약 hello라는 payload 가서버의메모리상에저장되있을때 length값은 5byte 여야합니다. 근데만약 length값을 10byte 라고속이게된다면서버의메모리상에서 hello라는 5byte 외에도서버의메모리에있는나머지 5byte 의정보를전송하게됩니다. bp += payload; /* Random padding */ RAND_pseudo_bytes(bp, padding); r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding); 6
정상적인 HeartBeat 프로토콜의구조입니다. HeartBleed 공격의원리입니다. 7
이렇게유출된정보는중에는서버의민감정보들이포함될가능성이있습니다. 실제로야후는 HeartBleed 취약점발표직후에실제한해커에게공격을당해한사용자의아이디와패 스워드가노출되는것이확인되었습니다. 6. 실습환경 Ubuntu 12.04 OpenSSL 1.0.1 CVE-2014-0160 https://github.com/sensepost/heartbleed-poc 취약한 OpenSSL 버전이탑재된 Ubuntu 12.04 를사용했습니다. SSL 묘듈을설치하기전에먼저웹서버가설치되어야합니다. 8
OpenSSL 을사용하기위해서는먼저인증서를발급해야합니다. 먼저 SSL 모듈을추가합니다. root@tempus:/home/tempus# a2enmod ssl root@tempus:/home/tempus# service apache2 restart root@tempus:/home/tempus# mkdir /etc/apache2/ssl 그리고 SSL 인증서를발급합니다. root@tempus:/etc/apache2/ssl# openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/apache2/ssl/webserver.key -out /etc/apache2/ssl/webserver.crt Generating a 2048 bit RSA private key...+++...+++ writing new private key to '/etc/apache2/ssl/webserver.key' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:KO State or Province Name (full name) [Some-State]:Seoul Locality Name (eg, city) []:Seoul Organization Name (eg, company) [Internet Widgits Pty Ltd]:Tempus 9
Organizational Unit Name (eg, section) []:Education Common Name (e.g. server FQDN or YOUR name) []:Tempus Email Address []:ben3679@naver.com root@tempus:/home/tempus# ifconfig eth0 eth0 Link encap:ethernet HWaddr 00:0c:29:48:ed:58 inet addr:192.168.106.128 Bcast::192.168.27.255 Mask:255.255.255.0 inet6 addr: fe80::20c:29ff:fe48:ed58/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:10289 errors:0 dropped:0 overruns:0 frame:0 TX packets:7061 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:3496929 (3.4 MB) TX bytes:1605943 (1.6 MB) Interrupt:19 Base address:0x2024 설정파일의 ServerName을서버의 IP로설정해주고 root@tempus:/home/tempus# vi /etc/apache2/sites-available/default-ssl 1 <IfModule mod_ssl.c> 2 <VirtualHost _default_:443> 3 ServerAdmin webmaster@localhost 4 ServerName 192.168.106.128 5................. # SSL Engine Switch: 10
44 # Enable/Disable SSL for this virtual host. 45 SSLEngine on 46 47 # A self-signed (snakeoil) certificate can be created by installing 48 # the ssl-cert package. See 49 # /usr/share/doc/apache2.2-common/readme.debian.gz for more info. 50 # If both key and certificate are stored in the same file, only the 51 # SSLCertificateFile directive is needed. 52 SSLCertificateFile /etc/apache2/ssl/webserver.crt 53 SSLCertificateKeyFile /etc/apache2/ssl/webserver.key SSL 인증서가있는디렉토리로바꿔줍니다. root@tempus:/home/tempus# a2ensite default-ssl root@tempus:/home/tempus# service apache2 restart 이제취약한 OpenSSL 1.0.1 버전이탑재된웹서버를완성했습니다. 이화면이뜨면은 I Understand the Risks 를눌러주시면됩니다. 11
설치한환경이 HeartBeat 프로토콜이활성화되어있는지확인합니다. root@tempus:/home/tempus# openssl s_client -connect 192.168.106.128:443 -tlsextdebug -debug -state grep -i heartbeat SSL_connect:before/connect initialization SSL_connect:unknown state TLS server extension "heartbeat" (id=15), len=1 SSL_connect:SSLv3 read server hello A depth=0 C = KO, ST = Seoul, L = Seoul, O = Tempus, OU = Education, CN = Tempus, emailaddress = ben3679@naver.com verify error:num=18:self signed certificate verify return:1 depth=0 C = KO, ST = Seoul, L = Seoul, O = Tempus, OU = Education, CN = Tempus, emailaddress = ben3679@naver.com verify return:1 SSL_connect:SSLv3 read server certificate A 12
SSL_connect:SSLv3 read server key exchange A SSL_connect:SSLv3 read server done A SSL_connect:SSLv3 write client key exchange A SSL_connect:SSLv3 write change cipher spec A SSL_connect:SSLv3 write finished A SSL_connect:SSLv3 flush data SSL_connect:SSLv3 read server session ticket A SSL_connect:SSLv3 read finished A SSL3 alert read:warning:close notify SSL3 alert write:warning:close notify HeartBeat 라는문자열이검색된다면 HeartBeat 프로토콜이활성화되어있는걸확인할수있습니다. GitHub 에공개되어있는 CVE-2014-0160 POC 코드를이용하여서버에테스트를합니다. root@tempus:/home/tempus/ 바탕화면 /CVE-2014-0160-master# python heartbleed-poc.py -n10 -f dump 192.168.106.129 위처럼서버의메모리내에있는정보가유출되고있다는걸확인할수있습니다. 13
7. 대응방안 HeartBleed 취약점을방지하려면 OpenSSL 을 1.0.1g 이상버전으로업데이트를해줘야합니다. Centos/Fedora 계열 yum update sudo pacman -Syu Ubuntu 계열 sudo apt-get update sudo apt-get dist-upgrade sudo apt-get install --only-upgrade openssl sudo apt-get install --only-upgrade libssl1.0.0 14