1
1
#!/usr/bin/env php
2
2
<?php
3
3
// Author: Jamie Davis <[email protected] >
4
- // Description: Try REDOS attack on PHP
4
+ // Description: Evaluate a regex in PHP
5
5
6
6
function my_log ($ msg ) {
7
7
fwrite (STDERR , $ msg . "\n" );
8
8
}
9
9
10
+ // Return a string that can be used
11
+ // Returns NULL if nothing could be found
12
+ function patternAsPHPRegex ($ pat ) {
13
+ //http://php.net/manual/en/regexp.reference.delimiters.php
14
+ $ pairedDelimiters = [
15
+ ['/ ' , '/ ' ],
16
+ ['# ' , '# ' ],
17
+ ['` ' , '` ' ],
18
+ ['( ' , ') ' ],
19
+ ['{ ' , '} ' ],
20
+ ['[ ' , '] ' ],
21
+ ['< ' , '> ' ],
22
+ ];
23
+ foreach ($ pairedDelimiters as $ delim ) {
24
+ $ first = $ delim [0 ];
25
+ $ last = $ delim [1 ];
26
+ if (strpos ($ pat , $ first ) === FALSE && strpos ($ pat , $ last ) === FALSE ) {
27
+ return $ first . $ pat . $ last ;
28
+ }
29
+ }
30
+
31
+ return NULL ;
32
+ }
33
+
10
34
function main () {
11
35
// Assume args are correct, this is a horrible language.
12
36
global $ argc , $ argv ;
@@ -18,43 +42,56 @@ function main() {
18
42
my_log ('obj ' );
19
43
20
44
// Query regexp.
21
- my_log ('matching: Pattern / ' . $ obj ->{'pattern ' } . '/, input: len ' . strlen ($ obj ->{'input ' }));
45
+ $ phpPattern = patternAsPHPRegex ($ obj ->{'pattern ' });
46
+ if (!is_null ($ phpPattern )) {
47
+ my_log ('matching: pattern ' . $ obj ->{'pattern ' } . ' --> phpPattern ' . $ phpPattern );
48
+ my_log ('matching: Pattern ' . $ phpPattern . ', input: len ' . strlen ($ obj ->{'input ' }));
22
49
23
- $ matched = @preg_match (' / ' . $ obj ->{ ' pattern ' } . ' / ' , $ obj ->{'input ' }, $ matches ); // Partial match
24
- //var_dump($matches);
25
- // NB: (a?)abc|(d) on "abc" --> (a?) is empty, but (d) is just dropped
50
+ $ matched = @preg_match ($ phpPattern , $ obj ->{'input ' }, $ matches ); // Partial match
51
+ //var_dump($matches);
52
+ // NB: (a?)abc|(d) on "abc" --> (a?) is empty, but trailing unused groups like (d) are just dropped
26
53
27
- // capture exception, if any.
28
- // will return OK even if there's compilation problems.
29
- // PHP 7.4-dev emits a warning unless we @ to ignore it.
30
- $ except = @array_flip (get_defined_constants (true )['pcre ' ])[preg_last_error ()];
54
+ // capture exception, if any.
55
+ // will return OK even if there's compilation problems.
56
+ // PHP 7.4-dev emits a warning unless we @ to ignore it.
57
+ $ except = @array_flip (get_defined_constants (true )['pcre ' ])[preg_last_error ()];
31
58
32
- // check for compilation
33
- $ compilation_failed_message = 'preg_match(): Compilation failed: ' ;
34
- $ last_error = error_get_last ();
35
- if (strpos ($ last_error ['message ' ], $ compilation_failed_message ) !== false ) {
36
- my_log ("caught the invalid input " );
37
- $ except = "INVALID_INPUT " ;
38
- $ obj ->{'validPattern ' } = 0 ;
39
- } else {
40
- $ obj ->{'validPattern ' } = 1 ;
41
- }
59
+ // check for compilation
60
+ $ compilation_failed_message = 'preg_match(): Compilation failed: ' ;
61
+ $ last_error = error_get_last ();
62
+ if (strpos ($ last_error ['message ' ], $ compilation_failed_message ) !== false ) {
63
+ my_log ("caught the invalid input " );
64
+ $ except = "INVALID_INPUT " ; // Override compilation failed
65
+ $ obj ->{'validPattern ' } = 0 ;
66
+ } else {
67
+ $ obj ->{'validPattern ' } = 1 ;
68
+ }
42
69
43
- // Compose output.
44
- $ obj ->{'matched ' } = $ matched ;
45
- if ($ matched ) {
46
- $ obj ->{'matchContents ' } = new stdClass ();
47
- $ obj ->{'matchContents ' }->{'matchedString ' } = $ matches [0 ];
70
+ // Compose output.
71
+ $ obj ->{'matched ' } = $ matched ;
72
+ if ($ matched ) {
73
+ $ obj ->{'matchContents ' } = new stdClass ();
74
+ $ obj ->{'matchContents ' }->{'matchedString ' } = $ matches [0 ];
48
75
49
- // Unset any capture groups keyed by name instead of number for consistency with other testers
50
- foreach ($ matches as $ key => $ value ) {
51
- if (!is_int ($ key )) {
52
- unset($ matches [$ key ]);
76
+ // Unset any capture groups keyed by name instead of number for consistency with other testers
77
+ foreach ($ matches as $ key => $ value ) {
78
+ if (!is_int ($ key )) {
79
+ unset($ matches [$ key ]);
80
+ }
53
81
}
54
- }
55
82
56
- $ obj ->{'matchContents ' }->{'captureGroups ' } = array_slice ($ matches , 1 );
83
+ $ obj ->{'matchContents ' }->{'captureGroups ' } = array_slice ($ matches , 1 );
84
+ }
85
+ } else {
86
+ $ except = "INVALID_INPUT " ; // Override compilation failed
87
+ $ obj ->{'validPattern ' } = 0 ;
88
+ // Dummy values
89
+ $ obj ->{'matched ' } = 0 ;
90
+ $ obj ->{'matchContents ' } = new stdClass ();
91
+ $ obj ->{'matchContents ' }->{'matchedString ' } = "" ;
92
+ $ obj ->{'matchContents ' }->{'captureGroups ' } = [];
57
93
}
94
+
58
95
$ obj ->{'inputLength ' } = strlen ($ obj ->{'input ' });
59
96
$ obj ->{'exceptionString ' } = $ except ;
60
97
fwrite (STDOUT , json_encode ($ obj ) . "\n" );
0 commit comments