티스토리 뷰

반응형

이번 퀴즈는 안전하지 않은 직접 객체 참조(Insecure Direct Object Reference)에 대한 내용이다.

API에서 SSRF와 함께 상당히 많이 발생하는 취약점 중 하나이다.

 

가이드에 작성된 것처럼, ID(username) ‘tom’, Password ‘cat’ 입력하여 로그인을 시도해보면 첫 번째 퀴즈는 간단히 통과된다.

 

두 번째 퀴즈에서 View Profile을 보면 name, color, size 정보를 보여주는 것을 알 수 있다.

그리고 응답값에는 위 3개 정보 외에도 2개 정보가 더 보여지고 있으니, 어떤 값들이 보여지고 있는지 확인해보라고 한다.

 

 

해당 API의 응답값을 보면, name, color, size를 포함하여 총 5개의 값이 전달되고 있다.

role, userId Profile 내용에 포함되어 노출되지 않는 데이터이지만 정보가 노출되고 있다.

 

src/main/java/org/owasp/webgoat/lessons/idor/IDORViewOwnProfile.java

 

소스코드를 보면 Profile 보기에서 필요하지않는 userId, role을 포함하여 응답값으로 전달하고 있는 것을 알 수 있다. API로 데이터를 제공할 때는 반드시 필요한 정보만 제공되어야 한다. 특히 개인정보나 인증정보와 같은 중요정보가 불필요하게 노출될 경우, 정보노출 또는 인증도용 등에 사용될 있다

 

실무에서 이러한 경우를 정말 많이 본다.

특히 개발자들은 Controller/Service 등에서 데이터를 주고받기 위해서 사용하는 DTO를 응답값 전용으로 생성하지 않는 경우가 많고, 이를 통해 전달이 필요없는 데이터가 불필요하게 포함되어 정보가 노출되는 경우가 매우 많이 발생한다. 이러한 불필요한 정보의 노출을 방지하기 위해서는 API를 통해 제공되어야 하는 데이터는 반드시 전달해야만 하는 정보만으로 구성되어야 한다.

 

퀴즈에서는 Profile에서 보여지지 않는 2개의 Attributes 제출하라고 되어 있으니, role userId 작성하에 제출해보면 번째 퀴즈에 통과한 것을 있다.

 

 

다음 퀴즈에서는 명확히 어떤 부분을 이야기 하는 것인지 잘 이해가 되지 않는다.

우선 퀴즈 내용은 Profile 보는 부분이 RESTful API로 되어 있고, 누구의 Profile 정보를 조회하려고 하는 것인지 알려주기 위해서 내부적으로 어떤 Path가 사용되어야 하는 것인지를 물어보는 것 같다. 예측 컨데, Profile을 제공하는 별도 리소스 서버가 있고, 본 WebGoat는 Front-end 서비스라고 가정한 것으로 보인다. 그리고 WebGoat 별도의 리소스 서버에 유저 Profile 정보를 조회하기 위해 유저 식별자를 전달해야 한다는 것을 이야기 하고 싶은 같다.

 

그럼 우선 이전에 Profile 조회했던 패킷을 다시 확인해보면 API URL /WebGoat/IDOR/profile 이다.

Path 이야기 하는 것이고, 일반적인 RESTful API에서 데이터 조회방식을 사용한다고 가정해보면, /WebGoat/IDOR/profile/{userId} 를 전달해야 하는 것으로 보인다. 

( 일반적인 RESTful API에서 조회 조건을 Path Variable을 통해 작성하여 GET method로 요청하기 때문이다. )

앞서 확인했었던 Tom의 userId를 위 Path에 대입하여 전달해보니 이번 퀴즈도 통과하였다. (WebGoat/IDOR/profile/2342384)

 

마지막 퀴즈는 그 동안 보았던 패턴을 활용하여 타인의 Profile을 보거나 수정하는 것을 목표로 하는 것 같다.

아마도 View Profile 요청에 Brute Force 공격을 통해 타인(Buffalo) 정보를 확인하고, Edit 통해 타인의 Profile 수정해야 하는 것으로 보인다. 

 

Burp의 Intruder를 사용하여 userId를 1씩 증가해보면서 응답값들을 확인해보았더니, UserID 2342388 Profile가 있는 것을 알 수 있다. 이 정보의 주인은 Buffalo Bill 이라는 사람이군요.

 

그럼 Buffalo의 정보를 변경해본다. 그런데 Edit를 요청하는 퀴즈의 Button이 Profile 보기 버튼이다.

실제 패킷도 기존에 Profile 보기에 사용된 API 그대로 호출되고 있다.

 

일반적으로 API를 구성할 때, Path Name에 '어떠한 기능을 할 것이다'는 것을 다른 사람들이 인지할 수 있도록 네이밍을 한다.

그래서 우리는 이 패킷을 수정할 때는 2가지 방법이 있을 것이다.

  1. URL Path를 변경하여 수정을 나타내는 Path를 찾기 (일반 API)
  2. Method를 GET에서 PUT으로 변경 (RESTful API)

