amocafe

웹 해킹보다는 리버싱에 가깝게 느껴졌던 문제였다.

일단 코드를 다운받고, 사이트에 들어가보자.

Untitled

Untitled

들어가면 amo가 가장 좋아하는 메뉴는 1_c_3_c_0__ff_3e 라고 나온다.

코드를 살펴보자.

#!/usr/bin/env python3
from flask import Flask, request, render_template

app = Flask(__name__)

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

@app.route('/', methods=['GET', 'POST'])
def index():
    menu_str = ''
    org = FLAG[10:29]
    org = int(org)
    st = ['' for i in range(16)]

    for i in range (0, 16):
        res = (org >> (4 * i)) & 0xf
        if 0 < res < 12:
            if ~res & 0xf == 0x4:
                st[16-i-1] = '_'
            else:
                st[16-i-1] = str(res)
        else:
            st[16-i-1] = format(res, 'x')
    menu_str = menu_str.join(st)

    # POST
    if request.method == "POST":
        input_str =  request.form.get("menu_input", "")
        if input_str == str(org):
            return render_template('index.html', menu=menu_str, flag=FLAG)
        return render_template('index.html', menu=menu_str, flag='try again...')
    # GET
    return render_template('index.html', menu=menu_str)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000)

입력값이 org 변수에 들어있는 값과 맞을경우, flag를 출력한다.

그런데 amo가 가장 좋아하는 메뉴를 대신 입력해주면 플래그를 가져온다고 한다.

메뉴에 들어갈 값(menu_str) 1_c_3_c_0__ff_3e 라고 가정하고, 문제를 생각해보자.

최종적으로 이 코드들을 다 거쳐서

def index():
    menu_str = ''
    org = FLAG[10:29]
    org = int(org)
    st = ['' for i in range(16)]

    for i in range (0, 16):
        res = (org >> (4 * i)) & 0xf
        if 0 < res < 12:
            if ~res & 0xf == 0x4:
                st[16-i-1] = '_'
            else:
                st[16-i-1] = str(res)
        else:
            st[16-i-1] = format(res, 'x')
    menu_str = menu_str.join(st)

menu_str값이 1_c_3_c_0__ff_3e 이 되어야 한다.

일단, 위의 코드들을 분석해 보자.

  1. org = FLAG[10:29]: FLAG 문자열에서 인덱스 10부터 28까지의 부분 문자열을 추출하여 org 변수에 할당한다.
  2. org = int(org): 문자열 형태로 저장된 **org**를 정수형으로 변환한다. 이를 통해 숫자로된 문자열을 정수로 변환하여 계산에 사용할 수 있게 된다.
  3. for i in range(0, 16):: 0부터 15까지의 값을 반복하는 for 반복문으로 st 리스트의 각 요소를 계산하여 패턴을 생성하는데 사용된다.
  4. res = (org >> (4 * i)) & 0xf: org 변수를 4비트씩 오른쪽으로 시프트한 후 0xf(1111)와 AND 연산을 수행하여 4비트의 숫자를 얻는다. 즉, **org**를 4비트씩 나누어서 처리하는 것(간단하게 생각하자)
  5. if 0 < res < 12:: **res**가 0보다 크고 12보다 작은지 확인한다.