/** @internal * @brief Sends a SSH banner to the server. * * @param session The SSH session to use. * * @param server Send client or server banner. * * @return 0 on success, < 0 on error. */ int ssh_send_banner(ssh_session session, int server) { const char *banner = NULL; char buffer[128] = {0}; int err=SSH_ERROR; enter_function(); banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2; if (server) { session->serverbanner = strdup(banner); if (session->serverbanner == NULL) { goto end; } } else { session->clientbanner = strdup(banner); if (session->clientbanner == NULL) { goto end; } } snprintf(buffer, 128, "%s\n", banner); if (ssh_socket_write(session->socket, buffer, strlen(buffer)) == SSH_ERROR) { goto end; } #ifdef WITH_PCAP if(session->pcap_ctx) ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,buffer,strlen(buffer),strlen(buffer)); #endif err=SSH_OK; end: leave_function(); return err; }
/** * @internal * * @brief Gets the banner from socket and saves it in session. * Updates the session state * * @param data pointer to the beginning of header * @param len size of the banner * @param user is a pointer to session * @returns Number of bytes processed, or zero if the banner is not complete. */ static int callback_receive_banner(const void *data, size_t len, void *user) { char *buffer = (char *) data; ssh_session session = (ssh_session) user; char *str = NULL; size_t i; int ret=0; enter_function(); for (i = 0; i < len; i++) { #ifdef WITH_PCAP if(session->pcap_ctx && buffer[i] == '\n') { ssh_pcap_context_write(session->pcap_ctx, SSH_PCAP_DIR_IN, buffer, i + 1, i + 1); } #endif if (buffer[i] == '\r') { buffer[i]='\0'; } if (buffer[i] == '\n') { buffer[i]='\0'; str = strdup(buffer); /* number of bytes read */ ret = i + 1; session->clientbanner = str; session->session_state = SSH_SESSION_STATE_BANNER_RECEIVED; ssh_log(session, SSH_LOG_PACKET, "Received banner: %s", str); session->ssh_connection_callback(session); leave_function(); return ret; } if(i > 127) { /* Too big banner */ session->session_state = SSH_SESSION_STATE_ERROR; ssh_set_error(session, SSH_FATAL, "Receiving banner: too large banner"); leave_function(); return 0; } } leave_function(); return ret; }
/** * @internal * * @brief Gets the banner from socket and saves it in session. * Updates the session state * * @param data pointer to the beginning of header * @param len size of the banner * @param user is a pointer to session * @returns Number of bytes processed, or zero if the banner is not complete. */ static int callback_receive_banner(const void *data, size_t len, void *user) { char *buffer = (char *)data; ssh_session session=(ssh_session) user; char *str = NULL; size_t i; int ret=0; if(session->session_state != SSH_SESSION_STATE_SOCKET_CONNECTED){ ssh_set_error(session,SSH_FATAL,"Wrong state in callback_receive_banner : %d",session->session_state); return SSH_ERROR; } for(i=0;i<len;++i){ #ifdef WITH_PCAP if(session->pcap_ctx && buffer[i] == '\n'){ ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_IN,buffer,i+1,i+1); } #endif if(buffer[i]=='\r') { buffer[i]='\0'; } if (buffer[i]=='\n') { buffer[i] = '\0'; str = strdup(buffer); if (str == NULL) { return SSH_ERROR; } /* number of bytes read */ ret = i + 1; session->serverbanner = str; session->session_state=SSH_SESSION_STATE_BANNER_RECEIVED; SSH_LOG(SSH_LOG_PACKET,"Received banner: %s",str); session->ssh_connection_callback(session); return ret; } if(i>127){ /* Too big banner */ session->session_state=SSH_SESSION_STATE_ERROR; ssh_set_error(session,SSH_FATAL,"Receiving banner: too large banner"); return 0; } } return ret; }
/** @internal * @brief Sends a SSH banner to the server. * * @param session The SSH session to use. * * @param server Send client or server banner. * * @return 0 on success, < 0 on error. */ int ssh_send_banner(ssh_session session, int server) { const char *banner = NULL; char buffer[128] = {0}; int err=SSH_ERROR; banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2; if (server) { if(session->opts.custombanner == NULL){ session->serverbanner = strdup(banner); } else { session->serverbanner = malloc(strlen(session->opts.custombanner) + 9); if(!session->serverbanner) goto end; strcpy(session->serverbanner, "SSH-2.0-"); strcat(session->serverbanner, session->opts.custombanner); } if (session->serverbanner == NULL) { goto end; } snprintf(buffer, 128, "%s\n", session->serverbanner); } else { session->clientbanner = strdup(banner); if (session->clientbanner == NULL) { goto end; } snprintf(buffer, 128, "%s\n", session->clientbanner); } if (ssh_socket_write(session->socket, buffer, strlen(buffer)) == SSH_ERROR) { goto end; } #ifdef WITH_PCAP if(session->pcap_ctx) ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,buffer,strlen(buffer),strlen(buffer)); #endif err=SSH_OK; end: return err; }
static int packet_send2(ssh_session session) { unsigned int blocksize = (session->current_crypto ? session->current_crypto->out_cipher->blocksize : 8); uint32_t currentlen = buffer_get_rest_len(session->out_buffer); unsigned char *hmac = NULL; char padstring[32] = {0}; int rc = SSH_ERROR; uint32_t finallen,payloadsize,compsize; uint8_t padding; payloadsize = currentlen; #ifdef WITH_ZLIB if (session->current_crypto && session->current_crypto->do_compress_out && buffer_get_rest_len(session->out_buffer)) { if (compress_buffer(session,session->out_buffer) < 0) { goto error; } currentlen = buffer_get_rest_len(session->out_buffer); } #endif /* WITH_ZLIB */ compsize = currentlen; padding = (blocksize - ((currentlen +5) % blocksize)); if(padding < 4) { padding += blocksize; } if (session->current_crypto) { ssh_get_random(padstring, padding, 0); } else { memset(padstring,0,padding); } finallen = htonl(currentlen + padding + 1); if (buffer_prepend_data(session->out_buffer, &padding, sizeof(uint8_t)) < 0) { goto error; } if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(uint32_t)) < 0) { goto error; } if (buffer_add_data(session->out_buffer, padstring, padding) < 0) { goto error; } #ifdef WITH_PCAP if(session->pcap_ctx){ ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT, buffer_get_rest(session->out_buffer),buffer_get_rest_len(session->out_buffer) ,buffer_get_rest_len(session->out_buffer)); } #endif hmac = packet_encrypt(session, buffer_get_rest(session->out_buffer), buffer_get_rest_len(session->out_buffer)); if (hmac) { if (buffer_add_data(session->out_buffer, hmac, 20) < 0) { goto error; } } rc = ssh_packet_write(session); session->send_seq++; SSH_LOG(SSH_LOG_PACKET, "packet: wrote [len=%d,padding=%hhd,comp=%d,payload=%d]", ntohl(finallen), padding, compsize, payloadsize); if (buffer_reinit(session->out_buffer) < 0) { rc = SSH_ERROR; } error: return rc; /* SSH_OK, AGAIN or ERROR */ }
/** * @internal * * @brief Gets the banner from socket and saves it in session. * Updates the session state * * @param data pointer to the beginning of header * @param len size of the banner * @param user is a pointer to session * @returns Number of bytes processed, or zero if the banner is not complete. */ static int callback_receive_banner(const void *data, size_t len, void *user) { char *buffer = (char *)data; ssh_session session=(ssh_session) user; char *str = NULL; size_t i; int ret=0; if (session->session_state != SSH_SESSION_STATE_SOCKET_CONNECTED) { ssh_set_error(session,SSH_FATAL, "Wrong state in callback_receive_banner : %d", session->session_state); return SSH_ERROR; } for (i = 0; i < len; ++i) { #ifdef WITH_PCAP if (session->pcap_ctx && buffer[i] == '\n') { ssh_pcap_context_write(session->pcap_ctx, SSH_PCAP_DIR_IN, buffer,i+1, i+1); } #endif if (buffer[i] == '\r') { buffer[i] = '\0'; } if (buffer[i] == '\n') { int cmp; buffer[i] = '\0'; /* The server MAY send other lines of data... */ cmp = strncmp(buffer, "SSH-", 4); if (cmp == 0) { str = strdup(buffer); if (str == NULL) { return SSH_ERROR; } /* number of bytes read */ ret = i + 1; session->serverbanner = str; session->session_state = SSH_SESSION_STATE_BANNER_RECEIVED; SSH_LOG(SSH_LOG_PACKET, "Received banner: %s", str); session->ssh_connection_callback(session); return ret; } else { SSH_LOG(SSH_LOG_DEBUG, "ssh_protocol_version_exchange: %s", buffer); ret = i + 1; break; } } /* According to RFC 4253 the max banner length is 255 */ if (i > 255) { /* Too big banner */ session->session_state=SSH_SESSION_STATE_ERROR; ssh_set_error(session, SSH_FATAL, "Receiving banner: too large banner"); return 0; } } return ret; }
/** @internal * @brief Sends a SSH banner to the server. * * @param session The SSH session to use. * * @param server Send client or server banner. * * @return 0 on success, < 0 on error. */ int ssh_send_banner(ssh_session session, int server) { const char *banner = NULL; const char *terminator = NULL; /* The maximum banner length is 255 for SSH2 */ char buffer[256] = {0}; size_t len; int rc = SSH_ERROR; banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2; terminator = session->version == 1 ? "\n" : "\r\n"; if (server == 1) { if (session->opts.custombanner == NULL){ len = strlen(banner); session->serverbanner = strdup(banner); if (session->serverbanner == NULL) { goto end; } } else { len = strlen(session->opts.custombanner); session->serverbanner = malloc(len + 8 + 1); if(session->serverbanner == NULL) { goto end; } snprintf(session->serverbanner, len + 8 + 1, "SSH-2.0-%s", session->opts.custombanner); } snprintf(buffer, sizeof(buffer), "%s%s", session->serverbanner, terminator); } else { session->clientbanner = strdup(banner); if (session->clientbanner == NULL) { goto end; } /* SSH version 1 has a banner length of 128 only */ len = session->version == 1 ? 128 : 0; snprintf(buffer, sizeof(buffer) - len, "%s%s", session->clientbanner, terminator); } rc = ssh_socket_write(session->socket, buffer, strlen(buffer)); if (rc == SSH_ERROR) { goto end; } #ifdef WITH_PCAP if (session->pcap_ctx != NULL) { ssh_pcap_context_write(session->pcap_ctx, SSH_PCAP_DIR_OUT, buffer, strlen(buffer), strlen(buffer)); } #endif rc = SSH_OK; end: return rc; }
static int packet_send2(ssh_session session) { unsigned int blocksize = (session->current_crypto ? session->current_crypto->out_cipher->blocksize : 8); uint32_t currentlen = buffer_get_rest_len(session->out_buffer); unsigned char *hmac = NULL; char padstring[32] = {0}; int rc = SSH_ERROR; uint32_t finallen; uint8_t padding; enter_function(); ssh_log(session, SSH_LOG_PACKET, "Writing on the wire a packet having %u bytes before", currentlen); #if defined(HAVE_LIBZ) && defined(WITH_LIBZ) if (session->current_crypto && session->current_crypto->do_compress_out && buffer_get_rest_len(session->out_buffer)) { ssh_log(session, SSH_LOG_PACKET, "Compressing out_buffer ..."); if (compress_buffer(session,session->out_buffer) < 0) { goto error; } currentlen = buffer_get_rest_len(session->out_buffer); } #endif padding = (blocksize - ((currentlen +5) % blocksize)); if(padding < 4) { padding += blocksize; } if (session->current_crypto) { ssh_get_random(padstring, padding, 0); } else { memset(padstring,0,padding); } finallen = htonl(currentlen + padding + 1); ssh_log(session, SSH_LOG_PACKET, "%d bytes after comp + %d padding bytes = %lu bytes packet", currentlen, padding, (long unsigned int) ntohl(finallen)); if (buffer_prepend_data(session->out_buffer, &padding, sizeof(uint8_t)) < 0) { goto error; } if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(uint32_t)) < 0) { goto error; } if (buffer_add_data(session->out_buffer, padstring, padding) < 0) { goto error; } #ifdef WITH_PCAP if(session->pcap_ctx){ ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT, buffer_get_rest(session->out_buffer),buffer_get_rest_len(session->out_buffer) ,buffer_get_rest_len(session->out_buffer)); } #endif hmac = packet_encrypt(session, buffer_get_rest(session->out_buffer), buffer_get_rest_len(session->out_buffer)); if (hmac) { if (buffer_add_data(session->out_buffer, hmac, 20) < 0) { goto error; } } rc = ssh_packet_write(session); session->send_seq++; if (buffer_reinit(session->out_buffer) < 0) { rc = SSH_ERROR; } error: leave_function(); return rc; /* SSH_OK, AGAIN or ERROR */ }
static int packet_send2(ssh_session session) { unsigned int blocksize = (session->current_crypto ? session->current_crypto->out_cipher->blocksize : 8); unsigned int lenfield_blocksize = (session->current_crypto ? session->current_crypto->out_cipher->lenfield_blocksize : 0); enum ssh_hmac_e hmac_type = (session->current_crypto ? session->current_crypto->out_hmac : session->next_crypto->out_hmac); uint32_t currentlen = ssh_buffer_get_len(session->out_buffer); unsigned char *hmac = NULL; char padstring[32] = { 0 }; int rc = SSH_ERROR; uint32_t finallen,payloadsize,compsize; uint8_t padding; ssh_buffer header_buffer = ssh_buffer_new(); payloadsize = currentlen; #ifdef WITH_ZLIB if (session->current_crypto && session->current_crypto->do_compress_out && ssh_buffer_get_len(session->out_buffer)) { if (compress_buffer(session,session->out_buffer) < 0) { goto error; } currentlen = ssh_buffer_get_len(session->out_buffer); } #endif /* WITH_ZLIB */ compsize = currentlen; /* compressed payload + packet len (4) + padding len (1) */ /* totallen - lenfield_blocksize must be equal to 0 (mod blocksize) */ padding = (blocksize - ((blocksize - lenfield_blocksize + currentlen + 5) % blocksize)); if(padding < 4) { padding += blocksize; } if (session->current_crypto != NULL) { int ok; ok = ssh_get_random(padstring, padding, 0); if (!ok) { ssh_set_error(session, SSH_FATAL, "PRNG error"); goto error; } } if (header_buffer == NULL){ ssh_set_error_oom(session); goto error; } finallen = currentlen + padding + 1; rc = ssh_buffer_pack(header_buffer, "db", finallen, padding); if (rc == SSH_ERROR){ goto error; } rc = ssh_buffer_prepend_data(session->out_buffer, ssh_buffer_get(header_buffer), ssh_buffer_get_len(header_buffer)); if (rc < 0) { goto error; } rc = ssh_buffer_add_data(session->out_buffer, padstring, padding); if (rc < 0) { goto error; } #ifdef WITH_PCAP if (session->pcap_ctx) { ssh_pcap_context_write(session->pcap_ctx, SSH_PCAP_DIR_OUT, ssh_buffer_get(session->out_buffer), ssh_buffer_get_len(session->out_buffer), ssh_buffer_get_len(session->out_buffer)); } #endif hmac = ssh_packet_encrypt(session, ssh_buffer_get(session->out_buffer), ssh_buffer_get_len(session->out_buffer)); if (hmac) { rc = ssh_buffer_add_data(session->out_buffer, hmac, hmac_digest_len(hmac_type)); if (rc < 0) { goto error; } } rc = ssh_packet_write(session); session->send_seq++; if (session->raw_counter != NULL) { session->raw_counter->out_bytes += payloadsize; session->raw_counter->out_packets++; } SSH_LOG(SSH_LOG_PACKET, "packet: wrote [len=%d,padding=%hhd,comp=%d,payload=%d]", finallen, padding, compsize, payloadsize); if (ssh_buffer_reinit(session->out_buffer) < 0) { rc = SSH_ERROR; } error: if (header_buffer != NULL) { ssh_buffer_free(header_buffer); } return rc; /* SSH_OK, AGAIN or ERROR */ }
static int packet_send2(ssh_session session) { unsigned int blocksize = (session->current_crypto ? session->current_crypto->out_cipher->blocksize : 8); enum ssh_hmac_e hmac_type = (session->current_crypto ? session->current_crypto->out_hmac : session->next_crypto->out_hmac); uint32_t currentlen = ssh_buffer_get_len(session->out_buffer); unsigned char *hmac = NULL; char padstring[32] = { 0 }; int rc = SSH_ERROR; uint32_t finallen,payloadsize,compsize; uint8_t padding; uint8_t header[sizeof(padding) + sizeof(finallen)] = { 0 }; payloadsize = currentlen; #ifdef WITH_ZLIB if (session->current_crypto && session->current_crypto->do_compress_out && ssh_buffer_get_len(session->out_buffer)) { if (compress_buffer(session,session->out_buffer) < 0) { goto error; } currentlen = ssh_buffer_get_len(session->out_buffer); } #endif /* WITH_ZLIB */ compsize = currentlen; padding = (blocksize - ((currentlen +5) % blocksize)); if(padding < 4) { padding += blocksize; } if (session->current_crypto) { ssh_get_random(padstring, padding, 0); } finallen = htonl(currentlen + padding + 1); memcpy(&header[0], &finallen, sizeof(finallen)); header[sizeof(finallen)] = padding; rc = ssh_buffer_prepend_data(session->out_buffer, &header, sizeof(header)); if (rc < 0) { goto error; } rc = ssh_buffer_add_data(session->out_buffer, padstring, padding); if (rc < 0) { goto error; } #ifdef WITH_PCAP if(session->pcap_ctx){ ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT, ssh_buffer_get(session->out_buffer),ssh_buffer_get_len(session->out_buffer) ,ssh_buffer_get_len(session->out_buffer)); } #endif hmac = ssh_packet_encrypt(session, ssh_buffer_get(session->out_buffer), ssh_buffer_get_len(session->out_buffer)); if (hmac) { rc = ssh_buffer_add_data(session->out_buffer, hmac, hmac_digest_len(hmac_type)); if (rc < 0) { goto error; } } rc = ssh_packet_write(session); session->send_seq++; if (session->raw_counter != NULL) { session->raw_counter->out_bytes += payloadsize; session->raw_counter->out_packets++; } SSH_LOG(SSH_LOG_PACKET, "packet: wrote [len=%d,padding=%hhd,comp=%d,payload=%d]", ntohl(finallen), padding, compsize, payloadsize); if (ssh_buffer_reinit(session->out_buffer) < 0) { rc = SSH_ERROR; } error: return rc; /* SSH_OK, AGAIN or ERROR */ }