Coverage Report

Created: 2026-03-31 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/util-file-decompression.c
Line
Count
Source
1
/* Copyright (C) 2017 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
/** \file
19
 *
20
 * \author Giuseppe Longo <giuseppe@glongo.it>
21
 *
22
 * \brief Decompress files transferred via HTTP corresponding to file_data
23
 * keyword.
24
 *
25
 */
26
27
#include "suricata-common.h"
28
#include "suricata.h"
29
30
#include "detect-engine.h"
31
#include "app-layer-htp.h"
32
33
#include "util-file-decompression.h"
34
#include "util-file-swf-decompression.h"
35
#include "util-misc.h"
36
#include "util-print.h"
37
38
1
#define SWF_ZLIB_MIN_VERSION    0x06
39
0
#define SWF_LZMA_MIN_VERSION    0x0D
40
41
int FileIsSwfFile(const uint8_t *buffer, uint32_t buffer_len)
42
14.5k
{
43
14.5k
    if (buffer_len >= 3 && buffer[1] == 'W' && buffer[2] == 'S') {
44
2
        if (buffer[0] == 'F')
45
0
            return FILE_SWF_NO_COMPRESSION;
46
2
        else if (buffer[0] == 'C')
47
2
            return FILE_SWF_ZLIB_COMPRESSION;
48
0
        else if (buffer[0] == 'Z')
49
0
            return FILE_SWF_LZMA_COMPRESSION;
50
0
        else
51
0
            return FILE_IS_NOT_SWF;
52
2
    }
53
54
14.5k
    return FILE_IS_NOT_SWF;
55
14.5k
}
56
57
/**
58
 * \brief This function decompresses a buffer with zlib/lzma algorithm
59
 *
60
 * \param buffer compressed buffer
61
 * \param buffer_len compressed buffer length
62
 * \param decompressed_buffer buffer that store decompressed data
63
 * \param decompressed_buffer_len decompressed data length
64
 * \param swf_type decompression algorithm to use
65
 * \param decompress_depth how much decompressed data we want to store
66
 * \param compress_depth how much compressed data we want to decompress
67
 *
68
 * \retval 1 if decompression works
69
 * \retval 0 an error occurred, and event set
70
 */
71
int FileSwfDecompression(const uint8_t *buffer, uint32_t buffer_len,
72
                         DetectEngineThreadCtx *det_ctx,
73
                         InspectionBuffer *out_buffer,
74
                         int swf_type,
75
                         uint32_t decompress_depth,
76
                         uint32_t compress_depth)
77
1
{
78
1
    int r = 0;
79
80
1
    int compression_type = FileIsSwfFile(buffer, buffer_len);
81
1
    if (compression_type == FILE_SWF_NO_COMPRESSION) {
82
0
        return 0;
83
0
    }
84
85
1
    uint32_t offset = 0;
86
1
    if (compression_type == FILE_SWF_ZLIB_COMPRESSION) {
87
        /* compressed data start from the 4th bytes */
88
1
        offset = 8;
89
1
    } else if (compression_type == FILE_SWF_LZMA_COMPRESSION) {
90
        /* compressed data start from the 17th bytes */
91
0
        offset = 17;
92
0
    }
93
94
1
    if (buffer_len <= offset) {
95
0
        DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_INVALID_SWF_LENGTH);
96
0
        return 0;
97
0
    }
98
99
1
    uint32_t compressed_data_len = 0;
100
1
    if (compress_depth > 0 && compress_depth <= buffer_len - offset) {
101
0
        compressed_data_len = compress_depth;
102
1
    } else {
103
1
        compressed_data_len = buffer_len - offset;
104
1
    }
105
106
    /* get swf version */
107
1
    uint8_t swf_version = FileGetSwfVersion(buffer, buffer_len);
108
1
    if (compression_type == FILE_SWF_ZLIB_COMPRESSION &&
109
1
        swf_version < SWF_ZLIB_MIN_VERSION)
110
0
    {
111
0
        DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_INVALID_SWF_VERSION);
112
0
        return 0;
113
0
    }
114
1
    if (compression_type == FILE_SWF_LZMA_COMPRESSION &&
115
0
        swf_version < SWF_LZMA_MIN_VERSION)
