Skip to content

Commit

Permalink
Fixing several security/compatibility issues
Browse files Browse the repository at this point in the history
This addresses issues including:
- XSS/content escaping
- Path traversal
- PHP 7/8 compatibility

This software is not currently actively maintained, but is something people are still finding useful, so for the time being I am keeping the repository available. I may at some point rewrite it completely, because it really needs it.
  • Loading branch information
Alanaktion committed Sep 9, 2021
1 parent 980268a commit 27d5a93
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 46 deletions.
5 changes: 5 additions & 0 deletions .gitignore
@@ -0,0 +1,5 @@
/data/config.php
/data/users/*.json
/inc/skintmp/
/.vscode
/.installed
18 changes: 9 additions & 9 deletions admin.php
Expand Up @@ -6,22 +6,22 @@
// Not logged in, redirect to login page
header('Location: .');
exit('Not Authorized');
} elseif (!$_SESSION['is_admin'] && $user['role'] != 'admin') {
} elseif (empty($_SESSION['is_admin']) && $user['role'] != 'admin') {
// Not an admin, redirect to login page
header('Location: .');
exit('Not Authorized');
}

// Switch users
if ($_POST['action'] == 'user-switch' && $_POST['user']) {
if (isset($_POST['action']) && $_POST['action'] == 'user-switch' && $_POST['user']) {
$_SESSION['is_admin'] = true;
$_SESSION['user'] = $_POST['user'];
header('Location: .');
exit('Switching Users');
}

//Manage a backup cron job
if($_POST['action'] == 'backup-manage' && $_POST['user']) {
if (isset($_POST['action']) && $_POST['action'] == 'backup-manage' && $_POST['user']) {

//Determine which button (create or delete) was pressed and pass it as an action
$action = (isset($_POST['create']) ? "create" : (isset($_POST['delete']) ? "delete" : exit("Action error")));
Expand All @@ -30,18 +30,18 @@
}

// Add new user
if ($_POST['action'] == 'user-add')
if (isset($_POST['action']) && $_POST['action'] == 'user-add')
user_add($_POST['user'], $_POST['pass'], $_POST['role'], $_POST['dir'], $_POST['ram'], $_POST['port']);

// Start a server
if ($_POST['action'] == 'server-start') {
if (isset($_POST['action']) && $_POST['action'] == 'server-start') {
$stu = user_info($_POST['user']);
if (!server_running($stu['user']))
server_start($stu['user']);
}

// Kill a server
if ($_POST['action'] == 'server-stop')
if (isset($_POST['action']) && $_POST['action'] == 'server-stop')
if ($_POST['user'] == 'ALL')
server_kill_all();
else
Expand Down Expand Up @@ -107,11 +107,11 @@ function check_cron() {
<?php require 'inc/top.php'; ?>
<div class="container-fluid">
<h1 class="pull-left">Administration</h1>
<?php if ($_POST['action'] == 'user-add') { ?>
<?php if (isset($_POST['action']) && $_POST['action'] == 'user-add') { ?>
<p class="alert alert-success pull-right"><i class="icon-ok"></i> User added successfully.</p>
<?php } elseif ($_POST['action'] == 'server-start') { ?>
<?php } elseif (isset($_POST['action']) && $_POST['action'] == 'server-start') { ?>
<p class="alert alert-success pull-right"><i class="icon-ok"></i> Server started.</p>
<?php } elseif ($_POST['action'] == 'server-stop') { ?>
<?php } elseif (isset($_POST['action']) && $_POST['action'] == 'server-stop') { ?>
<p class="alert alert-success pull-right"><i class="icon-ok"></i> Server killed.</p>
<?php } ?>
<div class="clearfix"></div>
Expand Down
26 changes: 13 additions & 13 deletions ajax.php
Expand Up @@ -12,12 +12,12 @@
$files = array();

// Get directory contents
$h = opendir($user['home'] . $_POST['dir']);
$h = opendir($user['home'] . sanitize_path($_POST['dir']));
while (false !== ($f = readdir($h)))
if ($f != '.' && $f != '..')
if (is_dir($user['home'] . $_POST['dir'] . '/' . $f))
if (is_dir($user['home'] . sanitize_path($_POST['dir']) . '/' . $f))
$dirs[] = $f;
elseif (is_file($user['home'] . $_POST['dir'] . '/' . $f))
elseif (is_file($user['home'] . sanitize_path($_POST['dir']) . '/' . $f))
$files[] = $f;
closedir($h);
unset($f);
Expand All @@ -29,7 +29,7 @@
// Get file sizes
$sizes = array();
foreach ($files as $f)
$sizes[] = filesize($user['home'] . $_POST['dir'] . '/' . $f);
$sizes[] = filesize($user['home'] . sanitize_path($_POST['dir']) . '/' . $f);

// Output data
echo json_encode(array(
Expand All @@ -40,17 +40,17 @@

break;
case 'file_get':
if (is_file($user['home'] . $_POST['file']))
echo file_get_contents($user['home'] . $_POST['file']);
if (is_file($user['home'] . sanitize_path($_POST['file'])))
echo file_get_contents($user['home'] . sanitize_path($_POST['file']));
break;
case 'file_put':
if (is_file($user['home'] . $_POST['file']))
file_put_contents($user['home'] . $_POST['file'], $_POST['data']);
if (is_file($user['home'] . sanitize_path($_POST['file'])))
file_put_contents($user['home'] . sanitize_path($_POST['file']), $_POST['data']);
break;
case 'delete':
foreach ($_POST['files'] as $f)
if (is_file($user['home'] . $f))
unlink($user['home'] . $f);
if (is_file($user['home'] . sanitize_path($f)))
unlink($user['home'] . sanitize_path($f));
break;
case 'rename':
file_rename($_POST['path'], $_POST['newname'], $user['home']);
Expand Down Expand Up @@ -90,8 +90,8 @@
// 1.6 and earlier
echo mclogparse2(file_backread($user['home'] . '/server.log', 64));
} elseif(is_file($user['home'] . "/proxy.log.0")) {
// BungeeCord
echo mclogparse2(file_backread($user['home'] . '/proxy.log.0', 64));
// BungeeCord
echo mclogparse2(file_backread($user['home'] . '/proxy.log.0', 64));
} else {
echo "No log file found.";
}
Expand All @@ -105,7 +105,7 @@
} elseif(is_file($user['home'] . '/server.log')) {
$file = $user['home'] . '/server.log';
} elseif(is_file($user['home'] . '/proxy.log.0')) {
$file = $user['home'] . '/proxy.log.0';
$file = $user['home'] . '/proxy.log.0';
} else {
exit(json_encode(array('error' => 1, 'msg' => 'No log file found.')));
}
Expand Down
14 changes: 7 additions & 7 deletions backup-run.php
@@ -1,4 +1,4 @@
<?php
<?php

require_once dirname(__FILE__) . '/data/config.php';

Expand Down Expand Up @@ -36,7 +36,7 @@
if (!$user) {
// Clean out the supplied user just incase
$user = preg_replace('/[^A-Za-z0-9\- ]/', '', $name);

// User does not exist, redirect to login page
error_log("MCHostPanel Backup: '" . $user . "' user does not exist!");
exit('Not Authorized\r\n');
Expand Down Expand Up @@ -72,7 +72,7 @@
//Delete old backups based on their delete interval
if($timeout !== 0) {
$backups = array_diff(scandir($user['home'] . "/" . "backups/"), array('.', '..'));

foreach($backups as $backup) {
$timeCreated = filectime($user['home'] . "/" . "backups/" . $backup);
//Times up!
Expand All @@ -85,13 +85,13 @@
$archiveFile = date('Y-m-d') . " - " . time() . " - Minecraft Backup.tar";

$phar = new PharData($user['home'] . "/" . "backups/" . $archiveFile);

$phar->buildFromDirectory($user['home'], '/^((?!backups).)*$/');
$phar->compress(Phar::GZ);

//Delete the .tar file since now we have a .tar.gz
unlink($user['home'] . "/" . "backups/" . $archiveFile);

} catch (Exception $e) {
error_log("MCHostPanel Backup: '" . $user . "' Backup Failure!\r\nException : " . $e);
exit("Exception : " . $e . "\r\n");
Expand All @@ -116,7 +116,7 @@ function server_cmd($name,$cmd) {
sprintf(
KT_SCREEN_CMD_EXEC, // Base command
KT_SCREEN_NAME_PREFIX.$name, // Screen Name
str_replace(array('\\','"'),array('\\\\','\\"'),(get_magic_quotes_gpc() ? stripslashes($cmd) : $cmd)) // Server command
str_replace(array('\\','"'),array('\\\\','\\"'),((function_exists("get_magic_quotes_gpc") && get_magic_quotes_gpc()) ? stripslashes($cmd) : $cmd)) // Server command
)
);
}
Expand Down
15 changes: 8 additions & 7 deletions edit.php
Expand Up @@ -23,15 +23,16 @@
if (isset($_POST['text']) && !empty($_POST['file'])) {
$file = $user['home'] . $_POST['file'];
$text = $_POST['text'];
if (get_magic_quotes_gpc())
if (function_exists("get_magic_quotes_gpc") && get_magic_quotes_gpc())
$text = stripslashes($text);
$saved = file_put_contents($file, $text);
}

// Determine current directory
$dir = rtrim($_REQUEST['file'], basename($_REQUEST['file']));
$dir = dirname($_REQUEST['file']);
$dir = rtrim($dir, '/');

$file = $user['home'] . sanitize_path($_REQUEST['file']);
?><!doctype html>
<html>
<head>
Expand Down Expand Up @@ -77,7 +78,7 @@
<div class="container-fluid">
<form action="edit.php" method="post">
<div class="row-fluid">
<h3 style="font-weight:400;" class="pull-left">Editing <?php echo $_REQUEST['file']; ?></h3>
<h3 style="font-weight:400;" class="pull-left">Editing <?php echo htmlspecialchars($_REQUEST['file']); ?></h3>
<?php if (isset($_POST['text']) && $saved !== false) { ?>
<p class="alert alert-success pull-right"><i class="icon-ok"></i> File was successfully saved.</p>
<?php } elseif (isset($_POST['text'])) { ?>
Expand All @@ -86,12 +87,12 @@
<p class="alert alert-info pull-right">File reloaded.</p>
<?php } ?>
<div class="clearfix"></div>
<input type="hidden" name="file" value="<?php echo $_REQUEST['file']; ?>">
<textarea name="text" style="width:100%;box-sizing:border-box;-moz-box-sizing:border-box;font-family:monospace;"><?php echo htmlspecialchars(file_get_contents($user['home'] . $_REQUEST['file'])); ?></textarea>
<input type="hidden" name="file" value="<?php echo htmlspecialchars($_REQUEST['file']); ?>">
<textarea name="text" style="width:100%;box-sizing:border-box;-moz-box-sizing:border-box;font-family:monospace;"><?php echo htmlspecialchars(file_get_contents($file)); ?></textarea>

<div class="btn-toolbar" style="text-align: right;">
<a href="files.php?dir=<?php echo urlencode($dir); ?>" id="cancel" class="btn">Cancel</a>
<a href="edit.php?file=<?php echo urlencode($_REQUEST['file']); ?>&action=reload" id="reload" class="btn btn-danger"><i class="icon-repeat icon-white"></i> Reload File</a>
<a href="files.php?dir=<?php echo htmlspecialchars(urlencode($dir)); ?>" id="cancel" class="btn">Cancel</a>
<a href="edit.php?file=<?php echo htmlspecialchars(urlencode($_REQUEST['file'])); ?>&action=reload" id="reload" class="btn btn-danger"><i class="icon-repeat icon-white"></i> Reload File</a>
<button type="submit" class="btn btn-primary"><i class="icon-download-alt icon-white"></i> Save File</button>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion files.php
Expand Up @@ -147,7 +147,7 @@
$('button.ht').tooltip();

// Load requested directory
loaddir('<?php echo $_GET["dir"] ? $_GET["dir"] : '/'; ?>');
loaddir('<?php echo !empty($_GET["dir"]) ? addslashes(htmlspecialchars($_GET["dir"])) : '/'; ?>');

});

Expand Down
34 changes: 25 additions & 9 deletions inc/lib.php
Expand Up @@ -36,6 +36,8 @@
* @return bool
*/
function file_rename($path,$newname,$home) {
$path = sanitize_path($path);
$newname = sanitize_path($newname);
return rename($home.$path,$home.rtrim($path,basename($path)).$newname);
}

