Ad:a

PHP execution vulnerability in DokuWiki

Sunday, September 19, 2010 Apache PHP Security .htaccess DokuWiki MultiViews mod_mime

Some days ago, a new security problem in DokuWiki got reported. It allows – assuming certain web server configurations – PHP (This probably applies to other languages interpreted by the web server as well) file execution for users permitted to create pages (Under some circumstances I’ll describe, even the right to edit suffices). This is quite a serious issue, but we are not able to fix it in any sane way apart from checking the server configuration and warning users. I’ll describe the problem, briefly discuss some potential solutions in DokuWiki and why we do not follow them and finally show the solutions we propose.

The problem

Unlike most other wiki engines, DokuWiki stores page text and metadata in plain text files in a data folder. The location of the data folder is configurable. Both meta and text files’ names are derived from the page name the wiki user has chosen: With the default data directory data/ in the DokuWiki root, a wiki page called pagename will have files data/meta/pagename.meta and data/pages/pagename.txt.

By default, the whole DokuWiki directory lies in the public web directory, making all files in it web-accessible. Directories which do not need to be accessed from clients are protected with .htaccess files – this applies to data/, for example. .htaccess files specify directory-related configuration options to the Apache web server. The normal, static Apache configuration files (and possibly .htaccess files from parent directories) define whether these files are used at all and which options might be configured in them. Using .htaccess files is generally slower than the static configuration, since they need to be read on every client request – static files are loaded once on server startup.

Some admins decide to disable .htaccess files, for example for performance reasons. In many cases, this is no security problem per sé: A user may read all wiki pages and metadata, but in a public wiki they are able to get this anyway. The configuration, password hashes and user data in the conf/ directory is protected by other means not depending on .htaccess files (They have a <?php exit() ?> before the data). Informations about the subscriptions users have and the DokuWiki cookie salt are accessible, but this imposes not much of a security issue (The subscriptions leak, but are not that private data; the cookie salt allows to decrypt a cookie, thus getting the user name and password, but you first have to intercept the cookie in the first place). So, not having .htaccess enabled for DokuWiki seemed not like a very clever choice, but in many cases the problems imposed by this choice were acceptable. This changed.

When asked for a file, Apache’s mod_mime module tries to determine which kind of a file it is. Afterwards, it checks whether a special handler is registered for this file type – for example the module mod_php for PHP files (Other extensions like .rb, .py, .pl could be handled by other modules and thus be executed as well). If such a handler is found, the handler is invoked instead of returning the plain file to the client. File type discovery is done based on all extensions a filename has, i. e. every part of the name starting with a dot (but not the part after a leading dot). I don’t really know what happens exactly if there are multiple recognized filetypes, this seems to depend on the server configuration (MultiViews might have some impact on this). Anyways, at least one of the two files page.php.txt and page.php.meta is probably recognized as a PHP script.

Now I am going to put the pieces together:

This ain’t good; you will probably not want to give PHP execution rights to your users – otherwise you may just have enabled PHP execution in DokuWiki in the first place. By indirectly granting PHP execution rights, DokuWiki breaks the wiki admin’s expectations about the impact of his decision to make the data folder world-readable. I consider this a bug.

Solutions in the code (rejected)

(I’ll further assume that configuration through .htaccess is not available and creation right is granted to not fully trusted users.)

We identified three main prerequisites for the issue:

Put together, users may construct arbitrary file names in a known location with their own content.

First, we could limit the control over filenames:

Second, we could limit the content:

Third, we could move the data folder around. This is something users already can perform through a config option. Doing it in DokuWiki would mean that we randomize the data folder’s name in install.php. This solution is not that bad, but still looks ugly in the file system: we would not want to do this for everybody while it’s only necessary for few vulnerable setups. Therefor, we decided to just warn the user about the security issue and let him take appropriate measures. Ideally, the installer would detect the problem, suggest some solutions and perform the data directory move automatically if the user does not fix the problem in some other way.

Solutions in the configuration

So, how to fix the problem. If you have access to the Apache config (i. e. run you own server), enable .htaccess with AllowOverwrite Limit or include all the .htaccess files in the static configuration:

<Directory /var/www/wiki/>
    RewriteEngine on

    RewriteBase /wiki

    RewriteRule ^_media/(.*)           lib/exe/fetch.php?media=$1  [QSA,L]
    RewriteRule ^_detail/(.*)          lib/exe/detail.php?media=$1  [QSA,L]
    RewriteRule ^_export/([^/]+)/(.*)  doku.php?do=export_$1&id=$2  [QSA,L]
    RewriteRule ^$                     doku.php  [L]
    RewriteCond %{REQUEST_FILENAME}    !-f
    RewriteCond %{REQUEST_FILENAME}    !-d
    RewriteRule (.*)                   doku.php?id=$1  [QSA,L]
</Directory>

<Directory /var/www/wiki/bin/>
    order allow,deny
    deny from all
</Directory>
<Directory /var/www/wiki/inc/>
    order allow,deny
    deny from all
</Directory>
<Directory /var/www/wiki/inc/lang/>
    order allow,deny
    deny from all
</Directory>
<Directory /var/www/wiki/lib/_fla/>
    order allow,deny
    deny from all
</Directory>
<Directory /var/www/wiki/data/>
    order allow,deny
    deny from all
</Directory>
<Directory /var/www/wiki/conf/>
    order allow,deny
    deny from all
</Directory>

If you have no access to the Apache configuration (i. e. only have some web space) and cannot use .htaccess files, there are two possibilities: First, you could just disable page create access to untrustworthy people (remove edit access if you already have page names with dots or plan to use them). Second and finally, if you have no way of changing the server configuration (static or dynamic) and do want to run a completely open wiki, you have to move the data directory to some unusual place. Ideally, you would move it out of your web root (Maybe called »public_html«). If you have no space not accessible via web, you could still move it to a random, hard-to-guess place. Wherever you move it, do not forget to change the DokuWiki configuration accordingly.