본문 바로가기
자바/시큐어코딩

파일 업로드 확장자 검증

by 베어그릴스 2022. 12. 28.
반응형

1. 파일 업로드 취약점이란

파일 업로드 시 확장자를 검증하는 이유는

 

주로 게시판 등에서 파일 업로드 기능을 악용하여 시스템 권한을 획득할 수 있는 취약점을 의미한다.

 

악성 스크립트가 업로드된 후, 서버상에서 스크립트를 실행하여 쉘을 획득하는 등의 행위로 서버를 장악할 수 있다.

즉, 흔히 말하는 웹쉘의 업로드를 통해 시스템의 권한을 장악한다는 이야기이다.
그렇다면 어떤 파일들이 웹에서 구동되는가? 웹 서버에서 실행 가능한 확장자는 다음과 같다.

 

언어 확장자
asp, aspx asp, aspx, htm, html, asa
php phtml, php, php3, php4, php5, inc, htm, html
jsp, java
jsp, jspx, jsw, jsv, jspf, htm, html
perl
pl, pm, cgi, lib, htm, html
coldfusion
cfm, cfml, cfc, dbm, htm, html

 

이러한 악성 파일이 업로드 된다면, 접근권한, 정보유출, 악성코드 배포 등의 문제를 야기할 수 있다.

2. 공격방법

이러한 취약점을 찾아 공격하는 방법은 크게 4가지 정도이다.

2-1. 취약점 점검

가장 간단한 방법으로 다음과 같은 과정을 거친다.

  1. 파일 업로드시에 확장자 제한이 없는지 확인하고,
  2. 업로드된 파일에 접근  실행이 가능한지 확인하여 공격하는 것이다.

2-2. Proxy 툴을 이용해 확장자 검사 우회 파일 업로드

파일타입 변조등의 우회공격을 통해 확장자 검사를 피하는 것을 의미한다.
업로드 시 파일의 유형 정보를 알려주는 헤더 중, Content-type 속성을 프락시를 이용해 우회하여 공격할 수 있다.

 

2-3. Null을 이용한 파일 업로드

널(%00) 문자가 문자의 끝을 의미하기 때문에 특정 확장자를 숨기기 위한 목적으로 사용될 수 있다.
해당 부분의 취약점은 내부 API를 호출할 때 발생될 가능성이 있다.

 

널 바이트(%00)와. jpeg확장자를 함께 접목하여 업로드하면 %00 다음의 문자열은 무시하게 된다.

 

언어 우회패턴 처리패턴
php test.php%00.jpeg test.php
asp test.asp%00.jpeg test.asp
jsp test.jsp%00.jpeg test.jsp

2-4. SQL Injection을 이용한 파일 업로드

2가지 정도의 방법이 존재하는데, 다음과 같다.
MySQL의 into outfile() 함수를 이용하여 웹서버에 파일을 생성할 수 있다.
MSSQL의 저장 프로시저(xp_cmdshell)를 이용하여 echo와 » (파이프) 명령어를 통해 특정 파일에 삽입할 수 있다.

3. 방어방법

모든 부분을 전부 작성할 수는 없지만, 대략적으로 다음과 같은 방법을 통하여 기초적인 방어를 할 수 있다.

  1. 확장자 검사
  2. 대소문자 구분하지 않고 확장자 비교
  3. 특수문자가 포함된 경우 업로드 금지
  4. 업로드된 파일명, 확장자를 난수 화하여 변경
  5. 업로드된 파일을 url 요청으로 직접 접근이 불가능한 위치에 저장
더보기

파일 업로드 유틸 부분

enum ExecutableExtensionType
{
    ASPX, ASP, PHP, JSP, HTML, CGI, PERL, SH, EXE, BAT, BIN
}
//파일처리부분

    Enumeration<String> fileNames = multipartrequest.getFileNames();
        
        List<String> files = null;

        while (fileNames.hasMoreElements())
        {
            String inputName = fileNames.nextElement(); // 파라미터명

            // 파라미터명 없으면 생략
            if(StringUtil.isEmpty(inputName))
            {
                continue;
            }

            String fileName = multipartrequest.getFilesystemName(inputName); // 파일명

            // 파라미터에 파일이 없으면 생략
            if(StringUtil.isEmpty(fileName))
            {
                continue;
            }

            // 업로드한 파일객체 얻기
            File uploadFile = multipartrequest.getFile(inputName);

            // 실행가능한 확장자인지 확인
            String fileExt = FileUtil.getExt(uploadFile.getName());
            ExecutableExtensionType[] exeExtTypes = ExecutableExtensionType.values();
            for(ExecutableExtensionType exeExt : exeExtTypes)
            {
                // 실행가능한 확장자일경우 415(지원되지 않는 미디어 유형) 상태로 반환해준다.
                if(exeExt.name().equalsIgnoreCase(fileExt))
                {
                    uploadFile.delete();
                    reqMap.put(SUCC_YN, "N");
                    reqMap.put("STATUS", 415);
                    reqMap.put(ERR_MSG, fileName + " is Executable!");
                }
            }

 

 

더보기

파일 업로드 시 javascript ajax 에러 핸들링

        error       : function(jqXHRr, textStatus, errorThrown)
        {
            if(jqXHRr.status == 415)
            {
                alert('실행가능한 파일은 업로드되지 않습니다.');
            }
            else
            {
                alert("code:"+jqXHRr.status+"\nerror:"+errorThrown);
            }
        }

 

오늘도 보람찬 생존 ^.^

반응형

'자바 > 시큐어코딩' 카테고리의 다른 글

XSS(Cross Site Scripting) 방어  (2) 2022.12.30

댓글