File Download 취약점?
웹 서버에 있는 파일을 Download 하는 기능이 있는 경우
다운로드 시 파일의 경로를 조작(Directory Traversal)을 통해서 내부에 데이터를 다운을 받을 수 있는 취약점이다.
.
.
.
OS 파악
파일 다운로드 취약점은 OS에 따라서 방법이 달라질 수가 있다.
경로를 조작을 하는데 사용되는 /(슬래시)는 윈도우에서는 \(역슬래시)로 대체가 가능하다.
이와 같은 점으로 인해서 os파악을 우선 해야한다.
서버의 os파악 같은 경우는
윈도우는 대/소문자를 구분하지 않지만 리눅스와 유닉스는 구분을 한다는 점으로 확인이 가능하다.
대문자로 파일명 변경 시
위와 같이 파일명을 대문자로 변경을 했을 때
해당 파일이 없는 경우 리눅스/ 유닉스 환경인 것을 알 수가 있다.
반대로 대소문자로 변경했을 때 파일이 존재하는 경우 윈도우 환경이라고 확인이 가능하다.
(※ 정적 자원을 기준으로 확인해봐야 한다.)
파일명만 받는 경우
filename 파라미터를 통해서
서버에 있는 파일을 다운로드하는 action을 하는 것 같다.
./을 파일명 앞에 붙여서 입력을 해봤다.
./을 입력을 했지만 동일하게 나오는 것으로 봐서는
./을 필터링을 해서 사라지게 하거나 또는 실제로 반영이 되는 것 같다.
(※./은 현재 폴더, ../은 이전 폴더)
그래서 ./이 필터링이 되는지 확인을 하기 위해서
파일명의 가운데에 넣어서 확인을 해봤다.
에러 메시지가 뜨는 것을 봐서는 필터링이 되는 것 같지는 않다.
그래서 이번에는 ../이 되는지를 확인을 해봤다.
확인 결과 에러 메시지가 뜬다.
필터링을 하지 않을 경우
현재 폴더에 1234.png가 있지만
../을 통해서 요청을 하면 값이 없다고 나온다. 이는 필터링이 되지 않고 있다고 볼 수가 있다.
위에서 확인한 점들을 토대로
서버에 있는 파일들에 대한 다운로드를 시도해봐야 한다.
서버에는 무조건 있어야 하는 파일들이 있는데 이 점들을 이용해서 다운로드를 시도를 할 수가 있다.
ex) index.php, 서버 관련 파일, 환경변수 관련 파일
서버에 저장된 파일명과 다운로드되는 파일명이 다른 경우
최근 사이트들은 아래와 같이 실제 파일명과 다운로드될 때의 파일명을 다르게 한다.
아래와 같은 경우는 실제 파일 이름 파라미터가 있지만,
해당 파라미터는 없는 상태인 경우도 있다. (※다운로드될 때의 파일명으로 DB에서 가져오는 경우도 있다.)
추가로 실제 파일명이 아닌 임의의 파일명에 경로 조작을 하는 사람을 본 적이 있는데..
임의의 파일명은 실제 서버에 있는 파일이 아니어서
경로를 조작해도 의미가 없는 행위이다.
(※임의의 값으로 파일을 저장하고 이에 매칭 하여서 DB에서 실제 파일명을 가져오게 구현을 할 수도 있다.
그러므로 확신을 가지고 테스트를 해서는 안된다.)
경로 조작은 위와 동일하게 해 주면 된다.
구분자를 통해서 업로드 경로를 다르게 해주는 경우
사이트가 업로드 경로를 한 가지가 아닌 다수를 만들어 놓는 경우도 있다.
이 같은 경우는 구분자를 통해서 경로를 정해주게 된다.
몇몇 개발자분들이 파일명에 경로 조작을 필터링을 적용을 했지만,
구분자에는 필터링을 실수로 안 하는 경우가 있다.
구분자에는 조작 경로가 가능하므로
원하는 서버의 데이터들을 다운로드가 가능하다.
전체 경로와 파일명을 받는 경우
전체 경로를 통해서 파일명을 받는 경우이다.
파일 다운로드를 할 때 다운로드 경로가
윈도우의 경우 다운로드를 할 경로가 다른 파티션일 가능성이 있다.
이 같은 경우에는 전체 경로를 통해서 다른 파티션으로 이동이 가능하고
원하는 데이터를 다운로드 가능하다.
.
.
.
이외에도 서버에서 여러 가지 방식의 검증을 할 수도 있다.
경로 조작 검증뿐만 아니라 확장자 검증, IPS 탐지... 등 여러 가지가 있다.
하지만 이도 여러가지 우회 방법들이 존재한다.
확장자 검증 같은 경우에는
파일명에 %00(Null Byte)를 넣어서 우회를 할 수도 있다.
(윈도우 환경에서는 불가능하며 이 또한 탐지 로직이 서버에 있을 수 있음)
IPS 같은 경우
패턴을 통한 탐지가 될 텐데 이는 해당 패턴에 충족하지 않으면
우회가 가능하다는 것이다.
URL 인코딩 또는 반복 패턴 변화 같은 점을 통해서 우회가 가능하다.
대응방안
정규 표현식 또는 입력 값 검증 통해서 경로 조작이 가능한 문자들을 필터링을 해야만 한다.
if(strpos($real_name, "/") !== false || strpos($real_filename, "..") !== false){
exit();
}
추가로... 해당 글 작성을 위해서 정보수집 중
다른 블로그들에서는 exit()을 안 쓰고 그냥 echo를 통해서 입력 값에 대한 경고 구문만 출력을 하는데..
이 같은 경우에는 exit을 하지 않기 때문에 그냥 값이 들어가는 것을 알 수가 있다.
또는 replace를 통해서 ../를 치환을 하는데
이 또한 ..././이런 식으로 우회가 가능하므로 잘 확인하고 대응해야만 한다.