이클립스에서 File Upload 취약점이 발생하는 원인 찾기
[보안 취약점 진단 및 대응/openeg] - openeg File Upload
[BoardController.java에서 원인 찾기]
(1) eclipse에서 Ctrl + Shift + R을 눌러 BoardController.Java를 검색합니다.
(2) 문제가 되는 부분을 확인합니다.
=> 업로드 파일의 크기와 개수를 제한하지 않았습니다.
=> 외부에서 접근 가능한 Web Root Directory 아래에 원본 파일명으로 저장하고 있습니다.
=> 따라서 이 코드는 File Upload 취약점이 존재합니다.
(3) 문제가 있는 코드를 수정합니다.
(4) 실행결과
(4)-1 서버에서 실행가능한 JSP 파일 업로드
=> JSP 파일은 업로드 가능한 파일 확장자에 정의되어있지 않기 때문에 업로드 되지 않습니다.
=> 확장자 기반으로 업로드 제한!
(4)-2 2M 이하의 이미지 업로드
=> 이미지 명은 출력되는데 이미지는 출력이 안되고 있습니다.
=> 이 이미지는 서버에 저장 되었을까?
=> c드라이브를 확인해보면 upload 파일이 없습니다.
파일이 정장될 디렉토리(C:\upload\files)를 만들어주고 다시 시도합니다.
=> 여전히 사이트에는 출력되지 않지만, C:\upload\files 디렉토리를 확인해보면 사진이 저장되어 있음을 확인할 수 있습니다.
사이트 소스를 확인해보면 업로드 파일을 Web Root Directory 아래에서 원본 파일명으로 참조하고 있기 때문에 출력되지 않는 것입니다.
=> 업로드한 파일은 Web Root Directory 아래에 있는 것이 아니라 웹에서 접근할 수 없는 C:\upload\files 아래에 있습니다.
=> 이런 방식으로는 파일을 보여줄 수 없는데 어떻게 해야할까요?
=> Web Root Directory에 소스코드와 같은 파일(../files/dog.jpg)이 존재하지 않기 때문에 출력이 되지 않고 있습니다.
=> 지금 업로드한 파일(dog.jpg)은 다른경로에 저장되어 있습니다.
파일 업로드 취약점을 보완하면 업로드 파일을 외부에서 접근할 수 없는 경로에 원본 파일명이 아닌 다른 이름으로 저장되기 때문에 URL 주소를 통해서는 접근할 수 없습니다. 따라서 다운로드 기능이 필요합니다.
=> 다운로드 기능은 접근할 수 없는 경로의 파일을 읽어서 반환하는 것입니다.
=> 사용자 브라우저에서 서버가 가지고 있는 파일들(c:/~/~)을 막 가져갈 수 없습니다. 시스템의 중요한 파일들을 가져갈 수 있기 때문에 안됩니다. 따라서 사용자가 요청을 하면 정해진 기준 디렉토리 안에 있는 것들만 가져갈 수 있습니다. 기준 디렉토리는 외부에서는 알 수 없고, 사용자가 URL을 통해 경로를 요청하면, 그 경로가 실제 서버의 디렉토리에 맵핑이 되어 그 안에 있는 파일을 읽어서 반환하는 형태입니다.
(5) 파일 다운로드 기능을 추가합니다.
[BoardController.java]
[view.jsp]
=> 첨부했던 파일을 URL이 아닌 다운로드 기능을 이용해서 내려받도록 수정하였습니다.
(6) 실행결과
=> 업로드 했던 게시글을 새로고침하면 다음과 같이 이미지를 볼 수 있습니다.
=> idx=22에서 id는 파일이 저장된 위치를 가지고 있는 정보를 참조하고 있는 값입니다.
=> idx로 id 값을 통해 파일명을 받아왔는데 만약 저장된 원본파일명을 그냥 넣게 되면 어떻게 될까요?
[추가] 다운로드 기능을 잘못 구현하는 경우
(7) 잘못 구현하는 경우를 보기 위해 BoardController.java와 view.jsp를 수정합니다.
(8) 실행결과
=> 추가한 코드도 사진이 나오는 것을 볼 수 있습니다.
=> 첫번째 방식은 id를 넘겨줘서 id를 조회하여 저장된 경로 파일명을 가져와서 읽어내는 방식입니다.
=> 두번째 방식은 매개변수로 저장된 파일명을 넘겨줘서 파일명을 직접적으로 공개합니다.
두번째 방식에서 이미지 다운로드 경로를 아래와 같이 변경 후 브라우저를 통해 요청합니다.
http://victim:8080/openeg/board/download2.do?file=../../../../../../../../Windows/System32/drivers/etc/hosts
=> 다운로드 받은 파일을 메모장으로 열어보면 해당 서버의 hosts 파일 내용을 볼 수 있습니다.
=> 다운로드 기능을 구현할 때, 구현한 이유는 파일이 웹에서 접근할 수 없는 경로이기 때문이었습니다. 또한 웹에서는 접근할 수 없는 경로가 어디인지 모릅니다. ../를 사용하면 그 경로의 상위 디렉토리로 이동할 수 있게 됩니다.(경로조작) 그리고 계속 사용하다보면 해당 디렉토리의 최상위 root 까지 도달할 수 있습니다. 즉, 시스템 디렉토리까지 접근이 가능해서 시스템을 제어할 수 있기 때문에 문제가 됩니다. 따라서 (7) 잘못 구현하는 경우는 굉장히 위험한 방식입니다.