Web Hacking 과제_1(Dreamhack_file-download-1)

2024. 11. 4. 01:34hacking : p_study/Dreamhack

file-download-1 | 워게임 | Dreamhack | 워게임 | Dreamhack

 

file-download-1

File Download 취약점이 존재하는 웹 서비스입니다. flag.py를 다운로드 받으면 플래그를 획득할 수 있습니다. Reference Introduction of Webhacking

dreamhack.io

 

 

문제 설명

File Download 취약점이 존재하는 웹 서비스입니다.
flag.py를 다운로드 받으면 플래그를 획득할 수 있습니다.

 

우선 File Download 취약점에 대해서 찾아보자.

 

1. 파일 다운로드 취약점이란?

파일 다운로드 기능 사용 시 임의의 문자나 주요 파일의 입력을 통해 웹 서버의 홈 디렉터리를 벗어나 임의의 위치에 있는 파일을 열람하거나 다운 가능한 취약점(passwd, 중요파일/백업, 데이터베이스, 소스코드 정보 등)을 뜻한다.

 

 

2. 발생 원인

  • 파일 다운로드 시 파일의 절대경로 또는 상대 경로가 노출되는 경우
  • 다운로드 모듈이 파일의 경로나 이름을 파라미터로 사용하는 경우
  • 파일 경로와 파일명 필터링 미흡하여 ../를 이용해 상위 디렉터리에 접근이 가능한 경우
  • 다운로드 경로가 노출되지 않더라도 구조가 단순하여 파라미터 변조를 통해 접근이 허용되지 않은 파일에 접근이 가능할 경우

 

3. 절대 경로란?

웹 페이지나 파일이 가지고 있는 고유한 경로를 말한다.

ex) C:\Apache24\bin\iconv\test.txt

 

4. 상대 경로란?

현재 위치한 곳을 기준으로 하여 그곳의 위치를 의미한다.

ex) http://192.168.0.0/board/data/../../qna/test.txt

 

5. 취약한 소스코드 형태

String fileName = request.getParameter("fileName"); -> 파일명을 입력값으로 받음

String Filepath = request.getParameter("filePath"); -> 파일 경로를 입력값으로 받음

File file=new File(filePath+fileName); 필터링 없이 경로명+파일명을 조합하여 File객체 생성

 

6. 진단 방법

  • 업로드 된 파일의 속성 정보를 확인하여 해당 파일의 경로 노출 여부 확인
  • 사용되는 파라미터 중 변조에 의해 다른 파일에 접근이 가능한 부분이 있는지 확인
  • 파일명으로 다운로드 하는것을 확인 후  상위 경로로 이동하는 명령어(../) 삽입
  • 다운로드한 주요 파일을 바탕으로 시스템 정보수집

 

7. 주요 파일 경로

Windows

  • ../../../../boot.ini
  • ../../../../winnt/win.ini
  • ..%2F..%2 Fboot.ini           %2F -> /값 인코딩
  • ..%5C..%5 Cboot.ini          %5C -> \(역슬래쉬) 인코딩
  • ../../../../writetest.txt
  •  /../../../windows/system32/config/sam

 

UNIX

  • etc/passwd
  • etc/shadow
  • etc/security/passwd
  • etc/security/user

 

8. 우회 기법

Windows

  • 경로 추적 - http://192.168.0.0/scripts/..%255c..%255c../winnt/system32/cmd.exe?c+dir+c:\
  • cmd를 통해 해당 시스템 경로를 추적하는 방법
  • URL인코딩 특수문자를 인코딩하여 경로 설정 시 적용
  • 유니코드 인코딩 파일명을 유니코드 인코딩을 적용하여 파일 다운로드 시도
  • 특수문자 변형 (.../.../..//) 사용하여 다운로드 시도

 

[참고 자료]

 

https://mokpo.tistory.com/28#9. 중요 정보 파일 [MSS:티스토리]

 

 

 

 

서버를 생성하여, 문제를 확인해보자.

위와 같이 Please upload your memo! 라고 적혀있다. 메모를 업로드하라는 의미인데, Upload My Memo로 가서 내용을 확인해보자.

 

 

마치 게시판 같은 형태로 구성되어있는데, file name을 넣고, content 내용을 입력하라고 되어있다. 일단 어떤식으로 기록되는지 확인해보고 싶어서 아무거나 입력해보았다.

 

이런식으로 정상적으로 업로드된 것을 확인할 수 있었다. 관련된 코드를 확인해봐야겠다.

 

#!/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)

 

 

 

코드를 확인해보니, html과 관련된 코드도 살펴보고 싶어졌다.

flag와 관련된 부분을 코드에서 찾아봤는데, 잘 찾아봐도 보이지가 않았다.

 

그래서 찾아봤다.

 

우선 메모가 작성되었을 때, 페이지 경로는 /read?name=swlug 이다.

read 페이지에서 name 파라미터로 전달된 이름의 파일을 읽는 것으로 추측되었다.

name 파라미터 값을 flag.py로 변경하여 시도해보자.

 

실패했다. 코드를 통해서 다시 풀어보자.

 

upload_memo() 함수에 정의된 내용을 살펴보았을때, 사용자가 메모를 작성하면 제목은 filename으로, 내용은 content로 저장되도록 되어있다.

 

여기서 POST 요청으로 전달한 filename 파라미터 값에 상위 디렉토리 이동 명령어 ".."를 탐지하며,

.. 문자열이 탐지되지 않으면, filename 파라미터 명으로 파일을 생성하고, content를 내용으로 작성하도록되어있다.

 

생성된 파일의 경로는 /uploads/{filename} 이다.

flag.py가 어디있는지 모르지만 ".." 문자열을 탐지하는 것으로 보아 웹 디렉토리 최상위 경로에 있는 것으로 추측된다.

 

read_memo() 함수에 정의된 내용을 보면 upload_memo() 와 다르게 ".." 문자열에 대한 탐지가 존재하지 않는다.

그럼 /read?name=../flag.py로 접근하면 flag.py 파일을 읽어올 것 같다.

 

 

코드를 찾았을때, flag와 관련된 내용이 없었는데, 직접 상위디렉토리에 있는 flag파일을 읽는 것이 목적이었던.. 생각해보면, 문제 설명에도 flag파일을 다운로드받으면 flag값을 얻을 수 있다고 설명이 되었으니, 그부분을 생각했으면, 굳이 힌트를 얻지 않았어도

쉽게 접근할 수 있었을 수 있겠다는 생각이 들었고, 경험치가 부족한 건지 공부를 더해야할 것 같았다.

 

 

[참고 자료]

 

[dreamhack] file-download-1 문제풀이

 

[dreamhack] file-download-1 문제풀이

[WEB] file-download-1 문제풀이 파일 다운로드 취약점이란 파일 다운로드 기능이 존재하는 웹에서 파일 다운로드 시 파일의 경로 및 파일명을 파라미터로 받아 처리하는 경우 이를 적절히 필터링 하

mokpo.tistory.com