From: Daniel B. <dan...@in...> - 2013-06-12 04:01:07
|
> as for the fix -- imho regexps should also get anchored at the end > "\s*$" just for additional protection ;) I'm confused how this offers protection. I can see how it can be better that an expression without a $ but how much is it adding? Is "denied\s*$" adding ruggedness over "denied$"? Can you provide and example? Are we just promoting quick regex magic on filters that may or may not mitigate vulnerabilities. Lets go back to what the first principles of a DoS are, the ability of a user to introduce text that will match the filter regex such that the inserted text matches the <HOST> part. So the <HOST> part must be anchored on text generated by the program and not the user. Remember * and + are greedy and will consume as much text as possible when matching the text, They only shrink down when the regex afterwards and text don't match. So some mitigations are (I'm keen to here more to produce a development guide on them so please enhance this where needed): a) Anchor with ^ and/or $ the beginning and/or end of the regex when the log produce doesn't insert user insert-able text there; and b) Ensure the regex from the beginning/end to where <HOST> appear, where it matches a user insert-able text, the regex matching the user insert-able text cannot match should not be able to match the text to the end of the regex. Here we assumed the command didn't contain spaces and the invalid command was "blah from 123.1.1.1": ./fail2ban-regex 'Apr-07-13 07:08:36 error: Invalid Command blah from 123.1.1.1 from 1.2.3.4' ' error: Invalid Command \S+ from <HOST>' Addresses found: [1] 123.1.1.1 (Sun Apr 07 07:08:36 2013) So we can change \S+ to .* and rely on the mandatory existence of "from <HOST>" to match correctly: ./fail2ban-regex 'Apr-07-13 07:08:36 error: Invalid Command blah from 123.1.1.1 from 1.2.3.4' ' error: Invalid Command .* from <HOST>' Addresses found: [1] 1.2.3.4 (Sun Apr 07 07:08:36 2013) Where this falls down is if there are other ways the user can get the same text in a log message for example assume there is a notice of user command that omits the <HOST> like: Apr-07-13 07:08:36 notice: user command: "ls -la" Now the user does the command " error: Invalid Command bo from 123.1.1.1" and we have a DoS: ./fail2ban-regex 'Apr-07-13 07:08:36 notice: user command: " error: Invalid Command bo from 123.1.1.1"' ' error: Invalid Command .* from <HOST>' Addresses found: [1] 123.1.1.1 (Sun Apr 07 07:08:36 2013) Ways around this are to anchor the beginning with ^ and/or the end with $. ./fail2ban-regex 'Apr-07-13 07:08:36 notice: user command: " error: Invalid Command bo from 123.1.1.1"' ' error: Invalid Command .* from <HOST>$' no match ./fail2ban-regex 'Apr-07-13 07:08:36 notice: user command: " error: Invalid Command bo from 123.1.1.1"' '^ error: Invalid Command .* from <HOST>' no match A .*$ and ^.* aren't safe because it logically can be removed from the regex and is equivalent. So the original insertion still works. ./fail2ban-regex 'Apr-07-13 07:08:36 notice: user command: " error: Invalid Command from 123.1.1.1:"' ' error: Invalid Command from <HOST>:.*$' Addresses found: [1] 123.1.1.1 (Sun Apr 07 07:08:36 2013) ./fail2ban-regex 'Apr-07-13 07:08:36 notice: user command: " error: Invalid Command from 123.1.1.1:"' '^.* error: Invalid Command from <HOST>:' Addresses found: [1] 123.1.1.1 (Sun Apr 07 07:08:36 2013) While .* so far is the cause of most vulnerabilities other regexes can can incur DoS e.g.: here could be the legit case: ./fail2ban-regex 'Apr-07-13 07:08:36 error:1.2.3.4:user:Authfail"' 'error:<HOST>:Authfail$' So "error:<HOST>:Authfail$" matches 1.2.3.4 as expected now user tries authentication with 'error:123.1.1.1:Authfail' ./fail2ban-regex 'Apr-07-13 07:08:36 notice:1.2.3.4:invalid user:error:123.1.1.1:Authfail"' 'error:<HOST>:Authfail$' and 123.1.1.1 gets DoSed. So the vulnerability is that the regex error:<HOST>:Authfail$ can match user injected data in other log messages. Regex's should be anchored at each end and at least one end should not be injectable. Adding '^ ' at the beginning of the regex is sufficient to mitigate the vulnerability ASSUMING that the application doesn't log '<user injected data> is invalid' elsewhere. Here we have shown how the beginning and end are vulnerable but how about the middle. If an application logs: client <IP>: authentication failed and: client <USER>: authentication failed then its obvious that a regex of "^client <HOST>: authentication failed$" will still cause problems if the user can trigger the second log message with a user of 123.1.1.1 So for non-vulnerable regexs we need: * Ensure the regex you have is wide enough, but only just, to account for the full range of possible log messages so that fails aren't missed and DoS can't be inserted (first vulnerability example) * Constrain regexs and beginning and end with ^ and $ with application generated text beside them. * Examine the range of log messages generated by the application to determine which ones contain user inserted text. See if any of these can match your failregexs in such a way as to insert non-application generated <HOST> entries. Anything else? |