ikiwiki hosting internals/ security/ privilege escalation

(I originally reported this by private email, but Joey is fairly sure it's not exploitable on branchable.com, so I'm summarizing discussion here. --smcv)

By design, the hosted users aren't meant to be able to execute arbitrary code. However, if they can (due to a bug), they can get arbitrary code executed as `www-data`, at which point they can interfere with other users, steal `httpauth` passwords (although those aren't supported on `branchable.com`), and so on.

For this page I'll assume that the user trying to escalate privilege is `b-example`.

> All issues raised here are done --Joey

# open issues

## apache.conf.tmpl

`apache.conf.tmpl` is, if not root-equivalent, then at least `www-data`-equivalent, because it can set security-related Apache configuration. I've noticed that it's not backed up, but it is restored from backups and `chown`'d to root, so restoring an untrusted backup is currently dangerous.

> `apache.conf.tmpl` is backed up; it's committed to the setup branch.

> Restoring from an untrusted backup is dangerous anyway, because for example `ikiwiki.setup` can be configured to make ikiwiki run arbitrary code. All the dangerous stuff should be confined to the setup branch, which is why pushing that branch is rejected. --Joey

> > Right, but my goal with this stuff is more or less: if bob is a user with shell access and b-example is his website, giving bob permission to become `b-example` via sudo doesn't let him escalate privileges any further than that. --smcv

> > > Ok, so the risk with apache.conf.tmpl is that while it's owned by root, the site user can move it out of the way. This allows three attacks:

> > > 1. find a somehow exploitable apache.conf.tmpl on the host that's owned by root, and move it into place.
> > > 2. race `ikisite enable`, which test the file owner and then reads it, so it thinks it's reading a file owned by root.
> > > 3. move it out of the way, put in a bad file, let `ikisite backup`, back it up, and then use some method to get the site restored; restore will trust the file and make it owned by root.

> > > 1 is unlikely, 3 can be fixed in `ikisite backup` perhaps, 2 should be solvable, with some difficulty (I think that hard linking the file and checking the owner of the hard link, the reading the hard link, would work?) Still, keeping the file in $HOME is not looking very smart. --Joey

Since only root can set this up anyway, I'd personally be inclined to treat it as server-wide configuration that should be backed up as part of `/etc`,

> There will be frontends to configure common stuff in it later, and it is site-specific apache configuration, that needs to be transferred along with the site if it is, say, bundled and transferred to a different server.

> What could be done is to use `apache-site.tmpl`, and add to it variables exposing and configuring stuff like htpasswd setup or whatever else is needed (we have some collectd monitoring snippets in one of our sites at branchable, for example). Then have ikiwiki.setup hold the configuration for those variables. --Joey

> > My feeling about moving the config to a site-wide template file(s) that are then enabled by ikiwiki.setup settings is that it's great for common things, but it loses a lot of easy flexability of being able to go in and use the full power of apache to tweak sites, in an ad-hoc way. That is flexability and power that I'm uncertian about sacrificing. --Joey

create `/etc/apache2/ikisite`, and put something like this in `apache-site.tmpl`:

    <VirtualHost *:80>
        ServerName <TMPL_VAR HOSTNAME>:80
        ...
        Include /etc/apache2/ikisite/<TMPL_VAR USER>.*.conf
    </VirtualHost>

    <VirtualHost *:80>
        ServerName <TMPL_VAR HOSTNAME>:80
        ...
        Include /etc/apache2/ikisite/src.<TMPL_VAR USER>.*.conf
    </VirtualHost>

Then you can put whatever you want in those files. Note that Apache considers it to be a syntax error if an `Include` directory doesn't exist, but is perfectly happy if a glob fails to match any files.

If the `HTML::Template` functionality is useful in practice (is it?), `ikisite` could perhaps automatically generate `foo.conf` from `foo.tmpl`.

> I haven't done this on my branch so far. --smcv

> > This is fine, except it adds a second thing that needs to be managed and transferred along with ikisite backups to move sites. It's important to me that ikisite sites be self-contained at the backup level. Now, the backups could be modified to include the site's file from /etc in them, and restore to restore them, I suppose.. --Joey

> > Ok, I have done something based on this but without the includes. I did keep the `HTML::Template` functionality, it's useful to have branchable sites whose apache config tweaks follow them when branched. Generalized to a `/etc/ikiwiki-hosting/config/$user/` directory for root-owned configs. --Joey

# resolved issues

## IkiWiki CGI

