It's possible to inject text in the not-found message in order to trick the user to make him visit website or do something an attacker might be interested in.
It is returning the user input in the not-found message body. This can be misused in a number of ways.
Proof Of Concept:
https://drupal7.example/.htcaccess/***Attention!***%2f../Site%20has%20been%20replace%20by%20a%20new%20one%20https://www.google.com%20so%20go%20to%20the%20new%20one%20since%20this%20one
In some other cases, like
https://drupal7.example/htaccess // without dot for example
everything's fine and
# Make Drupal handle any 404 errors.
ErrorDocument 404 /index.php
in .htaccess file working as expected and Drupal handle all 404 errors.
Any idea how to fix this and make Drupal handle all 404 errors including the one from example?
This behavior is due to the presence of %2F
(encoded slash /
) in URL.
Apache uses the AllowEncodedSlashes
directive to determine whether encoded path separators in URLs are allowed to be passed through. Default is Off
, in which case getting an Apache 404 instead of a Drupal 404 is "normal" when you have %2f
in URL :
The AllowEncodedSlashes directive allows URLs which contain encoded path separators (%2F for / and additionally %5C for \ on accordant systems) to be used in the path info.
Off : such URLs are refused with a 404 (Not found) error.
On : such URLs are accepted, and encoded slashes are decoded like all other encoded characters.
NoDecode : such URLs are accepted, but encoded slashes are not decoded but left in their encoded state.
Default is Off
because letting Apache blindly decodes path separators would expose your machine to directory traversal attacks (see CVE-2007-0450), setting this directive to On
is not safe.
Fortunately, the NoDecode
option (available since version 2.3.12) allows to accept such URLs without exposing your server, so to fix that and let Drupal handle such requests in 404 or whatever, just add the directive in httpd.conf :
AllowEncodedSlashes NoDecode
Note : Virtual hosts don't inherit this directive from the global context, it's required to reset the directive to the desired value in virtual host container(s), otherwise it will take the default value.
Now, if you still get a server 404 instead of a drupal 404, that's probably because the directive ErrorDocument 404
is not taken into account, or is overridden somewhere.
A quick way to check whether or not this directive is actually loaded is precisely to set a static content (by the way in this case there's no input display issue ;) :
ErrorDocument 404 "Page not found"
Maybe the correct behavior for Apache would be to catch this kind of urls as 403, and to let drupal handle it as well you would set ErrorDocument 403 /index.php
.
It's also worth noting that the generic drupal 404 "page not found" page can easily be overridden at admin/config/system/site-information
, as well as the 403 "access denied" page.