Expand All @@ -47,6 +49,7 @@ function file_rename($path,$newname,$home) {
* @return void
*/
function download($path,$home,$force = true) {
$path = sanitize_path($path);
if(is_file($home.$path) && $force) {
header('Content-type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($path).'";');
Expand All @@ -70,6 +73,7 @@ function download($path,$home,$force = true) {
* @return string
*/
function mimetype($filename) {
$filename = sanitize_path($filename);
$mime_types = array(
'txt' => 'text/plain',
'htm' => 'text/html',
Expand Down Expand Up @@ -138,14 +142,15 @@ function mimetype($filename) {
* @return int
*/
function getsize($file) {
$file = sanitize_path($file);
$size = filesize($file);
if($size < 0)
if(!(strtoupper(substr(PHP_OS,0,3))=='WIN'))
$size = trim(`stat -c%s $file`);
else {
$fsobj = new COM('Scripting.FileSystemObject');
$f = $fsobj->GetFile($file);
$size = $file->Size;
$size = $f->Size;
}
return $size;
}
Expand All @@ -171,6 +176,7 @@ function __file_backread_helper(&$haystack,$needle,$x) {
* @return string
*/
function file_backread($file,$lines,&$fsize=0){
$file = sanitize_path($file);
$f=fopen($file,'r');
if(!$f)return Array();

Expand All @@ -181,8 +187,7 @@ function file_backread($file,$lines,&$fsize=0){
$fsize=filesize($file);
$pos=$fsize;

$buff1=Array();
$cnt=0;
$buff1=array();

while($pos)
{
Expand Down Expand Up @@ -213,12 +218,15 @@ function file_backread($file,$lines,&$fsize=0){
* @return string|bool
*/
function file_download($url,$path) {
$url = sanitize_path($url);
$file = fopen($url,'rb');
if($file) {
$newf = fopen($path,'wb');
if($newf)
if($newf) {
while(!feof($file))
fwrite($newf,fread($file,1024*8),1024*8);
fclose($newf);
}
else
return false;
}
Expand All @@ -228,9 +236,6 @@ function file_download($url,$path) {
else
return false;

if($newf)
fclose($newf);

return $path;
}

Expand All @@ -241,6 +246,8 @@ function file_download($url,$path) {
* @return bool
*/
function rmdirr($dirname) {
$dirname = sanitize_path($dirname);

// Sanity check
if(!file_exists($dirname))
return false;
Expand Down Expand Up @@ -451,7 +458,7 @@ function server_cmd($name,$cmd) {
sprintf(
KT_SCREEN_CMD_EXEC, // Base command
KT_SCREEN_NAME_PREFIX.$name, // Screen Name
str_replace(array('\\','"'),array('\\\\','\\"'),(get_magic_quotes_gpc() ? stripslashes($cmd) : $cmd)) // Server command
str_replace(array('\\','"'),array('\\\\','\\"'),((function_exists("get_magic_quotes_gpc") && get_magic_quotes_gpc()) ? stripslashes($cmd) : $cmd)) // Server command
)
);
}
Expand Down Expand Up @@ -675,6 +682,15 @@ function check_email($email) {
return filter_var($email,FILTER_VALIDATE_EMAIL);
}

// Sanitize a path string
function sanitize_path($path) {
$path = preg_replace('/\.{2,}/', '.', $path);
$path = preg_replace('/\/+$/', '', $path);
$path = str_replace('./', '/', $path);
$path = preg_replace('/\/{2,}/', '/', $path);
return $path;
}


/*
.d8888b. 888 888
Expand All @@ -695,7 +711,7 @@ function base64_salt($len = 22) {
$characterList = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/';
$salt = '';
for($i=0;$i<$len;$i++)
$salt.= $characterList{mt_rand(0,(strlen($characterList)-1))};
$salt.= $characterList[mt_rand(0,(strlen($characterList)-1))];
return $salt;
}

Expand Down

0 comments on commit 27d5a93

Please sign in to comment.