2007年5月24日星期四

[Tips]php-fusion的一个Xday分析

by Superhei@ph4nt0m
2007-04-15
http://www.ph4nt0m.org


includes/update_profile_include.php

   
. . .
   
$newavatar = $_FILES['user_avatar'];
    
if ($userdata['user_avatar'== "" && !empty($newavatar['name']) && is_uploaded_file($newavatar['tmp_name'])) {
        
if (preg_match("/^[-0-9A-Z_\.\[\]]+$/i", $newavatar['name']) && $newavatar['size'<= 30720) {
                           
$avatarext = strrchr($newavatar['name'],".");
            
if (eregi(".gif", $avatarext|| eregi(".jpg", $avatarext|| eregi(".png", $avatarext)) {
                
$avatarname = substr($newavatar['name'], 0, strrpos($newavatar['name'], "."));
                
$avatarname = $avatarname."[".$userdata['user_id']."]".$avatarext;
                
$set_avatar = "user_avatar='$avatarname', ";
                
move_uploaded_file($newavatar['tmp_name'], IMAGES."avatars/".$avatarname);
                
chmod(IMAGES."avatars/".$avatarname,0644);
                
if ($size = @getimagesize(IMAGES."avatars/".$avatarname)) {
                    
if ($size['0'> 100 || $size['1'> 100) {
                        
unlink(IMAGES."avatars/".$avatarname);
                        
$set_avatar = "";
                    }
                } 
else {
                    
unlink(IMAGES."avatars/".$avatarname);
                    
$set_avatar = "";



判断的伪代码:

<?
$newavatar['name']= $_GET[a]; //提交 a=1.php.php.gifa
print preg_match("/^[-0-9A-Z_\.\[\]]+$/i", $newavatar['name']); //名字里可以有.
$avatarext = strrchr($newavatar['name'],".");//取后缀
print eregi(".gif", $avatarext); //只要后缀里包含有.gif就ok了 那么我们可以提交1.php.php.gif

$avatarname = substr($newavatar['name'], 0, strrpos($newavatar['name'], "."));取最文件名的前面的部分
$avatarname = $avatarname."[".$userdata['user_id']."]".$avatarext;
$set_avatar = "user_avatar='$avatarname', ";
print $avatarname//1.php.php.gifa==>1.php.php[id号].gifa
//move_uploaded_file($newavatar['tmp_name'], IMAGES."avatars/".$avatarname);



在apache下是可以利用了[1],那么下面的getimagesize()的判断:

if ($size = @getimagesize(IMAGES."avatars/".$avatarname)) {
    
if ($size['0'> 100 || $size['1'> 100) {
//可以利用关于paas getimagesize()的帖子构造图片 [2]



当时我是在官方下的v6.00.305测试的,不过无意中在milw0rm上已经有人发过了[3]。 :(

于是又到官方逛,在一个角落里发现了新点的版本:v6.01.10的Code:

. . . . . .
    
if ($userdata['user_avatar'== "" && !empty($newavatar['name']) && is_uploaded_file($newavatar['tmp_name'])) {
        
$avatarext = strrchr($newavatar['name'],".");
        
$avatarname = substr($newavatar['name'], 0, strrpos($newavatar['name'], "."));
        
if (preg_match("/^[-0-9A-Z_\[\]]+$/i", $avatarname&& preg_match("/(\.gif|\.GIF|\.jpg|\.JPG|\.png|\.PNG)

$/
", $avatarext&& $newavatar['size'<= 30720) {
            
$avatarname = $avatarname."[".$userdata['user_id']."]".$avatarext;
            
$set_avatar = "user_avatar='$avatarname', ";
            
move_uploaded_file($newavatar['tmp_name'], IMAGES."avatars/".$avatarname);
            
chmod(IMAGES."avatars/".$avatarname,0644);
            
if ($size = @getimagesize(IMAGES."avatars/".$avatarname)) {
                
if ($size['0'> 100 || $size['1'> 100) {
                    
unlink(IMAGES."avatars/".$avatarname);

. . . . . .



判断的伪代码:

<?
$newavatar['name']= $_GET[a];
$avatarext = strrchr($newavatar['name'],".");
$avatarname = substr($newavatar['name'], 0, strrpos($newavatar['name'], "."));
print $avatarext."<br>";
print $avatarname."<br>";
print preg_match("/^[-0-9A-Z_\[\]]+$/i", $avatarname)."<br>"//提取后缀的部分不可以有. [不可以提交1.php.gif这样的类型]
print preg_match("/(\.gif|\.GIF|\.jpg|\.JPG|\.png|\.PNG)$/", $avatarext)."<br>";



没戏了~~~

一些sy的思考:
如果

preg_match("/^[-0-9A-Z_\[\]]+$/i", $avatarname)

 


没有过滤.的话 是不是还有机会呢? code:


<?
$newavatar['name']= $_GET[a];
$avatarext = strrchr($newavatar['name'],".");
$avatarname = substr($newavatar['name'], 0, strrpos($newavatar['name'], "."));
print $avatarext."<br>";
print $avatarname."<br>";
print preg_match(""/^[-0-9A-Z_\.\[\]]+$/i"", $avatarname)."<br>"//我们使用v6.00.305的正则.
print preg_match("/(\.gif|\.GIF|\.jpg|\.JPG|\.png|\.PNG)$/", $avatarext)."<br>";



我们提交?a=1.php.php.gifa时


preg_match(""/^[-0-9A-Z_\.\[\]]+$/i"", $avatarname===>1
preg_match("/(\.gif|\.GIF|\.jpg|\.JPG|\.png|\.PNG)$/", $avatarext===>0

 


失败了,不过如果你看过se大牛的blog [4] ,


preg_match("/(\.gif|\.GIF|\.jpg|\.JPG|\.png|\.PNG)$/", $avatarext)


这个还是可以过的:
提交?a=1.php.php.gif%0a就可以绕过了,但是在


move_uploaded_file($newavatar['tmp_name'], IMAGES."avatars/".$avatarname);


win下是文件名1.php.php.gif\x0a 是不合法的,但是在*nix下是可以的 :).



参考:
[1]<系统特性与web安全>:http://www.4ngel.net/article/63.htm
[2]<Bypass getimagesize()>:http://my.opera.com/pstgroup/blog/tips-bypass-getimagesize
[3]http://www.milw0rm.com/exploits/1760
[4]http://blog.php-security.org/archives/76-Holes-in-most-preg_match-filters.html

没有评论: