/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 | } |