
외부에서 관찰 가능한 데이터만 사용하여 조직이 구독 중인 SaaS 서비스를 찾아냅니다. 섀도 IT 탐색을 위해 만들어졌습니다.
▄▄▓▓▓▓▓▓▓▓▓▄▄
▄▓▓▒▒▒▒▒▒▒▒▒▒▒▓▓▄ Yowie · tracking down the SaaS nobody told you about
▓▓▒▒░░░░░░░░░░░▒▒▓▓
▓▒░░ ● ● ░▒▓ Domain acme.com.au
▓▒░░ ▼ ░▒▓ Candidates acme, acmecorp
▓▓▒░░ ╰───╯ ░▒▓▓
▀▓▓▒▒░░░░░░░░░▒▒▓▓▀
▀▀▓▓▓▓▓▓▓▓▓▓▓▀▀
조직이 구독하는 SaaS 서비스를 외부에서 관찰 가능한 데이터만 사용하여 찾아냅니다. 섀도 IT 탐지를 위해 만들어졌습니다. 찾아야 할 가치가 있는 서비스는 아무도 당신에게 알려주지 않은 서비스입니다.
호주 부시 크립티드의 이름을 따서 명명되었습니다. 모두가 존재하지 않는다고 주장하는 무언가를 사냥하고 있기 때문입니다.

