본문 바로가기

웹 해킹

[주통기반] 로컬 웹 해킹 취약점 찾기 (파일 업로드)

파일 업로드 취약점은 이용자가 원하는 파일을 업로드 할 수 있을 때 발생하는 취약점입니다.

이때, 파일은 서버에서 실행할 수 있는 파일뿐 아니라 html, 설정파일 등도 포함될 수 있습니다.

 

서버에서 실행가능한 파일 같은 경우는 당연히 파일이 실행되면서 해당 서버에 원하는 코드를 실행시킬 수 있기 때문에 위험하지만 html 파일 같은 경우는 왜 위험할까요?

 

일단, 공격자가 악의적인 스크립트가 삽입되어있는 html을 업로드 시킨다면 이용자들은 도메인이 정상적인 사이트와 동일하기 때문에 당연히 속을 수 밖에 없습니다. 그래서 아이디, 비밀번호를 입력하면 공격자에게 보내는 코드로 인해 탈취당할 수도 있습니다.

하지만, 보통 파일 업로드가 가능하다면 서버에서 실행가능한 파일을 업로드하여 웹 쉘을 얻어 서버에 명령을 내릴 수 있도록 합니다. 가장 강력한 공격이기 때문입니다.

 

1. 프로필 사진 변경

1) 마이페이지에 접속합니다.

마이페이지

 

2) 프로필 사진 변경 요청

파일 선택

 

<?php
    echo "<script>alert(1)</script>"
?>

업로드한 파일의 내용은 위처럼 서버에서 파일이 실행되는 것을 확인할 수 있는 코드로 작성합니다.

실제 웹 쉘을 업로드하면 취약점 찾는 과정에서 해당 웹 쉘로 서버를 장악할 수 있는 취약점이 생길 수 있습니다.

 

3) 프로필 사진 변경

프로필 사진 변경 완료

 

프로필 사진이 변경되고 해당 파일이 이미지가 아니라서 위의 사진처럼 제대로 이미지를 가져오지 못하고 있습니다.

 

4) 실행하기 위한 파일 위치 찾기

파일 위치

 

이미지 파일을 가져오기위해 태그에 위치를 저장하고 있습니다.

 

5) 파일 요청하여 실행

파일을 요청

 

파일을 요청으로 was에서 해당 파일을 실행하고 우리에게 응답을 하기 때문에 실행시킬 수 있습니다.

파일 실행

 

파일이 실행되어 코드가 아닌 결과를 보여주는 것을 확인할 수 있습니다.

 

게시글에서 파일 업로드를 할 수 있습니다. 하지만, 저번에 파일 업로드 & 다운로드 취약점을 공부하면서 대응을 적용해놓아서 게시글에서는 해당 취약점이 발생하지 않았습니다.

 

[대응 방안]

업로드 파일을 저장할 때 기본적으로 파일의 확장자를 검사합니다. 확장자 검사 시에는 반드시 화이트리스트 필터링으로 정해진 확장자외에는 제한합니다.

그리고 데이터베이스에 파일을 저장하거나 따로 파일을 저장하는 서버를 구축하여 물리적으로 분리시키는 것이 가장 좋습니다.

데이터베이스에 파일을 저장하면 웹 서버에 파일이 저장되는 것이 아니라 url 경로로 파일을 요청할 수 없을 뿐아니라 요청 시 실행이 되지 않기 때문에 대응이 가능합니다.

 

저번에 데이터베이스에 파일저장하는 것을 해보았으니 이번에는 확장자로 필터링 만들어 대응해보겠습니다.

<?php
// 업로드된 파일 임시저장 되는 곳
$uploaded_file_name_tmp = $_FILES['myfile']['tmp_name'];
// 업로드된 파일 이름
$uploaded_file_name = $_FILES['myfile']['name'];
// 임시저장된 파일을 우리가 원하는 곳으로 이동시킬 위치
$upload_folder = "upload/images/";
$salt = hash('md5', (string) time());

// 파일명 검증
if (empty($uploaded_file_name)) {
    exit;
}

// 확장자 분리
$tmp = explode('.', $uploaded_file_name);
$ext = end($tmp);

// 파일 형식 설정
$haystack = array('jpg', 'jpeg', 'png', 'gif');

echo "<script>alert($ext)</script>";

// 확장자 검증
if (!in_array($ext, $haystack)) {
    echo "<script>alert('허용하지 않는 확장자입니다.')</script>";
    exit;
}

// 업로드된 파일을 각각 구별하기 위한 날짜로 이름 지정
$uploadPath = $upload_folder . $salt . $uploaded_file_name;

// 임시 저장된 파일을 원하는 곳으로 이동
move_uploaded_file($uploaded_file_name_tmp, $uploadPath);

// 데이터베이스에 파일 경로 저장
$updateUser = new User($userId);
$updateUser->uploadProfilePhoto($uploadPath);
?>

 

허용하는 확장자를 jpg, jpeg, png, gif 로만 제한하고 만약 일치하지 않는 경우 허용하지 않는 확장자라는 경고를 합니다.

 

php 파일 업로드

 

사진과 같이 php 파일을 업로드하려고 하면 경고창을 띄워주는 것을 확인할 수 있습니다.

이렇게 정해진 파일 확장자만 업로드 가능하도록 필터링을 진행합니다.

하지만, 어떤 우회가 가능할 지 모르기 때문에 기본적으로 필터링을 진행해주시고 물리적으로 웹 서버와 파일을 저장하는 서버를 분리시키는 것이 좋습니다.