Dreamhack/Dreamhack Wargame (Challenge)

[79] IT 비전공자 [dreamhack]out of money문제 풀기

imaginefuture-1 2024. 11. 27. 07:58

 

돈...돈 창조하는 방법 저도 알려줘요...돈..돈이 늘 문제야 ㅠ

 

 

시가가 행사가격보다 오히려 떨어져서 행사하는 것이 오히려 손해인 경우를 out of the money 또는 underwater라고 함.

 

 

 

app.py 소스코드

 

from flask import Flask, session, redirect, url_for, request, render_template
from threading import Thread
from util import get_price, deposit, liquidate

app = Flask(__name__)
app.secret_key = "[REDACTED]"

@app.route("/", methods=['GET', 'POST'])
def main():
    if request.method == 'POST' and request.form['name'] != "":
        session['name'] = request.form['name']

        session['DHH'] = 0.0
        session['DHC'] = 0.0
        session['DHD'] = 0.0

        session['debt_DHH'] = 0.0

        session['col_DHC'] = 0.0
        session['depo_DHC'] = 0.0
        session['depo_DHD'] = 0.0
        session['debt_DHD'] = 0.0

        return redirect(url_for('main'))

    if 'name' in session:
        return render_template("lobby.html", session=session)
    else:
        return render_template("login.html")

@app.route("/santa", methods=['GET', 'POST'])
def santa():
    return render_template("santa.html", session=session, message="")

@app.route("/santa/lend", methods=['POST'])
def santa_lend():
    value = float(request.form['value'])

    if session['debt_DHH'] + value >= 10000.0:
        return render_template("santa.html", session=session, message="그만 빌려욧!")
    if session['DHH'] + value < 0.0:
        return render_template("santa.html", session=session, message="더 갚으시게요...?")

    session['DHH'] += value
    session['debt_DHH'] += value
    return render_template("santa.html", session=session, message="대출완료!")

@app.route("/santa/flag", methods=['GET'])
def santa_flag():
    if session['DHH'] >= 1000.0:
        if session['debt_DHH'] == 0.0:
            return render_template("flag.html")
        else:
            return render_template("santa.html", session=session, message="빚을 먼저 값으세욧!")
    return render_template("santa.html", session=session, message="드핵코인이 없어욧!")

@app.route("/santa/change", methods=['POST'])
def santa_change():
    frm = int(request.form['from'])
    to = int(request.form['to'])
    value = float(request.form['value'])

    if value < 0:
        return render_template("santa.html", session=session, message="어디서 음수만큼 바꾸려고!")

    tbl = ['DHH', 'DHC', 'DHD']
    if frm in [0, 1, 2] and to in [0, 1, 2]:
        frm = tbl[frm]
        to = tbl[to]

        if session[frm] < value:
            return render_template("santa.html", session=session, message="가지고 있는 코인이 그만큼 없어욧!")

        if frm != to:
            frm_price = get_price(frm)
            to_price = get_price(to)

            to_balance = value * frm_price / to_price

            session[frm] -= value
            session[to] += to_balance
        return render_template("santa.html", session=session, message="교환 완료!")
    return render_template("santa.html", session=session, message="다른건 교환 못합니다!")

@app.route("/dream", methods=['GET'])
def dream():
    return render_template("dream.html", session=session, message="")

@app.route("/dream/collateral", methods=['POST'])
def dream_col():
    value = float(request.form['value'])

    if value < 0:
        if session['debt_DHD'] == 0.0:
            session['DHC'] += session['col_DHC']
            session['col_DHC'] = 0.0
            return render_template("dream.html", session=session, message="담보 반환 완료!")
        else:
            return render_template("dream.html", session=session, message="빚을 먼저 값으세욧!")
    if session['DHC'] - value < 0.0:
        return render_template("dream.html", session=session, message="가지고 있는 드냥코인이 부족합니다!")

    session['DHC'] -= value
    session['col_DHC'] += value
    return render_template("dream.html", session=session, message="담보 확인!")

@app.route("/dream/deposit", methods=['POST'])
def dream_deposit():
    type = int(request.form['type'])
    value = float(request.form['value'])

    if type not in [0, 1]:
        return render_template("dream.html", session=session, message="드핵코인, 드냥코인만 예금할 수 있습니다!")

    tbl = ['DHC', 'DHD']
    type = tbl[type]
    if session[type] - value < 0:
        return render_template("dream.html", session=session, message="가지고 있는 코인이 부족합니다!")
    if session["depo_" + type] + value < 0:
        return render_template("dream.html", session=session, message="에금한 코인보다 더 뺄수는 없습니다!")
    session[type] -= value
    session["depo_" + type] += value
    deposit(type, value)
    return render_template("dream.html", session=session, message="예금완료")

