[WEB] vuln-C&C

해당 서버는 공격자가 C&C 서버로 사용중인 서버이다. 해당 서버의 취약점을 식별하여라 파일 다운로드 경로 예: /download?filename=main.css

문제 설명에서 파일 다운로드 경로에 예시를 들어주는것을 보아 LFI(Local File Injection) 취약점을 예상할 수 있습니다. 실제로 저 경로로 들어가보니 main.css 파일 다운이 가능했습니다.

/etc/passwd 로 접근하여 확인해보니 LFI가 가능합니다.

image.png

/proc/self/cmdline 로 접근하여 현재 실행중인 프로세스 파일 명을 확인합니다.

image.png

app.py 가 실행중임을 확인할 수 있습니다.

../app.py 로 접근해보겠습니다.

from flask import Flask, render_template, abort, request, abort, send_file
from pathlib import Path
import os
import datetime as dt

app = Flask(__name__)

app.secret_key = os.urandom(128).hex()

def getReadableByteSize(num) -> str:
    for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']:
        if abs(num) < 1024.0:
            if num == int(num):
                return "%d%s" % (int(num), unit) 
            else:
                return "%3.1f%s" % (num, unit)
        num /= 1024.0
    
    if num == int(num):
        return "%d%s" % (int(num), unit) 
    else:
        return "%.1f%s" % (num, 'Y')
    
def getTimeStampString(tSec: float) -> str:
    tObj = dt.datetime.fromtimestamp(tSec)
    tStr = dt.datetime.strftime(tObj, '%Y-%m-%d %M:%S')
    return tStr

@app.route('/')
def index():
    return render_template("index.html")

@app.route('/', defaults={'reqPath': ''})
@app.route('/<path:reqPath>')
def directory_listing(reqPath):
    FolderPath = app.root_path
    absPath = os.path.join(FolderPath, reqPath)
    if not os.path.exists(absPath):
        return abort(404)

    def fObjFromScan(x):
        fileStat = x.stat()
        return {'name': x.name,
                'relPath': os.path.relpath(x.path, FolderPath).replace("\\\\", "/"),
                'mTime': getTimeStampString(fileStat.st_mtime),
                'size': getReadableByteSize(fileStat.st_size),
                'isdir': os.path.isdir(x.path),
                }
    if os.path.isdir(absPath):
        fileObjs = [fObjFromScan(x) for x in os.scandir(absPath)]
    else:
        abort(404)

    parentFolderPath = os.path.relpath(
        Path(absPath).parents[0], FolderPath).replace("\\\\", "/")
    
    return render_template('list.html', data={'files': fileObjs, 'parentFolder': parentFolderPath, 'req_path': request.path})

@app.route('/download', methods=['GET'])
def download():
    filename = request.args.get('filename')

    if not filename:
        abort(400)

    file_path = os.path.join('static', filename)
    
    if not os.path.isfile(file_path):
        return abort(404)
    
    return send_file(file_path, as_attachment=True)
    
if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000)

디렉토리 명으로 접속 시 Directory listing 하는것을 확인할 수 있습니다.

root 폴더에 들어가니 flag-c368132241ec56040bdd.zip 라는 파일이 있습니다.

해당 파일을 내려받고 zip 압축해제 하여 플래그를 확인할 수 있습니다.

image.png

whitehat2024{1330E4DE5DD8DF533D8D5C5388420249E71135B7}