
테스트가 잡아내지 못한 취약점을 찾아보세요. ReGrade 데모가 CVE-2023-5968을 모델링하여 앱을 자체와 비교함으로써 비밀번호 해시 유출을 잡아냅니다.
ReGrade를 사용한 제로데이 발견에 대한 실습 데모입니다. 일반 테스트 스위트를 ReGrade에 연결하고, 작은 서비스에 대해 기록한 다음, 동일한 서비스의 두 번째 복사본에 대해 재생하고, Claude Code + ReGrade MCP 도구를 사용하여 비밀번호 해시 누출을 표면화합니다. 이는 어떤 테스트도 작성되지 않은 취약점입니다.
실제 버그를 모델링합니다: CVE-2023-5968, 협업 플랫폼의 사용자 이름 업데이트 엔드포인트가 bcrypt 비밀번호 해시를 포함한 전체 사용자 객체를 반환한 사례입니다. 2017년에 출시되어 7년 동안 테스트, 리뷰 및 감사를 통과했습니다. (Curtail의 설명)
핵심: v2는 없습니다. 앱을 자기 자신과 비교합니다. 새 인스턴스는 다른 bcrypt 솔트로 비밀번호를 해시하므로, 누출된 해시의 값이 두 복사본 간에 다릅니다 — 그리고 그 엔트로피가 ReGrade가 플래그를 지정하는 부분입니다. 취약점은 이미 출시한 코드에 잠재되어 있습니다; 버전 변경 없이도 찾을 수 있습니다.
regrade 센서를 설치한 다음 REGRADE_API_KEY (또는 ~/.regrade/key)를 설정하세요.claude plugin marketplace add https://app.regrade.curtail.com/downloads/latest/marketplace.json 그 다음 claude plugin install regrade@regrade --scope user, 그리고 한 번 연결하세요 (/mcp, 키와 동일한 계정으로 로그인).사용자와 채널이 있는 작은 "팀 채팅" API (app/store.py)입니다. Docker Compose는 두 개의 동일한 복사본을 실행합니다 — 동일한 이미지, 동일한 코드, 버전 플래그 없음:
http://localhost:8001) — 이에 대해 기록합니다.http://localhost:8002) — 이에 대해 재생합니다.하나의 엔드포인트에 심어진 결함이 있습니다:
| 엔드포인트 | 동작 |
|---|---|
GET /users/<id> | 정리됨(Sanitized) — 비밀번호를 반환하지 않음. 깨끗한 기준선. |
PATCH /users/<id> (rename) |
비밀번호는 부팅 시 bcrypt로 해시되므로 instance-a와 instance-b는 동일한 사용자에 대해 다른 해시를 보유합니다.
git clone https://github.com/Curtail-Inc/hello-ReGrade-security
cd hello-ReGrade-security
docker compose up -d --build
traffic/test_api.py는 일반적인 기능 테스트 스위트입니다: 로그인, 사용자 읽기, 사용자 이름 변경, 채널 목록 조회. CRUD 동작을 검증하며 보안 검증은 전혀 수행하지 않습니다 — password가 누출되는지 확인하지 않습니다. (왜 그럴까요? 아무도 버그가 존재한다는 것을 몰랐기 때문입니다.)
instance-a 앞에 센서 프록시를 시작합니다:
regrade proxy --target http://localhost:8001 --port 19870
다른 터미널에서 동일한 테스트 스위트를 실행하세요 — BASE_URL을 프록시로 지정하기만 하면 됩니다. 이것이 유일한 변경 사항입니다:
BASE_URL=http://localhost:19870 python -m pytest traffic/test_api.py
모든 테스트가 변경 없이 통과합니다. 프록시를 중지하고(Ctrl-C); 녹화가 업로드되며 Recording ID: <uuid>가 출력됩니다 — 기록해 두세요.
regrade replay --rec-id <RECORDING_ID> --target http://localhost:8002
양쪽 모두 동일한 코드 — 유일한 차이점은 새로운 인스턴스가 생성하는 값들입니다.
이 저장소를 Claude Code에서 열고 재생 과정을 안내해 달라고 요청하세요. 이 저장소의 CLAUDE.md에 따라 다음을 수행합니다:
summarize_deltas 실행 → 여러 델타: 로그인 token, 채널 created_at 타임스탬프, 그리고 그 사이에 조용히 $.password.$.token에 대한 create_id_mapping (드롭할 노이즈가 아닌 동적 ID),$.channels[*].created_at에 대한 create_filter_rule DROP (부팅별 타임스탬프),apply_profile_to_replay, 그 다음 query_deltas(unlabeled_only=true) — 델타가 하나만 남을 때까지 반복.$.password — 응답 본문의 bcrypt 해시입니다. 사전 지식 없이 보안 검증 없이 발견된 CVE급 누출.세션 토큰과 비밀번호 해시는 둘 다 두 실행 간에 다릅니다 — 둘 다 매번 변경되는 높은 엔트로피 문자열입니다. 하나는 매핑하는 합법적인 노이즈이고, 다른 하나는 침해입니다. "변경되었다"는 것만으로는 구분할 수 없습니다 — 무엇이 변경되었는지 살펴봐야 합니다. 모든 높은 엔트로피 필드를 노이즈로 필터링하면 취약점을 숨기게 됩니다.
이것이 교훈입니다: ReGrade는 기대치를 검증하지 않고 동작을 비교합니다 — 따라서 아무도 테스트를 작성할 생각을 하지 못한 버그를 표면화할 수 있습니다.
app/store.py는 하나의 파일입니다. GET 경로는 sanitize()를 호출합니다; PATCH 경로는 호출하는 것을 잊습니다. ReGrade로 찾은 후에 살펴보세요 — 요점은 ReGrade가 트래픽만으로, 앱을 자기 자신과 비교하여 이를 발견했다는 것입니다.
Apache-2.0.
버그 — bcrypt password 해시를 포함한 전체 사용자 객체를 반환. sanitize() 호출이 하나 누락됨, 정확히 CVE-2023-5968처럼. |