PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.2
Jetpack – WP Security, Backup, Speed, & Growth v16.2
16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 All 506 releases
jetpack / jetpack_vendor / automattic / jetpack-waf / src / class-waf-transforms.php

class-waf-transforms.php in Jetpack – WP Security, Backup, Speed, & Growth 16.2, at jetpack_vendor/automattic/jetpack-waf/src/class-waf-transforms.php

404 lines 10.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Transforms for Jetpack Waf
4 *
5 * @package automattic/jetpack-waf
6 */
7
8 namespace Automattic\Jetpack\Waf;
9
10 /**
11 * Waf_Transforms class
12 */
13 class Waf_Transforms {
14
15 /**
16 * Decode a Base64-encoded string. This runs the decode without strict mode, to match Modsecurity's 'base64DecodeExt' transform function.
17 *
18 * @param string $value value to be decoded.
19 * @return string
20 */
21 public function base64_decode_ext( $value ) {
22 return base64_decode( $value );
23 }
24
25 /**
26 * Characters to match when trimming a string.
27 * Emulates `std::isspace` used by ModSecurity.
28 *
29 * @see https://en.cppreference.com/w/cpp/string/byte/isspace
30 */
31 const TRIM_CHARS = " \n\r\t\v\f";
32
33 /**
34 * Decode a Base64-encoded string. This runs the decode with strict mode, to match Modsecurity's 'base64Decode' transform function.
35 *
36 * @param string $value value to be decoded.
37 * @return string
38 */
39 public function base64_decode( $value ) {
40 return base64_decode( $value, true );
41 }
42
43 /**
44 * Remove all characters that might escape a command line command
45 *
46 * @see https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-%28v2.x%29#cmdLine
47 * @param string $value value to be escaped.
48 * @return string
49 */
50 public function cmd_line( $value ) {
51 return strtolower(
52 preg_replace(
53 '/\s+/',
54 ' ',
55 str_replace(
56 array( ',', ';' ),
57 ' ',
58 preg_replace(
59 '/\s+(?=[\/\(])/',
60 '',
61 str_replace(
62 array( '^', "'", '"', '\\' ),
63 '',
64 $value
65 )
66 )
67 )
68 )
69 );
70 }
71
72 /**
73 * Decode a SQL hex string.
74 *
75 * @example 414243 decodes to "ABC"
76 * @param string $value value to be decoded.
77 * @return string
78 */
79 public function sql_hex_decode( $value ) {
80 return preg_replace_callback(
81 '/0x[a-f0-9]+/i',
82 function ( $matches ) {
83 $str = substr( $matches[0], 2 );
84 if ( 0 !== strlen( $str ) % 2 ) {
85 $str = '0' . $str;
86 }
87 return hex2bin( $str );
88 },
89 $value
90 );
91 }
92
93 /**
94 * Encode a string using Base64 encoding.
95 *
96 * @param string $value value to be decoded.
97 * @return string
98 */
99 public function base64_encode( $value ) {
100 return base64_encode( $value );
101 }
102
103 /**
104 * Convert all whitespace characters to a space and remove any repeated spaces.
105 *
106 * @param string $value value to be converted.
107 * @return string
108 */
109 public function compress_whitespace( $value ) {
110 return preg_replace( '/\s+/', ' ', $value );
111 }
112
113 /**
114 * Encode string (possibly containing binary characters) by replacing each input byte with two hexadecimal characters.
115 *
116 * @param string $value value to be encoded.
117 * @return string
118 */
119 public function hex_encode( $value ) {
120 return bin2hex( $value );
121 }
122
123 /**
124 * Decode string that was previously encoded by hexEncode()
125 *
126 * @param string $value value to be decoded.
127 * @return string
128 */
129 public function hex_decode( $value ) {
130 return pack( 'H*', $value );
131 }
132
133 /**
134 * Decode the characters encoded as HTML entities.
135 *
136 * @param mixed $value value do be decoded.
137 * @return string
138 */
139 public function html_entity_decode( $value ) {
140 return html_entity_decode( $value, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
141 }
142
143 /**
144 * Return the length of the input string.
145 *
146 * @param string $value input string.
147 * @return int
148 */
149 public function length( $value ) {
150 return strlen( $value );
151 }
152
153 /**
154 * Convert all characters to lowercase.
155 *
156 * @param string $value string to be converted.
157 * @return string
158 */
159 public function lowercase( $value ) {
160 return strtolower( $value );
161 }
162
163 /**
164 * Calculate an md5 hash for the given data
165 *
166 * @param mixed $value value to be hashed.
167 * @return string
168 */
169 public function md5( $value ) {
170 return md5( $value, true );
171 }
172
173 /**
174 * Removes multiple slashes, directory self-references, and directory back-references (except when at the beginning of the input) from input string.
175 *
176 * @param string $value value to be normalized.
177 * @return string
178 */
179 public function normalize_path( $value ) {
180 $parts = explode(
181 '/',
182 // replace any duplicate slashes with a single one.
183 preg_replace( '~/{2,}~', '/', $value )
184 );
185
186 $i = 0;
187 while ( isset( $parts[ $i ] ) ) {
188 switch ( $parts[ $i ] ) {
189 // If this folder is a self-reference, remove it.
190 case '..':
191 // If this folder is a backreference, remove it unless we're already at the root.
192 if ( isset( $parts[ $i - 1 ] ) && ! in_array( $parts[ $i - 1 ], array( '', '..' ), true ) ) {
193 array_splice( $parts, $i - 1, 2 );
194 --$i;
195 continue 2;
196 }
197 break;
198 case '.':
199 array_splice( $parts, $i, 1 );
200 continue 2;
201 }
202 ++$i;
203 }
204
205 return implode( '/', $parts );
206 }
207
208 /**
209 * Convert backslash characters to forward slashes, and then normalize using `normalizePath`
210 *
211 * @param string $value to be normalized.
212 * @return string
213 */
214 public function normalize_path_win( $value ) {
215 return $this->normalize_path( str_replace( '\\', '/', $value ) );
216 }
217
218 /**
219 * Removes all NUL bytes from input.
220 *
221 * @param string $value value to be filtered.
222 * @return string
223 */
224 public function remove_nulls( $value ) {
225 return str_replace( "\x0", '', $value );
226 }
227
228 /**
229 * Remove all whitespace characters from input.
230 *
231 * @param string $value value to be filtered.
232 * @return string
233 */
234 public function remove_whitespace( $value ) {
235 return preg_replace( '/\s/', '', $value );
236 }
237
238 /**
239 * Replaces each occurrence of a C-style comment (/ * ... * /) with a single space.
240 * Unterminated comments will also be replaced with a space. However, a standalone termination of a comment (* /) will not be acted upon.
241 *
242 * @param string $value value to be filtered.
243 * @return string
244 */
245 public function replace_comments( $value ) {
246 $value = preg_replace( '~/\*.*?\*/|/\*.*?$~Ds', ' ', $value );
247 return explode( '/*', $value, 2 )[0];
248 }
249
250 /**
251 * Removes common comments chars (/ *, * /, --, #).
252 *
253 * @param string $value value to be filtered.
254 * @return string
255 */
256 public function remove_comments_char( $value ) {
257 return preg_replace( '~/*|*/|--|#|//~', '', $value );
258 }
259
260 /**
261 * Replaces each NUL byte in input with a space.
262 *
263 * @param string $value value to be filtered.
264 * @return string
265 */
266 public function replace_nulls( $value ) {
267 return str_replace( "\x0", ' ', $value );
268 }
269
270 /**
271 * Decode a URL-encoded input string.
272 *
273 * @param string $value value to be decoded.
274 * @return string
275 */
276 public function url_decode( $value ) {
277 return urldecode( $value );
278 }
279
280 /**
281 * Decode a URL-encoded input string.
282 *
283 * @param string $value value to be decoded.
284 * @return string
285 */
286 public function url_decode_uni( $value ) {
287 error_log( 'JETPACKWAF TRANSFORM NOT IMPLEMENTED: urlDecodeUni' );
288 return $value;
289 }
290
291 /**
292 * Decode a json encoded input string.
293 *
294 * @param string $value value to be decoded.
295 * @return string
296 */
297 public function js_decode( $value ) {
298 error_log( 'JETPACKWAF TRANSFORM NOT IMPLEMENTED: jsDecode' );
299 return $value;
300 }
301
302 /**
303 * Convert all characters to uppercase.
304 *
305 * @param string $value value to be encoded.
306 * @return string
307 */
308 public function uppercase( $value ) {
309 return strtoupper( $value );
310 }
311
312 /**
313 * Calculate a SHA1 hash from the input string.
314 *
315 * @param mixed $value value to be hashed.
316 * @return string
317 */
318 public function sha1( $value ) {
319 return sha1( $value, true );
320 }
321
322 /**
323 * Remove whitespace from the left side of the input string.
324 *
325 * @param string $value value to be trimmed.
326 * @return string
327 */
328 public function trim_left( $value ) {
329 return ltrim( $value, self::TRIM_CHARS );
330 }
331
332 /**
333 * Remove whitespace from the right side of the input string.
334 *
335 * @param string $value value to be trimmed.
336 * @return string
337 */
338 public function trim_right( $value ) {
339 return rtrim( $value, self::TRIM_CHARS );
340 }
341
342 /**
343 * Remove whitespace from both sides of the input string.
344 *
345 * @param string $value value to be trimmed.
346 * @return string
347 */
348 public function trim( $value ) {
349 return trim( $value, self::TRIM_CHARS );
350 }
351
352 /**
353 * Convert UTF-8 characters to Unicode characters.
354 *
355 * This function iterates through each character of the input string, checks the ASCII value,
356 * and converts it to its corresponding Unicode representation. It handles characters that are
357 * represented with 1 to 4 bytes in UTF-8.
358 *
359 * @param string $str The string value to be encoded from UTF-8 to Unicode.
360 * @return string The converted string with Unicode representation.
361 */
362 public function utf8_to_unicode( $str ) {
363 $unicodeStr = '';
364 $strLen = strlen( $str );
365 $i = 0;
366
367 // Iterate through each character of the input string.
368 while ( $i < $strLen ) {
369 // Get the ASCII value of the current character.
370 $value = ord( $str[ $i ] );
371
372 if ( $value < 128 ) {
373 // If the character is in the ASCII range (0-127), directly add it to the Unicode string.
374 $unicodeStr .= chr( $value );
375 ++$i;
376 } else {
377 // For characters outside the ASCII range, determine the number of bytes in the UTF-8 representation.
378 $unicodeValue = '';
379 if ( $value >= 192 && $value <= 223 ) {
380 // For characters represented with 2 bytes in UTF-8.
381 $unicodeValue = ( ord( $str[ $i ] ) & 0x1F ) << 6 | ( ord( $str[ $i + 1 ] ) & 0x3F );
382 $i += 2;
383 } elseif ( $value >= 224 && $value <= 239 ) {
384 // For characters represented with 3 bytes in UTF-8.
385 $unicodeValue = ( ord( $str[ $i ] ) & 0x0F ) << 12 | ( ord( $str[ $i + 1 ] ) & 0x3F ) << 6 | ( ord( $str[ $i + 2 ] ) & 0x3F );
386 $i += 3;
387 } elseif ( $value >= 240 && $value <= 247 ) {
388 // For characters represented with 4 bytes in UTF-8.
389 $unicodeValue = ( ord( $str[ $i ] ) & 0x07 ) << 18 | ( ord( $str[ $i + 1 ] ) & 0x3F ) << 12 | ( ord( $str[ $i + 2 ] ) & 0x3F ) << 6 | ( ord( $str[ $i + 3 ] ) & 0x3F );
390 $i += 4;
391 } else {
392 // If the sequence does not match any known UTF-8 pattern, skip to the next character.
393 ++$i;
394 continue;
395 }
396 // Convert the Unicode value to a formatted string and append it to the Unicode string.
397 $unicodeStr .= sprintf( '%%u%04X', $unicodeValue );
398 }
399 }
400
401 return strtolower( $unicodeStr );
402 }
403 }
404