9개의 탐지기에 걸쳐 593개 벤더를 커버하는 786개의 시그니처, 그리고 확인을 기다리는 109개의 대기 항목이 있습니다. 발견 사항은 등급이 매겨지며, 각 발견 사항에는 이를 생성한 레코드 또는 응답이 함께 제공됩니다.
go build -o yowie ./cmd/yowie
Go 1.22 이상. 서명 팩은 바이너리에 내장되어 있으므로 단일 파일만 배포하면 됩니다.
yowie [flags] <domain> [candidate ...]
도메인은 조직의 루트 도메인입니다. 후보는 벤더 테넌트의 이름이 될 수 있는 짧은 문자열입니다 — 상호, 약어, 인수로 이어져 내려온 옛 브랜드 등입니다. 가능한 한 많이 제공하세요. 각 후보는 테넌트를 찾을 수 있는 또 하나의 기회입니다. 아무것도 제공하지 않으면 도메인의 첫 번째 레이블이 사용됩니다.
yowie acme.com.au acme acmecorp acmegroup
yowie -format html -o report.html acme.com.au acme
yowie -format json acme.com.au | jq '.findings[] | select(.confidence=="high")'
yowie -only dns,spf,dmarc -compact acme.com.au
yowie -signatures ./signatures -validate
| 탐지기 | 신호 |
|---|---|
dns | TXT 검증 토큰, CNAME, MX 및 NS 레코드 |
vanity | 조직 이름을 딴 벤더 호스팅 테넌트 (acme.zendesk.com) |
http | DNS 흔적이 없는 서비스에 대한 애플리케이션 계층 지문 |
spf | 중첩된 include와 redirect를 따라가는 전체 SPF include 그래프 |
dmarc | DMARC 집계/포렌식 보고서 수신지 |
bimi | BIMI 로고 및 Verified Mark Certificate 호스팅 |
mta-sts | MTA-STS 정책 내용 |
tenant | Microsoft 테넌트 ID, 페더레이션 ID 공급자, 형제 도메인 |
ct | Certificate Transparency 로그에서 가져온 하위 도메인, 확인 및 귀속됨 |
-only 또는 -skip으로 선택합니다. 예: 빠른 DNS 전용 패스에는 -skip ct,http.
마지막 두 가지는 시그니처 목록으로는 찾을 수 없는 것을 찾아내므로 따로 설명할 가치가 있습니다.
**tenant**는 Microsoft의 인증 없는 엔드포인트에 해당 도메인이 누구에게 속하는지 묻습니다. Autodiscover의 페더레이션 정보는 동일한 테넌트에 연결된 모든 도메인을 반환하며, 이를 통해 사업부, 인수 기업, 폐기된 브랜드가 흔히 드러납니다. 각각은 스캔할 가치가 있는 또 다른 도메인입니다.
**ct**는 발견 모델을 뒤집습니다. 다른 모든 검사는 고정된 목록에 대해 "이 조직이 벤더 X를 사용하는가?"를 묻기 때문에 누군가 이미 시그니처를 작성한 벤더만 찾을 수 있습니다. CT는 "이 조직이 실제로 하위 도메인을 어디로 향하게 했는가?"를 묻습니다. 제품에 가입하고 support.acme.com을 연결한 팀은 인증서를 발급받게 되며, 그 인증서는 공개적이고 영구적입니다. 어떤 시그니처와도 일치하지 않는 대상은 리드로 보고되며, 이는 찾아야 할지 몰랐던 것을 찾는 방법입니다.
발견 항목은 등급이 매겨지며, 등급이 핵심입니다:
acme.blogspot.com이 당신의 acme가 아닐 수 있습니다.두 개의 독립적인 탐지기가 동일한 벤더에 대해 일치하면 Probable 발견 항목이 Confirmed로 승격됩니다. 모든 발견 항목은 이를 촉발한 정확한 레코드나 응답을 함께 담고 있어, 도구를 다시 실행하지 않고도 보고서를 방어할 수 있습니다.
승격에는 예외가 하나 있으며, 이는 "이 테넌트가 존재한다"와 "이 테넌트가 당신의 것이다"의 차이입니다 — 정확성 아래의 네임스페이스 관련 설명을 참조하세요.
신호만 원한다면 -no-unknown이 귀속되지 않은 리드를 제거합니다.
-format cli(기본값), json, jsonl, csv, html. 파일에 쓰려면 -o를 사용합니다. HTML 보고서는 자체 포함되어 있어 — 외부 자산이 없으므로 — 이메일로 보내거나 공유 드라이브에 올려도 그대로 유지됩니다.
진행 상황은 stderr로, 결과는 stdout으로 출력되므로 yowie -format json acme.com > out.json은 여전히 실시간 진행 표시줄을 보여줍니다.
시그니처는 signatures/*.yaml에 있습니다. 바이너리에 내장되어 있으며, -signatures <dir> 또는 YOWIE_SIGNATURES=<dir>을 사용하면 디스크에서 대신 로드하므로 재빌드 없이 반복 작업할 수 있습니다.
version: 1
pack: dns-txt
description: "Domain-ownership verification tokens published as TXT records."
defaults:
confidence: high
signatures:
- id: txt-1password
vendor: "1Password"
category: "Identity & Secrets"
type: txt
query: "{domain}"
match:
contains: "1password-site-verification"
{domain}은 루트 도메인으로, {candidate}는 각 후보 문자열로 확장됩니다.
{candidate}를 참조하는 시그니처는 후보마다 한 번씩 평가됩니다.
| 유형 | 일치 기준 | 비고 |
|---|---|---|
txt, cname, mx, ns | query의 레코드에 대한 match.contains | 대소문자 구분 없음 |
vanity_a, vanity_cname | 기준선 비교; match 블록 없음 | query에 {candidate}가 포함되어야 함 |
http | match.present, match.absent, 또는 match.status 단독 | 아래 상태 처리 참조 |
spf_include | 확인된 SPF include 그래프에 대한 match.contains | |
dmarc_rua | DMARC 보고서 수신 대상에 대한 match.contains | |
cname_target | query는 호스팅 접미사만 해당 | ct로 발견된 호스트에 적용됨; *는 하나의 레이블과 일치 |
disabled: true는 시그니처를 비활성 상태로 보관하면서 그 뒤의 연구 내용을 잃지 않게 합니다.
notes:는 분석가의 안내 사항을 보고서까지 전달합니다.
편집 후 yowie -validate를 실행하세요. 검증은 엄격합니다 — 알 수 없는 키는
조용히 무시되는 것이 아니라 오류입니다 — 또한 팩은 go test로도 검사되므로,
오타 하나가 향후 모든 스캔에서 조용히 커버리지를 잃게 만들 수 없습니다.
| 팩 | 내용 |
|---|---|
dns-txt, dns-cname, dns-mx | 검증 토큰 및 위임된 호스트명. 활성. |
email-spf, email-dmarc | 발신자 및 DMARC 처리기. 활성. |
vanity-tenants, http-endpoints | 테넌트 호스트명 및 앱 지문. 활성. |
cname-targets | CT로 발견된 서브도메인용 호스팅 접미사. 활성. |
ai-services | AI 및 LLM 플랫폼. 보류됨. |
file-transfer | 관리형 파일 전송 — MOVEit, GoAnywhere, Egnyte. 보류됨. |
finance-procurement | 재무, 경비, 급여, 조달. 보류됨. |
security-grc | 보안 도구 및 컴플라이언스 자동화. 보류됨. |
graveyard | 미검증 항목 및 운영자를 식별할 수 없는 플랫폼. 보류됨. |
다섯 개의 팩은 전부 비활성 상태로 제공됩니다. 구조적으로 완전하고 검증을 통과하지만, 일치 기준이 실제 테넌트에 대해 확인된 적이 없으므로 스캔 중에 평가되지 않습니다.
이는 의도된 것입니다. contains 값이 잘못된 시그니처는 절대 발동하지도, 오류를 내지도 않습니다 — 단지 실제로는 커버되지 않는 벤더를 커버되는 것처럼 보이게 할 뿐입니다. 이를 비활성 상태로 제공함으로써 수치를 부풀리지 않으면서 연구 내용을 저장소에 유지합니다.
지금까지 다섯 개가 승격되었으며, 나머지를 신뢰하기 전에 그 기록을 알아둘 가치가 있습니다: 두 개는 작성된 그대로 정확했고, 하나는 도메인이 잘못되었으며, 두 개는 도메인은 맞았지만 채널이 틀렸습니다 — 벤더가 항목이 예측한 고객별 호스트명이 아니라 SPF include로 나타났습니다. 나머지 보류 항목은 잠재적 커버리지가 아니라 연구 노트로 취급하세요.
-validate는 백로그를 팩별로 그룹화하여 출력합니다:
$ ./yowie -validate
786 signatures across 13 packs, covering 593 vendors
...
109 signature(s) parked behind `disabled: true`, awaiting confirmation against a live tenant:
ai-services.yaml (24)
txt-fireflies-ai Fireflies.ai
...
프로모션하려면:
dig +short TXT known-customer.com | grep -i <vendor> # token signatures
dig +short A acme.egnyte.com # vanity signatures
dig +short A $(openssl rand -hex 6).egnyte.com # ...and its baseline
베니티 테넌트는 무작위 레이블과 다르게 응답해야 합니다.disabled: true를 삭제한 뒤, 정직한 신뢰도를 설정하세요.notes:를 다시 작성하여 확인한 내용을 기술하세요../yowie -signatures ./signatures -validate어떤 메커니즘이 작동하지 않는 것으로 밝혀지면, 비활성화된 상태로 두고
부정적인 결과를 notes:에 기록하세요. 이는 작동하는 시그니처만큼이나
가치가 있습니다 — 다음 사람이 한나절을 들여 그것을 다시 발견하는 일을
막아주기 때문입니다. security-grc에는 이미 이러한 사례가 여러 개 있으며,
CrowdStrike, Wiz, Tenable에 베니티 시그니처가 없는 이유를 설명합니다:
이들은 모든 고객을 공유 콘솔에 배치하므로, 고객별로 탐지할 것이 없습니다.
이 도구는 자체적인 백로그를 생성합니다. 귀속되지 않은 발신자와 호스트는 바로 시그니처를 작성할 가치가 있는 벤더이며, 여러 스캔에 걸쳐 빈도순으로 스스로 순위를 매깁니다:
for d in $(cat domains.txt); do ./yowie -format json -quiet "$d"; done \
| jq -r '.findings[] | select(.category|startswith("Unidentified")) | .vendor' \
| sort | uniq -c | sort -rn | head -40
서로 무관한 조직들에 걸쳐 반복되는 것은 실제입니다. 이는 또한 무료로 확인된 라이브 샘플을 제공합니다 — SPF 및 DMARC 증거에는 실제 발신자 호스트명이 포함되어 있으며, 이것이 바로 파킹된 항목에 필요한 것입니다.
많은 벤더가 테넌트 존을 와일드카드로 처리하므로 "해석된다"는 것만으로는 아무것도 증명하지 못합니다. 각 템플릿은 먼저 두 개의 무작위 레이블로 프로브되어 존재하지 않는 테넌트에 대해 벤더가 어떻게 응답하는지 학습합니다. 후보는 그 응답이 기준선과 다를 때만 카운트됩니다. 두 기준선이 서로 일치하지 않으면 — 지오-DNS, 라운드 로빈 — 비교는 무의미하므로 시그니처는 추측하지 않고 경고와 함께 건너뜁니다.
NXDOMAIN 기준선은 Confirmed 발견을 산출합니다. 다른 응답을 보이는 와일드카드 기준선은 시그니처 자체의 신뢰도와 그것이 더 약한 이유를 설명하는 노트를 산출합니다.