
File Upload 취약점은 웹 서버가 사용자로부터 업로드된 파일의 이름, 유형, 내용 또는 크기를 적절하게 검증하지 않을 때 발생할 수 있는 취약점입니다
File Inclusion 취약점은 웹 애플리케이션이 외부 입력을 사용하여 파일을 포함 (Include)할 때 사용자 입력을 적절히 필터링 하지 않으면 의도하지 않은 파일을 열거나 실행할 수 있는 취약점입니다
더 상세한 내용은 File Upload & File Inclusion에 대해 알아보기를 참고해주시면 감사하겠습니다
본 실습은 DVWA 환경을 구축한 후 가장 취약한 환경인
Low레벨에서 진행되었습니다!
먼저 File Upload를 실습해보겠습니다
dvwa에서 File Upload를 눌러줍시다
폴더에서 파일을 찾아서 업로드가 가능하도록 되어있네요
음.. 간단하게 text파일을 넣어보겠습니다
test라는 제목의 파일을 업로드했습니다
그런데 경로가 노출이 되어있네요
../../hackable/uploads/에 저장이 되는 것을 확인할 수 있습니다!
그럼 이번에는 View Source를 통해 소스를 확인해봅시다
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
// Can we move the file to the upload folder?
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
?>
문제가 많이 보이네요
여기서는 업로드 파일 확장자 검증을 하지 않습니다
따라서 악성 파일을 업로드하게 되면 그대로 서버에 저장되는 것입니다
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
다음으로는 basename()으로 경로를 정리하나 악의적으로 조작된 파일명은 완전 방지하지 못합니다
그리고 마지막으로 업로드 경로가 웹 루트 내에 있어서 웹서버를 통해 직접 접근이 가능합니다
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
그럼 ../../hackable/uploads/이 경로로 한번 들어가봅시다
이렇게 저희가 원하는대로 들어가지네요!
아까 봤던 uploads 디렉토리도 보이는데 한번 들어가봅시다
제가 아까 업로드한 test 파일이 보이는 것을 확인할 수 있네요
제가 test 파일에 뭐라 썼을까요? 파일까지 열어봅시다
저는 간단하게 Hello World!를 작성했습니다ㅎㅎ
지금은 단순한 텍스트 파일이기 때문에 내용만 출력하고 끝이지만 만약 php 파일이나 JavaScript 파일이 업로드되었다면 어떨까요?
서버는 제대로 처리를 하지 않았기 때문에 아마 피해를 입게될 것 입니다!
아래는 제가 쿠키를 보여주는 xss.php 파일을 작성한 후 업로드해서 실행했을 때 입니다
쿠키 내용이 잘 보이네요!
코드는 아주 간단하게 아래와 같이 작성했습니다
<?php
echo "<script>alert(document.cookie);</script>";
?>
이렇게 File Upload 실습을 진행해봤습니다
이번에는 File Inclusion을 실습해보겠습니다
File Inclusion에 들어가봅시다
빨간색으로 allow_url_include가 Off라고 뜨네요
On으로 바꿔줘야겠습니다
php.ini파일을 수정해야 하는데 /etc/php/7.0/apache2에 파일이 존재합니다 (숫자는 다를 수 있습니다)
Off를 On으로 바꿔줍시다
그리고 아파치 서버를 재시작합시다
저는 service apache2 restart를 이용했습니다 (명령어가 약간은 다를 수 있습니다)
서버까지 재시작하니 없어진 것을 확인할 수 있습니다
먼저 LFI 실습을 진행해봅시다
php확장자의 파일이 3가지가 나타나네요
확인해봅시다!
file1.php을 클릭했더니 위 사진같이 나타나네요
그럼 다른 파일을 볼까요?
그렇네요
사실 내용은 중요하지 않습니다
여기서 주목할 점은 URL인데요
아래 URL을 봅시다
http://localhost/vulnerabilities/fi/?page=file2.php
제가 file2.php를 클릭했을 때 이렇게 나타났고 file1.php를 클릭했을 때는 file1.php였습니다
즉 해당 include되는 파일명을 파라미터로 받아 해당 파일을 include해서 출력한다는 것을 알 수 있습니다!
그렇다면 다른 파일도 되지 않을까요?
아까 File Upload 실습을 다시 생각해봅시다
여기서 uploads/를 들어갔지만 이번에는 flags/로 들어가봅시다
fi.php 파일이 나타나는데 클릭을 해봅시다
좋은 시도였다고 하면서 file include를 이용하라고 합니다
그럼 이제 어떤 파일을 저희가 include할지 감이 잡히시죠?
바로 fi.php입니다!
이제 경로를 알아야하는데 경로는 hackable/에서 uploads/가 아닌 flags/로 설정하고 파일인 fi.php로 해주면 아래와 같습니다
../../hackable/flags/fi.php
자 그럼 이를 파라미터로 넣어봅시다!
url에 아래와 같이 입력해봅시다
http://localhost/vulnerabilities/fi/?page=../../hackable/flags/fi.php
그러면 아래와 같이 나타납니다
아까는 Nice try~ 이렇게 나타났는데 이제는 문장들이 나타나네요!
그런데 LINE HIDDEN이 거슬리네요
저 문장을 찾아봅시다
이 문제를 해결하기 위해 알아야할 것이 있습니다
바로 PHP Wrapper라는 것입니다
PHP에는 URL style 프로토콜을 위한 Wrapper들이 존재합니다
파일 시스템 관련 함수로 filename에 Wrapper를 써서 다른 행위를 할 수 있게 해줍니다
대표적인 시스템 함수들은 아래와 같습니다
| 시스템 함수 (Wrapper) | 기능 설명 |
|---|---|
file:// | 로컬 파일 시스템에 접근 |
http://, https:// | 원격 HTTP/HTTPS URL에 접근 |
ftp://, ftps:// | 원격 FTP/FTPS 서버에 접근 |
php:// | 다양한 내부 I/O 스트림에 접근 (예: php://input, php://memory, php://stdout 등) |
php://filter/ | 파일 내용을 읽거나 쓰기 전에 필터를 적용 (예: base64 인코딩, 디코딩 등) |
zlib:// | 압축 스트림 처리 (gzip 압축된 파일 읽기/쓰기) |
zip:// | ZIP 파일 내부에 접근 (zip://archive.zip#file.txt 형식) |
data:// | RFC 2397 형식의 데이터 URL 사용 (직접 데이터를 URL에 포함시켜 처리) |
glob:// | 와일드카드 패턴으로 파일 경로 검색 (예: glob://*.txt) |
phar:// | PHP 아카이브(Phar) 내부 파일 접근 |
expect:// | 외부 명령어 실행 및 입출력 제어 (expect 스크립팅과 유사 — 매우 위험) |
여기서PHP filter를 사용해봅시다
아까 파일명을 아래와 같이 써봅시다
php://filter/convert.base64-encode/resource=../../hackable/flags/fi.php
여기서 convert.base64-encode는 base64로 인코딩하는 필터를 적용한다는 의미입니다
url은 아래와 같습니다
http://localhost/vulnerabilities/fi/?page=php://filter/convert.base64-encode/resource=../../hackable/flags/fi.php
자 이제 이걸 입력해봅시다
이렇게 많은 문자가 나타날텐데 이걸 이제 디코딩하면 됩니다
그럼 최종적으로 아래와 같이 나타납니다
<?php
if( !defined( 'DVWA_WEB_PAGE_TO_ROOT' ) ) {
exit ("Nice try ;-). Use the file include next time!");
}
?>
1.) Bond. James Bond
<?php
echo "2.) My name is Sherlock Holmes. It is my business to know what other people don't know.\n\n<br /><br />\n";
$line3 = "3.) Romeo, Romeo! Wherefore art thou Romeo?";
$line3 = "--LINE HIDDEN ;)--";
echo $line3 . "\n\n<br /><br />\n";
$line4 = "NC4pI" . "FRoZSBwb29s" . "IG9uIH" . "RoZSByb29mIG1" . "1c3QgaGF" . "2ZSBh" . "IGxlY" . "Wsu";
echo base64_decode( $line4 );
?>
<!-- 5.) The world isn't run by weapons anymore, or energy, or money. It's run by little ones and zeroes, little bits of data. It's all just electrons. -->
이제 모든 문장을 알 수 있네요!
다음은 리눅스 시스템의 사용자 계정 정보를 갖고 있는 passwd 파일을 확인해봅시다
상대경로는 ../../../../../../etc/passwd 이며 절대경로는 /etc/passwd 입니다
그럼 마찬가지로 파라미터에 위와 같이 넣어봅시다
이렇게 뜨는 것을 확인할 수 있습니다!
다음은 RFI 실습입니다
이번에는 파일명 말고 URL을 넣어봅시다
아무래도 google URL이 간단하면서도 자주 쓰이니 넣어보겠습니다!
아래와 같이 넣어봅시다
http://localhost/vulnerabilities/fi/?page=http://google.com
그럼 아래와 같이 나타날 것입니다
신기하지 않나요?
google 웹 페이지가 include 되어 해당 페이지에서 출력되는 모습을 확인할 수 있습니다!
아쉽게도 검색은 안되네요ㅎㅎ
사실 File Upload, File Inclusion을 실습해보기 전에는 재미없을 줄 알았는데 특히 RFI 실습으로 google 페이지를 불러온 건 정말 신기했습니다
그리고 경로 하나 노출했는데 온갖 파일들을 다 확인할 수 있는게 무서우면서도 경로 노출을 최대한 안 하도록 해야겠다는 생각을 하게 되었습니다
어느덧 4주차 실습까지 해서 제가 스터디를 마무리하게 되었습니다
1년 전에 웹 해킹을 공부해본다고 드림핵에서 세션까지 했던 기억이 이제 나네요
아직 많이 부족하지만 1년동안 전공 수업도 더 듣고 올해 5월에는 스터디까지 해보면서 기초적이지만 SQLI부터 CMD Injection, XSS, CSRF, Authorization Bypass 그리고 File Upload / File Inclusion까지 넓게 배울 수 있었던 것 같습니다
처음 블로그를 쓸 때에는 쓰기 귀찮아서 괜히 한다고 했나 생각하면서도 지금 돌아보면 정말 도움이 많이 된 것 같습니다
4주차 커리큘럼을 제공해주신 덕분에 제가 잘 따라갈 수 있었기에 멘토님께 감사의 말을 전하고 싶습니다
스터디는 여기서 끝나지만 멈추지 않고 dvwa도 Low 레벨에서 멈추지 않고 Medium, High까지 도전해보고 워게임도 참여해 볼 생각입니다
기초적인 틀을 잡았으니 이를 더 발전시키면서 이제는 스스로 찾아보고 공부할 수 있도록 하겠습니다
앞으로는 블로그에 글을 얼마나 열심히 쓸 지는 모르겠으나 시간이 난다면 공부한 내용 등을 쓸 것 같습니다
배움을 향해 나아가는 모든 분들, 파이팅입니다!
한달이라는 기간 동안의 짧고 빡빡한 스터디를 계획하면서 '잘 따라오실 수 있을까'라는 걱정이 앞섰는데 정말 가장 열심히 참여해주셔서 감사드립니다. 워게임 , CTF 참여하시면서 언젠가 블로그에 작성한 내용들이 도움이 될거라고 생각합니다. 그리고 추후 1년 , 2년후 돌아봤을때 내가 이렇게 글을 썼었구나 하면서 부족한점을 돌아보고 보충할 수 있게 될거라고 확신합니다. 제가 그러고 있거든요
궁금한점이 생기신다면 제가 아는선에서 얼마든지 답변드리겠습니다. 고생하셨습니다!