Summary: | SSI include ignores SymlinkIfOwnerMatch directive | ||
---|---|---|---|
Product: | Apache httpd-2 | Reporter: | Paul B. Henson <henson> |
Component: | mod_include | Assignee: | Apache HTTPD Bugs Mailing List <bugs> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | dlandin, johannes+bugs, mikevs |
Priority: | P2 | Keywords: | FixedInTrunk |
Version: | 2.2.8 | ||
Target Milestone: | --- | ||
Hardware: | Sun | ||
OS: | Solaris | ||
Attachments: | Patch to disable ap_directory_walk cache |
Description
Paul B. Henson
2008-10-06 18:56:00 UTC
Just wondering if anyone had any thoughts on this? I'd like to verify if this is actually a bug, or expected behavior... Thanks... Include cgi and include file do not validate their context. Include virtual is what you were looking for, it does validate the cgi or file resource included virtually. Thanks for taking a look at this. However, include virtual appears to have the exact same problem. Given the following files in my web home directory: lrwxrwxrwx 1 henson csupomona 27 Oct 3 14:01 pass.html -> /usr/pkg/etc/httpd/htpasswd -rw-r--r-- 1 henson csupomona 37 Oct 9 17:50 test_ssi.shtml If I attempt to access /~henson/pass.html, I receive "Forbidden You don't have permission to access /~henson/pass.html on this server." as expected. The contents of test_ssi.shtml are: <!--#include virtual="pass.html" --> When I access /~henson/test_ssi.shtml, the contents of /usr/pkg/etc/httpd/htpasswd appear in my browser. As far as I can tell, "include virtual" also appears to ignore the setting of SymlinkIfOwnerMatch. In addition, while you can enable includes without exec, I don't believe there is a way to allow include virtual only, IncludesNoExec allows both file and virtual includes. So even if include virtual respected SymlinkIfOwnerMatch (which it appears not to, unless I am missing something), it would not resolve the issue of being able to have SSI enabled on a server while preventing users from serving content via symbolic links. can you take a moment to ensure your browser cache is completely flushed out and the server is restarted before trying /~henson/test_ssi.shtml once more? Just want to rule out that you aren't looking at the prior request. I'll do you one better than flushing my browser cache ;) : ----- $ telnet 134.71.248.148 80 Trying 134.71.248.148... Connected to 134.71.248.148. Escape character is '^]'. GET /~henson/test_ssi.shtml HTTP/1.1 Host: www.csupomona.edu HTTP/1.1 200 OK Date: Fri, 10 Oct 2008 01:28:09 GMT Server: Apache/2.2.8 (Unix) mod_ssl/2.2.8 OpenSSL/0.9.8g Accept-Ranges: bytes Transfer-Encoding: chunked Content-Type: text/html 7 secret ----- "secret" is the contents of /usr/pkg/etc/httpd/htpasswd, I'm just using it as a test. It's quite possible I am doing something stupid anyway, in which case I apologize in advance; but as far as I can tell everything is configured correctly. Ideally I would like both virtual and file SSI includes to respect symbolic link restrictions, as I was counting on that for my deployment; the users will revolt if our new services don't include SSI, but my plan for deploying authenticated content will not be secure if any of them are able to create symlinks to and serve arbitrary web server readable content :(. Thanks much... Please post your configuration. I stripped the configuration down to the bare minimum to demonstrate the problem: ------------------------------------- ServerRoot "/usr/pkg" Listen 0.0.0.0:8080 LoadModule authz_host_module lib/httpd/mod_authz_host.so LoadModule include_module lib/httpd/mod_include.so LoadModule log_config_module lib/httpd/mod_log_config.so LoadModule mime_module lib/httpd/mod_mime.so User webservd Group webservd ServerAdmin root@csupomona.edu ServerName www.csupomona.edu:8080 UseCanonicalName On DocumentRoot "/usr/pkg/share/httpd/htdocs" PidFile "/var/run/httpd-test.pid" LockFile "/var/log/httpd/accept-test.lock" <Directory /> Options -FollowSymLinks AllowOverride None Order deny,allow Deny from all </Directory> <Directory "/usr/pkg/share/httpd/htdocs"> Options -FollowSymLinks AllowOverride None Order allow,deny Allow from all </Directory> LogLevel warn ErrorLog "/var/log/httpd/error-test_log" LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined CustomLog "/var/log/httpd/access-test_log" combined AddOutputFilter INCLUDES .shtml ------------------------------- The contents of /usr/pkg/share/httpd/htdocs are: -rw-r--r-- 1 root root 2326 Jun 25 09:58 apache_pb.gif -rw-r--r-- 1 root root 1385 Jun 25 09:58 apache_pb.png -rw-r--r-- 1 root root 2410 Jun 25 09:58 apache_pb22.gif -rw-r--r-- 1 root root 1502 Jun 25 09:58 apache_pb22.png -rw-r--r-- 1 root root 2205 Jun 25 09:58 apache_pb22_ani.gif -rw-r--r-- 1 root root 44 Jun 25 09:58 index.html lrwxrwxrwx 1 root root 32 Oct 10 17:01 secret.html -> /usr/pkg/etc/httpd/htaccess-test -rw-r--r-- 1 root root 39 Oct 10 16:55 test_ssi.shtml The ownership/permissions of the file /usr/pkg/etc/httpd/htaccess-test are: -rw-r----- 1 root webservd 12 Oct 10 17:01/usr/pkg/etc/httpd/htaccess-test (Note: in this case, the ownership of the actual file matches the ownership of the symbolic link, but I changed the test configuration to "Options -FollowSymLinks" so it should not be allowed regardless) The contents of test_ssi.shtml are: <!--#include virtual="secret.html" --> To rule out any browser caching or idiosyncrasies, I tested by connecting directly to the web server via telnet. Attempting to access the symbolic link directly failed as expected: ----- # telnet 0 8080 Trying 0.0.0.0... Connected to 0. Escape character is '^]'. GET /secret.html HTTP/1.1 Host: www.csupomona.edu HTTP/1.1 403 Forbidden Date: Sat, 11 Oct 2008 00:03:08 GMT Server: Apache/2.2.8 (Unix) Content-Length: 213 Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>403 Forbidden</title> </head><body> <h1>Forbidden</h1> <p>You don't have permission to access /secret.html on this server.</p> </body></html> -------------- With the following in the access/error log: 127.0.0.1 - - [10/Oct/2008:17:03:08 -0700] "GET /secret.html HTTP/1.1" 403 213 "-" "-" [Fri Oct 10 17:03:11 2008] [error] [client 127.0.0.1] Symbolic link not allowed or link target not accessible: /usr/pkg/share/httpd/htdocs/secret.html However, accessing the SSI file did not result in any errors, and returned the contents of the file pointed to by the symbolic link: ------ # telnet 0 8080 Trying 0.0.0.0... Connected to 0. Escape character is '^]'. GET /test_ssi.shtml HTTP/1.1 Host: www.csupomona.edu HTTP/1.1 200 OK Date: Sat, 11 Oct 2008 00:04:12 GMT Server: Apache/2.2.8 (Unix) Accept-Ranges: bytes Transfer-Encoding: chunked Content-Type: text/plain c secret data ------ There was nothing in the error log, and only the following in the access log: 127.0.0.1 - - [10/Oct/2008:17:04:12 -0700] "GET /test_ssi.shtml HTTP/1.1" 200 13 "-" "-" Ideally, I would expect the server-side include code to follow the same configuration regarding symbolic links as accessing the links directly would. Is this expected behavior? A bug? A problem with my configuration or misunderstanding on my part? Thanks... Any further thoughts on this? Thanks... I dug into this some more. In the file request.c, the function ap_directory_walk contains the following code: /* If we have a file already matches the path of r->filename, * and the vhost's list of directory sections hasn't changed, * we can skip rewalking the directory_walk entries. */ if (cache->cached && ((r->finfo.filetype == APR_REG) || ((r->finfo.filetype == APR_DIR) && (!r->path_info || !*r->path_info))) && (cache->dir_conf_tested == sec_ent) && (strcmp(entry_dir, cache->cached) == 0)) { /* Well this looks really familiar! If our end-result (per_dir_result) * didn't change, we have absolutely nothing to do :) * Otherwise (as is the case with most dir_merged/file_merged requests) * we must merge our dir_conf_merged onto this new r->per_dir_config. */ if (r->per_dir_config == cache->per_dir_result) { return OK; } if (r->per_dir_config == cache->dir_conf_merged) { r->per_dir_config = cache->per_dir_result; return OK; } When the SSI include is processed, either file or virtual, the check in the last if statement shown above is true, and the function immediately returns OK with no further processing. If I comment out the section of code that checks for a cached entry, and force it to fully process the request, the attempted inclusion of the symbolic link fails: [Wed Oct 29 19:30:50 2008] [error] [client 134.71.248.12] Symbolic link not allowed or link target not accessible: /export/user/bldewolf/www/secrets3 [Wed Oct 29 19:30:50 2008] [error] [client 134.71.248.12] unable to include "secrets3" in parsed file /export/user/bldewolf/www/test3.shtml There appears to be an invalid assumption in this cache check, clearly behavior is different if the subrequest is fully processed rather than using the cache. I think this is a security bug, the configured restriction on symbolic link handling is being bypassed by the cache optimization. Please let me know what you think of this. I've done some further testing, and confirmed that this is only a problem if the included symbolic link is in the same directory as the shtml file. Consider the following file served via apache: $ ls -l /export/user/henson/www/ total 2-rw-------+ 1 henson csupomona 13 Nov 14 19:24 secured.html For the sake of discussion, assume this file is readable by the web server, but restricted to require authentication. Now, another user creates a symbolic link to that file: $ ls -l /export/user/astudent/www/symlink.html lrwxrwxrwx 1 astudent csupomona 36 Nov 14 19:31 /export/user/astudent/www/symlink.html ->/export/user/henson/www/secured.html Attempting to access the symbolic link directly fails, as SymlinkIfOwnerMatch is configured: $ curl http://stan.unx.csupomona.edu/~astudent/symlink.html <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>403 Forbidden</title> </head><body> <h1>Forbidden</h1> <p>You don't have permission to access /~astudent/symlink.html on this server.</p> </body></html> [Fri Nov 14 19:29:06 2008] [error] [client 134.71.248.140] Symbolic link not allowed or link target not accessible: /export/user/astudent/www/symlink.html Now, the user creates an SSI file: $ ls -l /export/user/astudent/www/symlink_ssi.html -rw-r--r--+ 1 astudent csupomona 40 Nov 14 19:27 /export/user/astudent/www/symlink_ssi.shtml Whose contents are: $cat /export/user/astudent/www/symlink_ssi.shtml <!--#include virtual="/~astudent/symlink.html" --> Accessing this file: $ curl http://stan.unx.csupomona.edu/~astudent/symlink_ssi.shtml Secret data. Returns the restricted data, bypassing the SymlinkIfOwnerMatch configuration directive. As I discovered, this appears to be a bug in ap_directory_walk. Let's say we move the SSI file to a subdirectory: $ ls -l /export/user/astudent/www/subdir/symlink_ssi.shtml -rw-r--r--+ 1 astudent csupomona 40 Nov 14 19:27 /export/user/astudent/www/subdir/symlink_ssi.shtml Attempting to request it then fails as expected: $ curl http://stan.unx.csupomona.edu/~astudent/subdir/symlink_ssi.shtml [an error occurred while processing this directive] [Fri Nov 14 19:37:04 2008] [error] [client 134.71.248.140] Symbolic link not allowed or link target not accessible: /export/user/astudent/www/symlink.html [Fri Nov 14 19:37:04 2008] [error] [client 134.71.248.140] unable to include "/~astudent/symlink.html" in parsed file /export/user/astudent/www/subdir/symlink_ssi.shtml The exact same include behaves differently depending on whether or not the included file happens to be in the same directory as the SSI. Again, this would appear to be a security bug to me. Not a critical one by any means, but still a security bug. I would greatly appreciate some feedback from a developer on this issue. This looks like a duplicate of PR#41960, which was fixed in 2.2.9. Please reopen if an upgrade doesn't fix it for you. *** This bug has been marked as a duplicate of bug 41960 *** My most recent testing was under 2.2.9: [Fri Nov 14 19:04:27 2008] [notice] Apache/2.2.9 (Unix) mod_ssl/2.2.9 OpenSSL/0.9.8h configured -- resuming normal op erations I don't think they are related. The other bug was regarding ap_location_walk for subrequests that don't have an associated file. This bug appears to be in ap_directory_walk, and there is a file associated. Created attachment 22915 [details]
Patch to disable ap_directory_walk cache
For now, I'm running with this patch which disables the caching in ap_directory_walk, and instead logs a notice that the cache would have been used. Seems to be working fine, solves my problem. Not sure what extra inefficiency this is, but I need security first.
Please let me know when you have time to investigate this problem and find a better resolution.
OK, I've just had a good hack at this, and I can reproduce the problem. It seems "Options" values are completely ignored in subrequests, so it never tests for symlinks, let alone if owner matches. That applies both to file and virtual/uri lookups. Please bug me if I don't apply your patch or something equivalent within a week. Thanks for persisting with the report! Thanks, I appreciate the acknowledgment that this is a valid bug. All my patch does is disable the caching, which might not be the best thing to do. I didn't have the time to familiarize myself with the code enough to see if there was a way to cache while still respecting options. If there isn't, then getting rid of the caching might be the only secure approach. There's a propose for backporting patches which have been applied to trunk some time ago, see r732133 Based on my inexpert review, the referenced patch does look like it would resolve the problem. I look forward to its inclusion :). Fix backported in r733754. *** Bug 14206 has been marked as a duplicate of this bug. *** *** Bug 47039 has been marked as a duplicate of this bug. *** *** Bug 47337 has been marked as a duplicate of this bug. *** |