Heartbleed漏洞是openssl的一个漏洞,这个严重漏洞(CVE-2014-0160)的产生是由于未能在memcpy()调用受害用户输入内容作为长度参数之前正确进行边界检查。攻击者可以追踪OpenSSL所分配的64KB缓存、将超出必要范围的字节信息复制到缓存当中再返回缓存内容,这样一来受害者的内存内容就会以每次64KB的速度进行泄露。
SSL(安全套接层)协议是使用最为普遍网站加密技术,而OpenSSL则是开源的 SSL 套件,为全球成千上万的web服务器所使用。Web服务器正是通过它来将密钥发送给访客然后在双方的连接之间对信息进行加密。URL中使用 https打头的连接都采用了SSL加密技术。在线购物、网银等活动均采用SSL技术来防止窃密及避免中间人攻击。
Heartbleed漏洞之所以得名,是因为用于安全传输层协议(TLS)及数据包传输层安全协议(DTLS)的 Heartbeat扩展存在漏洞。Heartbeat扩展为TLS/DTLS提供了一种新的简便的连接保持方式,但由于OpenSSL 1.0.2-beta与OpenSSL 1.0.1在处理TLS heartbeat扩展时的边界错误,攻击者可以利用漏洞披露连接的客户端或服务器的存储器内容,导致攻击者不仅可以读取其中机密的加密数据,还能盗走用于加密的密钥。
通过读取网络服务器内存,攻击者可以访问敏感数据,从而危及服务器及用户的安全。敏感的安全数据,如服务器的专用主密钥,可使攻击者在服务器和客户端未使用完全正向保密时,通过被动中间人攻击解密当前的或已存储的传输数据,或在通信方使用完全正向保密的情况下,发动主动中间人攻击。
漏洞还可能暴露其他用户的敏感请求和响应,包括用户任何形式的POST请求数据,会话cookie和密码,这能使攻击者可以劫持其他用户的服务身份。在其披露时,约有17%或五十万通过认证机构认证的互联网安全网络服务器被认为容易受到攻击。
漏洞让特定版本的openSSL成为无需钥匙即可开启的“废锁”,入侵者每次可以翻检户主的64K信息,只要有足够的耐心和时间,就可以翻检足够多的数据,拼凑出户主的银行密码、私信等敏感数据。
问题出heartbeat扩展,在源码d1_both.c中,进入openssl源码目录,找到该源码,找到以下代码:
开始我们得到指针p,指向一条SSLv3记录中的数据。结构体SSL3_RECORD的定义如下:
如上图所示,SSLv3记录的第一个字节标明了心跳包的类型。看下图,宏n2s从指针p指向的数组中取出前两个字节,并把它们存入变量payload中——这实际上是心跳包载荷的长度域(length)。注意程序并没有检查这条SSLv3记录的实际长度。变量pl则指向由访问者提供的心跳包数据。
如下图,接下来,程序将分配一段由访问者指定大小的内存区域,这段内存区域最大为 (65535 + 1 + 2 + 16) 个字节。变量bp是用来访问这段内存区域的指针。
宏s2n与宏n2s干的事情正好相反:s2n读入一个16 bit长的值,然后将它存成双字节值,所以s2n会将与请求的心跳包载荷长度相同的长度值存入变量payload。然后程序从pl处开始复制payload个字节到新分配的bp数组中——pl指向了用户提供的心跳包数据。最后,程序将所有数据发回给用户。
Bug出在用户可以控制变量payload和pl。直接影响在s2n代码下面的memcpy函数——如果用户并没有在心跳包中提供足够多的数据,比如pl指向的数据实际上只有一个字节,那么memcpy会把这条SSLv3记录之后的数据(长度为payload)——无论那些数据是什么——都复制出来。
下载受到该漏洞影响的openssl版本,我选择的是openssl-1.0.1b。
wget http://www.openssl.org/source/openssl-1.0.1b.tar.gz
--prefix:安装路径,
shared 是为了生成动态共享库,用来替换系统在的openssl共享库(主要是libssl.so和libcrypto.so 文件),这个非常关键,不使用的话虽然安装了漏洞版的openssl,但是最后发现Linux内核的openssl的版本仍然没有被替换,导致实验失败,因此该实验一定要保证内核版本也是openssl漏洞版本。
执行rm -f /usr/bin/pod2man,再执行make install即可
/usr/local/openssl/lib
在/etc/profile的最后一行,添加:
export OPENSSL=/usr/local/ssl/bin
export PATH=$OPENSSL:$PATH:$HOME/bin
mv /usr/bin/ssl /usr/bin/openssl.old
mv /usr/include/ssl /usr/include/openssl.old
ln -s /usr/local/ssl/bin/openssl /usr/bin/openssl
ln -s /usr/local/ssl/include/openssl /usr/include/openssl
ln -sf /usr/local/ssl/lib/libcrypto.so.1.0.0 /lib/libcrypto.so.6
echo "/usr/local/ssl/lib" >>/etc/ld.so.conf
ldconfig -v
显示openssl-1.0.1b表示安装成功
创建apr的安装目录:mkdir /usr/local/apr
创建apr-util的安装目录:mkdir /usr/local/apr-util
cd /httpd-2.2.34/srclib/apr
安装apr至/usr/local/apr:./configure --prefix=/usr/local/apr && make && make install
安装至/usr/local/apr-util:./configure --prefix=/usr/local/apr-util/ --with-apr=/usr/local/apr && make && make install
安装apache2至/usr/local/httpd:./configure --prefix=/usr/local/httpd --enable-so --enable-rewrite --enable-ssl --with-ssl=/usr/local/ssl --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr-util && make && make install
确定是443端口:
SSL密钥的存放位置,需要把对应的两个server文件放在对应的目录,这里选择不修改,直接把server.crt和server.key放在/usr/local/httpd/conf/里:
DocumentRoot为要访问的页面的位置,如index.html 文件位置
首先,生成2048位的加密私钥:openssl genrsa -out server.key 2048
然后,生成证书签名请求(CSR),这里需要填写许多信息,如国家,省市,公司等:openssl req -new -key server.key -out server.csr(“.“表示为空)
最后,生成类型为X509的自签名证书。有效期设置365天,即有效期为1年:
openssl x509 -req -days 3650 -in server.csr -signkey server.key -out s
./apachectl start
将网上的POC文件保存为sqltest.py,发送到127.0.0.1,得到回复:
(1)POC程序首先发送向OpenSSl服务端程序发送“hello”数据包。
(2)收到反馈信息后证明服务端开启并且连接正常。
(3)向服务端发送经修改过的心跳包。
(4)接收服务端返回的数据,并解析出心跳包中的三个变量(分别为SSL3_RECORD结构体中的type、length、data)。
(5)判断type类型变量的值,是否为空,如果为空则服务端未返回数据,判断为没有该漏洞;如果为21则判断服务器报错,判断为没有漏洞;如果为24则心跳包正常,继续判断返回数据长度是否大于3,如果大于3则说明返回了大量服务端越界访问的内存数据,判定为存在该漏洞。
心跳包的构造大致如下:
第二行01表示请求方向,40 00表示响应包的长度,占2个字节。此次dump 16 kb内存,如果将40 00 改为ff ff 可以dump 64 kb 内存
发现heartbleed bug: