CTF 03

전수경·2023년 5월 4일
0

write-up

목록 보기
2/10

1. out of money(드림핵)


-접속해보면 로그인하라고 뜬다.

그냥 입력했더니 자산이 나온다.. 아까 문제 정보에서 돈이 없다는게 이 말인가보다.

산타 사설 거래소, 드림 유동성 풀 들어가보기


-산타 사설 거래소는 무담보로 대출이 가능하고 flag구매 혹은 코인의 종류를 교환할 수 있다.

-드림 유동성 풀에서는 담보, 예금, 대출이 가능하고 해당 내역들이 뜬다.

이제 코드를 살펴보자.

util.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
    # 만들어짐
    # 나만 이득 못봐!

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")
  • flag를 얻으려면 DHH가 1000이상이어야 하고, 대출한 DHH가 0원이어야 한다.

=>유동성 풀에서 DHD를 빌릴 수 있으니까 돈 교환하는 것을 이용해 DHD를 DHH로 돌리면 가능할 것 같다!!!


-DHD를 빌리려고 하니 담보가 없다길래 빌린 DHH를 DHC로 변환해서 담보로 보냈다.

-DHD를 한번에 많이씩 빌릴 수 없어서 나눠서 총 2000을 빌렸다.


-빌린 DHD를 이제 DHH 갚는데 사용해야 하니까 다시 산타거래소에서 DHD를 DHH로 바꾼다.

-계속 빚 먼저 갚으라고 난리다.. (앞서 말한 것처럼 DH_debt가 0이 되어야 한다.)도대체 돈을 어떻게 갚는걸까..? 빌리는 것밖에 없고 갚는 곳은 없는데..?


-그러던 중 음수를 이용하라는 문제 설명이 생각났고 -1000을 입력하니 '대출완료!'라고 뜨지만 빌린 돈이 갚아졌다!!

-이제 다시 DHD를 DHH로 변환하면 코드에서 원하는 것처럼 DHH가 1000이 되고 빌린 드핵코인는 0이 되어서 Flag 구매를 할 수 있다.

2. Basic_Forensics_1(드림핵)



-파일을 다운해 열어보면 귀여운 곰 이미지가 있다.

-이미지 파일 안에 Hidden 메시지가 숨겨 있으므로 Stegsolve를 열어본다.

메시지가 숨겨져 있으니 Data Extract를 이용해본다.

-bit를 어떻게 해야할 지는 모르겠어서 preview이용해서 계속 해보다가 모두 0으로 맞추니 문제에서 알려준 keyword를 찾을 수 있었고 그 앞에 flag가 있었다.
+그대로 복사하니 띄어쓰기가 있어서 계속 정답이 안 나왔다.. 띄어쓰기 주의하길!

3. cat(H4CKING GAME)


-CTF-d가 없어져서 새로운 포렌식 문제가 있는 사이트를 찾았다. 문제 정보는 별게 없다.. 고양이는 당연히 귀엽지..

-HxD에다가 파일을 넣어보았다..


-시그니처는 이상이 없는 것을 확인했고 푸터를 확인했는데 그 뒤로 데이터가 더 존재한다. (jpg의 footer는 FF D9이다.)
근데 Decoded text가 숫자로만 구성이 되어 있어서 파일 같지는 않으므로 따로 잘라내지 않고 text를 변환해보기로 했다.


-문자열 변환기 사이트에 해당 16진수를 넣어서 변환해보니 flag가 나왔다.(여러가지 인코딩 가능한데 ASCII이 젤 먼저 있었는데 바로 됐다. 근데 플래그에서는 강아지를 좋아한다고 한다..)

profile
Cyber Security

0개의 댓글