If the user can remove the setuid/setgid bits from their ikiwiki.cgi wrapper (which they own), it'll execute as `www-data`. They could then get anything executed with `www-data` privileges.

Possible fixes:

### Use Apache's `suexec`

Something like this: http://git.pseudorandom.co.uk/smcv/ikiwiki-hosting.git/shortlog/escalation. (If you don't want to put the Debian dependencies one per line, leave out that commit, but I find git diff isn't very useful for long dependency lists otherwise...)

suexec will only work if the CGI script is under /var/www, owned by `b-example`, not writeable by anyone else, and in a directory also meeting those conditions; CGIs not meeting those conditions won't be executed at all.

> Done in your branch, which I've merged. --Joey

### Central setuid-root wrapper

Have a central setuid-root wrapper `/usr/lib/ikiwiki-hosting/ikiwiki.cgi` which is only executable by www-data, and when run with `IKISITE_USER=b-example` or something, switches user/group to `b-example` and execs `/home/b-example/public_html/ikiwiki.cgi`. This is basically reinventing suexec.

Joey pointed out that because ikiwiki plugins are allowed to add C code to the `cgi_wrapper`, every site's C CGI wrapper can be different, so the central setuid-root wrapper would have to be a wrapper for a wrapper.

## Gitweb CGI

`gitweb` will run arbitrary Perl code from `.ikiwiki/gitweb.conf.real`. Possible fixes:

### Configuration elsewhere

Put the gitweb.conf somewhere else (`/var/lib/ikiwiki-hosting-web/gitweb`?) and have root own it, so `www-data` can't be subverted.

### Use `suexec` again

Install a wrapper in each user's `suexec` directory, owned by the user themselves, so that each user's gitweb runs with the privileges of that user, via suexec. The wrapper can be as simple as this: the important thing for suexec is that the user owns it.

    #!/bin/sh
    exec /usr/lib/cgi-bin/gitweb.cgi "$@"

As noted on homedir perms this has the nice side-effect that more of the home directory can be private.

> I've done this on my `escalation` branch, which is the earlier `suexec` branch redone so that existing users will (mostly) keep working, with their old log/CGI directory (if you disable/enable sites it might still break, not sure). It'd be great if you could merge some or all of this. --smcv

> > And merged. --Joey

## ikisite parsing `ikiwiki.setup`

ikisite loads `ikiwiki.setup` in "safe mode", so hopefully there's no possibility of arbitrary code execution there.

> Specifically, safe mode prevents ikiwiki.setup from being a perl script. Of course, if any value is used in an insecure way by ikisite, it loses. --Joey

> > I haven't audited this thoroughly yet, but nothing jumps out at me... --smcv

## logs

http://httpd.apache.org/docs/2.2/misc/security_tips.html#serverroot says:

> If the logs directory is writeable (by a non-root user), someone could replace a log file with a symlink to some other system file, and then root might overwrite that file with arbitrary data.

I don't know how plausible that is in practice, but on shared hosting services I've used in the past, the base directory for my website has been owned by root, with docroot, cgi-bin etc. subdirectories owned and writeable by me, and a logs directory not owned by me.

If you want users to own their own home directories (which ikisite does currently assume), an alternative way to do this would be to put the logs in `/var/log/apache2/b-example/` or `/var/log/apache2/example.branchable.com/` or whatever, and have the home directory contain a logs/ symlink for convenience?

> I think it's reasonable to move the logs outside of home. Having a symlink would only encourage something to write through the symlink, breaking security again. The other issue with having them outside of home is /var needs to have space for them -- but this also means that something filling the logs doesn't necessarily full the home partition too. --Joey

> > I've added that to my branch; I used `/var/log/ikiwiki-hosting/b-example` owned by `root:b-example` so the hosting user can (potentially) read their own logs later. --smcv

> > > And merged. --Joey

## users not owning their own $HOME?

One way to avoid various privilege escalations would be for the site users' home directories to be owned by root and not writeable by the user, with particular subdirectories writeable. Things that that would break:

- the code in ikisite that replaces ikiwiki.setup
- ikiwiki.setup in general, possibly, depending how ikiwiki rewrites it (an easy workaround would be to put it in a subdirectory)
- any random program that assumes it can replace a dotfile by creating a temporary file and renaming over the original

Probably not worth it...

> I agree, this is not an approach I really want to pursue. --Joey

## `~/apache/`

I don't know what you put in here in practice, so I don't know whether it can cause privilege escalation :-)

> Currently, only htpasswd files. Exploitability unlikely. --Joey