File Upload Vulnerability 란?
서버 측에서 실행될 수 있는 스크립트 파일(asp, jsp, php 파일 등)이 업로드 가능하고, 이 파일을 공격자가 웹을 통해 직접 실행시킬 수 있는 경우 File upload 취약점이 발생할 수 있다. 공격자는 스크립트 파일을 업로드하고 이 파일을 통해 시스템 내부 명령어를 실행하거나 외부와 연결할 경우 시스템을 제어할 수 있게 된다.
File Upload Vulnerability 공격 원리
1. 공격자가 스크립트 파일을 웹 사이트에 업로드
2. 공격자가 해당 스크립트 파일 (php, jsp, asp, cgi, inc, pl, php3 등) 이 저장된 경로에 접근이 가능할 경우, 업로드 된 경로로 이동
3. 해당 파일에 접근하여 파일을 실행
4. 웹 쉘 실행
파일 업로드 취약점에서 자주 사용하는 우회 방식
[이미지 파일 형식만 업로드 가능한 경우]
1. hack.php 형식으로 파일 업로드 버튼을 누른 후 Burp Suite Tool 을 사용하여 중간에서 가로 챈 후, Content-Type 을 image/jpeg 로 바꿔준다.
2. 이름의 확장자만 확인할 경우, hack.php%00.jpg 이와 같이 적어준 후, Burp Suite Tool 로 hack.php로 수정하여 업로드한다.
3. 이미지 파일에다가 Reverse 쉘 코드를 Redirect 를 통해 삽입하여 업로드 한다.
이 때, 파일에 접근이 어려울 경우, File Inclusion 취약점이 발생하는 곳을 찾아주어 공격할 때도 있다.
[안전하지 않은 코드]
public void upload(HttpServletRequest request) throws ServletException {
MultipartHttpServletRequest mRequest = (MultipartHttpServletRequest) request ;
String next = (String)mRequest.getFileNames().next();
MultipartFile file = mRequest.getFile(next);
// MultipartFile로부터 file을 얻음
String filename = file.getOriginalFilename();
File uploadDir = new File("파일 경로");
String uploadFilePath = uploadDir.getAbsoultePath() + "/" + filename;
/* 이하 파일 업로드 루틴 */
}
위 코드를 보면, 어떠한 파일 타입 및 확장자, 크기 등을 확인하지 않고 파일 경로를 형성하는 것을 볼 수 있다. 이러한 경우 File upload 취약점이 발생할 수 있다. 이를 기본적으로 해결하기 위해서는 타입 및 확장자, 파일 크기 또한 확인해주는 과정을 거쳐줘야한다.
[안전한 코드]
public void upload(HttpServletRequest request) throws ServletException {
MultipartHttpServletRequest mRequest = (MultipartHttpServletRequest) request;
String next = mRequest.getFileNames().next();
MultipartFile file = mRequest.getFile(next);
if (file == null) {
return ;
}
// Secure Coding (업로드 파일 크기 제한)
int size = file.getSize();
if( size > MAX_FILE_SIZE) throw new ServletException("에러");
String filename = file.getOriginalFilename().toLowercase();
if( filename != null) {
// Secure Coding (화이트 리스트 방식으로 확장자 체크)
if(fileName.endsWith(".doc") || fileName.endsWith(".hwp") || fileName.endsWith(".pdf") || fileName.endsWith(".xls")) {
// file upload
...
}else {
throw new ServletExpection("에러");
}
}
// Secure Coding (업로드 파일의 디렉터리 위치는 다큐먼트 루트의 밖에 위치 시킴)
File uploadDir = new File("/app/webapp/data/upload/notice");
String uploadFilePath = upload.getAbsolutePath() + "/" + fileName ;
}
위 코드는 업로드 파일 크기 제한, 화이트 리스트 방식으로 확장자 체크, 업로드 파일의 디렉터리 위치를 루트의 밖에 위치 시킴으로써 보안 코드를 작성하였다. 이것 외에도 아래와 같이 파일 내용을 기반으로 file 의 type 을 판별하는 코드 또한 필요하다.
if(extractFileType(file) == EXECUTEABLE_FILE_TYPE){
// error
return ;
}
만일, 파일 타입이 실행 가능한 파일일 경우 에러를 발생시켜 해당 파일이 업로드 되는 것을 막아준다. 이러한 보안 기법들을 사용하더라도 조금 더 보안을 높이기 위해선 파일 명을 암호화 알고리즘을 사용하여 저장하는 방식 또한 보안 수준을 높여줄 수 있다.
아래 코드는 md5 암호화 알고리즘 코드이기에, 참고하면 좋을 것 같다.
[md5 암호화 알고리즘]
//Create checksum for this file
File file = new File("c:/temp/testOut.txt");
//Use MD5 algorithm
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
//Get the checksum
String checksum = getFileChecksum(md5Digest, file);
보안 방법
해당 파일이 "image/jpeg" 혹은 "image/jpg" 인지 타입 및 확장자를 확인한 후, 파일 크기 또한 확인해준다. 더 나아가, 파일 명을 암호화 알고리즘을 사용하여 저장해주면 해당 파일의 이름에 접근이 어렵기 때문에 보안 수준을 높일 수 있다. 추가적으로, 업로드 경로에 접근을 불가능하도록 제한을 걸어주거나 업로드 디렉터리를 웹 서버의 다큐먼트 외부에 설정해놓으면 된다.
참고 문헌
[1] 시큐어 코딩 보안 가이드 https://www.kisa.or.kr/public/laws/laws3_View.jsp?mode=view
[2] MD5 https://howtodoinjava.com/java/io/sha-md5-file-checksum-hash/
'Web Security > Secure Coding' 카테고리의 다른 글
시큐어 코딩 (XQuery Injection) (0) | 2021.07.30 |
---|---|
시큐어 코딩 (Open Redirect) (0) | 2021.07.30 |
시큐어 코딩 (Command Injection) (0) | 2021.07.29 |
시큐어 코딩 (Cross-Site Scripting) (0) | 2021.07.29 |
시큐어 코딩 (Resource Injection) (0) | 2021.07.29 |