Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-33936 — ecdsa(PyPI)의 서비스 거부(DoS) 취약점 | Kitploit
도구/GitHubGitHub/0xmrma/cve-2026-33936
Vulnerability AnalysisCode AnalysisCryptographyPapers & ResearchLearning & Education
GitHub0xmrma/cve-2026-33936

CVE-2026-33936

ecdsa(PyPI)의 서비스 거부(DoS) 취약점

저장소 보기
14개월 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-33936

ecdsa(PyPI)의 서비스 거부(Denial of Service) 취약점

소개

저는 널리 사용되는 Python 암호화 라이브러리인 python-ecdsa에서 중간(Moderate) 심각도 취약점을 식별하고 책임 있는 공개(responsible disclosure)를 수행했습니다. 이 라이브러리는 지난 한 달간 4,780만 회 다운로드되었습니다.

저는 아주 구체적인 질문을 염두에 두고 python-ecdsa를 검토하던 중 이 문제를 발견했습니다:

잘못된 형식의 DER이 길이를 속이고 파서가 이를 지나치게 신뢰하면 어떤 일이 발생할까?

이 경우, 그 질문은 실제 버그로 이어졌습니다.

ecdsa.der의 DER 파싱 헬퍼들은 인코딩된 길이가 실제로 존재하는 바이트 수보다 더 많은 바이트를 주장하는 경우 잘린(truncated) 데이터를 수용했습니다. 그러한 잘못된 입력은 즉시 거부되었어야 합니다. 그러나 그 대신 파싱 로직 깊숙이 통과하여 키 파싱 중에 내부 IndexError를 결국 트리거할 수 있었습니다.

그 문제는 CVE-2026-33936이 되었습니다.

프로젝트: GitHub의 python-ecdsa
패키지: ecdsa (pip)
CVE: CVE-2026-33936

photo0

공격 체인

attacker-controlled malformed DER → truncated length accepted as valid → parser continues past trust boundary → SigningKey.from_der() reaches internal exception path → unexpected IndexError / application-level DoS risk


python-ecdsa가 하는 일

python-ecdsa는 타원 곡선 암호화를 위한 널리 사용되는 Python 라이브러리입니다.

무엇보다도 다음을 처리합니다:

  • 키 파싱
  • 키 직렬화
  • DER/ASN.1 디코딩
  • 서명 및 검증 워크플로우

즉, 이 라이브러리의 파싱 코드는 보안 경계(security boundary)에 직접적으로 위치합니다.

라이브러리가 외부에서 제공된 키 자료나 구조화된 바이너리 입력을 수용할 때마다, 정확성은 단순한 품질 문제가 아닙니다. 그것은 보안 속성입니다.

거부되어야 할 잘못된 입력이 수용되면, 다운스트림 코드는 유효하지 않은 상태 위에서 가정을 시작합니다. 바로 그 지점에서 버그는 "단순한 파싱 실수"가 아니라 취약점이 되기 시작합니다.


이 공격 표면을 조사할 가치가 있었던 이유

DER 파싱은 작은 검증 실수가 과도한 영향을 미칠 수 있는 영역 중 하나입니다.

버그 클래스는 단순합니다:

  • 길이 필드는 한 가지를 말합니다
  • 실제 버퍼는 더 짧은 내용을 포함합니다
  • 파서는 그 주장을 지나치게 신뢰합니다
  • 이후 코드는 존재해서는 안 되는 상태를 기반으로 동작합니다

이것은 정확히 보안 리뷰에서 확인할 가치가 있는 종류의 경계 실패입니다.

저는 여기서 이상한 암호화 동작을 찾고 있던 것이 아닙니다. 저는 구조화된 입력 처리에서의 신뢰 실패를 찾고 있었습니다.

그것이 바로 찾아야 할 올바른 곳이었습니다.


근본 원인

근본 문제는 잘못된 형식 또는 잘린 입력을 파싱할 때 DER 길이 필드 검증이 부적절했다는 것입니다.

구체적으로, ecdsa.der.remove_octet_string()은 선언된 DER 길이가 버퍼에 실제로 사용 가능한 바이트 수를 초과하는 입력을 수용했습니다.

그래서 다음과 같은 잘못된 DER을 거부하는 대신:

  • 선언된 길이: 4096
  • 실제 남은 바이트: 3

헬퍼는 이를 수용하고 잘린 내용을 마치 유효한 것처럼 반환했습니다.

그것만으로도 이미 버그입니다.

그러나 더 강력한 영향은 다운스트림에서 나타났습니다.

경계에서 잘못된 입력이 거부되지 않고 수용되었기 때문에, SigningKey.from_der()는 이후 내부 예외 경로에 도달하여 다음을 발생시킬 수 있었습니다:

root@kitploit:~
IndexError: index out of bounds on dimension 1

이것이 중요한 이유는 호출자가 잘못된 입력에서 기대하는 실패 유형이 아니기 때문입니다. 올바른 동작은 UnexpectedDER 또는 ValueError와 같은 깔끔한 파싱 거부입니다.

따라서 취약점은 단독으로 "IndexError가 존재한다"는 것이 아니었습니다.