@app.route("/dream/lend", methods=['POST'])
def dream_loan():
    value = float(request.form['value'])

    dhc_price = get_price('DHC')
    dhd_price = get_price('DHD')

    max_lend = session['col_DHC'] * dhc_price / dhd_price * 0.8

    print(max_lend)

    if session['DHD'] + value < 0.0:
        return render_template("dream.html", session=session, message="더 갚으시게요...?")
    if max_lend < value:
        return render_template("dream.html", session=session, message="그만큼 빌리기에는 담보가 부족합니다!")

    session['DHD'] += value
    session['debt_DHD'] += value

    return render_template("dream.html", session=session, message="대출 완료!")

@app.route("/logout")
def logout():
    session.pop('name', None)
    return redirect(url_for('main'))

import time
def loop_liquid():
    while True:
        time.sleep(2)
        liquidate()

if __name__ == '__main__':
    t1 = Thread(target = loop_liquid, daemon=True)
    t1.start()
    app.run(host="0.0.0.0")

 

 

untl.py 소스코드

dhc_balance = 1000.0
dhd_balance = 1000.0

def get_price(name):
    if name == "DHH":
        return 1.0
    if name == "DHC":
        return 1.0
    if name == "DHD":
        return dhc_balance * get_price("DHC") / dhd_balance

def deposit(name, value):
    global dhc_balance, dhd_balance
    if name == "DHC":
        dhc_balance += value
    if name == "DHD":
        dhd_balance += value

def liquidate():
    pass
    # 차익거래 후, dhc_balance * dhc_price == dhd_balance * dhd_price
    # 만들어짐
    # 나만 이득 못봐!

 

 

꽤나 템플릿보면 복잡해보이지만 WEB에 실제로 들어가서 이것저것 작동해보면 아 바로 이해가간다

 

 

이런 사설거래소에서 돈 거래 하면 인생 망한다

 

우리가 해야할껀 플래그를 찾아야하는데, 어떤 조건에서 플래그를 찾아야하는지 힌트는 음수의 값이 허용된다면 그 행동의 반대를 하게된다.

 

뭔가 개발자 도구이용해서 음수 허용하게 코드 수정 후 엄청난 양의 코인을 창조(?)하면 플래그가 나오지않을까 싶다

는 소스코드에 답이있는댑쇼

 

@app.route("/santa/flag", methods=['GET'])
def santa_flag():
    if session['DHH'] >= 1000.0:
        if session['debt_DHH'] == 0.0:
            return render_template("flag.html")

 

DHH>= 1000이고 빌린 DHH가 0이면 flag를 획득 가능하다

 

빚을 갚을때 음수의 값을 써주면 되갚기 가능하다

 

 

if session['DHD'] + value < 0.0:
        return render_template("dream.html", session=session, message="더 갚으시게요...?")
    if max_lend < value:
        return render_template("dream.html", session=session, message="그만큼 빌리기에는 담보가 부족합니다!")

    session['DHD'] += value
    session['debt_DHD'] += value

    return render_template("dream.html", session=session, message="대출 완료!")
DHD코인은 현재 내가 가진 담보의 max_lend만큼 빌릴 수 있다. 하지만 한 번에 빌릴 수 있는 DHD코인만 지정해 두고 최대량은 정해두지 않았다 해당 취약점을 이용하여 DHD코인을 여러 번 빌릴 경우 담보금 보다 더 큰 코인을 빌릴 수 있다.

출처ㅣhttps://st-together.tistory.com

 

이 말은 예를 들어) 친구한테 만원 담보로 맡기고 5000원 빌릴 수 있는데 그걸 무한대로 빌릴 수 있다

 

아니 이거 진짜 무에서 유로 창조가능한건데

 

만원 담보로 5000원씩 20번 빌려서 100만원으로 빌리는...

이런 은행 없나?

 

따서 갚으면돼 실환데

 

자 돈 무한 창조하러 가볼게여~

 

아까 이것저것 만지나다 1020이 빌려졌다 좋아 1020빌릴게여~

 

그걸 담보로 넣는다 10DHD는 무시해달라, 이것저것 만지다가 들어갔다

 

1010 DHC 담보로 500DHD가 빌려진다 보통 담보로 이정도 빌리면 끝이다, 더 우찌빌리냐, 담보보다 높은걸 어떻게 빌리냐 하지만 여기 사설 거래소는 가능하다
500X8번 빌렸다. 1010 담보로 4000 드멍코인을 빌렸다. 이게 창조아닙니까
드멍코인을 드핵코인으로 하나씩 교환한다 캬캬캬캬캬
그렇게 FLAG 조건에 맞춘다 그리고 FLAG구매를 누른다
짜자잔~