scmno****@osdn*****
scmno****@osdn*****
2018年 1月 11日 (木) 22:20:04 JST
Revision: 7020 http://sourceforge.jp/projects/ttssh2/scm/svn/commits/7020 Author: doda Date: 2018-01-11 22:20:04 +0900 (Thu, 11 Jan 2018) Log Message: ----------- SSH ペイロードの長さをきちんとチェックするようにした。 これも方針決定の試験実装の為、とりあえず handle_SSH2_kexinit() のみ。 SSH1 専用や SSH1/2 共用のパケットハンドラ関数では大体問題は無いのだが、 SSH2 専用のパケットハンドラ関数ではペイロードの残りの長さを確認せずに アクセスする事を多用している。この為、ちょっとした問題によってすぐに 確保したメモリ領域を超えてアクセスして Application Fault によって落ちる という事が起きてしまう。 ちょっとした問題の例: ・何らかの問題でパケットの復号に失敗した ・同じ番号に割り当てられた他のメッセージを処理しようとした ・サーバからのパケットが壊れていた (バグや悪意のあるサーバの攻撃等) してはいけないメモリアクセスによって Application Fault で落ちるのは セキュリティ的にも望ましくないので、必要な量のデータが残っていなかった 場合は警告メッセージを表示して切断する。 基本的には、SSH ペイロードからデータを取り出す場合は、grab_payload() によって必要な長さのペイロードが残っている事を確認してからアクセスする。 Modified Paths: -------------- trunk/ttssh2/ttxssh/ssh.c -------------- next part -------------- Modified: trunk/ttssh2/ttxssh/ssh.c =================================================================== --- trunk/ttssh2/ttxssh/ssh.c 2018-01-11 13:20:00 UTC (rev 7019) +++ trunk/ttssh2/ttxssh/ssh.c 2018-01-11 13:20:04 UTC (rev 7020) @@ -4833,7 +4833,6 @@ char buf[1024]; char *data; int len, size; - int offset = 0; char *msg = NULL; char tmp[1024+512]; char str_keytype[20]; @@ -4853,7 +4852,7 @@ data = remained_payload(pvar); len = remained_payloadlen(pvar); - // KEX \x82̍Ō\xE3\x82\xC5 hash (session-id) \x82\xF0\x8Cv\x8EZ\x82\xB7\x82\xE9\x82̂Ɏg\x82\xA4\x82̂ŕۑ\xB6\x82\xB5\x82Ă\xA8\x82\xAD + // KEX \x82̍Ō\xE3\x82\xC5 exchange-hash (session-id) \x82\xF0\x8Cv\x8EZ\x82\xB7\x82\xE9\x82̂Ɏg\x82\xA4\x82̂ŕۑ\xB6\x82\xB5\x82Ă\xA8\x82\xAD if (pvar->peer_kex != NULL) { // already allocated buffer_clear(pvar->peer_kex); @@ -4867,33 +4866,35 @@ } buffer_append(pvar->peer_kex, data, len); - // TODO: buffer overrun check - push_memdump("KEXINIT", "exchange algorithm list: receiving", data, len); - if (offset + 20 >= len) { - msg = "payload size too small @ handle_SSH2_kexinit()"; + // cookie; \x82\xB1\x82\xB1\x82ł͎g\x82\xED\x82Ȃ\xA2\x82̂œǂݔ\xF2\x82\xB7 + if (! grab_payload(pvar, SSH2_COOKIE_LENGTH)) { + msg = __FUNCTION__ ": truncated packet (cookie)"; goto error; } // get rid of Cookie length - offset += SSH2_COOKIE_LENGTH; + data += SSH2_COOKIE_LENGTH; + // \x8Ae\x97v\x91f(\x8C\xAE\x8C\xF0\x8A\xB7,\x88Í\x86\x89\xBB\x93\x99)\x82Ŏg\x97p\x82\xB7\x82\xE9\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80\x82̌\x88\x92\xE8\x81B + // \x83T\x81[\x83o\x82\xA9\x82\xE7\x82̓J\x83\x93\x83}\x8B\xE6\x90\xE8\x82ł̃\x8A\x83X\x83g\x82\xAA\x91\x97\x82\xE7\x82\xEA\x82ė\x88\x82\xE9\x81B + // \x83N\x83\x89\x83C\x83A\x83\x93\x83g\x82ƃT\x81[\x83o\x97\xBC\x95\xFB\x82\xAA\x83T\x83|\x81[\x83g\x82\xB5\x82Ă\xA2\x82镨\x82̂\xA4\x82\xBF\x81A + // \x83N\x83\x89\x83C\x83A\x83\x93\x83g\x91\xA4\x82ōł\xE0\x91O\x82Ɏw\x92肵\x82\xBD\x95\xA8\x82\xAA\x8Eg\x82\xED\x82\xEA\x82\xE9\x81B - // KEX\x82̌\x88\x92\xE8\x81B\x94\xBB\x92菇\x82\xF0myproposal[PROPOSAL_KEX_ALGS]\x82̕\xC0\x82тƍ\x87\x82킹\x82邱\x82ƁB - // \x83T\x81[\x83o\x82́A\x83N\x83\x89\x83C\x83A\x83\x93\x83g\x82\xA9\x82瑗\x82\xE7\x82\xEA\x82Ă\xAB\x82\xBD myproposal[PROPOSAL_KEX_ALGS] \x82̃J\x83\x93\x83}\x95\xB6\x8E\x9A\x97\xF1\x82̂\xA4\x82\xBF\x81A - // \x90擪\x82\xA9\x82玩\x95\xAA\x82\xCC myproposal[] \x82Ɣ\xE4\x8Ar\x82\xF0\x8Ds\x82\xA2\x81A\x8Dŏ\x89\x82Ƀ}\x83b\x83`\x82\xB5\x82\xBD\x82\xE0\x82̂\xAAKEX\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80\x82Ƃ\xB5\x82\xC4 - // \x91I\x91\xF0\x82\xB3\x82\xEA\x82\xE9\x81B(2004.10.30 yutaka) + // \x8C\xAE\x8C\xF0\x8A\xB7\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80 + if (!grab_payload(pvar, 4) + || !grab_payload(pvar, size = get_uint32(data))) { + msg = __FUNCTION__ ": truncated packet (kex algorithms)"; + goto error; + } + data += 4; - // \x83L\x81[\x8C\xF0\x8A\xB7\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80\x83`\x83F\x83b\x83N - size = get_payload_uint32(pvar, offset); - offset += 4; - if (size >= sizeof(buf)) { logputs(LOG_LEVEL_WARNING, __FUNCTION__ ": server proposed kex algorithms is too long."); } - strncpy_s(buf, sizeof(buf), data+offset, _TRUNCATE); - offset += size; + strncpy_s(buf, sizeof(buf), data, _TRUNCATE); + data += size; logprintf(LOG_LEVEL_VERBOSE, "server proposal: KEX algorithm: %s", buf); @@ -4905,16 +4906,19 @@ goto error; } + // \x83z\x83X\x83g\x8C\xAE\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80 + if (!grab_payload(pvar, 4) + || !grab_payload(pvar, size = get_uint32(data))) { + msg = __FUNCTION__ ": truncated packet (hostkey algorithms)"; + goto error; + } + data += 4; - // \x83z\x83X\x83g\x83L\x81[\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80\x83`\x83F\x83b\x83N - size = get_payload_uint32(pvar, offset); - offset += 4; - if (size >= sizeof(buf)) { logputs(LOG_LEVEL_WARNING, __FUNCTION__ ": server proposed hostkey algorithms is too long."); } - strncpy_s(buf, sizeof(buf), data+offset, _TRUNCATE); - offset += size; + strncpy_s(buf, sizeof(buf), data, _TRUNCATE); + data += size; logprintf(LOG_LEVEL_VERBOSE, "server proposal: server host key algorithm: %s", buf); @@ -4934,63 +4938,72 @@ goto error; } + // \x88Í\x86\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80(\x83N\x83\x89\x83C\x83A\x83\x93\x83g -> \x83T\x81[\x83o) + if (!grab_payload(pvar, 4) + || !grab_payload(pvar, size = get_uint32(data))) { + msg = __FUNCTION__ ": truncated packet (encryption algorithms client to server)"; + goto error; + } + data += 4; - // \x83N\x83\x89\x83C\x83A\x83\x93\x83g -> \x83T\x81[\x83o\x88Í\x86\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80\x83`\x83F\x83b\x83N - size = get_payload_uint32(pvar, offset); - offset += 4; - if (size >= sizeof(buf)) { logputs(LOG_LEVEL_WARNING, __FUNCTION__ ": server proposed encryption algorithms (client to server) is too long."); } - strncpy_s(buf, sizeof(buf), data+offset, _TRUNCATE); - offset += size; + strncpy_s(buf, sizeof(buf), data, _TRUNCATE); + data += size; logprintf(LOG_LEVEL_VERBOSE, "server proposal: encryption algorithm client to server: %s", buf); pvar->ciphers[MODE_OUT] = choose_SSH2_cipher_algorithm(buf, myproposal[PROPOSAL_ENC_ALGS_CTOS]); - if (pvar->ciphers[MODE_OUT] == NULL) { - strncpy_s(tmp, sizeof(tmp), "unknown Encrypt algorithm(ctos): ", _TRUNCATE); + if (pvar->ciphers[MODE_OUT]->id == SSH_CIPHER_NONE) { + strncpy_s(tmp, sizeof(tmp), "unknown Encrypt algorithm(client to server): ", _TRUNCATE); strncat_s(tmp, sizeof(tmp), buf, _TRUNCATE); msg = tmp; goto error; } + // \x88Í\x86\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80(\x83T\x81[\x83o -> \x83N\x83\x89\x83C\x83A\x83\x93\x83g) + if (!grab_payload(pvar, 4) + || !grab_payload(pvar, size = get_uint32(data))) { + msg = __FUNCTION__ ": truncated packet (encryption algorithms server to client)"; + goto error; + } + data += 4; - // \x83T\x81[\x83o -> \x83N\x83\x89\x83C\x83A\x83\x93\x83g\x88Í\x86\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80\x83`\x83F\x83b\x83N - size = get_payload_uint32(pvar, offset); - offset += 4; - if (size >= sizeof(buf)) { logputs(LOG_LEVEL_WARNING, __FUNCTION__ ": server proposed encryption algorithms (server to client) is too long."); } - strncpy_s(buf, sizeof(buf), data+offset, _TRUNCATE); - offset += size; + strncpy_s(buf, sizeof(buf), data, _TRUNCATE); + data += size; logprintf(LOG_LEVEL_VERBOSE, "server proposal: encryption algorithm server to client: %s", buf); pvar->ciphers[MODE_IN] = choose_SSH2_cipher_algorithm(buf, myproposal[PROPOSAL_ENC_ALGS_STOC]); - if (pvar->ciphers[MODE_IN] == NULL) { - strncpy_s(tmp, sizeof(tmp), "unknown Encrypt algorithm(stoc): ", _TRUNCATE); + if (pvar->ciphers[MODE_IN]->id == SSH_CIPHER_NONE) { + strncpy_s(tmp, sizeof(tmp), "unknown Encrypt algorithm(server to client): ", _TRUNCATE); strncat_s(tmp, sizeof(tmp), buf, _TRUNCATE); msg = tmp; goto error; } + // MAC\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80(\x83N\x83\x89\x83C\x83A\x83\x93\x83g -> \x83T\x81[\x83o) + if (!grab_payload(pvar, 4) + || !grab_payload(pvar, size = get_uint32(data))) { + msg = __FUNCTION__ ": truncated packet (MAC algorithms client to server)"; + goto error; + } + data += 4; - // MAC(Message Authentication Code)\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80\x82̌\x88\x92\xE8 (2004.12.17 yutaka) - size = get_payload_uint32(pvar, offset); - offset += 4; - if (size >= sizeof(buf)) { logputs(LOG_LEVEL_WARNING, __FUNCTION__ ": server proposed MAC algorithms (client to server) is too long."); } - strncpy_s(buf, sizeof(buf), data+offset, _TRUNCATE); - offset += size; + strncpy_s(buf, sizeof(buf), data, _TRUNCATE); + data += size; logprintf(LOG_LEVEL_VERBOSE, "server proposal: MAC algorithm client to server: %s", buf); if (pvar->ciphers[MODE_OUT]->auth_len > 0) { - logputs(LOG_LEVEL_VERBOSE, "AEAD cipher is selected, ignoring MAC algorithms. (c2s)"); + logputs(LOG_LEVEL_VERBOSE, "AEAD cipher is selected, ignoring MAC algorithms. (client to server)"); pvar->macs[MODE_OUT] = get_ssh2_mac(HMAC_IMPLICIT); } else { @@ -5003,19 +5016,24 @@ } } - size = get_payload_uint32(pvar, offset); - offset += 4; + // MAC\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80(\x83T\x81[\x83o -> \x83N\x83\x89\x83C\x83A\x83\x93\x83g) + if (!grab_payload(pvar, 4) + || !grab_payload(pvar, size = get_uint32(data))) { + msg = __FUNCTION__ ": truncated packet (MAC algorithms server to client)"; + goto error; + } + data += 4; if (size >= sizeof(buf)) { logputs(LOG_LEVEL_WARNING, __FUNCTION__ ": server proposed MAC algorithms (server to client) is too long."); } - strncpy_s(buf, sizeof(buf), data+offset, _TRUNCATE); - offset += size; + strncpy_s(buf, sizeof(buf), data, _TRUNCATE); + data += size; logprintf(LOG_LEVEL_VERBOSE, "server proposal: MAC algorithm server to client: %s", buf); if (pvar->ciphers[MODE_IN]->auth_len > 0) { - logputs(LOG_LEVEL_VERBOSE, "AEAD cipher is selected, ignoring MAC algorithms. (s2c)"); + logputs(LOG_LEVEL_VERBOSE, "AEAD cipher is selected, ignoring MAC algorithms. (server to client)"); pvar->macs[MODE_IN] = get_ssh2_mac(HMAC_IMPLICIT); } else { @@ -5028,17 +5046,19 @@ } } - // \x88\xB3\x8Fk\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80\x82̌\x88\x92\xE8 - // pvar->ssh_state.compressing = FALSE; \x82Ƃ\xB5\x82ĉ\xBA\x8BL\x83\x81\x83\x93\x83o\x82\xF0\x8Eg\x97p\x82\xB7\x82\xE9\x81B - // (2005.7.9 yutaka) - size = get_payload_uint32(pvar, offset); - offset += 4; + // \x88\xB3\x8Fk\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80(\x83N\x83\x89\x83C\x83A\x83\x93\x83g -> \x83T\x81[\x83o) + if (!grab_payload(pvar, 4) + || !grab_payload(pvar, size = get_uint32(data))) { + msg = __FUNCTION__ ": truncated packet (compression algorithms client to server)"; + goto error; + } + data += 4; if (size >= sizeof(buf)) { logputs(LOG_LEVEL_WARNING, __FUNCTION__ ": server proposed compression algorithms (client to server) is too long."); } - strncpy_s(buf, sizeof(buf), data+offset, _TRUNCATE); - offset += size; + strncpy_s(buf, sizeof(buf), data, _TRUNCATE); + data += size; logprintf(LOG_LEVEL_VERBOSE, "server proposal: compression algorithm client to server: %s", buf); @@ -5050,15 +5070,19 @@ goto error; } + // \x88\xB3\x8Fk\x83A\x83\x8B\x83S\x83\x8A\x83Y\x83\x80(\x83T\x81[\x83o -> \x83N\x83\x89\x83C\x83A\x83\x93\x83g) + if (!grab_payload(pvar, 4) + || !grab_payload(pvar, size = get_uint32(data))) { + msg = __FUNCTION__ ": truncated packet (compression algorithms server to client)"; + goto error; + } + data += 4; - size = get_payload_uint32(pvar, offset); - offset += 4; - if (size >= sizeof(buf)) { logputs(LOG_LEVEL_WARNING, __FUNCTION__ ": server proposed compression algorithms (server to client) is too long."); } - strncpy_s(buf, sizeof(buf), data+offset, _TRUNCATE); - offset += size; + strncpy_s(buf, sizeof(buf), data, _TRUNCATE); + data += size; logprintf(LOG_LEVEL_VERBOSE, "server proposal: compression algorithm server to client: %s", buf); @@ -5070,40 +5094,32 @@ goto error; } - - // \x8C\x88\x92\xE8 +skip: + // \x8C\x88\x92肵\x82\xBD\x95\xFB\x8E\xAE\x82\xF0\x83\x8D\x83O\x82ɏo\x97\xCD logprintf(LOG_LEVEL_VERBOSE, "KEX algorithm: %s", get_kex_algorithm_name(pvar->kex_type)); - logprintf(LOG_LEVEL_VERBOSE, - "server host key algorithm: %s", + logprintf(LOG_LEVEL_VERBOSE, "server host key algorithm: %s", get_ssh_keytype_name(pvar->hostkey_type)); - logprintf(LOG_LEVEL_VERBOSE, - "encryption algorithm client to server: %s", + logprintf(LOG_LEVEL_VERBOSE, "encryption algorithm client to server: %s", get_cipher_string(pvar->ciphers[MODE_OUT])); - logprintf(LOG_LEVEL_VERBOSE, - "encryption algorithm server to client: %s", + logprintf(LOG_LEVEL_VERBOSE, "encryption algorithm server to client: %s", get_cipher_string(pvar->ciphers[MODE_IN])); - logprintf(LOG_LEVEL_VERBOSE, - "MAC algorithm client to server: %s", + logprintf(LOG_LEVEL_VERBOSE, "MAC algorithm client to server: %s", get_ssh2_mac_name(pvar->macs[MODE_OUT])); - logprintf(LOG_LEVEL_VERBOSE, - "MAC algorithm server to client: %s", + logprintf(LOG_LEVEL_VERBOSE, "MAC algorithm server to client: %s", get_ssh2_mac_name(pvar->macs[MODE_IN])); - logprintf(LOG_LEVEL_VERBOSE, - "compression algorithm client to server: %s", + logprintf(LOG_LEVEL_VERBOSE, "compression algorithm client to server: %s", get_ssh2_comp_name(pvar->ctos_compression)); - logprintf(LOG_LEVEL_VERBOSE, - "compression algorithm server to client: %s", + logprintf(LOG_LEVEL_VERBOSE, "compression algorithm server to client: %s", get_ssh2_comp_name(pvar->stoc_compression)); - // we_need\x82̌\x88\x92\xE8 (2004.11.6 yutaka) // \x83L\x81[\x8Dč쐬\x82̏ꍇ\x82̓X\x83L\x83b\x83v\x82\xB7\x82\xE9\x81B if (pvar->rekeying == 0) {