https://dreamhack.io/wargame/challenges/1816
curling
Description simple api server
dreamhack.io
이번 드림핵 ctf에 출제되었던 웹 해킹 문제
타깃 사이트로 이동해도 api server만 구현되어 있기 때문에 404 not found가 뜬다. 바로 코드를 살펴보자.
code
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**]"
ALLOWED_HOSTS = ['dreamhack.io', 'tools.dreamhack.io']
@app.route("/api/v1/test/curl", methods=["POST"])
def admin():
url = request.form["url"].strip()
for host in ALLOWED_HOSTS: # 호스트가 allowed_hosts인 경우
if url.startswith('http://' + host):
break # for 문 탈출
return {'result': False, 'msg': 'Not Allowed host'}
if url.endswith('/test/internal'): # /api/v1/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"]) # get 메소드
def test(): # ip는 원격 주소 정보
ip = request.remote_addr
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/curl 로 들어오는 post 요청을 검증하는 2개의 로직이 있다.
1. ALLOWED_HOST 목록 확인
ALLOWED_HOSTS = ['dreamhack.io', 'tools.dreamhack.io'] 에 있는 도메인만 허용한다는 의미
2. url이 /test/internal로 끝날 경우 필터링
post 요청으로 들어오는 변수값 url이 /test/internal로 끝날 경우 필터링
만약 위의 검증 로직을 우회해서 /api/v1/test/internal 엔드포인트로 get 메소드로 요청을 보낼 수 있다면, 그리고 해당 요청을 보낼 때 로컬 주소로 요청을 보낼 수 있다면 flag를 알아낼 수 있을 것으로 보인다.
Exploit
※ user info(사용자 정보) url에 포함시키기
만약 @ 문자를 넣고 그 뒤에 다른 호스트를 넣으면 실제 요청은 @ 뒤의 호스트가 받게된다.
문자열의 시작 : 허용 도메인 / 실제 요청 : 다른 호스트
http://dreamhack.io@127.0.0.1:8000
이 경우, 실제 요청은 127.0.0.1:8000 에서 받게된다.
※ url에 더미값을 담은 쿼리변수 넣기
url이 정확히 /test/internal로 끝나면 필터링이 되는 로직
-> 이경우, url 끝부분에 쿼리변수를 넣고, 해당 변수에 더미값을 넣으면 /test/internal로 끝나지 않게 되면서 우회할 수 있다
ex> ?foo=bar 를 넣으면 사이트 요청에는 영향이 가지 않으면서 동시에 /test/internal로 끝나지 않게 되면서 우회할 수 있게 된다.
payload
curl -X POST -d "url=http://dreamhack.io@127.0.0.1:8000/api/v1/test/internal?foo=bar" http://host1.dreamhack.games:12024/api/v1/test/curl
post 요청을 보낼때 url 변수에 우선 ALLOWED_HOSTS를 우회하기 위한 http://dreamhack.io를를 넣고, 그 후 @를 넣어 실제 요청은 127.0.0.1:8000/api/v1/test/internal?foo=bar 가 받게 되고, /api/v1/test/internal은 foo를 쿼리 변수로 받지 않기 때문에 ?foo=bar는 아무 효력이 없어지게 되면서 실질적으로는 127.0.0.1:8000/api/v1/test/internal 에 대해 요청이 가게 된다.
위의 payload를 실행하면
플래그 출력
'보안 > Web hacking' 카테고리의 다른 글
[Dreamhack] Simple Note Manager (0) | 2025.02.11 |
---|---|
[Dreamhack] Base64 based (0) | 2025.02.10 |
[Dreamhack] Pearfect Markdown (0) | 2025.02.05 |
[Dreamhack] baby-jwt (0) | 2025.01.31 |
[Dreamhack] 삐리릭... 삐리리릭... (0) | 2025.01.30 |