https://dreamhack.io/wargame/challenges/1816
curling
Descriptionsimple api server
dreamhack.io

일단 서버를 생성해서 들어가면 404가 뜬다.
from flask import Flask, request
from os import urandom
from subprocess import run, TimeoutExpired
app = Flask(__name__)
# 세션 보호를 위한 랜덤 비밀키 설정
app.secret_key = urandom(32)
# 플래그 로딩 시도, 없으면 기본값 사용
try:
FLAG = open("/flag", "r").read().strip()
except:
FLAG = "[**FLAG**]"
# curl 요청을 보낼 수 있는 허용된 호스트 목록
ALLOWED_HOSTS = ['dreamhack.io', 'tools.dreamhack.io']
@app.route("/api/v1/test/curl", methods=["POST"])
def admin():
# 클라이언트가 보낸 form 데이터에서 url 추출
url = request.form["url"].strip()
# 허용된 호스트로 시작하는 url인지 확인
for host in ALLOWED_HOSTS:
if url.startswith('http://' + host):
break
return {'result': False, 'msg': 'Not Allowed host'}
# 내부 접근이 불가능하도록 특정 엔드포인트 필터링
if url.endswith('/test/internal'):
return {'result': False, 'msg': 'Not Allowed endpoint'}
try:
response = run(
["curl", f"{url}"], capture_output=True, text=True, timeout=1
)
return {'result': True, 'msg': response.stdout}
except TimeoutExpired:
return {'result': False, 'msg': 'Timeout'}
# 내부에서만 접근 가능한 민감한 플래그 엔드포인트
@app.route('/api/v1/test/internal', methods=["GET"])
def test():
ip = request.remote_addr
# 요청자의 IP가 로컬이 아니면 거부
if not ip == '127.0.0.1':
return {'result': False, 'msg': 'Only local access is allowed'}
return {'result': True, 'msg': FLAG}
if __name__ == '__main__':
app.run(host='0.0.0.0', port='8000')
/api/v1/test/internal에 서버로부터 접근하도록 해서 FLAG를 얻는 것이 목표이다.
클라이언트에서 직접 접근은 안되기 때문에, 반드시 /curl을 통해 서버가 대신 접근하도록 해야한다.
SSRF(Server-Side Request Forgery)
서버측 위조 공격으로 서버가 다른 서버로 요청을 보내도록 조작하는 공격 기법이다.
서버가 사용자의 입력을 제대로 검증하지 않아 공격자가 원하는 주소로 서버가 대신 요청을 보내게 만드는 것이다.
for host in ALLOWED_HOSTS:
if url.startswith('http://' + host):
break
return {'result': False, 'msg': 'Not Allowed host'}
/api/v1/test/curl은 POST로 호출되며, 사용자가 보낸 url을 curl 명령어로 내부에서 실행하고 있다.
조건으로는 url이 http://dreamhack.io 또는 http://tools.dreamhack.io로 시작해야하고, /test/internal로 끝나면 안된다.
여기서 만약 url이 http://dreamhack.io@127.0.0.1:8000처럼 작성하게 된다면 startswitch는 통과된다.
그리고 실제 요청은 127.0.0.1:8000으로 가게 되며, SSRF 우회에서 흔하게 쓰이는 패턴이다.
curl -X POST -d "url=http://dreamhack.io@127.0.0.1:8000/api/v1/test/internal?dummy=1" http://host3.dreamhack.games:10479/api/v1/test/curl
post 요청의 form 데이터로 url 값을 전달하고 있는데, 서버 코드에서는 이 url을 받아 내부에서 curl 명령어로 실행한다.
Flask는 url path를 기준으로 라우팅하고, 쿼리 스트링은 무시하는 특징을 가진다.
http://127.0.0.1:8000/api/v1/test/internal?dummy=1 따라서 이 라우팅도 결국에는,
@app.route('/api/v1/test/internal') 실제 요청은 이 라우트로 가게 되는 것이므로 curl 실행으로 넘어간다.

'해킹 스터디' 카테고리의 다른 글
| [DreamHack] easy-login (2) | 2025.07.24 |
|---|---|
| [DreamHack] Small Counter (0) | 2025.07.23 |
| [DreamHack] Addition calculator (1) | 2025.07.23 |
| [DreamHack] Description (1) | 2025.07.09 |
| [DreamHack] baby-ai (0) | 2025.06.30 |
