업로드 필터는 php/php3/php4/php5/pht/phtml 확장자만 막는다. .htaccess라는 "확장자 없는" 파일명은 블랙리스트에 걸리지 않고, AllowOverride All인 서버는 업로드 디렉토리에 떨어진 그 .htaccess를 그대로 적용한다. AddType 한 줄로 .jpg를 PHP로 만들어 웹쉘을 올리고, 실행 전용 flag 바이너리를 그 웹쉘로 실행시켜 flag를 받는다.
"htaccess"는 블랙리스트(php, php3, ...)에 없다. 그래서 .htaccess라는 이름의 파일은 이 검사를 그냥 통과해 upload/.htaccess로 저장된다. 그리고 AllowOverride All 덕분에, Apache는 upload/ 디렉토리 요청을 처리할 때마다 이 파일을 실제 설정으로 읽어 들인다.
여기에 이 한 줄을 넣으면:
AddType application/x-httpd-php .jpg
그 순간부터 upload/ 안의 모든 .jpg 파일은 PHP로 실행된다..jpg는 당연히 블랙리스트에 없으니, PHP 코드가 든 shell.jpg를 올리는 것도 아무 제지 없이 통과한다. 필터는 "확장자로 위험한 파일을 막는다"는 가정 위에 서 있었는데, 그 확장자 자체를 재정의하는 파일은 막을 대상으로 생각하지 못했다.
이 문제의 교훈은 명확하다. 파일 업로드 화이트리스트/블랙리스트는 "그 파일이 콘텐츠로만 존재할 때"를 가정한다. 하지만 업로드 디렉토리에 애플리케이션 실행 규칙 자체를 바꿀 수 있는 파일(.htaccess, web.config 등)을 올릴 수 있다면, 그 가정은 통째로 무너진다 — 확장자가 아무리 안전해 보여도, 서버 설정이 그 의미를 바꿔버릴 수 있기 때문이다.
방어는 세 겹으로 해야 한다. 업로드 파일 확장자는 블랙리스트가 아니라 화이트리스트로 검사하고, .htaccess처럼 확장자 없이 시작하는 점 파일(dotfile) 업로드 자체를 별도로 차단하며, 무엇보다 업로드 디렉토리에는 AllowOverride None을 적용해 애초에 사용자가 웹서버 설정을 바꿀 수 없게 만들어야 한다. 업로드된 파일은 실행 권한이 없는 별도 스토리지(혹은 스크립트 실행이 꺼진 디렉토리)에 두는 게 가장 근본적인 대책이다.
Comments
댓글
댓글을 남기려면 로그인이 필요해요. (네이버 · 구글 계정)
댓글 불러오는 중…