실제 취약점은 다음과 같습니다:

  • 잘못된 형식의 DER 길이 필드가 올바르게 검증되지 않았고
  • 잘린 입력이 파싱 경계를 넘어섰으며
  • 그 결과 다운스트림 코드가 내부 예외 경로에 도달했습니다

이것은 하나의 버그 체인이며, 서로 관련 없는 두 가지 문제가 아닙니다.


단순한 파싱 위생 문제가 아니라 보안 문제인 이유

파서가 잘못된 입력을 거부하는 것은 외형적인 개선이 아닙니다. 그것은 보안 모델의 일부입니다.

여기서 중요한 구분은 입력이 유효하지 않았는지 여부가 아닙니다. 물론 유효하지 않았습니다.

중요한 구분은 라이브러리가 유효하지 않은 입력 앞에서 어떻게 동작했는가입니다.

다음 사이에는 실질적인 차이가 있습니다:

  • 경계에서 잘못된 형식의 DER을 깔끔하게 거부하는 것과
  • 잘못된 형식의 DER을 수용하고 더 깊이 진행한 다음 내부 예외로 충돌하는 것

전자는 견고한 동작입니다.

후자는 소프트웨어가 신뢰할 수 없는 DER을 파싱하면서 라이브러리 실패가 예상된 예외 유형 내에 머무를 것이라고 가정하는 경우 애플리케이션 수준의 위험을 만듭니다.

그것이 바로 이것이 단순한 파서 품질 버그가 아닌 취약점으로 적절히 분류된 이유입니다.


개념 증명(PoC)

저는 동일한 버그 체인의 서로 다른 두 부분을 입증했기 때문에 두 개의 PoC를 사용했습니다.

PoC 1: 잘린 DER이 수용됨

첫 번째 PoC는 remove_octet_string()이 선언된 길이가 사용 가능한 버퍼를 초과하는 잘린 DER을 수용한다는 것을 보여주었습니다.

이를 통해 핵심 검증 실패가 확립되었습니다:

  • 버퍼가 인코딩된 길이보다 짧았음
  • 헬퍼는 이를 거부했어야 함
  • 그러나 거부하지 않았음

PoC 2: 결정적 내부 예외 경로

두 번째 PoC는 더 중요한 다운스트림 영향을 보여주었습니다: 수정 전에는 SigningKey.from_der()에 제공된 잘못된 형식의 DER이 결정적으로 내부 IndexError를 트리거했습니다.

이를 통해 보안 관련 영향이 확립되었습니다:

  • 잘못된 입력이 경계를 넘어섰음
  • 파싱이 너무 깊이 진행되었음
  • 라이브러리 코드가 깔끔한 파싱 오류 대신 내부 예외를 발생시켰음

이것은 "파서가 이상한 바이트를 수용했다"보다 훨씬 강력한 결과입니다. 경계 실패와 실제 운영상의 결과를 모두 보여줍니다.


PoC를 이렇게 선택한 이유

첫 번째 PoC는 근본 원인을 입증합니다.

두 번째 PoC는 영향을 입증합니다.

이러한 구분이 중요합니다.

많은 보고서는 다음에서 멈춥니다:

"이 파서는 잘못된 형식의 데이터를 수용합니다."

그것은 유용하지만, 버그가 왜 중요한지 보여주기에는 항상 충분하지 않습니다.

이 경우, 더 강력한 보고서는 다음과 같았습니다:

  • 잘못된 형식의 DER이 부적절하게 수용됨
  • 그 수용은 자체적으로 완결되지 않음
  • 키 파싱에서 충돌성 내부 예외 경로로 전파될 수 있음

이것이 보안 스토리를 훨씬 더 명확하게 만듭니다.


수정 분석

수정은 최소한이면서도 정확했습니다.

패치는 remove_sequence()에서 이미 사용 중이던 동일한 누락된 안전 규칙을 추가했습니다:

선언된 길이는 사용 가능한 버퍼 내에 맞아야 합니다

해당 검사는 다음에 적용되었습니다:

  • remove_constructed()
  • remove_implicit()
  • remove_octet_string()

이러한 경계 검사가 추가되자, 잘못된 형식/잘린 DER은 즉시 다음과 같이 거부되었습니다:

root@kitploit:~
UnexpectedDER: Length longer than the provided buffer

그리고 이전에 IndexError를 트리거했던 PoC는 더 이상 내부 예외 경로에 도달하지 않았습니다. 파싱 중에 깔끔하게 실패했으며, 이는 처음부터 발생했어야 하는 바로 그 동작입니다.

이것은 파서 취약점에서 볼 수 있기를 바라는 종류의 수정입니다:

  • 좁은 범위
  • 명시적
  • 신뢰 경계에 직접적으로 연결
  • 추론하기 쉬움
  • 회귀 테스트로 강화

재설계 없음. 모호함 없음. 누락된 곳에 올바른 검증만 추가.


회귀 테스트

저는 또한 이 정확한 클래스의 잘못된 형식 DER이 계속 거부되도록 보장하기 위해 집중적인 회귀 테스트를 추가했습니다.

