[하루한줄] CVE-2024-24569: Pixee Java Code Security Toolkit의 Path Traversal 취약점
URL
https://github.com/pixee/java-security-toolkit/security/advisories/GHSA-qh4g-4m4w-jgv2
Target
- java-security-toolkit ≤ 1.1.1
Explain
Java Code Secutiry Toolkit은 Java로 개발할 때 발생할 수 있는 다양한 범주의 취약점들을 시큐어코딩을 통해 예방할 수 있도록 입력 데이터의 검증이나 필터링 등의 기능을 하는 API를 제공합니다.
개발자는 이러한 API를 사용해서 사용자로부터 전달된 데이터를 필터링하거나 ObjectInputStream
을 통한 역직렬화처럼 매우 취약한 기존 방식을 대체할 수 있습니다.
예를 들어 HtmlEncoder.java
에서는 텍스트에 포함된 \t
, <
등을 HTML 엔티티로 변환시켜 XSS나 CSRF 등의 취약점을 방지하는데 사용할 수 있는 API를 제공하고 이번에 취약점이 발견된 ZipSecurity.java
는 Zip slip 공격을 검사하는 API를 제공합니다.
/dir
- malicious.tar
- **../secret.txt**
/secret.txt **overwritten**
Zip slip이란 .zip
,.tar
등의 아카이브 파일에 위처럼 path traversal 구문이 포함되어 압축이 해제될 때 해당 경로의 파일을 덮어 쓰는 공격으로 malicious.tar
을 dir
에 압축 해제하게 되면 ../secret
의 path traversal 구문에 의해 /secret.txt
가 덮어 쓰일 것입니다.
ZipSecutiry.java
에서는 zip slip을 감지하기 위해 아래의 isBelowCurrentDirectory
메소드를 통해 압축 해제될 경로가 현재 디렉터리와 일치하는지 확인했습니다.
boolean isBelowCurrentDirectory(final File fileWithEscapes) throws IOException {
final File currentDirectory = new File("");
String canonicalizedTargetPath = fileWithEscapes.getCanonicalPath();
String canonicalizedCurrentPath = currentDirectory.getCanonicalPath();
return !canonicalizedTargetPath.startsWith(canonicalizedCurrentPath);
}
정확히는 아카이브 파일에 포함된 파일의 경로 문자열이 현재 디렉터리로 시작(startsWith
)하는지 검사하는 방식을 사용했고 getCanonicalPath
를 통해 ./
나 ../
가 정리된 파일의 압축 해제 경로와 현재 디렉터리의 경로를 얻었습니다.
문제는 getCanonicalPath
가 반환하는 경로 문자열은 맨 끝에 /
가 없기 때문에 아래처럼 현재 디렉터리와 앞부분은 똑같은 형제 디렉터리가 있다면 이곳으로의 path traversal은 탐지하지 못합니다
/*
/victim
- malicious.tar
- ../victim22/secret.txt
/victim22
- secret.txt
*/
boolean isBelowCurrentDirectory(final File fileWithEscapes) throws IOException {
final File currentDirectory = new File("");
String canonicalizedTargetPath = fileWithEscapes.getCanonicalPath();
// canonicalizedTargetPath = "/victim22/secret.txt"
String canonicalizedCurrentPath = currentDirectory.getCanonicalPath();
// canonicalizedCurrentPath = "/victim"
return !canonicalizedTargetPath.startsWith(canonicalizedCurrentPath);
// "/victim22/secret.txt".startsWith("/victim") => true
}
따라서 아카이브 파일을 추출할 디렉터리의 이름 + @인 형제 디렉터리가 있다면 해당 디렉터리로 path traversal이 가능합니다.
이 취약점은 현재는 아래와 같이 String
클래스의 startsWith
이 아닌 Path
클래스의 startsWith
메소드를 사용하도록 패치되었습니다.
private boolean isBelowOrSisterToCurrentDirectory(final String untrustedFileWithEscapes) throws IOException {
// Get the absolute path of the current directory
final File currentDirectory = new File("").getCanonicalFile();
final Path currentPathRoot = currentDirectory.toPath();
// Get the absolute path of the untrusted file
final File untrustedFile = new File(currentDirectory, untrustedFileWithEscapes);
final Path pathWithEscapes = untrustedFile.getCanonicalFile().toPath();
return !pathWithEscapes.startsWith(currentPathRoot);
}
본 글은 CC BY-SA 4.0 라이선스로 배포됩니다. 공유 또는 변경 시 반드시 출처를 남겨주시기 바랍니다.