diff --git a/doc/userguide/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst index 3435ced216..cac456c8ad 100644 --- a/doc/userguide/configuration/suricata-yaml.rst +++ b/doc/userguide/configuration/suricata-yaml.rst @@ -1729,11 +1729,11 @@ use of libhtp. # 2 types: 'deflate', 'lzma', 'both' will decompress deflate and lzma # compress-depth: # Specifies the maximum amount of data to decompress, - # set 0 for unlimited. + # set 0 for unlimited. The maximum is 4294967282 bytes. # decompress-depth: # Specifies the maximum amount of decompressed data to obtain. The # output buffer grows on demand up to this limit. Set 0 to use the - # default limit of 50 MB. + # default limit of 50 MB. The maximum is 2147483640 bytes. swf-decompression: enabled: yes type: both diff --git a/doc/userguide/rules/http-keywords.rst b/doc/userguide/rules/http-keywords.rst index e4ea9b9872..1dd0a1c91c 100644 --- a/doc/userguide/rules/http-keywords.rst +++ b/doc/userguide/rules/http-keywords.rst @@ -872,11 +872,11 @@ setting. # 2 types: 'deflate', 'lzma', 'both' will decompress deflate and lzma # compress-depth: # Specifies the maximum amount of data to decompress, - # set 0 for unlimited. + # set 0 for unlimited. The maximum is 4294967282 bytes. # decompress-depth: # Specifies the maximum amount of decompressed data to obtain. The # output buffer grows on demand up to this limit. Set 0 to use the - # default limit of 50 MB. + # default limit of 50 MB. The maximum is 2147483640 bytes. swf-decompression: enabled: yes type: both diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 0aa9b122b1..e577dfa764 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -58,6 +58,7 @@ #include "app-layer-events.h" #include "util-debug.h" +#include "util-file-decompression.h" #include "util-misc.h" #include "util-unittest.h" @@ -2336,17 +2337,19 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, SCConfNode *s, struct exit(EXIT_FAILURE); } } else if (strcasecmp("compress-depth", pval->name) == 0) { - if (ParseSizeStringU32(pval->val, &cfg_prec->swf_compress_depth) < 0) { - SCLogError("Error parsing swf-decompression.compression-depth " - "from conf file - %s. Killing engine", - p->val); + if (ParseSizeStringU32(pval->val, &cfg_prec->swf_compress_depth) < 0 || + cfg_prec->swf_compress_depth > MAX_SWF_COMPRESS_DEPTH) { + SCLogError("Invalid swf-decompression.compress-depth value %s: the " + "maximum is %u bytes. Killing engine", + pval->val, MAX_SWF_COMPRESS_DEPTH); exit(EXIT_FAILURE); } } else if (strcasecmp("decompress-depth", pval->name) == 0) { - if (ParseSizeStringU32(pval->val, &cfg_prec->swf_decompress_depth) < 0) { - SCLogError("Error parsing swf-decompression.decompression-depth " - "from conf file - %s. Killing engine", - p->val); + if (ParseSizeStringU32(pval->val, &cfg_prec->swf_decompress_depth) < 0 || + cfg_prec->swf_decompress_depth > MAX_SWF_DECOMPRESS_DEPTH) { + SCLogError("Invalid swf-decompression.decompress-depth value %s: the " + "maximum is %u bytes. Killing engine", + pval->val, MAX_SWF_DECOMPRESS_DEPTH); exit(EXIT_FAILURE); } } else { diff --git a/src/tests/detect-file-data.c b/src/tests/detect-file-data.c index 6ef40b2ce2..3ade7f6097 100644 --- a/src/tests/detect-file-data.c +++ b/src/tests/detect-file-data.c @@ -349,6 +349,30 @@ static int DetectFiledataSwfDecompressDepthTest02(void) PASS; } +/** + * \test SWF decompression rejects depth values above the supported limits. + */ +static int DetectFiledataSwfDecompressDepthTest03(void) +{ + DetectEngineThreadCtx *det_ctx = SCCalloc(1, sizeof(*det_ctx)); + FAIL_IF_NULL(det_ctx); + InspectionBuffer out_buffer = { 0 }; + + int r = FileSwfDecompression(swf_lzma_fixture, (uint32_t)sizeof(swf_lzma_fixture), det_ctx, + &out_buffer, HTTP_SWF_COMPRESSION_LZMA, MAX_SWF_DECOMPRESS_DEPTH + 1, 0); + FAIL_IF(r != 0); + FAIL_IF_NOT_NULL(out_buffer.buf); + + r = FileSwfDecompression(swf_lzma_fixture, (uint32_t)sizeof(swf_lzma_fixture), det_ctx, + &out_buffer, HTTP_SWF_COMPRESSION_LZMA, 0, MAX_SWF_COMPRESS_DEPTH + 1); + FAIL_IF(r != 0); + FAIL_IF_NOT_NULL(out_buffer.buf); + + SCAppLayerDecoderEventsFreeEvents(&det_ctx->decoder_events); + SCFree(det_ctx); + PASS; +} + static int DetectEngineSMTPFiledataTest02(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); @@ -401,6 +425,8 @@ void DetectFiledataRegisterTests(void) "DetectFiledataSwfDecompressDepthTest01", DetectFiledataSwfDecompressDepthTest01); UtRegisterTest( "DetectFiledataSwfDecompressDepthTest02", DetectFiledataSwfDecompressDepthTest02); + UtRegisterTest( + "DetectFiledataSwfDecompressDepthTest03", DetectFiledataSwfDecompressDepthTest03); UtRegisterTest("DetectEngineSMTPFiledataTest02", DetectEngineSMTPFiledataTest02); UtRegisterTest("DetectFiledataParseTest04", DetectFiledataParseTest04); } diff --git a/src/util-file-decompression.c b/src/util-file-decompression.c index b00bb1b72b..b3287e2328 100644 --- a/src/util-file-decompression.c +++ b/src/util-file-decompression.c @@ -77,6 +77,10 @@ int FileSwfDecompression(const uint8_t *buffer, uint32_t buffer_len, { int r = 0; + if (decompress_depth > MAX_SWF_DECOMPRESS_DEPTH || compress_depth > MAX_SWF_COMPRESS_DEPTH) { + return 0; + } + int compression_type = FileIsSwfFile(buffer, buffer_len); if (compression_type == FILE_SWF_NO_COMPRESSION) { return 0; @@ -160,7 +164,7 @@ int FileSwfDecompression(const uint8_t *buffer, uint32_t buffer_len, * | 5 bytes | 8 bytes | n bytes | * | LZMA properties | Uncompressed length | Compressed data | */ - compressed_data_len += 13; + compressed_data_len += SWF_LZMA_HEADER_LEN; uint8_t *compressed_data = SCCalloc(1, compressed_data_len); if (compressed_data == NULL) { DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_NO_MEM); @@ -171,7 +175,8 @@ int FileSwfDecompression(const uint8_t *buffer, uint32_t buffer_len, /* put lzma end marker */ memset(compressed_data + 5, 0xFF, 8); /* put compressed data */ - memcpy(compressed_data + 13, buffer + offset, compressed_data_len - 13); + memcpy(compressed_data + SWF_LZMA_HEADER_LEN, buffer + offset, + compressed_data_len - SWF_LZMA_HEADER_LEN); /* the first 8 bytes represents the fws header, see 'FWS format' above. * data will start from 8th bytes diff --git a/src/util-file-decompression.h b/src/util-file-decompression.h index e62f6a5e4d..8889c55eea 100644 --- a/src/util-file-decompression.h +++ b/src/util-file-decompression.h @@ -27,6 +27,12 @@ #include "detect.h" +#define SWF_HEADER_LEN 8 +#define SWF_LZMA_HEADER_LEN 13 + +#define MAX_SWF_DECOMPRESS_DEPTH (UINT32_MAX / 2 + 1 - SWF_HEADER_LEN) +#define MAX_SWF_COMPRESS_DEPTH (UINT32_MAX - SWF_LZMA_HEADER_LEN) + enum { FILE_IS_NOT_SWF = 0, FILE_SWF_NO_COMPRESSION, diff --git a/src/util-file-swf-decompression.h b/src/util-file-swf-decompression.h index 6a169fe1b4..dab96e8a25 100644 --- a/src/util-file-swf-decompression.h +++ b/src/util-file-swf-decompression.h @@ -32,7 +32,6 @@ #define MAX_SWF_DECOMPRESSED_LEN 50000000 -#define SWF_HEADER_LEN 8 #define SWF_DECOMPRESS_INITIAL_BUFFER_LEN 4096 uint8_t FileGetSwfVersion(const uint8_t *buffer, const uint32_t buffer_len); diff --git a/suricata.yaml.in b/suricata.yaml.in index 6ada008b8a..ef6d7d711a 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1172,10 +1172,11 @@ app-layer: # Two types: 'deflate', 'lzma', 'both' will decompress deflate and lzma # compress-depth: # Specifies the maximum amount of data to decompress, - # set 0 for unlimited. + # set 0 for unlimited. The maximum is 4294967282 bytes. # decompress-depth: - # Specifies the maximum amount of decompressed data to obtain, - # set 0 for unlimited. + # Specifies the maximum amount of decompressed data to obtain. The + # output buffer grows on demand up to this limit. Set 0 to use the + # default limit of 50 MB. The maximum is 2147483640 bytes. swf-decompression: enabled: no type: both