새 테스트는 다음에 대한 잘린 길이 거부를 다룹니다:

  • remove_octet_string
  • remove_constructed
  • remove_implicit

그것이 중요했던 이유는 버그가 하나의 이상한 런타임 경로에 관한 것이 아니었기 때문입니다. 그것은 관련된 DER 헬퍼들 전반에 걸쳐 일관되게 유지되어야 하는 검증 규칙에 관한 것이었습니다.

수정과 테스트가 추가된 후, 전체 테스트 스위트가 로컬에서 통과했습니다:

root@kitploit:~
python -m pytest -q
# 2018 passed, 5 skipped

이것은 실제 공개 작업에서 중요합니다. 경계를 고정하는 테스트가 함께 제공될 때 수정은 훨씬 더 강력합니다.


심각도 및 분류

이 문제는 합리적으로 중간(Moderate) 심각도로 분류되었습니다.

여기서 핵심 영향은 기밀성이나 무결성이 아닌 가용성/견고성입니다.

보안 권고의 분류는 다음과 같습니다:

  • CWE-20: 부적절한 입력 검증(Improper Input Validation)
  • CVSS: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

그것은 타당합니다.

주장은 잘못된 형식의 DER이 공격자에게 코드 실행을 허용한다는 것이 아닙니다. 주장은 잘못된 형식의 DER이 이 라이브러리를 사용하여 신뢰할 수 없는 DER 자료를 파싱하는 소프트웨어에서 예기치 않은 내부 예외를 트리거할 수 있다는 것입니다.

이것은 실제적이고 방어 가능한 DoS 방식의 파싱 버그입니다.


공개(Disclosure)

이 문제는 GitHub Security Advisories를 통해 비공개로 보고되었습니다.

보고서에는 다음이 포함되었습니다:

  • 검증 버그
  • 결정적 다운스트림 IndexError 재현 코드
  • 최소 패치
  • 회귀 테스트
  • 로컬 검증 결과

유지보수자는 문제를 검증하고 단위 테스트와 함께 수정이 이루어지도록 요청했으며, 조정된 수정은 GHSA 임시 비공개 포크 워크플로우를 통해 진행되었습니다.

CVE 처리 중에 GitHub는 권고 텍스트가 둘 이상의 취약점을 설명하는 것처럼 보였기 때문에 처음에 할당을 거부했습니다. 명확화는 간단했습니다:

이것은 단일 근본 원인(부적절한 DER 길이 검증)을 가진 단일 취약점이며, SigningKey.from_der()의 IndexError는 동일한 잘못된 입력 수용의 다운스트림 결과일 뿐 별도로 독립적으로 수정 가능한 문제가 아니라는 것입니다.

그 명확화로 충분했고, 문제에는 다음이 할당되었습니다:

CVE-2026-33936


이 버그가 실제로 주는 교훈

여기서의 교훈은 "DER은 까다롭다"가 아닙니다. 모두가 이미 DER이 까다롭다는 것을 알고 있습니다.

실제 교훈은 다음과 같습니다:

잘못된 형식의 구조화된 입력은 파서가 그것이 유효하지 않다는 것을 아는 정확한 지점에서 거부되어야 합니다.

그 경계를 놓치면, 이후 코드는 더 이상 신뢰할 수 없는 가정 위에서 동작하게 됩니다.

그것이 저수준 파싱 실수가 보안 문제가 되는 방식입니다.

이 버그는 또한 writeup(분석 보고서)과 triage(트라이지)에 관한 중요한 점을 강화합니다:

  • 근본 원인이 중요하다
  • 영향 경로가 중요하다
  • 그리고 둘을 깔끔하게 연결하는 것이 훨씬 더 중요하다

"잘못된 입력 수용"은 이야기의 시작이었습니다. "잘못된 입력이 수용된 후 키 파싱 중 내부 예외 경로로 전파됨"이 완전한 이야기였습니다.

그 구분은 사안을 명확하고 정확하게 설명하는 데 도움이 되었습니다.


핵심 요점

  • DER 파서는 보안 경계입니다
  • 잘못된 형식의 길이 필드는 실제 버퍼에 대해 검증되어야 합니다
  • 잘린 구조화된 입력의 수용은 이미 버그입니다
  • 다운스트림 파싱이 내부 예외 경로에 도달하면 더 강력한 취약점이 됩니다
  • 깔끔한 파싱 거부는 안전한 동작의 일부입니다
  • 최소한의 검증 수정과 회귀 테스트는 파서 버그 수정에서 정확히 원하는 것입니다

마무리

이 취약점은 이국적인 암호화에 관한 것이 아니었습니다. 그것은 파서가 잘못된 입력을 원래보다 더 오래 신뢰한 것에 관한 것이었습니다.

잘린 DER 길이 필드가 경계를 넘어섰고, 거부되었어야 했음에도 검증을 통과했으며, 결국 키 파싱에서 충돌성 동작을 일으켰습니다.

그것이 이 문제가 CVE-2026-33936이 된 이유입니다.

영향을 받은 헬퍼 파서들에서 적절한 DER 길이 경계 검사를 적용함으로써 수정되었습니다.

photo0
도구 다운로드