내가 싫어하는 언어..

 

올해 codegate 2022 웹 문제 중에서 java에 `URL class`를 이용한 SSRF 문제가 나왔다.

 

아래 코드는 `URL class`를 이용하여 외부 사이트에 요청 및 응답 값을 출력하는 코드 이다.

import java.net.URL;
import java.net.MalformedURLException;
import java.io.InputStreamReader;
import java.io.BufferedReader;

public class test{
    public static void main(String[] args){
        String url = "https://lactea.kr";
        String result = "";
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(new URL(url).openStream()));
            while (true) {
                String inputLine = in.readLine();
                if (inputLine != null) {
                    result = result + inputLine + "\n";
                } else {
                    in.close();
                    try {
                        System.out.println("== result ==");
                        System.out.println(result);
                    } catch (Exception e) {
                        System.out.println("error 1");
                    }
                }
            }
        } catch (Exception e2) {
            System.out.println("error 2");
        }
    }
}

 

 

위 코드를 실행하면 `url` 변수에 저장된 주소로 요청 및 응답 값을 출력하게 된다.

URL class에서 사용 가능한 scheme 종류는 다음과 같다.
https://stackoverflow.com/questions/41784555/print-all-supported-url-schemes-in-java8#:~:text=want%20more%20than-,http%2C%20https%2C%20file%2C%20and%20jar,-%2C%20you%20need%20to

http:// https:// file:// jar://

 

 

따라서 위 코드에서 `url` 변수의 값을 `file:///etc/passwd` 라고 변경한 뒤 실행하면 아래 사진처럼 내부 파일을 읽을 수 있다.

 

만약, 위 코드에서 `file://` scheme 문자열을 검증하는 코드가 추가가 된다면, 내부 파일을 읽을 수 가 없을 것이다. 

if (url.startsWith("file")) {
    System.out.println("No");
}

 

 

이를 우회하기 위해 `URL class` 파일을 보면 다음과 같다.

`spec` 변수는 url 주소 값이 들어간다. 아래 사진을 보면 575번째 줄에 `url:` 이라는 문자열로 시작하면 `start` 변수에 4를 더해준다. 이는 url 구조를 분석하기 위해 `start` 변수로 시작 index를 정하는 것이다.

https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/net/URL.java#L575

 

 

즉, 위 코드를 통해 공격자가 `file:///etc/passwd` 에서 `file://` scheme 검증 절차를 우회하기 위해
`url:file:///etc/passwd` 라고 변경하면 내부 코드를 읽을 수 있다.