RCE in F*EX
Background
F*EX is a Perl-based HTTP file exchange service. Quoting from the vendor’s homepage:
F*EX (Frams’ Fast File EXchange) is a service to send big (large, huge, giant, …) files from a user A to a user B. The sender uploads the file to the F*EX server using a WWW upload form and the recipient automatically gets a notification e-mail with a download-URL.
Issue Description
While reviewing the F*EX implementation, the function copy
from lib/fex.pp
was analyzed:
# copy file (and modify) or symlink
# returns chomped file contents or link name
# preserves permissions and time stamps
sub copy {
my ($from,$to,$mod) = @_;
my $link;
local $/;
local $_;
$to .= '/'.basename($from) if -d $to;
if (defined($link = readlink $from)) {
mksymlink($to,$link);
return $link;
} else {
open $from,'<',$from or return;
open $to,'>',$to or return;
$_ = <$from>;
close $from;
eval $mod if $mod;
print {$to} $_;
close $to or http_die("internal error: $to - $!");
if (my @s = stat($from)) {
chmod $s[2],$to;
utime @s[8,9],$to unless $mod;
}
chomp;
return $_;
}
}
The eval $mod if $mod
call indicates a potential eval
injection issue. Identifying the callers reveals that the copy
function is invoked by bintar
from bin/fexsrv
, which is shown below.
sub bintar {
my $tmpdir = "$FEXHOME/tmp";
my $fs = "$ENV{PROTO}://$ENV{HTTP_HOST}";
if (chdir "$FEXHOME/bin") {
fexlog($connect,@log);
chdir $fstb if $fstb;
mkdir $tmpdir;
foreach my $f (@_) {
copy($f,"$tmpdir/$f","s#fexserver = ''#fexserver = '$fs'#");
chmod 0755,"$tmpdir/$f";
}
chdir $tmpdir or http_die("internal error: $tmpdir - $!");
my $tar = `tar cf - @_ 2>/dev/null`;
unlink @_;
nvt_print(
'HTTP/1.1 200 OK',
'Server: fexsrv',
"Content-Length: ".length($tar),
"Content-Type: application/x-tar",
'',
);
print $tar;
exit;
}
}
It can be observed that in this call, the $mod
argument is indeed passed to copy
. Parts of the $mod
argument are based on the HTTP_HOST
variable, which is user-controlled. Further tracing down callers of bintar
yields the following code from bin/fexsrv
, which is part of the HTTP request parsing logic:
# special request for F*EX UNIX clients
if ($ENV{SCRIPT_NAME} eq 'xx.tar') {
bintar(qw'fexget fexsend xx zz ezz');
}
It should be noted that no authentication is required in order to trigger this code path. The vulnerability hence is a pre-auth RCE issue.
Fix
The issue has been fixed in fex-20160919_2
.
Credit
Gregor Kopf of Secfault Security GmbH
Disclaimer
The information provided is released “as is” without warranty of any kind. The publisher disclaims all warranties, either express or implied, including all warranties of merchantability. No responsibility is taken for the correctness of this information. In no event shall the publisher be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages, even if the publisher has been advised of the possibility of such damages.
The contents of this advisory are copyright (c) 2020 Secfault Security GmbH and may be distributed freely provided that no fee is charged for this distribution and proper credit is given.