00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
00003 // Copyright (C) 2004-2013 Sourcefire, Inc.
00004 //
00005 // This program is free software; you can redistribute it and/or modify it
00006 // under the terms of the GNU General Public License Version 2 as published
00007 // by the Free Software Foundation. You may not use, modify or distribute
00008 // this program under any other version of the GNU General Public License.
00009 //
00010 // This program is distributed in the hope that it will be useful, but
00011 // WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00013 // General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License along
00016 // with this program; if not, write to the Free Software Foundation, Inc.,
00017 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018 //--------------------------------------------------------------------------
00019
00020 /*
00021 * SSH preprocessor
00022 * Author: Chris Sherwin
00023 * Contributors: Adam Keeton, Ryan Jordan
00024 */
00025
00026 #ifdef HAVE_CONFIG_H
00027 #include "config.h"
00028 #endif
00029
00030 #include "ssh.h"
00031
00032 #include "detection/detection_engine.h"
00033 #include "events/event_queue.h"
00034 #include "log/messages.h"
00035 #include "profiler/profiler.h"
00036 #include "protocols/packet.h"
00037 #include "stream/stream.h"
00038
00039 #include "main/snort_debug.h"
00040
00041 #include "ssh_module.h"
00042
00043 THREAD_LOCAL ProfileStats sshPerfStats;
00044 THREAD_LOCAL SshStats sshstats;
00045
00046 /*
00047 * Function prototype(s)
00048 */
00049 static void snort_ssh(SSH_PROTO_CONF* GlobalConf, Packet* p);
00050 static unsigned int ProcessSSHProtocolVersionExchange(SSH_PROTO_CONF*, SSHData*, Packet*, uint8_t);
00051 static unsigned int ProcessSSHKeyExchange(SSHData*, Packet*, uint8_t, unsigned int);
00052 static unsigned int ProcessSSHKeyInitExchange(SSHData*, Packet*, uint8_t, unsigned int);
00053
00054 unsigned SshFlowData::inspector_id = 0;
00055
00056 SshFlowData::SshFlowData() : FlowData(inspector_id)
00057 {
00058 memset(&session, 0, sizeof(session));
00059 sshstats.concurrent_sessions++;
00060 if(sshstats.max_concurrent_sessions < sshstats.concurrent_sessions)
00061 sshstats.max_concurrent_sessions = sshstats.concurrent_sessions;
00062 }
00063
00064 SshFlowData::~SshFlowData()
00065 {
00066 assert(sshstats.concurrent_sessions > 0);
00067 sshstats.concurrent_sessions--;
00068 }
00069
00070 static SSHData* SetNewSSHData(Packet* p)
00071 {
00072 SshFlowData* fd = new SshFlowData;
00073 p->flow->set_flow_data(fd);
00074 return &fd->session;
00075 }
00076
00077 static SSHData* get_session_data(Flow* flow)
00078 {
00079 SshFlowData* fd = (SshFlowData*)flow->get_flow_data(SshFlowData::inspector_id);
00080 return fd ? &fd->session : nullptr;
00081 }
00082
00083 static void PrintSshConf(SSH_PROTO_CONF* config)
00084 {
00085 if ( !config )
00086 return;
00087
00088 LogMessage("SSH config: \n");
00089
00090 LogMessage(" Max Encrypted Packets: %d\n", config->MaxEncryptedPackets);
00091 LogMessage(" Max Server Version String Length: %d\n", config->MaxServerVersionLen);
00092 LogMessage(" MaxClientBytes: %d\n", config->MaxClientBytes);
00093
00094 LogMessage("\n");
00095 }
00096
00097 /* Returns the true length of the ssh packet, including
00098 * the ssh packet header and all padding.
00099 *
00100 * If the packet length is invalid, 0 is returned.
00101 * The return value is never larger than buflen.
00102 *
00103 * PARAMETERS:
00104 * p: Pointer to the SSH packet.
00105 * buflen: the size of packet buffer.
00106 */
00107 static unsigned int SSHPacket_GetLength(const SSH2Packet* p, size_t buflen)
00108 {
00109 unsigned int ssh_length;
00110
00111 if (buflen < sizeof(SSH2Packet))
00112 return 0;
00113
00114 ssh_length = ntohl(p->packet_length);
00115 if ((ssh_length < sizeof(SSH2Packet) + 1) || ssh_length > SSH2_PACKET_MAX_SIZE)
00116 return 0;
00117
00118 /* Everything after packet length field (including padding) is included in the packet_length */
00119 ssh_length += sizeof(p->packet_length);
00120
00121 if (buflen < ssh_length)
00122 return buflen; /* truncated */
00123
00124 return ssh_length;
00125 }
00126
00127 /* Main runtime entry point for SSH preprocessor.
00128 * Analyzes SSH packets for anomalies/exploits.
00129 *
00130 * PARAMETERS:
00131 *
00132 * p: Pointer to current packet to process.
00133 * contextp: Pointer to context block, not used.
00134 *
00135 * RETURNS: Nothing.
00136 */
00137 static void snort_ssh(SSH_PROTO_CONF* config, Packet* p)
00138 {
00139 Profile profile(sshPerfStats);
00140
00141 // Attempt to get a previously allocated SSH block.
00142 SSHData* sessp = get_session_data(p->flow);
00143
00144 if (sessp == nullptr)
00145 {
00146 /* Check the stream session. If it does not currently
00147 * have our SSH data-block attached, create one.
00148 */
00149 sessp = SetNewSSHData(p);
00150
00151 if ( !sessp )
00152 // Could not get/create the session data for this packet.
00153 return;
00154
00155 }
00156
00157 // Don't process if we've missed packets
00158 if (sessp->state_flags & SSH_FLG_MISSED_PACKETS)
00159 return;
00160
00161 // Make sure this preprocessor should run.
00162 // check if we're waiting on stream reassembly
00163 if ( p->packet_flags & PKT_STREAM_INSERT )
00164 return;
00165
00166 // If we picked up mid-stream or missed any packets (midstream pick up
00167 // means we've already missed packets) set missed packets flag and make
00168 // sure we don't do any more reassembly on this session
00169 if ((p->flow->get_session_flags() & SSNFLAG_MIDSTREAM)
00170 || Stream::missed_packets(p->flow, SSN_DIR_BOTH))
00171 {
00172 // Order only matters if the packets are not encrypted
00173 if ( !(sessp->state_flags & SSH_FLG_SESS_ENCRYPTED ))
00174 {
00175 sessp->state_flags |= SSH_FLG_MISSED_PACKETS;
00176 return;
00177 }
00178 }
00179
00180 uint8_t direction;
00181 uint32_t search_dir_ver;
00182 uint32_t search_dir_keyinit;
00183
00184 // Get the direction of the packet.
00185 if ( p->is_from_server() )
00186 {
00187 direction = SSH_DIR_FROM_SERVER;
00188 search_dir_ver = SSH_FLG_SERV_IDSTRING_SEEN;
00189 search_dir_keyinit = SSH_FLG_SERV_PKEY_SEEN | SSH_FLG_SERV_KEXINIT_SEEN;
00190 }
00191 else
00192 {
00193 direction = SSH_DIR_FROM_CLIENT;
00194 search_dir_ver = SSH_FLG_CLIENT_IDSTRING_SEEN;
00195 search_dir_keyinit = SSH_FLG_CLIENT_SKEY_SEEN | SSH_FLG_CLIENT_KEXINIT_SEEN;
00196 }
00197
00198 unsigned int offset = 0;
00199
00200 if ( !(sessp->state_flags & SSH_FLG_SESS_ENCRYPTED ))
00201 {
00202 // If server and client have not performed the protocol
00203 // version exchange yet, must look for version strings.
00204 if ( !(sessp->state_flags & search_dir_ver) )
00205 {
00206 offset = ProcessSSHProtocolVersionExchange(config, sessp, p, direction);
00207 if (!offset)
00208 // Error processing protovers exchange msg
00209 return;
00210
00211 // found protocol version.
00212 // Stream reassembly might have appended an ssh packet,
00213 // such as the key exchange init.
00214 // Thus call ProcessSSHKeyInitExchange() too.
00215 }
00216
00217 // Expecting to see the key init exchange at this point
00218 // (in SSH2) or the actual key exchange if SSH1
00219 if ( !(sessp->state_flags & search_dir_keyinit) )
00220 {
00221 offset = ProcessSSHKeyInitExchange(sessp, p, direction, offset);
00222
00223 if (!offset)
00224 {
00225 if ( !(sessp->state_flags & SSH_FLG_SESS_ENCRYPTED ))
00226 return;
00227 }
00228 }
00229
00230 // If SSH2, need to process the actual key exchange msgs.
00231 // The actual key exchange type was negotiated in the
00232 // key exchange init msgs. SSH1 won't arrive here.
00233 offset = ProcessSSHKeyExchange(sessp, p, direction, offset);
00234 if (!offset)
00235 return;
00236 }
00237
00238 if ( (sessp->state_flags & SSH_FLG_SESS_ENCRYPTED ))
00239 {
00240 // Traffic on this session is currently encrypted.
00241 // Two of the major SSH exploits, SSH1 CRC-32 and
00242 // the Challenge-Response Overflow attack occur within
00243 // the encrypted portion of the SSH session. Therefore,
00244 // the only way to detect these attacks is by examining
00245 // amounts of data exchanged for anomalies.
00246 sessp->num_enc_pkts++;
00247
00248 if ( sessp->num_enc_pkts <= config->MaxEncryptedPackets )
00249 {
00250 if ( direction == SSH_DIR_FROM_CLIENT )
00251 {
00252 if (!offset)
00253 sessp->num_client_bytes += p->dsize;
00254
00255 else
00256 sessp->num_client_bytes += (p->dsize - offset);
00257
00258 if ( sessp->num_client_bytes >= config->MaxClientBytes )
00259 {
00260 // Probable exploit in progress.
00261 if (sessp->version == SSH_VERSION_1)
00262 DetectionEngine::queue_event(GID_SSH, SSH_EVENT_CRC32);
00263
00264 else
00265 DetectionEngine::queue_event(GID_SSH, SSH_EVENT_RESPOVERFLOW);
00266
00267 Stream::stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
00268 }
00269 }
00270
00271 else
00272 {
00273 // Have seen a server response, so this appears to be a valid
00274 // exchange. Reset suspicious byte count to zero
00275 sessp->num_client_bytes = 0;
00276 }
00277 }
00278
00279 else
00280 {
00281 // Have already examined more than the limit
00282 // of encrypted packets. Both the Gobbles and
00283 // the CRC32 attacks occur during authentication
00284 // and therefore cannot be used late in an
00285 // encrypted session. For performance purposes,
00286 // stop examining this session.
00287 Stream::stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
00288 }
00289 }
00290 }
00291
00292 /* Checks if the string 'str' is 'max' bytes long or longer.
00293 * Returns 0 if 'str' is less than or equal to 'max' bytes;
00294 * returns 1 otherwise.
00295 */
00296
00297 static inline int SSHCheckStrlen(const char* str, int max)
00298 {
00299 if ( memchr(str, '\0', max) )
00300 return 0; /* str size is <= max bytes */
00301
00302 return 1;
00303 }
00304
00305 /* Attempts to process current packet as a protocol version exchange
00306 * packet. This function will be called if either the client or server
00307 * protocol version message (or both) has not been sent.
00308 *
00309 * PARAMETERS:
00310 *
00311 * sessionp: Pointer to SSH data for packet's session.
00312 * p: Pointer to the packet to inspect.
00313 * direction: Which direction the packet is going.
00314 *
00315 * RETURNS: offset processed
00316 */
00317 static unsigned int ProcessSSHProtocolVersionExchange(SSH_PROTO_CONF* config, SSHData* sessionp,
00318 Packet* p, uint8_t direction)
00319 {
00320 const char* version_stringp = (const char*)p->data;
00321 uint8_t version;
00322 const char* version_end;
00323
00324 /* Get the version. */
00325 if ( p->dsize >= 6 &&
00326 !strncasecmp(version_stringp, "SSH-1.", 6))
00327 {
00328 if (( p->dsize > 7 ) && ( version_stringp[6] == '9')
00329 && (version_stringp[7] == '9'))
00330 {
00331 /* SSH 1.99 which is the same as SSH2.0 */
00332 version = SSH_VERSION_2;
00333 }
00334 else
00335 {
00336 version = SSH_VERSION_1;
00337 }
00338
00339 /* CAN-2002-0159 */
00340 /* Verify the version string is not greater than
00341 * the configured maximum.
00342 * We've already verified the first 6 bytes, so we'll start
00343 * check from &version_string[6] */
00344 /* First make sure the data itself is sufficiently large */
00345 if ((p->dsize > config->MaxServerVersionLen) &&
00346 /* CheckStrlen will check if the version string up to
00347 * MaxServerVersionLen+1 since there's no reason to
00348 * continue checking after that point*/
00349 (SSHCheckStrlen(&version_stringp[6], config->MaxServerVersionLen-6)))
00350 {
00351 DetectionEngine::queue_event(GID_SSH, SSH_EVENT_SECURECRT);
00352 }
00353 }
00354 else if ( p->dsize >= 6 &&
00355 !strncasecmp(version_stringp, "SSH-2.", 6))
00356 {
00357 version = SSH_VERSION_2;
00358 }
00359 else
00360 {
00361 return 0;
00362 }
00363
00364 /* Saw a valid protocol exchange message. Mark the session
00365 * according to the direction.
00366 */
00367 switch ( direction )
00368 {
00369 case SSH_DIR_FROM_SERVER:
00370 sessionp->state_flags |= SSH_FLG_SERV_IDSTRING_SEEN;
00371 break;
00372 case SSH_DIR_FROM_CLIENT:
00373 sessionp->state_flags |= SSH_FLG_CLIENT_IDSTRING_SEEN;
00374 break;
00375 }
00376
00377 sessionp->version = version;
00378 version_end = (char*)memchr(version_stringp, '\n', p->dsize);
00379 if (version_end)
00380 return ((version_end - version_stringp) + 1);
00381 /* incomplete version string, should end with \n or \r\n for sshv2 */
00382 return p->dsize;
00383 }
00384
00385 /* Called to process SSH1 key exchange or SSH2 key exchange init
00386 * messages. On failure, inspection will be continued, but the packet
00387 * will be alerted on, and ignored.
00388 *
00389 * PARAMETERS:
00390 *
00391 * sessionp: Pointer to SSH data for packet's session.
00392 * p: Pointer to the packet to inspect.
00393 * direction: Which direction the packet is going.
00394 *
00395 * RETURNS: offset processed
00396 */
00397 static unsigned int ProcessSSHKeyInitExchange(SSHData* sessionp, Packet* p,
00398 uint8_t direction, unsigned int offset)
00399 {
00400 const SSH2Packet* ssh2p = nullptr;
00401 uint16_t dsize = p->dsize;
00402 const unsigned char* data = p->data;
00403 unsigned int ssh_length = 0;
00404
00405 if (dsize < sizeof(SSH2Packet) || (dsize < (offset + sizeof(SSH2Packet)))
00406 || (dsize <= offset))
00407 return 0;
00408
00409 dsize -= offset;
00410 data += offset;
00411
00412 if ( sessionp->version == SSH_VERSION_1 )
00413 {
00414 uint32_t length;
00415 uint8_t padding_length;
00416 uint8_t message_type;
00417
00418 /*
00419 * Validate packet data.
00420 * First 4 bytes should have the SSH packet length,
00421 * minus any padding.
00422 */
00423 if ( dsize < 4 )
00424 {
00425 {
00426 DetectionEngine::queue_event(GID_SSH, SSH_EVENT_PAYLOAD_SIZE);
00427 }
00428
00429 return 0;
00430 }
00431
00432 /*
00433 * SSH1 key exchange is very simple and
00434 * consists of only two messages, a server
00435 * key and a client key message.`
00436 */
00437 memcpy(&length, data, sizeof(length));
00438 length = ntohl(length);
00439
00440 /* Packet data should be larger than length, due to padding. */
00441 if ( dsize < length )
00442 {
00443 {
00444 DetectionEngine::queue_event(GID_SSH, SSH_EVENT_PAYLOAD_SIZE);
00445 }
00446
00447 return 0;
00448 }
00449
00450 padding_length = (uint8_t)(8 - (length % 8));
00451
00452 /*
00453 * With the padding calculated, verify data is sufficiently large
00454 * to include the message type.
00455 */
00456 if ( dsize < (padding_length + 4 + 1 + offset))
00457 {
00458 if (offset == 0)
00459 {
00460 DetectionEngine::queue_event(GID_SSH, SSH_EVENT_PAYLOAD_SIZE);
00461 }
00462
00463 return 0;
00464 }
00465
00466 message_type = *( (const uint8_t*)(data + padding_length + 4));
00467
00468 switch ( message_type )
00469 {
00470 case SSH_MSG_V1_SMSG_PUBLIC_KEY:
00471 if ( direction == SSH_DIR_FROM_SERVER )
00472 {
00473 sessionp->state_flags |=
00474 SSH_FLG_SERV_PKEY_SEEN;
00475 }
00476 else
00477 {
00478 /* Server msg not from server. */
00479 DetectionEngine::queue_event(GID_SSH, SSH_EVENT_WRONGDIR);
00480 }
00481 break;
00482 case SSH_MSG_V1_CMSG_SESSION_KEY:
00483 if ( direction == SSH_DIR_FROM_CLIENT )
00484 {
00485 sessionp->state_flags |=
00486 SSH_FLG_CLIENT_SKEY_SEEN;
00487 }
00488 else
00489 {
00490 /* Client msg not from client. */
00491 DetectionEngine::queue_event(GID_SSH, SSH_EVENT_WRONGDIR);
00492 }
00493 break;
00494 default:
00495 /* Invalid msg type*/
00496 break;
00497 }
00498
00499 /* Once the V1 key exchange is done, remainder of
00500 * communications are encrypted.
00501 */
00502 ssh_length = length + padding_length + sizeof(length) + offset;
00503
00504 if ( (sessionp->state_flags & SSH_FLG_V1_KEYEXCH_DONE) ==
00505 SSH_FLG_V1_KEYEXCH_DONE )
00506 {
00507 sessionp->state_flags |= SSH_FLG_SESS_ENCRYPTED;
00508 }
00509 }
00510 else if ( sessionp->version == SSH_VERSION_2 )
00511 {
00512 /* We want to overlay the data on our data packet struct,
00513 * so first verify that the data size is big enough.
00514 * This may legitimately occur such as in the case of a
00515 * retransmission.
00516 */
00517 if ( dsize < sizeof(SSH2Packet) )
00518 {
00519 return 0;
00520 }
00521
00522 /* Overlay the SSH2 binary data packet struct on the packet */
00523 ssh2p = (const SSH2Packet*)data;
00524 if ( dsize < SSH2_HEADERLEN + 1)
00525 {
00526 /* Invalid packet length. */
00527
00528 return 0;
00529 }
00530
00531 ssh_length = offset + ntohl(ssh2p->packet_length) + sizeof(ssh2p->packet_length);
00532
00533 switch ( data[SSH2_HEADERLEN] )
00534 {
00535 case SSH_MSG_KEXINIT:
00536 sessionp->state_flags |=
00537 (direction == SSH_DIR_FROM_SERVER ?
00538 SSH_FLG_SERV_KEXINIT_SEEN :
00539 SSH_FLG_CLIENT_KEXINIT_SEEN );
00540 break;
00541 default:
00542 /* Unrecognized message type. */
00543 break;
00544 }
00545 }
00546 else
00547 {
00548 {
00549 /* Unrecognized version. */
00550 DetectionEngine::queue_event(GID_SSH, SSH_EVENT_VERSION);
00551 }
00552
00553 return 0;
00554 }
00555
00556 if (ssh_length < p->dsize)
00557 return ssh_length;
00558 else
00559 return 0;
00560 }
00561
00562 /* Called to process SSH2 key exchange msgs (key exch init msgs already
00563 * processed earlier). On failure, inspection will be continued, but the
00564 * packet will be alerted on, and ignored.
00565 *
00566 * PARAMETERS:
00567 *
00568 * sessionp: Pointer to SSH data for packet's session.
00569 * p: Pointer to the packet to inspect.
00570 * direction: Which direction the packet is going.
00571 *
00572 * RETURNS: offset processed
00573 */
00574 static unsigned int ProcessSSHKeyExchange(SSHData* sessionp, Packet* p,
00575 uint8_t direction, unsigned int offset)
00576 {
00577 const SSH2Packet* ssh2p = nullptr;
00578 uint16_t dsize = p->dsize;
00579 const unsigned char* data = p->data;
00580 unsigned int ssh_length;
00581 bool next_packet = true;
00582 unsigned int npacket_offset = 0;
00583
00584 if (dsize < sizeof(SSH2Packet) || (dsize < (offset + sizeof(SSH2Packet)))
00585 || (dsize <= offset))
00586 {
00587 return 0;
00588 }
00589
00590 dsize -= offset;
00591 data += offset;
00592
00593 while (next_packet)
00594 {
00595 ssh2p = (const SSH2Packet*)(data + npacket_offset);
00596 ssh_length = SSHPacket_GetLength(ssh2p, dsize);
00597
00598 if (ssh_length == 0)
00599 {
00600 if ( sessionp->state_flags & SSH_FLG_SESS_ENCRYPTED )
00601 {
00602 return ( npacket_offset + offset );
00603 }
00604 {
00605 /* Invalid packet length. */
00606 DetectionEngine::queue_event(GID_SSH, SSH_EVENT_PAYLOAD_SIZE);
00607 }
00608
00609 return 0;
00610 }
00611
00612 switch (data[npacket_offset + SSH2_HEADERLEN] )
00613 {
00614 case SSH_MSG_KEXDH_INIT:
00615 if ( direction == SSH_DIR_FROM_CLIENT )
00616 {
00617 sessionp->state_flags |=
00618 SSH_FLG_KEXDH_INIT_SEEN;
00619 }
00620 else
00621 {
00622 /* Client msg from server. */
00623 DetectionEngine::queue_event(GID_SSH, SSH_EVENT_WRONGDIR);
00624 }
00625 break;
00626 case SSH_MSG_KEXDH_REPLY:
00627 if ( direction == SSH_DIR_FROM_SERVER )
00628 {
00629 /* KEXDH_REPLY has the same msg
00630 * type as the new style GEX_REPLY
00631 */
00632 sessionp->state_flags |=
00633 SSH_FLG_KEXDH_REPLY_SEEN |
00634 SSH_FLG_GEX_REPLY_SEEN;
00635 }
00636 else
00637 {
00638 /* Server msg from client. */
00639 DetectionEngine::queue_event(GID_SSH, SSH_EVENT_WRONGDIR);
00640 }
00641 break;
00642 case SSH_MSG_KEXDH_GEX_REQ:
00643 if ( direction == SSH_DIR_FROM_CLIENT )
00644 {
00645 sessionp->state_flags |=
00646 SSH_FLG_GEX_REQ_SEEN;
00647 }
00648 else
00649 {
00650 /* Server msg from client. */
00651 DetectionEngine::queue_event(GID_SSH, SSH_EVENT_WRONGDIR);
00652 }
00653 break;
00654 case SSH_MSG_KEXDH_GEX_GRP:
00655 if ( direction == SSH_DIR_FROM_SERVER )
00656 {
00657 sessionp->state_flags |=
00658 SSH_FLG_GEX_GRP_SEEN;
00659 }
00660 else
00661 {
00662 /* Client msg from server. */
00663 DetectionEngine::queue_event(GID_SSH, SSH_EVENT_WRONGDIR);
00664 }
00665 break;
00666 case SSH_MSG_KEXDH_GEX_INIT:
00667 if ( direction == SSH_DIR_FROM_CLIENT )
00668 {
00669 sessionp->state_flags |=
00670 SSH_FLG_GEX_INIT_SEEN;
00671 }
00672 else
00673 {
00674 /* Server msg from client. */
00675 DetectionEngine::queue_event(GID_SSH, SSH_EVENT_WRONGDIR);
00676 }
00677 break;
00678 case SSH_MSG_NEWKEYS:
00679 /* This message is required to complete the
00680 * key exchange. Both server and client should
00681 * send one, but as per Alex Kirk's note on this,
00682 * in some implementations the server does not
00683 * actually send this message. So receiving a new
00684 * keys msg from the client is sufficient.
00685 */
00686 if ( direction == SSH_DIR_FROM_CLIENT )
00687 {
00688 sessionp->state_flags |= SSH_FLG_NEWKEYS_SEEN;
00689 }
00690 break;
00691 default:
00692 /* Unrecognized message type. Possibly encrypted */
00693 sessionp->state_flags |= SSH_FLG_SESS_ENCRYPTED;
00694 return ( npacket_offset + offset);
00695 }
00696
00697 /* If either an old-style or new-style Diffie Helman exchange
00698 * has completed, the session will enter encrypted mode.
00699 */
00700 if (( (sessionp->state_flags &
00701 SSH_FLG_V2_DHOLD_DONE) == SSH_FLG_V2_DHOLD_DONE )
00702 || ( (sessionp->state_flags &
00703 SSH_FLG_V2_DHNEW_DONE) == SSH_FLG_V2_DHNEW_DONE ))
00704 {
00705 sessionp->state_flags |= SSH_FLG_SESS_ENCRYPTED;
00706 if (ssh_length < dsize)
00707 {
00708 if ( ssh_length >= 4 )
00709 {
00710 npacket_offset += ssh_length;
00711 dsize -= ssh_length;
00712 continue;
00713 }
00714 return ( npacket_offset + offset );
00715 }
00716 else
00717 return 0;
00718 }
00719
00720 if ((ssh_length < dsize) && (ssh_length >= 4))
00721 {
00722 npacket_offset += ssh_length;
00723 dsize -= ssh_length;
00724 }
00725 else
00726 {
00727 next_packet = false;
00728 npacket_offset = 0;
00729 }
00730 }
00731
00732 return (npacket_offset + offset);
00733 }
00734
00735 //-------------------------------------------------------------------------
00736 // class stuff
00737 //-------------------------------------------------------------------------
00738
00739 class Ssh : public Inspector
00740 {
00741 public:
00742 Ssh(SSH_PROTO_CONF*);
00743 ~Ssh() override;
00744
00745 void show(SnortConfig*) override;
00746 void eval(Packet*) override;
00747
00748 private:
00749 SSH_PROTO_CONF* config;
00750 };
00751
00752 Ssh::Ssh(SSH_PROTO_CONF* pc)
00753 {
00754 config = pc;
00755 }
00756
00757 Ssh::~Ssh()
00758 {
00759 if ( config )
00760 delete config;
00761 }
00762
00763 void Ssh::show(SnortConfig*)
00764 {
00765 PrintSshConf(config);
00766 }
00767
00768 void Ssh::eval(Packet* p)
00769 {
00770 // precondition - what we registered for
00771 assert(p->has_tcp_data());
00772 assert(p->flow);
00773
00774 new_invoked_inspector(28, p, 0);
00775
00776 ++sshstats.total_packets;
00777 snort_ssh(config, p);
00778 }
00779
00780 //-------------------------------------------------------------------------
00781 // api stuff
00782 //-------------------------------------------------------------------------
00783
00784 static Module* mod_ctor()
00785 { return new SshModule; }
00786
00787 static void mod_dtor(Module* m)
00788 { delete m; }
00789
00790 static void ssh_init()
00791 {
00792 SshFlowData::init();
00793 }
00794
00795 static Inspector* ssh_ctor(Module* m)
00796 {
00797 SshModule* mod = (SshModule*)m;
00798 return new Ssh(mod->get_data());
00799 }
00800
00801 static void ssh_dtor(Inspector* p)
00802 {
00803 delete p;
00804 }
00805
00806 const InspectApi ssh_api =
00807 {
00808 {
00809 PT_INSPECTOR,
00810 sizeof(InspectApi),
00811 INSAPI_VERSION,
00812 0,
00813 API_RESERVED,
00814 API_OPTIONS,
00815 SSH_NAME,
00816 SSH_HELP,
00817 mod_ctor,
00818 mod_dtor
00819 },
00820 IT_SERVICE,
00821 (uint16_t)PktType::PDU,
00822 nullptr, // buffers
00823 "ssh",
00824 ssh_init,
00825 nullptr, // pterm
00826 nullptr, // tinit
00827 nullptr, // tterm
00828 ssh_ctor,
00829 ssh_dtor,
00830 nullptr, // ssn
00831 nullptr // reset
00832 };
00833
00834 #ifdef BUILDING_SO
00835 SO_PUBLIC const BaseApi* snort_plugins[] =
00836 {
00837 &ssh_api.base,
00838 nullptr
00839 };
00840 #else
00841 const BaseApi* sin_ssh = &ssh_api.base;
00842 #endif
00843
END OF CODE