Bypassif

mercure·2024년 7월 25일
0

Dreamhack

목록 보기
16/18

if문 우회


KEY값을 얻는 우회방법을 찾아 FLAG 탈취

코드분석

  • app.py
#!/usr/bin/env python3
import subprocess
from flask import Flask, request, render_template, redirect, url_for
import string
import os
import hashlib

app = Flask(__name__)

try:
    FLAG = open("./flag.txt", "r").read()
except:
    FLAG = "[**FLAG**]"

KEY = hashlib.md5(FLAG.encode()).hexdigest()
guest_key = hashlib.md5(b"guest").hexdigest()

# filtering
def filter_cmd(cmd):
    alphabet = list(string.ascii_lowercase)
    alphabet.extend([' '])
    num = '0123456789'
    alphabet.extend(num)
    command_list = ['flag','cat','chmod','head','tail','less','awk','more','grep']

    for c in command_list:
        if c in cmd:
            return True
    for c in cmd:
        if c not in alphabet:
            return True

@app.route('/', methods=['GET', 'POST'])
def index():
    # GET request
    return render_template('index.html')



@app.route('/flag', methods=['POST'])
def flag():
     # POST request
    if request.method == 'POST':
        key = request.form.get('key', '')
        cmd = request.form.get('cmd_input', '')
        if cmd == '' and key == KEY:
            return render_template('flag.html', txt=FLAG)
        elif cmd == '' and key == guest_key:
            return render_template('guest.html', txt=f"guest key: {guest_key}")
        if cmd != '' or key == KEY:
            if not filter_cmd(cmd):
                try:
                    output = subprocess.check_output(['/bin/sh', '-c', cmd], timeout=5)
                    return render_template('flag.html', txt=output.decode('utf-8'))
                except subprocess.TimeoutExpired:
                    return render_template('flag.html', txt=f'Timeout! Your key: {KEY}')
                except subprocess.CalledProcessError:
                    return render_template('flag.html', txt="Error!")
            return render_template('flag.html')
        else:
            return redirect('/')
    else: 
        return render_template('flag.html')


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000, debug=True)
  • /flag.txt의 flag값을 읽어서 md5 암호화를 통해 KEY변수에 저장

  • guest문자열을 md5 암호화를 통해 guest_key에 저장

  • 필터링 존재

    • 알파벳,숫자만 가능
    • 금지 명령어 ( flag,cat,chmod,head,tail,less,awk,more,grep)
  • key,cmd_input을 받아서 if문에 따라 결과 도출

취약점

  • IF 문
if cmd != '' or key == KEY:
            if not filter_cmd(cmd):
                try:
                    output = subprocess.check_output(['/bin/sh', '-c', cmd], timeout=5)
                    return render_template('flag.html', txt=output.decode('utf-8'))
                except subprocess.TimeoutExpired:
                    return render_template('flag.html', txt=f'Timeout! Your key: {KEY}')
                except subprocess.CalledProcessError:
                    return render_template('flag.html', txt="Error!")
            return render_template('flag.html')
        else:
            return redirect('/')

key값에 따라 FLAG값을 얻거나 guest로 진입하거나 이상한 값일 경우 redirect된다.
하지만 key값 입력 없이 위 if문에서 cmd 명령 전송이나, KEY값을 입력 둘중 하나만 만족하고 , 필터링에만 걸리지 않는다면 아래의 try문으로 진입할 수 있다.
try문에서는 timeout예외처리에서 KEY값을 얻을 수 있다. 따라서 try문에 진입후 timeout 조건 5초를 넘긴다면 KEY값을 얻을 수 있다.

웹상에서 직접적으로 cmd_input값을 전달할 수 없기 때문에 TRY문으로 먼저 진입하기 위해
Burp Suite를 통해 cmd_input값을 전달한다. 이때 timeout에 진입하기 위해서 cmd_input의 값은 sleep 6명령을 전송한다

위와 같이 전송한다면 Timeout! Your key: {KEY} 를 통해 KEY값을 얻을 수 있는데 처음 화면에서 KEY값을 입력하면 FLAG값을 얻을 수 있다.

profile
하루에 한걸음씩

0개의 댓글

관련 채용 정보