포스트

GraphQL 실습(2) - Accidental exposure of private GraphQL fields (PortSwigger Academy)

GraphQL introspection과 IDOR을 이용해 관리자 계정 정보를 탈취하는 과정

GraphQL 실습(2) - Accidental exposure of private GraphQL fields (PortSwigger Academy)

Lab: Accidental exposure of private GraphQL fields

Lab Link: Accidental exposure of private GraphQL fields


핵심 포인트와 취약점 개념

이번 랩은 이전 Lab인 Accessing private GraphQL posts와 유사하게, GraphQL에서의 접근제어 문제를 다룬다.

  • Introspection을 통한 Schema 노출
  • IDOR을 통한 사용자 (관리자) 정보 조회
  • 민감 정보 필드 (username, password) 노출

우리의 목표는 GraphQL query를 조작하여 관리자 계정 정보(Credentials)를 획득하는 것이다.


공격 흐름

1. GraphQL 사용 확인 및 로그인 요청 분석

우선 My account 페이지에서 로그인한 뒤, 사이트를 탐색하며 Burp의 Site map을 채워준다.

이 과정에서 POST /graphql/v1 endpoint를 확인할 수 있었지만, 활용 가능한 query는 발견되지 않았다.
GraphQL은 단일 endpoint를 통해 다양한 데이터를 조회하는 구조이기 때문에, endpoint만으로는 내부 동작을 파악하기 어렵다.

따라서 Introspection 요청을 이용해 Schema를 직접 확인해보았다.

설명

Schema 요청 응답

Schema를 분석해보면 getUser라는 query를 확인할 수 있다. 이 query는 id를 인자로 받아 특정 사용자 정보를 반환한다.

이때 User이라는 이름의 Object를 반환하는 코드를 확인할 수 있다.

User 오브젝트의 구성 요소를 보기 위해 코드를 탐색 해보니 아래와 같이 발견할 수 있었다.

설명

User오브젝트는

  • Int id
  • String username
  • String password 를 반환한다.

이 구조는 전형적인 Direct Object Reference 형태로, 적절한 권한 검증이 없다면 다른 사용자의 정보도 조회할 수 있다. 즉, user id만 알 수 있다면 getUser query를 통해 다른 사용자의 정보도 직접 조회할 수 있는 구조다.


2. GraphQL Query 분석 및 Exploit 실행

반환된 응답에서 getUserUser오브젝트를 참조했을때 아래와 같은 Query를 만들 수 있다.

query($id: Int!) {
  getUser(id: $id) {
    id
    username
    password
  }
}

여기서 Int!getUser 필드중

"type": {
    "kind": "NON_NULL",
    "name": null,
    "ofType": {
        "kind": "SCALAR",
        "name": "Int",
        "ofType": null
        }
    }

kind: NON_NULL을 참조하면 알 수 있다. 뜻은 id는 필수 값이다 (Null 불가)라는 의미다.
즉, 해당 query는 반드시 id 값을 필요로 하며, ID 기반 조회 구조라는 점에서 IDOR 공격 가능성이 높다.

다른 방법으로는 Burp 에서 반환된 Response를 우클릭 → GraphQL → Save GraphQL queries to site map을 실행하면 자동으로 Site Map에 발견된 query를 추가해준다.

설명

Schema → Site Map 추가

설명

Site Map에 getUser 쿼리가 추가된 것을 확인

요청 조작을 위해 해당 Request를 Repeater로 옮겨주거나 위에 작성된 Query를 넣어준다.

설명

Variables 값을 "id":0으로 전송했을때 응답으로 "getUser":null을 반환하는걸 확인할 수 있다.

설명

요청은 제대로 들어갔으나 id값이 잘못 기입 된것 같아 "id":1로 바꿔서 전송 해줬다.

설명

Variables "id":1 요청

설명

응답 결과

별 다른 검증 없이 Response에 관리자의 Username과 Password를 반환하는것을 확인할 수 있다.

결과적으로 아래의 admin 계정을 입수하는데 성공했다.

1
2
"username": "administrator",
"password": "md1m2ifgu5heo2goe7ey"
설명

해당 계정으로 로그인 한 후, Admin Panel에 접속해서 user carlos의 계정을 삭제하면서 lab이 마무리 된다.


정리

이번 lab을 통해 다시 한 번 Introspection이 활성화된 환경에서는
공격자가 API 구조를 쉽게 파악할 수 있다는 점을 확인할 수 있었다.

또한 GraphQL에서는 필드 단위 접근제어가 반드시 필요하며,
단순히 endpoint 접근을 제한하는 것만으로는 충분하지 않다.

특히 password와 같은 민감 정보는 절대 직접 반환되지 않도록 설계해야 한다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.