ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 파일 업로드를 통한 XSS공격 중 소스코드 관점의 보안 대책
    프로젝트 2016. 6. 24. 21:13
    약 2년전에 과제로 작성했던 것.


    1. 취약성 점검 방법

    A.         먼저 사용자 게시판에 파일첨부 기능이 있는지 조사한다.

    예) 게시판, 공개 자료실, 관리자 자료실, 이미지 자료실 등

    B.         첨부기능이 존재하는 경우, 확장자가 jsp, php, asp, cgi 등 Server Side Script 프로그램을 업로드 하여 업로드가 가능한지 조사한다. 이 때 클라이언트 프로그램에서 JavaScript, VBScript 등의 스크립트로 파일첨부를 차단하는 경우 차단기능을 수정하여 파일을 첨부한다.

    C.         홈페이지에 있는 디렉토리 정보를 이용하여 첨부한 Server Side Script 프로그램의 위치를 조사한 후 브라우저 주소 창에서 해당 프로그램을 실행한다.

    D.         실행 창에서 프로그램 소유자를 조사하거나 중요정보가 존재하는지 조사한다.

     

    2. 개발 언어별 조치 방법

    (1) 첨부 파일에 대한 검사는 반드시 Server Side Script에서 구현해야 한다.

    (2) 첨부파일을 체크하여 특정 종류의 파일들만 첨부 가능하도록 하고 에러코드를 삽입하거나 첨부 파일을 처리하는 파일 업로드 프로그램(php,php3, cgi, html, jsp 등)에서 모든 실행 가능한 파일은 첨부할 수 없도록 한다

    (3) 프로그램에서 필터링을 할 경우 단순히 파일이름 기준으로 점검하지 말고 확장자 명에 대하여 검사하되 대소문자를 모두 검사하도록 한다.

    (4) 너무 작거나 큰 파일을 처리하는 로직을 포함해야 하고, 임시 디렉토리에서 업로드 된 파일을 지우거나 다른 곳으로 이동시켜야 한다. 또한 폼에서 어떠한 파일도 선택되지 않았다면, 파일 업로드에 사용되는 변수를 초기화 시켜주어야 한다.

    (5) 웹 서버 엔진 설정 시 업로드 된 디렉토리의 Server Side Script 언어의 실행 권한을 제거하고 업로드 된 파일이름을 임의로 변경하여 저장하는 것도 안전한 방법이다

     

     1) ASP

        취약한 파일 업로드 예


    <%

    Set Up = Server.CreateObject("SiteGalaxyUpload.Form")

     

    uploadPath = server.mappath(".") & "\upload\"' 업로드 디렉토리

     

    Fname = Up("file1")

    if Fname <> "" then'파일 첨부가 되었으면

    fileName=Mid(Fname,InstrRev(Fname,"\")+1)'파일이름부분 추출

    savePath = uploadPath & fileName

     

    Set fso = CreateObject("Scripting.FileSystemObject")

    Up("file1").SaveAs(savePath)

    response.write(savePath & " 저장 완료")

    else

    response.write("Error")

    end if

    Set Up = nothing

    %>

     

     

         안전한 파일 업로드 예


    <%

    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)'파일이름부분 추출

     

    ' 중복시에 파일이름부분을 변경하기 위해 분리를 한다

    Farry=split(Filename,".")'.을 기준으로 분리

    preFname=Farry(0)'파일이름 앞부분

    extFname=Farry(1)'파일의 확장자

     

    ' 저장할 전체 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

    %>

     

     

     

     2) PHP

       취약한 파일 업로드 예


    <?php

    $uploaddir = '/var/www/uploads/';

     

    $uploadfile = $uploaddir. $_FILES['userfile']['name'];

     

    if(copy($_FILES['userfile']['tmp_name'], $uploadfile))

    print "성공적으로 업로드 되었습니다.";

    print_r($_FILES);

    else

    print "파일 업로드 실패";

    print_r($_FILES);

     

    ?>

     

     

       안전한 파일 업로드 예


    <?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;

     

    //파일 확장자중 업로드를 허용할 확장자를 정의한다.

    $full_filename = explode(".", $_FILES['userfile']['name']);

    $extension = $full_filename[sizeof($full_filename)-1];

    /* PHP의 경우 확장자 체크를 할 때 strcmp(확장자,"php3"); 로 체크를 하게 되면

    pHp3 이나 phP3는 구별을 하지 못하게 되므로 strcasecmp처럼 대소문자 구별을 하지

    않고 비교하는 함수를 사용한다. 또한 .를 기준으로 하여 확장자가 하나로 간주하고

    프로그램을 할 경우 file.zip.php3 이라고 올린다면 zip파일로 인식하고 그냥 첨부가

    되므로 아래와 같이 제일 끝에 존재하는 확장자를 기준으로 점검하도록 한다. */

     

    $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);

     

    ?>

     

     3) 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, new DefaultFileRenamePolicy());

    Enumeration formNames=multi.getFileNames();//폼의 이름 반환

    String formName=(String)formNames.nextElement();

    String fileName=multi.getFilesystemName(formName);// 파일의 이름 얻기

     

    if(fileName == null)

    out.print("Error");

     else

    fileName=new String(fileName.getBytes("8859_1"),"euc-kr");

    out.print("User Name : " + multi.getParameter("userName") + "<BR>");

    out.print("Form Name : " + formName + "<BR>");

    out.print("File Name  : " + fileName);

     

     catch(Exception e)

    out.print("Error");

     

    %>

     

     

      안전한 파일 업로드 예

    <%@ 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);

     

     catch(Exception e)

     

     

     

     

     

    발췌 및 참고자료

    1)http://wikisecurity.net/guide:jsp_%EA%B0%9C%EB%B0%9C_%EB%B3%B4%EC%95%88_%EA%B0%80%EC%9D%B4%EB%93%9C  

    2)웹_애플리케이션_취약점_대응_가이드_v1.1.doc

     



    댓글 0

Designed by Tistory.