[svn r21145] Security improvement in arbitrary file injection vulnerability (see FS#4261)

Improvements to PEAR coding conventions usage
skala
Yannick Warnier 16 years ago
parent 3d217c0dc4
commit 56245c52af
  1. 251
      main/exercice/hotpotatoes.lib.php

@ -1,34 +1,11 @@
<?php <?php //$id: $
/* /* For licensing terms, see /dokeos_license.txt */
DOKEOS - elearning and course management software
For a full list of contributors, see documentation/credits.html
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.
See "documentation/licence.html" more details.
Contact:
Dokeos
Rue des Palais 44 Paleizenstraat
B-1030 Brussels - Belgium
Tel. +32 (2) 211 34 56
*/
/** /**
* Code library for HotPotatoes integration. * Code library for HotPotatoes integration.
* @package dokeos.exercise * @package dokeos.exercise
* @author Istvan Mandak * @author Istvan Mandak (original author)
* @version $Id: hotpotatoes.lib.php 21086 2009-05-29 17:46:56Z juliomontoya $
*/ */
$dbTable = Database::get_course_table(TABLE_DOCUMENT); $dbTable = Database::get_course_table(TABLE_DOCUMENT);
/** /**
* Creates a hotpotato directory * Creates a hotpotato directory
* *
@ -36,14 +13,11 @@ $dbTable = Database::get_course_table(TABLE_DOCUMENT);
* @param string Wanted path * @param string Wanted path
* @return boolean Always true so far * @return boolean Always true so far
*/ */
function hotpotatoes_init($baseWorkDir) function hotpotatoes_init($baseWorkDir) {
{
//global $_course, $_user; //global $_course, $_user;
$documentPath=$baseWorkDir.'/'; $documentPath=$baseWorkDir.'/';
if (!is_dir($documentPath)) if (!is_dir($documentPath)) {
{ if (is_file($documentPath)) {
if (is_file($documentPath))
{
@unlink($documentPath); @unlink($documentPath);
} }
@mkdir($documentPath); @mkdir($documentPath);
@ -51,7 +25,7 @@ function hotpotatoes_init($baseWorkDir)
$perm = octdec(!empty($perm)?$perm:'0770'); $perm = octdec(!empty($perm)?$perm:'0770');
chmod ($documentPath,$perm); chmod ($documentPath,$perm);
return true; return true;
}else{ } else {
//if this directory already exists, return false //if this directory already exists, return false
return false; return false;
} }
@ -71,13 +45,12 @@ function hotpotatoes_init($baseWorkDir)
* @param string File path * @param string File path
* @return string The exercise title * @return string The exercise title
*/ */
function GetQuizName($fname,$fpath) function GetQuizName($fname,$fpath) {
{
$title = ""; $title = "";
$title = GetComment($fname); $title = GetComment($fname);
if($title=="") { if ($title=="") {
if (file_exists($fpath.$fname)) { if (file_exists($fpath.$fname)) {
if (!($fp = fopen($fpath.$fname, "r"))) { if (!($fp = fopen($fpath.$fname, "r"))) {
//die("could not open Quiz input"); //die("could not open Quiz input");
@ -100,7 +73,6 @@ function GetQuizName($fname,$fpath)
} }
} }
return $title; return $title;
} }
/** /**
@ -108,14 +80,12 @@ function GetQuizName($fname,$fpath)
* @param string File path * @param string File path
* @return string Comment from the database record * @return string Comment from the database record
*/ */
function GetComment($path) function GetComment($path) {
{
global $dbTable; global $dbTable;
$path = Database::escape_string($path); $path = Database::escape_string($path);
$query = "select comment from $dbTable where path='$path'"; $query = "select comment from $dbTable where path='$path'";
$result = api_sql_query($query,__FILE__,__LINE__); $result = api_sql_query($query,__FILE__,__LINE__);
while($row = mysql_fetch_array($result)) while ($row = mysql_fetch_array($result)) {
{
return $row[0]; return $row[0];
} }
return ""; return "";
@ -127,8 +97,7 @@ function GetComment($path)
* @param string Comment to set * @param string Comment to set
* @return string Result of the database operation (api_sql_query will output some message directly on error anyway) * @return string Result of the database operation (api_sql_query will output some message directly on error anyway)
*/ */
function SetComment($path,$comment) function SetComment($path,$comment) {
{
global $dbTable; global $dbTable;
$path = Database::escape_string($path); $path = Database::escape_string($path);
$comment = Database::escape_string($comment); $comment = Database::escape_string($comment);
@ -145,8 +114,7 @@ function SetComment($path,$comment)
* @param string Path * @param string Path
* @return string File name * @return string File name
*/ */
function GetFileName($fname) function GetFileName($fname) {
{
$name = explode('/',$fname); $name = explode('/',$fname);
$name = $name[sizeof($name)-1]; $name = $name[sizeof($name)-1];
return $name; return $name;
@ -155,32 +123,42 @@ function GetFileName($fname)
/** /**
* Reads the file contents into a string * Reads the file contents into a string
* @param string Urlencoded path * @param string Urlencoded path
* @return string The file contents * @return string The file contents or false on security error
*/ */
function ReadFileCont($full_file_path) function ReadFileCont($full_file_path) {
{ if (Security::check_abs_path(dirname($full_file_path).'/',api_get_path(SYS_COURSE_PATH))) {
if(is_file($full_file_path)) { if (is_file($full_file_path)) {
if (!($fp = fopen(urldecode($full_file_path), "r"))) { if (!($fp = fopen(urldecode($full_file_path), "r"))) {
return ""; return "";
} }
$contents = fread($fp, filesize($full_file_path)); $contents = fread($fp, filesize($full_file_path));
fclose($fp); fclose($fp);
return $contents; return $contents;
} }
}
return false;
} }
/** /**
* Writes the file contents into the file given * Writes the file contents into the given filepath
* @param string Urlencoded path * @param string Urlencoded path
* @param string The file contents * @param string The file contents
* @return boolean True on success, false on security error
*/ */
function WriteFileCont($full_file_path,$content) function WriteFileCont($full_file_path,$content) {
{ // check if this is not an attack, trying to get into other directories or something like that
if (!($fp = fopen(urldecode($full_file_path), "w"))) { global $_course;
//die("could not open Quiz input"); if (Security::check_abs_path(dirname($full_file_path).'/',api_get_path(SYS_COURSE_PATH).$_course['path'].'/')) {
} // check if this is not an attack, trying to upload a php file or something like that
fwrite($fp,$content); if (basename($full_file_path) != Security::filter_filename(basename($full_file_path))) { return false; }
fclose($fp); if (!($fp = fopen(urldecode($full_file_path), "w"))) {
//die("could not open Quiz input");
}
fwrite($fp,$content);
fclose($fp);
return true;
}
return false;
} }
/** /**
@ -189,35 +167,28 @@ function WriteFileCont($full_file_path,$content)
* @return string The image file name or an empty string * @return string The image file name or an empty string
* @uses GetFileName No comment * @uses GetFileName No comment
*/ */
function GetImgName($imgtag) function GetImgName($imgtag) {
{ // select src tag from img tag // select src tag from img tag
$match = array(); $match = array();
//preg_match('/(src=(["\'])1.*(["\'])1)/i',$imgtag,$match); //src //preg_match('/(src=(["\'])1.*(["\'])1)/i',$imgtag,$match); //src
preg_match('/src(\s)*=(\s)*[\'"]([^\'"]*)[\'"]/i',$imgtag,$match); //get the img src as contained between " or ' preg_match('/src(\s)*=(\s)*[\'"]([^\'"]*)[\'"]/i',$imgtag,$match); //get the img src as contained between " or '
//list($key,$srctag)=each($match); //list($key,$srctag)=each($match);
$src=$match[3]; $src=$match[3];
//$src = substr($srctag,5,(strlen($srctag)-7)); //$src = substr($srctag,5,(strlen($srctag)-7));
if (stristr($src,"http")===false) // valid or invalid image name if (stristr($src,"http")===false) {
{ // valid or invalid image name
if($src=="") if ($src=="") {
{
return ""; return "";
} } else {
else
{
$tmp_src = GetFileName($src) ; $tmp_src = GetFileName($src) ;
if ($tmp_src == "") if ($tmp_src == "") {
{
return $src; return $src;
} } else {
else
{
return $tmp_src; return $tmp_src;
} }
} }
} } else {
else //the img tag contained "http", which means it is probably external. Ignore it. //the img tag contained "http", which means it is probably external. Ignore it.
{
return ""; return "";
} }
} }
@ -227,20 +198,17 @@ function GetImgName($imgtag)
* @param string An image tag * @param string An image tag
* @return string The image source or "" * @return string The image source or ""
*/ */
function GetSrcName($imgtag) function GetSrcName($imgtag) {
{ // select src tag from img tag // select src tag from img tag
$match = array(); $match = array();
preg_match("|(src=\".*\" )|U",$imgtag,$match); //src preg_match("|(src=\".*\" )|U",$imgtag,$match); //src
list($key,$srctag)=each($match); list($key,$srctag)=each($match);
$src = substr($srctag,5,(strlen($srctag)-7)); $src = substr($srctag,5,(strlen($srctag)-7));
if (stristr($src,"http")==false) // valid or invalid image name if (stristr($src,"http")==false) {
{ // valid or invalid image name
return $src; return $src;
} } else {
else
{
return ''; return '';
} }
} }
@ -251,21 +219,19 @@ function GetSrcName($imgtag)
* @param reference Reference to a list of image parameters (emptied, then used to return results) * @param reference Reference to a list of image parameters (emptied, then used to return results)
* @param reference Reference to a counter of images (emptied, then used to return results) * @param reference Reference to a counter of images (emptied, then used to return results)
*/ */
function GetImgParams($fname,$fpath,&$imgparams,&$imgcount) function GetImgParams($fname,$fpath,&$imgparams,&$imgcount) {
{ //select img tags from context //select img tags from context
$imgparams = array(); $imgparams = array();
//phpinfo(); //phpinfo();
$contents = ReadFileCont("$fpath"."$fname"); $contents = ReadFileCont("$fpath"."$fname");
$matches = array(); $matches = array();
preg_match_all("(<img .*>)",$contents,$matches); preg_match_all("(<img .*>)",$contents,$matches);
$imgcount = 0; $imgcount = 0;
while (list($int,$match)=each($matches)) while (list($int,$match)=each($matches)) {
{
//each match consists of a key and a value //each match consists of a key and a value
while(list($key,$imgtag)=each($match)) while (list($key,$imgtag)=each($match)) {
{
$imgname = GetImgName($imgtag); $imgname = GetImgName($imgtag);
if ($imgname!="" && !in_array($imgname,$imgparams)){ if ($imgname!="" && !in_array($imgname,$imgparams)) {
array_push($imgparams,$imgname); // name (+ type) of the images in the html test array_push($imgparams,$imgname); // name (+ type) of the images in the html test
$imgcount = $imgcount + 1; // number of images in the html test $imgcount = $imgcount + 1; // number of images in the html test
} }
@ -278,12 +244,10 @@ function GetImgParams($fname,$fpath,&$imgparams,&$imgcount)
* @param array List of image parameters * @param array List of image parameters
* @return string String containing the hidden parameters built from the list given * @return string String containing the hidden parameters built from the list given
*/ */
function GenerateHiddenList($imgparams) function GenerateHiddenList($imgparams) {
{
$list = ""; $list = "";
if(is_array($imgparams)){ if (is_array($imgparams)) {
while (list($int,$string)=each($imgparams)) while (list($int,$string)=each($imgparams)) {
{
$list .= "<input type=\"hidden\" name=\"imgparams[]\" value=\"$string\" />\n"; $list .= "<input type=\"hidden\" name=\"imgparams[]\" value=\"$string\" />\n";
} }
} }
@ -296,18 +260,15 @@ function GenerateHiddenList($imgparams)
* @param string Node we are looking for in the array * @param string Node we are looking for in the array
* @return mixed Node name or false if not found * @return mixed Node name or false if not found
*/ */
function myarraysearch(&$array,$node) function myarraysearch(&$array,$node) {
{
$match = FALSE; $match = FALSE;
$tmp_array = array(); $tmp_array = array();
for($i=0;$i<count($array);$i++) for($i=0;$i<count($array);$i++) {
{ if (!strcmp($array[$i],$node)) {
if (!strcmp($array[$i],$node)) $match = $node;
{ } else {
$match = $node; array_push($tmp_array,$array[$i]);
} }
else
{ array_push($tmp_array,$array[$i]); }
} }
$array = $tmp_array; $array = $tmp_array;
return $match; return $match;
@ -331,16 +292,13 @@ function CheckImageName(&$imgparams,$string)
* @param string The content to replace * @param string The content to replace
* @return string The modified content * @return string The modified content
*/ */
function ReplaceImgTag($content) function ReplaceImgTag($content) {
{
$newcontent = $content; $newcontent = $content;
$matches = array(); $matches = array();
preg_match_all("(<img .*>)",$content,$matches); preg_match_all("(<img .*>)",$content,$matches);
$imgcount = 0; $imgcount = 0;
while (list($int,$match)=each($matches)) while (list($int,$match)=each($matches)) {
{ while (list($key,$imgtag)=each($match)) {
while(list($key,$imgtag)=each($match))
{
$imgname = GetSrcName($imgtag); $imgname = GetSrcName($imgtag);
if ($imgname=="") {} // valid or invalid image name if ($imgname=="") {} // valid or invalid image name
else { else {
@ -360,11 +318,9 @@ function ReplaceImgTag($content)
* @param integer Length to reach * @param integer Length to reach
* @return string Modified folder name * @return string Modified folder name
*/ */
function FillFolderName($name,$nsize) function FillFolderName($name,$nsize) {
{
$str = ""; $str = "";
for($i=0;$i < $nsize-strlen($name);$i++) for($i=0;$i < $nsize-strlen($name);$i++) {
{
$str .= "0"; $str .= "0";
} }
$str .= $name; $str .= $name;
@ -376,17 +332,14 @@ function FillFolderName($name,$nsize)
* @param string Folder path * @param string Folder path
* @return string Folder name (modified) * @return string Folder name (modified)
*/ */
function GenerateHpFolder($folder) function GenerateHpFolder($folder) {
{
$filelist = array(); $filelist = array();
if ($dir = @opendir($folder)) { if ($dir = @opendir($folder)) {
while (($file = readdir($dir)) !== false) { while (($file = readdir($dir)) !== false) {
if ( $file != ".") { if ( $file != ".") {
if ($file != "..") if ($file != "..") {
{
$full_name = $folder."/".$file; $full_name = $folder."/".$file;
if (is_dir($full_name)) if (is_dir($full_name)) {
{
$filelist[] = $file; $filelist[] = $file;
} }
} }
@ -410,8 +363,7 @@ function GenerateHpFolder($folder)
* @param string Path * @param string Path
* @return string Folder name stripped down * @return string Folder name stripped down
*/ */
function GetFolderName($fname) function GetFolderName($fname) {
{
$name = explode('/',$fname); $name = explode('/',$fname);
$name = $name[sizeof($name)-2]; $name = $name[sizeof($name)-2];
return $name; return $name;
@ -422,12 +374,12 @@ function GetFolderName($fname)
* @param string Path * @param string Path
* @return string Path stripped down * @return string Path stripped down
*/ */
function GetFolderPath($fname) function GetFolderPath($fname) {
{
$str = ""; $str = "";
$name = explode('/',$fname); $name = explode('/',$fname);
for($i=0;$i < sizeof($name)-1; $i++) for ($i=0;$i < sizeof($name)-1; $i++) {
{ $str = $str.$name[$i]."/"; } $str = $str.$name[$i]."/";
}
return $str; return $str;
} }
@ -436,8 +388,7 @@ function GetFolderPath($fname)
* @param string Path * @param string Path
* @return integer 1 if a subfolder was found, 0 otherwise * @return integer 1 if a subfolder was found, 0 otherwise
*/ */
function CheckSubFolder($path) function CheckSubFolder($path) {
{
$folder = GetFolderPath($path); $folder = GetFolderPath($path);
$dflag = 0; $dflag = 0;
if ($dir = @opendir($folder)) { if ($dir = @opendir($folder)) {
@ -462,21 +413,17 @@ function CheckSubFolder($path)
* @param integer User id * @param integer User id
* @return void No return value, but echoes results * @return void No return value, but echoes results
*/ */
function HotPotGCt($folder,$flag,$userID) function HotPotGCt($folder,$flag,$userID) {
{ // Garbage Collector // Garbage Collector
$filelist = array(); $filelist = array();
if ($dir = @opendir($folder)) { if ($dir = @opendir($folder)) {
while (($file = readdir($dir)) !== false) { while (($file = readdir($dir)) !== false) {
if ( $file != ".") { if ( $file != ".") {
if ($file != "..") if ($file != "..") {
{
$full_name = $folder."/".$file; $full_name = $folder."/".$file;
if (is_dir($full_name)) if (is_dir($full_name)) {
{
HotPotGCt($folder."/".$file,$flag,$userID); HotPotGCt($folder."/".$file,$flag,$userID);
} } else {
else
{
$filelist[] = $file; $filelist[] = $file;
} }
} }
@ -484,19 +431,13 @@ function HotPotGCt($folder,$flag,$userID)
} }
closedir($dir); closedir($dir);
} }
while (list ($key, $val) = each ($filelist)) while (list ($key, $val) = each ($filelist)) {
{ if (stristr($val,$userID.".t.html")) {
if (stristr($val,$userID.".t.html")) if ($flag == 1) {
{
if ($flag == 1)
{
my_delete($folder."/".$val); my_delete($folder."/".$val);
} } else {
else
{
echo $folder."/".$val."<br />"; echo $folder."/".$val."<br />";
} }
} }
} }
} }
?>
Loading…
Cancel
Save