ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [WEBHACKING] SSRF(Server-side Request Forgery) 에 대해서
    # 웹해킹 공부중 2020. 12. 11. 02:27

    1. SSRF란?

    CSRF가 클라이언트 측에서 위조된 요청을 보내는 거라면 SSRF는 서버 측에서 위조된 요청을 보내도록 하는 취약점이다. SSRF 취약점을 이용해서 공격자는 웹앱과 같은 서버측 프로그램이 임의의 주소로 HTTP 요청을 보내게 된다. 그러면 일반적으로 사용자들이 접근할 수 없었던 서버 내부 자원에 접근해서 API key와 같은 중요 데이터가 유출되거나 내부 네트워크 스캔 그리고 경우에 따라 임의 코드 실행이나 임의 파일 쓰기 등의 허가받지 않은 행위가 가능할 수 있다.

    예를 들어 아래 이미지처럼 사용자가 입력한 이미지 URL을 통해 이미지를 가져와 출력하는 서비스를 하는 게시판이 있다고 가정한다.

    그림 1

    $url = $_POST['url'];
    $ext = pathinfo($url, PATHINFO_EXTENSION);
    $image = base64_encode(file_get_contents($url));
    $image_src = 'data:image/'.$ext.';base64,'.$image;
    echo '<img src="'.$image_src.'">';

    코드를 대략적으로 본다면 위와 같다. 사용자로부터 URI를 입력받고 해당 URI로 HTTP 요청을 보내고 돌아온 응답을 리턴한다. 그리고 응답받은 이미지를 <img> 태그를 이용해서 출력한다. 이때 URI를 이미지 URI가 아닌 127.0.0.1이나 내부 특정 파일의 URI, 인스턴스 IP 등 내부에서만 접근 가능한 곳으로 요청을 보내서 SSRF를 시도할 수 있다. 

    예시로 file:///etc/passwd를 요청으로 보낸다면 아래와 같이 해당 파일을 받아와서 출력시킬 수 있다. file:// scheme은 내부 파일 시스템을 가리키는 url scheme이다. 

    그림 2
    그림 3

    file:///etc/passwd를 URL 대신에 입력하면 [그림 2]와 같이 소스코드에(원래는 이미지가 base64로 인코딩 되어 있는 자리) base64로 인코딩된 값이 있다. 해당 값을 decode 해보면 [그림 3]과 같이 /etc/passwd 파일이 출력되는 것을 확인할 수 있다.

    대략적인 SSRF의 컨셉은 다음 그림과 같다. 

    2. Blind SSRF

    Blind SSRF는 사용자의 요청에 대해 서버에서 내부적으로 요청은 발생하지만 그 응답이 사용자에게까지 가지 않아서 확인을 할 수 없는 형태의 SSRF이다. 이런 경우에는 공격자의 서버로 요청을 보내 공격자의 요청이 타겟 서버로부터 오는지를 확인하는 방식으로 확인을 할 수 있다. Blind SSRF는 중요 정보를 유출하기는 힘들지만 내부 네트워크에 있는 취약한 서비스에 1-day 취약점 payload를 보내서 exploit 할 수도 있고 공격자의 서버로 요청을 보내서 타겟 서버의 http client를 공격하는 응답을 보내서 RCE를 시도할 수도 있다. 

    3. SSRF 취약점

    사용자의 입력값으로 URL을 받아서 처리하는 서비스의 경우 잠재적으로 SSRF 취약점이 존재할 수 있다. 예로 위에서 본 것처럼 URL로부터 이미지를 가져오는 서비스나 URL 입력 시 페이지 정보를 가져오는 등 추가 요청이 필요한 경우 취약점이 존재할 수 있다.

    - 입력으로 URL을 받고 해당 URL로부터 어떤 데이터나 정보를 가져오는 서비스의 경우 취약점 발생 가능하다.
    - Referer 헤더의 링크를 통해서 정보를 수집하고 통계에 이용하는 경우가 있다. Referer 링크에서 요청하고 meta 데이터들을 읽거나 페이지를 읽어서 내부 데이터로 이용하는 경우가 있는데 이 때도 역시 SSRF는 발생 가능하다.
    - 데이터를 XML로 전송할 경우 XXE Inejction을 통해서 SSRF를 트리거할 수도 있다.
    - Open Redirection 취약점이 있을 때 경우에 따라 SSRF를 트리거할 수 있다.

    만약 전체 URL을 받지 않더라도 URL의 일부를 사용자로부터 입력받아서 전체 URL을 서버 측에서 구성한 다음에 요청을 하는 경우도 존재한다. 입력값이 특정 자원에 대한 경로 거나 호스트를 입력받는 경우 잠재적으로 SSRF가 존재할 수 있다. 

    보안진단 시에는 타겟 서버 내부로 접근 가능한 자원이 있는지 확인하기 위해서 127.0.0.1 이나 localhost 를 URL에 넣어서 테스트해볼 수 있다. 외부에서는 접근이 불가능한 서비스나 웹앱이지만 서버 자체에서는 접근이 가능한 서비스나 페이지들이 존재할 수 있다. 또한 해당 서버가 현재 Listening 중인 포트를 스캐닝해볼 수도 있다. 

    서버뿐만 아니라 내부 네트워크에 있는 사설 IP를 스캔하고 망 내부에서만 접근 가능한 데이터나 서비스에 접근하여 중요 데이터를 가져오거나 기능을 실행시킬 수 있으며 AWS를 사용하는 경우 169.254.169.254 로 접속해서 meta data를 유출할 수 있다. 

    그리고 서버에서 사용하는 URL 처리기에 따라서 @나 #과 같은 기호를 사용해서 SSRF를 시도할 수 있다.

    @의 경우 cURL에서 id:pw@domain.com과 같은 방식으로 @ 앞을 id와 pw 값을 전달하는 곳으로 사용한다. 즉 이 앞부분은 무시하고 뒤에 domain.com으로 접속하게 되는데 이를 활용해서 앞부분에 허가된 도메인을 넣고 domain.com 부분에 공격자가 원하는 URL을 넣으면 서버에서 whitelist 방식으로 필터링할 때 우회할 수 있다. 비슷한 예로 # 역시 domain.com/#normal_domain.com과 같이 입력할 경우 # 뒤쪽이 무시돼서 whitelist 방식의 필터링을 우회할 수 있다.

    4. 보안 방안

    입력 데이터에 대해 전체 URL을 입력받을 필요가 없다면 사용자로부터 입력을 최소로 받을 수 있도록 한다. 그리고 어쩔 수 없이 URL을 입력받아야 할 경우 입력값에 대한 검증을 철저히 한다.

    - 입력값을 블랙리스트 방식으로 필터링한다. 서버 내부에서 접근해선 안 되는 값들을 필터링하거나 127.0.0.1, localhost, 사설 IP 대역 등을 필터링할 수 있다. 주의해야 할 점은 필터링할 때 우회 가능한 값들도 같이 필터링을 해야 한다. 대소문자를 구분하지 않는다거나 16진수, 8진수, 123.123.123, 1과 같은 값들을 함께 필터링하는 등 우회 지점들을 신경 써야 한다.
    - 입력값을 화이트리스트 방식으로 필터링한다. 허용된 도메인과 URL에 대해서만 허용을 하도록 한다. 가장 안전할 수 있는 방법이지만 서비스에 제약이 생기고 필터링 시 예외처리의 미흡으로 우회가 될 수 있음에 주의한다. 
    - URL 검사할 때 단순히 문자열 포함여부를 검사하지 않고 정규식을 활용하며 정확히 host domain을 검사하도록 하고 @나 #기호를 이용해 우회할 수 없도록 기능을 막거나 필터링을 해야한다. 
    - 서버 내부 정보나 내부 네트워크의 정보가 빠져나가지 않도록 비록 내부 네트워크에서의 접근이라도 중요한 데이터일 경우 추가 인증을 받도록 해서 SSRF 취약점이 있어도 피해가 발생하지 않도록 한다.
    - 요청을 처리하는 서버와 중요 정보가 있는 내부망을 분리시키는 것도 좋은 방법이다. 
    - 요청한 URL에 대한 응답 값이 예상한 값인지를(응답이 이미지인지 동영상인지 등) 검사할 수도 있다. 하지만 이 경우 404, 403과 같은 에러코드가 응답되면서 서버 내부 ip 혹은 포트스캔에 이용될 수 있으니 URL에 대한 추가적인 필터링이 필요하다.
    - http나 https를 제외하고 사용하지 않는 URI scheme은 비활성화하거나 필터링한다.

     

     

     

    댓글

Designed by Tistory.