📄 spp_ssl.c
字号:
/*** Copyright (C) 2007-2008 Sourcefire, Inc.**** This program is free software; you can redistribute it and/or modify** it under the terms of the GNU General Public License Version 2 as** published by the Free Software Foundation. You may not use, modify or** distribute this program under any other version of the GNU General** Public License.**** This program is distributed in the hope that it will be useful,** but WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the** GNU General Public License for more details.**** You should have received a copy of the GNU General Public License** along with this program; if not, write to the Free Software** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*//* * Adam Keeton * SSLPP Preprocessor * 10/10/07 **/#ifdef HAVE_CONFIG_H#include "config.h"#endif /* HAVE_CONFIG_H */#include "sf_snort_packet.h"#include "sf_dynamic_preprocessor.h"#include "sf_snort_plugin_api.h"#include "debug.h"#include "preprocids.h"#include "spp_ssl.h"#include <stdio.h>#include <syslog.h>#include <string.h>#ifndef WIN32#include <strings.h>#include <sys/time.h>#endif#include <stdlib.h>#include <ctype.h>#include "profiler.h"#ifdef PERF_PROFILINGPreprocStats sslpp_perf_stats;#endif#define GENERATOR_SPP_SSLPP 133/* Ultimately calls SnortEventqAdd *//* Arguments are: gid, sid, rev, classification, priority, message, rule_info */#define ALERT(x,y) { _dpd.alertAdd(GENERATOR_SPP_SSLPP, x, 1, 0, 3, y, 0 ); }/* Wraps disabling detect with incrementing the counter */#define DISABLE_DETECT() { _dpd.disableDetect(packet); counts.disabled++; }extern DynamicPreprocessorData _dpd;static SSLPP_config_t config;static SSLPP_counters_t counts;static void SSL_UpdateCounts(const uint32_t);#if DEBUGstatic void SSL_PrintFlags(uint32_t);#endifstatic INLINE int SSLPP_is_encrypted(u_int32_t ssl_flags, SFSnortPacket *packet) { if (config.flags & SSLPP_TRUSTSERVER_FLAG) { if(ssl_flags & SSL_SAPP_FLAG) return SSLPP_TRUE; } if (SSL_IS_CLEAN(ssl_flags)) { if (((ssl_flags & SSLPP_ENCRYPTED_FLAGS) == SSLPP_ENCRYPTED_FLAGS) || ((ssl_flags & SSLPP_ENCRYPTED_FLAGS2) == SSLPP_ENCRYPTED_FLAGS2)) { counts.completed_hs++; return SSLPP_TRUE; } /* Check if we're either midstream or if packets were missed after the * connection was established */ else if ((_dpd.streamAPI->get_session_flags (packet->stream_session_ptr) & SSNFLAG_MIDSTREAM) || (_dpd.streamAPI->missed_packets(packet->stream_session_ptr, SSN_DIR_BOTH))) { if ((ssl_flags & (SSL_CAPP_FLAG | SSL_SAPP_FLAG)) == (SSL_CAPP_FLAG | SSL_SAPP_FLAG)) { return SSLPP_TRUE; } } } return SSLPP_FALSE;}static INLINE u_int32_t SSLPP_process_alert( u_int32_t ssn_flags, u_int32_t new_flags, SFSnortPacket *packet){ DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Process Alert\n");); ssn_flags |= new_flags; /* Check if we've seen a handshake, that this isn't it, * that the cipher flags is not set, and that we are disabling detection */ if(SSL_IS_HANDSHAKE(ssn_flags) && !SSL_IS_HANDSHAKE(new_flags) && !(new_flags & SSL_CHANGE_CIPHER_FLAG) && (config.flags & SSLPP_DISABLE_FLAG)) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Disabling detect\n");); DISABLE_DETECT(); } /* Need to negate the application flags from the opposing side. */ if(packet->flags & FLAG_FROM_CLIENT) return ssn_flags & ~SSL_SAPP_FLAG; else if(packet->flags & FLAG_FROM_SERVER) return ssn_flags & ~SSL_CAPP_FLAG; return ssn_flags;}static INLINE u_int32_t SSLPP_process_hs(u_int32_t ssl_flags, u_int32_t new_flags){ DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Process Handshake\n");); if(!SSL_BAD_HS(new_flags)) { ssl_flags |= new_flags & (SSL_CLIENT_HELLO_FLAG | SSL_SERVER_HELLO_FLAG | SSL_CLIENT_KEYX_FLAG | SSL_SFINISHED_FLAG); } else { counts.bad_handshakes++; } return ssl_flags;}static INLINE u_int32_t SSLPP_process_app( u_int32_t ssn_flags, u_int32_t new_flags, SFSnortPacket *packet) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Process Application\n");); if(!(config.flags & SSLPP_DISABLE_FLAG)) return ssn_flags | new_flags; if(SSLPP_is_encrypted(ssn_flags | new_flags, packet) ) { ssn_flags |= SSL_ENCRYPTED_FLAG; DEBUG_WRAP(DebugMessage(DEBUG_SSL, "STOPPING INSPECTION (process_app)\n");); _dpd.streamAPI->stop_inspection(packet->stream_session_ptr, packet, SSN_DIR_BOTH, -1, 0); counts.stopped++; } return ssn_flags | new_flags;}static INLINE void SSLPP_process_other( u_int32_t ssn_flags, u_int32_t new_flags, SFSnortPacket *packet) { /* Encrypted SSLv2 will appear unrecognizable. Check if the handshake was * seen and stop inspecting if so. */ /* Check for an existing handshake from both sides */ if((ssn_flags & SSL_VER_SSLV2_FLAG) && SSL_IS_CHELLO(ssn_flags) && SSL_IS_SHELLO(ssn_flags) && (config.flags & SSLPP_DISABLE_FLAG) && !(new_flags & SSL_CHANGE_CIPHER_FLAG)) { ssn_flags |= SSL_ENCRYPTED_FLAG | new_flags; DEBUG_WRAP(DebugMessage(DEBUG_SSL, "STOPPING INSPECTION (process_other)\n");); _dpd.streamAPI->stop_inspection(packet->stream_session_ptr, packet, SSN_DIR_BOTH, -1, 0); } else { counts.unrecognized++; /* Special handling for SSLv2 */ if(new_flags & SSL_VER_SSLV2_FLAG) ssn_flags |= new_flags; if(new_flags & SSL_UNKNOWN_FLAG) ssn_flags |= new_flags;/* The following block is intentionally disabled. *//* If we were unable to decode the packet, and previous packets had been * missed, we will not assume it is encrypted SSLv2. */#if 0 /* More special handling for SSLv2. * If both server-side and client-side data was missed, and it has not * been identified it as TLS, it is possibly encrypted SSLv2. */ if( !(ssn_flags & ( SSL_VER_SSLV3_FLAG | SSL_VER_TLS10_FLAG | SSL_VER_TLS11_FLAG | SSL_VER_TLS12_FLAG)) ) { if(packet->stream_session_ptr && _dpd.streamAPI->missed_packets( packet->stream_session_ptr, SSN_DIR_SERVER) && _dpd.streamAPI->missed_packets( packet->stream_session_ptr, SSN_DIR_CLIENT) ) ssn_flags |= SSL_VER_SSLV2_FLAG; }#endif } /* Still need to set application data here because some of the ssn_flags * flags were cleared in SSL_CLEAR_TEMPORARY_FLAGS */ _dpd.streamAPI->set_application_data(packet->stream_session_ptr, PP_SSL, (void *)(uintptr_t)ssn_flags, NULL);}/* SSL Preprocessor process callback. */static void SSLPP_process(void *raw_packet, void *context){ SFSnortPacket *packet; u_int32_t ssn_flags; u_int32_t new_flags; PROFILE_VARS; PREPROC_PROFILE_START(sslpp_perf_stats); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL Start ================================\n");); packet = (SFSnortPacket*)raw_packet; if(!packet || !packet->payload || !packet->payload_size || !packet->tcp_header || !packet->stream_session_ptr) {#ifdef DEBUG if (packet == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL - Packet is NULL\n");); } if (packet->payload == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL - Packet payload is NULL\n");); } if (packet->payload_size == 0) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL - Packet payload size is 0\n");); } if (packet->tcp_header == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL - Packet is not TCP\n");); } if (packet->stream_session_ptr == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL - No stream session pointer\n");); } DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL - Not inspecting packet\n");); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL End ================================\n"););#endif PREPROC_PROFILE_END(sslpp_perf_stats); return; } /* Make sure the packet is on the right port */ if(!config.ports[ PORT_INDEX(packet->src_port) ] && !config.ports[ PORT_INDEX(packet->dst_port) ]) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL - Not configured for these ports\n");); PREPROC_PROFILE_END(sslpp_perf_stats); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL End ================================\n");); return; }#ifdef DEBUG if (packet->flags & FLAG_FROM_SERVER) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Server packet\n");); } else { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Client packet\n");); } if (packet->flags & FLAG_REBUILT_STREAM) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Packet is rebuilt\n");); }#endif ssn_flags = (u_int32_t)(uintptr_t) _dpd.streamAPI->get_application_data(packet->stream_session_ptr, PP_SSL); /* Flush opposite direction to keep conversation in sync */ if (!(packet->flags & FLAG_REBUILT_STREAM)) { switch (_dpd.streamAPI->get_reassembly_direction(packet->stream_session_ptr)) { case SSN_DIR_SERVER: if (packet->flags & FLAG_FROM_SERVER) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Flushing server side\n");); _dpd.streamAPI->response_flush_stream(packet); } break; case SSN_DIR_CLIENT: if (packet->flags & FLAG_FROM_CLIENT) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Flushing client side\n");); _dpd.streamAPI->response_flush_stream(packet); } break; case SSN_DIR_BOTH: DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Flushing opposite side\n");); _dpd.streamAPI->response_flush_stream(packet); break; case SSN_DIR_NONE: default: break; } } if (packet->flags & FLAG_STREAM_INSERT) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Packet is stream inserted - not inspecting\n");); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL End ================================\n");); return; }#ifdef DEBUG DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Ssn flags before ----------------------\n");); SSL_PrintFlags(ssn_flags); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "---------------------------------------\n"););#endif SSL_CLEAR_TEMPORARY_FLAGS(ssn_flags);#ifdef DEBUG if (packet->payload_size >= 5) { const uint8_t *pkt = packet->payload; DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Five bytes of data: %02x %02x %02x %02x %02x\n", pkt[0], pkt[1], pkt[2], pkt[3], pkt[4]);); } else { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Payload size < 5 bytes");); }#endif new_flags = SSL_decode(packet->payload, packet->payload_size, packet->flags); counts.decoded++;#ifdef DEBUG DEBUG_WRAP(DebugMessage(DEBUG_SSL, "New flags -----------------------------\n");); SSL_PrintFlags(new_flags); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "---------------------------------------\n"););#endif SSL_UpdateCounts(new_flags); /* Note, there can be multiple record types in each SSL packet. * Processing them in this order is intentional. If there is an * Alert, we don't care about the other records */ if(SSL_IS_ALERT(new_flags)) { ssn_flags = SSLPP_process_alert(ssn_flags, new_flags, packet); } else if(SSL_IS_HANDSHAKE(new_flags)) { ssn_flags = SSLPP_process_hs(ssn_flags, new_flags); } else if(SSL_IS_APP(new_flags)) { ssn_flags = SSLPP_process_app(ssn_flags, new_flags, packet); } else { /* Different record type that we don't care about. * Either it's a 'change cipher spec' or we failed to recognize the * record type. Do not update session data */ SSLPP_process_other(ssn_flags, new_flags, packet); /* Application data is updated inside of SSLPP_process_other */ PREPROC_PROFILE_END(sslpp_perf_stats); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL End ================================\n");); return; } ssn_flags |= new_flags;#if DEBUG DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Ssn flags after -----------------------\n");); SSL_PrintFlags(ssn_flags); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "---------------------------------------\n"););#endif _dpd.streamAPI->set_application_data( packet->stream_session_ptr, PP_SSL, (void*)(uintptr_t)ssn_flags, NULL); PREPROC_PROFILE_END(sslpp_perf_stats); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL End ================================\n"););}static void SSL_UpdateCounts(const uint32_t new_flags){ if(new_flags & SSL_CHANGE_CIPHER_FLAG) counts.cipher_change++; if (new_flags & SSL_ALERT_FLAG) counts.alerts++; if (new_flags & SSL_CLIENT_HELLO_FLAG) counts.hs_chello++; if (new_flags & SSL_SERVER_HELLO_FLAG) counts.hs_shello++; if (new_flags & SSL_CERTIFICATE_FLAG) counts.hs_cert++; if (new_flags & SSL_SERVER_KEYX_FLAG) counts.hs_skey++; if (new_flags & SSL_CLIENT_KEYX_FLAG) counts.hs_ckey++; if (new_flags & SSL_SFINISHED_FLAG) counts.hs_finished++; if (new_flags & SSL_HS_SDONE_FLAG) counts.hs_sdone++; if (new_flags & SSL_SAPP_FLAG)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -