웹 해킹보다는 리버싱에 가깝게 느껴졌던 문제였다.
일단 코드를 다운받고, 사이트에 들어가보자.
들어가면 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 이 되어야 한다.
일단, 위의 코드들을 분석해 보자.
org = FLAG[10:29]
: FLAG
문자열에서 인덱스 10부터 28까지의 부분 문자열을 추출하여 org
변수에 할당한다.org = int(org)
: 문자열 형태로 저장된 **org
**를 정수형으로 변환한다. 이를 통해 숫자로된 문자열을 정수로 변환하여 계산에 사용할 수 있게 된다.for i in range(0, 16):
: 0부터 15까지의 값을 반복하는 for 반복문으로 st
리스트의 각 요소를 계산하여 패턴을 생성하는데 사용된다.res = (org >> (4 * i)) & 0xf
: org
변수를 4비트씩 오른쪽으로 시프트한 후 0xf(1111)와 AND 연산을 수행하여 4비트의 숫자를 얻는다. 즉, **org
**를 4비트씩 나누어서 처리하는 것(간단하게 생각하자)if 0 < res < 12:
: **res
**가 0보다 크고 12보다 작은지 확인한다.