116
0
    {
117
0
        DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_INVALID_SWF_VERSION);
118
0
        return 0;
119
0
    }
120
121
    /* get flash decompressed file length */
122
1
    uint32_t decompressed_swf_len = FileGetSwfDecompressedLen(buffer, buffer_len);
123
1
    if (decompressed_swf_len == 0) {
124
0
        decompressed_swf_len = MIN_SWF_LEN;
125
0
    }
126
127
    /* if decompress_depth is 0, keep the flash file length */
128
1
    uint32_t decompressed_data_len = (decompress_depth == 0) ? decompressed_swf_len : decompress_depth;
129
1
    decompressed_data_len += 8;
130
131
    /* make sure the inspection buffer has enough space */
132
1
    InspectionBufferCheckAndExpand(out_buffer, decompressed_data_len);
133
1
    if (out_buffer->size < decompressed_data_len) {
134
0
        DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_NO_MEM);
135
0
        return 0;
136
0
    }
137
1
    out_buffer->len = decompressed_data_len;
138
139
    /*
140
     * FWS format
141
     * | 4 bytes         | 4 bytes    | n bytes |
142
     * | 'FWS' + version | script len | data    |
143
     */
144
1
    out_buffer->buf[0] = 'F';
145
1
    out_buffer->buf[1] = 'W';
146
1
    out_buffer->buf[2] = 'S';
147
1
    out_buffer->buf[3] = swf_version;
148
1
    memcpy(out_buffer->buf + 4, &decompressed_swf_len, 4);
149
1
    memset(out_buffer->buf + 8, 0, decompressed_data_len - 8);
150
151
1
    if ((swf_type == HTTP_SWF_COMPRESSION_ZLIB || swf_type == HTTP_SWF_COMPRESSION_BOTH) &&
152
1
            compression_type == FILE_SWF_ZLIB_COMPRESSION)
153
1
    {
154
        /* the first 8 bytes represents the fws header, see 'FWS format' above.
155
         * data will start from 8th bytes
156
         */
157
1
        r = FileSwfZlibDecompression(det_ctx,
158
1
                                     (uint8_t *)buffer + offset, compressed_data_len,
159
1
                                     out_buffer->buf + 8, out_buffer->len - 8);
160
1
        if (r == 0)
161
0
            goto error;
162
163
1
    } else if ((swf_type == HTTP_SWF_COMPRESSION_LZMA || swf_type == HTTP_SWF_COMPRESSION_BOTH) &&
164
0
               compression_type == FILE_SWF_LZMA_COMPRESSION)
165
0
    {
166
        /* we need to setup the lzma header */
167
        /*
168
         * | 5 bytes         | 8 bytes             | n bytes         |
169
         * | LZMA properties | Uncompressed length | Compressed data |
170
         */
171
0
        compressed_data_len += 13;
172
0
        uint8_t *compressed_data = SCCalloc(1, compressed_data_len);
173
0
        if (compressed_data == NULL) {
174
0
            goto error;
175
0
        }
176
        /* put lzma properties */
177
0
        memcpy(compressed_data, buffer + 12, 5);
178
        /* put lzma end marker */
179
0
        memset(compressed_data + 5, 0xFF, 8);
180
        /* put compressed data */
181
0
        memcpy(compressed_data + 13, buffer + offset, compressed_data_len - 13);
182
183
        /* the first 8 bytes represents the fws header, see 'FWS format' above.
184
         * data will start from 8th bytes
185
         */
186
0
        r = FileSwfLzmaDecompression(det_ctx,
187
0
                                     compressed_data, compressed_data_len,
188
0
                                     out_buffer->buf + 8, out_buffer->len - 8);
189
0
        SCFree(compressed_data);
190
0
        if (r == 0)
191
0
            goto error;
192
0
    } else {
193
0
        goto error;
194
0
    }
195
196
    /* all went well so switch the buffer's inspect pointer/size
197
     * to use the new data. */
198
1
    out_buffer->inspect = out_buffer->buf;
199
1
    out_buffer->inspect_len = out_buffer->len;
200
201
1
    return 1;
202
203
0
error:
204
0
    return 0;
205
1
}