일반적인 RESTful API에서는 데이터 조회/수정/삭제에 따라서 각가 GET/POST, PUT, DELETE를 사용한다. 그리고 위 질문의 지문에서도 RESTful API를 언급했었기 때문에 2번째 방식을 사용해 본다.

 

그럼 수정하기 위한 Profile 정보를 전달해야 하는데, 문제에서는 Role과 Color를 변경하는 것을 퀴즈로 내는 것 같다.

Color Red 바꾸라고 명확하고, Role 현재 3보다 낮추라고 하니 1~2 사이의 값을 사용하면 될 것 같다. 

그런데 에러가 발생했다.

 

에러 내용을 보니 Content-Type이 잘못되어 Body 데이터를 제대로 읽지 못하는 것 같다. 

JSON 형태로 보내기 위해 Content-Typer과 파라미터를 JSON 형태로 변경하여 전송해본다.

Content-Type: application/json

{“role”: 3, “color”:“brown”, “size”:”large”, “name”:”Buffalo Bill”, “userId”:2342388}

 

 

이를 통해 마지막 퀴즈까지 모두 통과하였다.

 

 

소스코드를 확인해보면, PUT으로 처리하고 있는 것을 알 수 있고, 유저 식별자 정보를 Path Variable로 전달받고 있으며, Body로 전달한 Json 데이터를 업데이트 하는 것을 알 수 있었다.

src/main/java/org/owasp/webgoat/lessons/idor/IDOREditOtherProfile.java

 

이번 퀴즈에서 확인할 수 있는 취약점 및 요구사항은 다음과 같다.

 

일반적으로 Profile은 본인의 정보만 조회 및 수정이 가능해야 한다. 이를 위해 요청자가 접근하려는 정보 객체에 대한 권한이 있는지 검증해야 한다. 이 코드를 자세히 보면, 세션 데이터를 사용하여 수정하려는 객체의 소유자 정보를 검증하려고 한다. 그런데 조건절을 보면, Body로 전달한 객체내 userId와 세션 내 저장된 userId가 다른 경우에 Exception 처리하지 않고, 데이터를 업데이트 해주고 있다. Profile 정보를 업데이트 할 때에는 반드시 요청자가 접근하려는 객체에 대한 권한이 있는지 올바르게 검증되어야 한다. 

 

두 번째는 API Spec에서의 문제다. 여기에는 크게 2가지 문제가 있다.

첫 번째는 불필요한 정보가 제공되고 있다는 것이다. 실제로 이번 퀴즈에서도 불필요한 정보가 제공되었고, 이를 활용하여 타인의 role을 변경할 수 있었다. 두 번째는 Profile 정보를 조회하기 위한 API가 Client에게 직접 제공이 되는데, Profile 정보를 조회하거나 수정할 때 Profile 객체를 조회하기 위해 파라미터로 유저식별자를 사용한다는 것이다. Server-to-Server로 제공되는 API였다면, WebGoat의 서버측 코드에서 별도로 관리되고 있는 Resource 서버에서 데이터를 조회하기 위해 유저식별자를 전달해야 하는 것이라면 문제가 되지 않았겠으나, Client-to-Server API이였기 때문에 유저를 통해 타인의 정보를 조회 및 변겨에 활용될 수 있었다. 이를 해결하기 위해서 Client-to-Server API에서는 유저 식별자를 파라미터로 전달받지 않고, 세션 데이터와 같이 변조가 불가능한 값을 활용하여 요청자의 정보만을 조회할 수 있도록 해야 한다.

 

세 번째는 일반적으로 role과 같은 정보는 관리자 권한의 유저가 변경할 수 있어야 한다. 또는 별도의 백오피스 서비스에서 Role 변경에 대한 권한이 있는 유저에게만 해당 기능을 제공해야 한다. 만약 본인이 Role을 직접 수정을 요청할 수 있어야 한다면, 별도의 승인절차가 있어야 한다. 하지만 이 소스코드에서는 role이 전달되었을 때, 특별한 절차없이 전달 받은 값으로 업데이트하고 있다. Profile 정보는 주소와 같이 변경이 가능한 정보가 있고, 이름, ID(username) 등과 같이 일반적으로 변경이 불가능한 정보가 있기 때문에 이런 정보들을 구분해야 한다. 그리고 변경 요청을 처리할 때도, 파라미터 추가 등을 통해 변경이 불가능한 정보를 함께 전달하더라도 반드시 변경이 허용되는 정보만을 업데이트 해야 한다. 또한 Role의 변경은 매우 중요한 이벤트이므로 적절한 감사로그가 기록되어야 한다.

 

추가적으로 이야기 해보자면, CSRF 또는 세션탈취/재사용 공격 등을 통해 타인의 정보를 조회하거나 변경하는 것을 방지하기 위해 Profile 조회/변경 등의 기능은 사용자 재인증 과정이 필요하며, 해당 요청을 하면 사용자 재인증을 진행하고, 재인증 사용자에게만 해당 기능을 제공해야 한다.

 

 

 

 

반응형
댓글
반응형
최근에 올라온 글
Total
Today
Yesterday