안녕하세요? 허니입니다. 악성 파일 업로드 및 원격 실행 취약점에 대해서 알아보고 대응 방법에 대해 알아보도록 하겠습니다. 사이버 해킹에 대해 공부하시는 학생이나 연구원 분이 계시면 도움이 될 것이라 생각합니다.
웹 어플리케이션 서버 환경에서 악성 코드로 작성된 실행 가능한 확장자(*.php, *.asp, *.aspx, *.jsp등) 업로드 시 악성 코드가 실행되는 취약점이며, 이를 통해 서버 조작, DB정보 탈취, Backdoor 설치, 악성파일 업로드 등 다양한 공격을 수행할 수 있습니다.
일반적인 대응방법
업로드 파일을 위한 디렉터리에는 실행 권한을 제거 해야 하며 업로드 된 파일 이름을 임의로 변경하여 저장해야 합니다. 업로드 된 파일의 절대경로를 노출 시키지 않아야 합니다. 첨부되는 파일의 확장자를 필터링 해야 하며, 웹 사이트에서 허용하는 파일 확장자를 제외한 나머지 모든 확장자에 대해서 차단해야 합니다. 첨부파일에 대한 검사는 반드시 Server side Script 에서 구현해야 합니다.
개발 언어별 대응방법
- 보안코딩(ASP)
<% Set Up = Server.CreateObject("SiteGalaxyUpload.Form") Path1 = server.mappath(".") & "\upload\"
Fname = Up("file1")
if Fname <> "" then // 파일 첨부가 되었으면 if Up("file1").Size > 10240 then // 용량 제한 Response.Write "용량 초과" Response.End end if
if Up("file1").MimeType <> "image" then // 이미지만 업로드 허용 Response.Write "이미지 파일이 아닙니다." Response.End end if
Filename=Mid(Fname,InstrRev(Fname,"\")+1) // 파일이름부분 추출
// 파일이름에서 세미콜론(;)이 존재하는지 검사한다 if NOT(InStr(Filename,”;”) Then response.write "<script>alert(‘업로드 금지 파일 입니다’);history.back()</script>" response.End End if
// 중복 시에 파일이름 부분을 변경하기 위해 분리를 한다 Farry=split(Filename,".") // .을 기준으로 분리 preFname=Farry(0) // 파일이름 앞부분 extFname=Farry(UBound(Farry)) // 파일이름의 마지막 확장자
// 파일이름의 마지막 확장자를 검사한다 if (NOT(extFname <> "jpg") or (extFname <> "hwp") or (extFname <> "pdf")) then response.write " 업로드 금지 파일 입니다 " response.End End If
// 저장할 전체 path를 만든다, 파일이름을 만든다 Path2 = Path1 & Filename saveFname=preFname & "." & extFname
Set fso = CreateObject("Scripting.FileSystemObject") countNo = 0 // 파일 중복될경우 셋팅 값 fExist=0 // 같은 이름의 파일 존재 체크 Do until fExist = 1 If(fso.FileExists(Path2)) Then countNo = countNo + 1 Path2 = Path1 & preFname & countNo & "." & extFname saveFname=preFname & countNo & "." & extFname else fExist=1 End If Loop
Up("file1").SaveAs(Path2) response.write(saveFname & " 저장완료") else response.write("Error") end if
Set Up = nothing %> |
- 보안코딩(PHP)
<?php $uploaddir = ‘/var/www/uploads/”;
// 파일 사이즈가 0byte 보다 작거나 최대 업로드 사이즈보다 크면 업로드를 금지 시킨다. If($_FILES[‘userfile’][‘name’]) If($_FILES[‘userfile’][‘size’] <= 0) // 최대 업로드 사이즈 체크 삽입 print “파일 업로드 에러”; exit;
// 파일 이름의 특수문자가 있을 경우 업로드를 금지 시킨다. If (eregi(“[^a-z0-9\._\-]”, $_FILES[‘userfile’][‘name’])) print “파일 이름의 특수문자 체크”; exit;
// 파일명 중 “.”으로 구분되어 있는 문자열 모두 검사하여 허용되지 않는 문자열 변환 // Apache mod_mime Module취약점 보완 $filename = preg_replace('/\.(php|phtm|htm|cgi|pl|exe|jsp|asp|inc)/i','$0-x', $_FILES[‘userfile’][‘name’]);
// 파일 확장자 중 제일 끝에 존재하는 확장자를 기준으로 재검사 $full_filename = explode(“.”, $filename); $extension = $full_filename[sizeof($full_filename)-1]; $extension = strtolower($extension); If (!( ereg($extension”,”hwp”) || ereg($extension”,”pdf”) || ereg($extension”,”jpg”)) ) print “업로드 금지 파일 입니다”; exit;
$uploadfile = $uploaddir. $_FILES[‘userfile’][‘name’]; If (move_uploaded_file($_FILES[‘userfile’][‘tmp_name’], $uploadfile)) print “파일이 존재하고, 성공적으로 업로드 되었습니다.”; print_r($_FILES); Else Print “파일 업로드 공격의 가능성이 있습니다! 디버깅 정보입니다:\n”; print_r($_FILES); ?> |
- 보안코딩(JSP)
<%@ page contentType=”text/html;charset=euc-kr” %> <%@ page import=”com.oreilly.servlet.MultipartRequest,com.oreilly.servlet.multipart.DefaultFileRenamePolicy , java.util.*”%> <% String savePath=”/var/www/uploads”; // 업로드 디렉터리 Int sizeLimit = 5*1024*1024; // 업로드 파일 사이즈 제한
try MultipartRequest multi=new MultipartRequest(request, savePath, sizeLimit, “euc-kr”, new DefaultFileRenamePolicy()); Enumeration formNames=multi.getFileNames(); // 폼의 이름 반환 String formName=(String)formNames.nextElement(); String fileName=multi.getFilesystemName(formName); // 파일의 이름 얻기
String file_ext = fileName.substring(fileName.lastIndexOf(‘.’) + 1); If(!( file_ext.equalsIgnoreCase(“hwp”) || file_ext.equalsIgnoreCase(“pdf”) || file_ext.equalsIgnoreCase(“jpg”))) out.print(“업로드 금지 파일”);
If(fileName == null) out.print(“파일 업로드 실패”); else fileName=new String(fileName.getBytes(“8859_1”), “euc-kr”); // 한글인코딩 out.print(“File Name : “ + fileName);
catche(Exception e) |