Step 314. 버그바운티 시작 — 제도 이해와 첫 타깃 선정

Step 314. 버그바운티 시작 — 제도 이해와 첫 타깃 선정

Level 4 — 버그바운티 | 난이도 ★★☆☆☆ | 예상 소요 시간 2시간

전제: Step 171(OSINT 심화)의 공격 표면 개념, Level 2~3의 웹 취약점 기초를 마쳤다. 파이썬 기본 문법을 읽을 수 있다.

  • 준비물: 파이썬 3, 메모장(작전 명세서용). 실제 플랫폼 가입은 선택이며, 이 챕터의 플랫폼 화면은 전부 예시입니다.
  • ⚠️ 이 챕터의 실습은 내 랩·합법 플랫폼 전용입니다. 허가 없는 시스템에 적용하면 범죄입니다.
  • 주의: 버그바운티는 프로그램이 명시한 스코프(scope)와 규칙 안에서만 합법입니다. 스코프 밖 단 한 번의 요청도 불법이 될 수 있습니다. 이 경계가 이 Level 전체의 대전제입니다.

지금까지 배운 공격 기술은 전부 랩 안에서만 쓸 수 있었습니다. 오늘부터는 다릅니다 — 세상에는 "우리 서비스를 공격해 보고, 찾으면 돈을 드립니다"라고 공개 선언한 기업들이 있습니다. 이것이 버그바운티(bug bounty)입니다. 하지만 자유는 아니고 계약입니다. 오늘은 공격 기술이 아니라 그 계약서를 읽는 법을 배웁니다.


1. 학습 목표

이 챕터를 끝내면 다음을 할 수 있습니다:

  • 버그바운티 제도의 구조(플랫폼·프로그램·트리아지)를 설명한다
  • 프로그램 정책 페이지에서 스코프·금지 행위·보상 표를 찾아 읽는다
  • *.example.com 같은 와일드카드 스코프가 무엇을 포함하고 제외하는지 판정한다
  • 유효(valid)·중복(duplicate)·정보성(informative)·해당 없음(N/A) 판정의 차이를 말한다
  • 첫 타깃 선정 기준을 적용해 "작전 명세서" 1부를 작성한다

2. 배경 지식 — 오늘의 도구와 개념

오늘의 도구 한눈에 보기

구분 내용
언어·환경 파이썬 3 (스코프 판정 원리 실습)
오늘의 도구 (개념 소개) HackerOne · Bugcrowd · KISA 신고포상제(KVE), (실습) 스코프 판정 스크립트
필요한 개념 스코프(scope), 와일드카드, 보상 등급, 판정 종류, 경쟁 밀도
오늘의 산출물 타깃 프로그램 1개 + 작전 명세서 1부

2-1. 버그바운티란 — 공격 허가증이 달린 계약

버그바운티(bug bounty)는 기업이 자사 서비스의 취약점 제보에 보상금을 지급하는 제도입니다. 핵심은 이것입니다 — 이 책 전체에서 유일하게 실제 서비스를 대상으로 한 공격 행위가 합법이 되는 구역입니다.

단, 조건이 붙습니다. 각 프로그램이 명시한 스코프(scope, 대상 도메인·IP·앱)와 규칙 안에서만 허용됩니다. 스코프가 허가증의 유효 구역입니다. 스코프 밖 시스템에 대한 요청은 버그바운티 참여 중에도 그냥 불법 침입입니다.

2-2. 플랫폼의 구조 — 누가 중간에 있는가

대표적인 창구는 세 갈래입니다. HackerOneBugcrowd는 해외 플랫폼으로, 수많은 기업의 프로그램이 모여 있습니다. 국내에는 KISA 소프트웨어 신규 취약점 신고포상제(KVE)가 있습니다.

플랫폼에서 여러분이 상대할 사람은 트리아저(triager, 제보 심사자)입니다. 제보가 접수되면 트리아저가 재현해 보고 판정을 내립니다. 이 흐름 — 제출, 심사, 판정, 보상 — 이 버그바운티의 기본 루프입니다.

2-3. 스코프와 규칙 — 계약서의 본문

프로그램 정책 페이지에는 네 가지가 적혀 있습니다. ① 인 스코프(in-scope): 테스트해도 되는 자산 목록. ② 아웃 오브 스코프(out-of-scope): 건드리면 안 되는 자산. ③ 금지 행위: 서비스 거부 공격, 사회공학, 자동화 스캔 제한 같은 행위 규칙. ④ 보상 표: 취약점 등급별 금액.

와일드카드 해석이 초보가 가장 많이 틀리는 부분입니다. *.example.com이 인 스코프라면 서브도메인 전체가 대상일까요? 루트 도메인(example.com) 자체는 포함일까요? 모바일 앱은요? 제3자 서비스(결제 대행사 등)는요? 정답은 프로그램마다 다르므로, 정책 페이지에 적힌 문장만이 정답입니다.

2-4. 판정의 종류 — 대부분은 보상이 아니다

제보를 내면 돌아오는 답은 대체로 넷 중 하나입니다.

판정 보상
유효(valid) / 채택(resolved) 진짜 취약점으로 인정 있음
중복(duplicate) 누군가 먼저 제보함 없음
정보성(informative) 사실이지만 보안 영향이 약함 없음
해당 없음(N/A) 취약점으로 볼 수 없음 없음

냉정한 사실 하나 — 제보의 대부분은 중복·정보성·N/A로 끝납니다. 첫 유효 판정까지 시간이 걸리는 것이 정상이고, 그래서 첫 목표는 "고액 보상"이 아니라 "유효 판정 1건의 경험"이어야 합니다.

2-5. 첫 타깃 선정 기준 — 경쟁이 적은 곳으로

구글·애플 같은 유명 프로그램은 세계 최고수들이 매일 훑는 곳입니다. 초보가 여기서 첫 유효 제보를 얻을 확률은 낮습니다. 초보에게 유리한 프로그램의 조건은 이렇습니다.

  • 스코프가 넓다 — 와일드카드(*.도메인)로 열려 있어 탐색할 자산이 많다
  • 경쟁이 낮다 — 신생 프로그램이거나 참여자(제보 해결 수)가 적다
  • 보상 표가 명확하다 — 등급별 금액이 적혀 있어 기대치를 잡을 수 있다
  • 응답이 빠르다 — 트리아지 평균 응답 시간이 짧게 공개되어 있다

3. 따라 하기

3-1. 프로그램 정책 페이지 해부 — 화면 예시

정책 페이지의 전형적인 모양을 화면 예시로 익힙니다. 플랫폼에 가입해 실제 페이지를 보면 이 구조 그대로입니다.

화면 예시 (HackerOne 프로그램 정책 페이지의 모양 — 가상의 프로그램):

  Example Corp Security Program
  ┌──────────────────────────────────────────────┐
  │ Scope (대상)                                  │
  │   In scope:  *.example-corp.com              │
  │              Example iOS/Android 앱          │
  │   Out of scope: status.example-corp.com      │
  │                 제3자 서비스 전체            │
  │                                              │
  │ Rules (금지 행위)                            │
  │   - DoS/DDoS 테스트 금지                     │
  │   - 사회공학·피싱 금지                       │
  │   - 자동화 스캔은 초당 5요청 이하            │
  │   - 타인 계정·데이터 접근 금지               │
  │                                              │
  │ Rewards                                      │
  │   Critical $5,000 / High $1,500              │
  │   Medium $500   / Low $100                   │
  └──────────────────────────────────────────────┘

읽는 법: 네 칸을 순서대로 봅니다 — 대상, 제외, 금지 행위, 보상. 이 페이지가 계약서이고, "몰랐다"는 통하지 않습니다. 예시의 프로그램·도메인·금액은 전부 가공 데이터입니다.

3-2. 스코프 읽기 연습 — 네 가지 질문

화면 예시의 스코프를 보고 네 가지를 스스로 답해 보세요.

질문 이 예시의 답
api.dev.example-corp.com은 대상인가? 예 — *.example-corp.com에 걸린다
루트 example-corp.com은 대상인가? 불명확 — 정책에 명시가 없으면 문의하거나 제외로 간주
status.example-corp.com은? 아니요 — 명시적 제외
결제 대행사 페이지는? 아니요 — 제3자 서비스 제외

읽는 법: 핵심 감각은 "명시가 없으면 대상이 아니다"입니다. 애매한 자산을 테스트하는 순간 합법 구역을 벗어날 수 있으므로, 애매하면 하지 않거나 프로그램에 먼저 묻습니다.

3-3. 와일드카드 판정 원리 — 실측

"*.lab.local에 걸리는가?"를 코드로 판정해 봅니다. 정책 문장을 기계가 어떻게 해석하는지 보면, 스코프 읽기가 감각이 됩니다.

입력: scope_check.py:

import re

scope_in  = ["*.lab.local"]                                # 인 스코프
scope_out = ["status.lab.local", "thirdparty.example.com"] # 명시적 제외

def in_scope(host):
    for pat in scope_out:                                  # 제외가 항상 먼저
        if re.fullmatch(pat.replace("*.", r"(.+)\."), host):
            return False, f"제외 항목({pat})에 해당"
    for pat in scope_in:
        if re.fullmatch(pat.replace("*.", r"(.+)\."), host):  # 엄격: 서브도메인 필수
            return True, f"대상 패턴({pat})에 일치"
    return False, "대상 패턴에 해당 없음"

tests = ["www.lab.local", "lab.local", "dev.api.lab.local",
         "status.lab.local", "lab.local.evil.com", "thirdparty.example.com"]
for h in tests:
    ok, why = in_scope(h)
    print(f"{h:28s} -> {'IN ' if ok else 'OUT'} ({why})")

출력 (2026-09-09 실측):

www.lab.local                -> IN  (대상 패턴(*.lab.local)에 일치)
lab.local                    -> OUT (대상 패턴에 해당 없음)
dev.api.lab.local            -> IN  (대상 패턴(*.lab.local)에 일치)
status.lab.local             -> OUT (제외 항목(status.lab.local)에 해당)
lab.local.evil.com           -> OUT (대상 패턴에 해당 없음)
thirdparty.example.com       -> OUT (제외 항목(thirdparty.example.com)에 해당)

읽는 법: 세 가지를 봅니다. ① dev.api.lab.local처럼 깊은 서브도메인도 와일드카드에 걸립니다. ② lab.local.evil.com은 겉모습이 비슷해도 다른 도메인입니다 — OUT. ③ 그리고 가장 중요한 것 — 루트 도메인 lab.local이 OUT으로 나왔습니다. 이 판정기는 *.를 "서브도메인이 반드시 있어야 한다"로 엄격하게 해석했기 때문입니다.

왜 하는가: 실제 프로그램들도 이 해석이 갈립니다. 어떤 프로그램은 루트 도메인을 포함시키고 어떤 곳은 아닙니다. 그래서 정책에 명시가 없으면 루트 도메인은 건드리지 않는 것이 안전한 기본값입니다. 코드로 직접 판정해 보면 이 모호함이 손에 익습니다.

3-4. 보상 등급표 읽기 — 화면 예시

보상 표는 보통 심각도 4단으로 되어 있습니다. 화면 예시입니다.

화면 예시 (가상 프로그램의 보상 표):
  Critical — 원격 코드 실행, 인증 없는 전체 DB 접근     $5,000
  High     — 타인 계정 탈취, 저장형 XSS(관리자 대상)     $1,500
  Medium   — IDOR(타인 데이터 열람), 권한 상승            $500
  Low      — 반사형 XSS, 정보 노출(제한적)               $100

읽는 법: 보상 금액보다 등급의 기준 문장을 읽으세요. "타인 데이터 열람 = Medium"이라는 기준이 있어야, 나중에 내 발견이 어느 등급인지 주장할 근거가 생깁니다. 같은 IDOR도 노출되는 데이터에 따라 등급이 달라진다는 점을 기억해 두세요.

3-5. 작전 명세서 작성

첫 타깃을 골랐다면(또는 연습용 가상 프로그램으로), 한 장짜리 작전 명세서를 만듭니다. 이 문서가 앞으로 모든 활동의 경계선입니다.

# 작전 명세서 — (프로그램명) / 작성일: ____

### 스코프 (절대 벗어나지 않는다)
- IN:  *.example-corp.com, 모바일 앱
- OUT: status.example-corp.com, 제3자 서비스 전체

### 금지 행위
- DoS 금지 / 자동화 스캔 초당 5요청 이하 / 타인 데이터 접근 금지

### 보상 기준 (내 목표 등급: Medium)
- Medium $500 — IDOR 등 타인 데이터 열람

### 선정 이유
- 신생 프로그램(제보 해결 수 적음), 와일드카드 스코프로 자산 넓음

### 내 테스트 계정
- 계정 A: ____ / 계정 B: ____ (테스트는 이 두 계정 사이에서만)

읽는 법: "내 테스트 계정" 칸이 중요합니다. 버그바운티의 검증은 원칙적으로 본인이 만든 계정들 사이에서만 이루어집니다. 이 명세서를 벗어나는 행위는 "공부"가 아니라 침해입니다.


4. 미션과 연습문제

미션 — 작전 명세서 1부 완성

  1. 실제 플랫폼(HackerOne 등)에서 프로그램 3개의 정책 페이지를 읽거나, 3-1의 가상 프로그램을 대상으로 삼습니다
  2. 2-5의 선정 기준 4개(스코프 넓이, 경쟁, 보상 표, 응답 속도)로 후보를 비교하는 표를 만듭니다
  3. 3-5 형식의 작전 명세서를 완성합니다 — 스코프·금지 행위·보상 기준·선정 이유 전부 포함
  4. 3-3의 scope_check.py에 호스트 3개를 추가해 판정을 실행하고, 결과를 명세서에 첨부합니다
  5. 명세서 마지막 줄에 "이 문서의 범위를 절대 벗어나지 않는다"를 쓰고 날짜를 적습니다

연습문제

문제 1. 버그바운티에서의 공격이 합법인 이유를 "계약"의 관점에서 설명하고, 스코프 밖 요청이 왜 버그바운티 참여 중에도 불법인지 설명해 보세요.

문제 2. *.example.com이 인 스코프일 때 루트 도메인 example.com의 처리가 프로그램마다 갈리는 이유를 3-3의 실측 결과를 근거로 설명해 보세요.

문제 3. 중복(duplicate) 판정은 왜 "실력이 없어서"가 아니라 "흔한 일"인지, 버그바운티의 구조를 들어 설명해 보세요.

문제 4. 초보에게 "스코프가 넓고 경쟁이 낮은 프로그램"이 유리한 이유를 두 가지 들어 보세요.


5. 모범 답안과 완료 기준

미션 모범 답안

후보 비교 표의 예시 (프로그램명은 가공):

기준 프로그램 A(유명) 프로그램 B(신생)
스코프 도메인 3개로 제한 *.도메인 와일드카드
해결된 제보 수 4,000+ (경쟁 치열) 30 (경쟁 낮음)
보상 표 명확 명확
첫 타깃 적합도 낮음 높음 — 선정

검증하는 법: ① 비교 기준 4개가 표에 있는가. ② 명세서에 IN/OUT 스코프가 문장 그대로 옮겨 있는가. ③ scope_check.py 실행 결과가 첨부됐는가. ④ "벗어나지 않는다" 선언이 있는가. 전부 ‘예’이면 완성입니다.

연습문제 해답

문제 1 해답. 버그바운티는 기업이 "이 범위(스코프)에 대해, 이 규칙으로, 테스트를 허가한다"고 공개 약속한 계약이고, 참여자는 그 조건을 수락한 것입니다. 허가는 스코프라는 경계 안에서만 존재하므로, 스코프 밖 시스템에 대한 요청은 허가가 없는 일반 침입 행위와 법적으로 같습니다. "버그바운티 참여자"라는 신분이 아니라 "허가받은 범위 안의 행위"만이 보호됩니다.

문제 2 해답. 3-3 실측에서 lab.local은 OUT으로 판정됐습니다 — *.를 "서브도메인 필수"로 엄격 해석했기 때문입니다. 그런데 이 해석은 프로그램 작성자의 의도와 다를 수 있습니다. 어떤 프로그램은 *.example.com에 루트를 포함시키려는 의도였을 수 있고, 실제로 별도로 example.com을 명시하는 프로그램도 있습니다. 기계적 해석이 갈리므로, 정책에 명시가 없으면 루트 도메인은 건드리지 않거나 문의해야 합니다.

문제 3 해답. 인기 프로그램의 같은 기능은 수백 명의 헌터가 동시에 보고 있습니다. 취약점은 하나이고 제보는 여러 건이므로, 가장 먼저 온 한 건만 유효가 되고 나머지는 전부 중복이 됩니다. 실력과 무관하게 타이밍의 문제인 것입니다. 그래서 중복 판정은 "찾을 실력은 있는데 늦었다"는 뜻으로 읽는 것이 정확하고, 경쟁이 낮은 프로그램을 고르는 것이 중복률을 낮추는 전략이 됩니다.

문제 4 해답. 첫째, 스코프가 넓으면 탐색할 자산(서브도메인·기능)이 많아 남들이 아직 안 본 구석이 남아 있을 확률이 높습니다. 둘째, 경쟁이 낮으면 발견과 제보 사이에 누가 먼저 낼 확률이 낮아 중복 판정을 덜 받습니다. 첫 목표가 "유효 판정의 경험"이라면 이 두 조건이 성공 확률을 가장 크게 올립니다.

완료 기준 체크리스트

  • [ ] 버그바운티가 "스코프 안에서만 합법인 계약"임을 설명할 수 있다
  • [ ] 정책 페이지의 4요소(대상·제외·금지·보상)를 찾아 읽을 수 있다
  • [ ] 와일드카드 스코프의 루트 도메인 모호함을 실측으로 확인했다
  • [ ] 판정 4종(유효·중복·정보성·N/A)을 구분해 말할 수 있다
  • [ ] 첫 타깃 선정 기준 4개를 적용해 후보를 비교했다
  • [ ] 작전 명세서 1부를 완성했다

6. 흔한 실수와 해결

벽 1. 유명 프로그램부터 욕심낸다

증상: 구글·애플·페이스북 프로그램부터 봅니다.
원인: 보상 금액으로 고르는 것입니다.
해결: 첫 목표는 금액이 아니라 유효 판정 1건의 경험입니다. 유명 프로그램은 세계 최고수들이 매일 훑으므로 남은 취약점이 적고 중복률이 높습니다. 2-5의 기준대로 신생·넓은 스코프 프로그램부터 시작하세요.

벽 2. 스코프를 대충 읽고 시작한다

증상: "와일드카드니까 다 되겠지" 하고 테스트하다가 제외 자산을 건드립니다.
원인: 정책 페이지를 정독하지 않은 것입니다.
해결: 3-5의 작전 명세서를 테스트 전에 만드세요. 명세서에 없는 자산은 손대지 않는 것이 규칙입니다. lab.local.evil.com처럼 겉모습이 비슷한 스쿼팅 도메인은 절대 대상이 아닙니다 (3-3 실측).

벽 3. 판정기 결과와 기대가 다르다

증상: scope_check.py에서 lab.local이 OUT으로 나와 당황합니다.

lab.local                    -> OUT (대상 패턴에 해당 없음)

원인: 버그가 아니라 의도된 엄격 해석입니다 — *.를 "서브도메인이 반드시 있어야 함"으로 구현했습니다 (2026-09-09 실측).
해결: 이 모호함 자체가 오늘의 교훈입니다. 실제 정책에서도 명시가 없으면 루트 도메인은 보류하고 프로그램에 묻는 것이 안전한 기본값입니다.

벽 4. 중복 판정에 좌절한다

증상: 첫 제보가 duplicate로 돌아와 의욕을 잃습니다.
원인: 중복을 "실력 없음"의 신호로 읽는 것입니다.
해결: 중복은 "찾았는데 늦었다"이며 실력의 증거입니다. 구조상 인기 프로그램에서는 대부분이 중복으로 끝납니다 (문제 3). 경쟁이 낮은 프로그램으로 옮기는 것이 확률을 올리는 정답입니다.


7. 정리

오늘의 개념

개념 한 줄 설명
버그바운티 취약점 제보에 보상을 주는 제도 — 스코프 안에서만 합법인 계약
스코프(scope) 테스트 허가 구역 — IN/OUT 목록과 금지 행위가 계약의 본문
트리아저(triager) 제보를 재현하고 판정하는 심사자
판정 4종 유효(보상) · 중복 · 정보성 · 해당 없음(보상 없음)
와일드카드 *.도메인 서브도메인 전체 — 루트 도메인 포함 여부는 프로그램마다 다름
작전 명세서 내 활동의 경계선 문서 — 스코프·규칙·테스트 계정의 요약
첫 타깃 기준 넓은 스코프 · 낮은 경쟁 · 명확한 보상 표 · 빠른 응답

오늘의 명령어·코드

도구 하는 일
re.fullmatch(패턴, 호스트) 호스트가 스코프 패턴에 정확히 맞는지 판정
패턴.replace("*.", r"(.+)\.") 와일드카드를 정규식으로 변환 (서브도메인 필수 해석)
제외 목록 먼저 검사 OUT이 IN보다 우선 — 명시적 제외가 항상 이긴다

명령어보다 중요한 감각

오늘 배운 것은 기술이 아니라 경계입니다. 버그바운티는 "공격해도 되는 세상"이 아니라 "허가서를 읽고 그 안에서만 움직이는 게임"입니다. 정책 페이지를 정독하는 습관, 애매하면 건드리지 않는 기본값, 중복을 실패가 아니라 통계로 읽는 태도 — 이 세 가지가 Level 4 전체의 뿌리입니다. 작전 명세서가 완성됐다면, 다음부터는 그 경계 안에서 실제로 지도를 그리고 취약점을 찾습니다.


전부 체크되면 Step 314 완료입니다. 사이드바의 체크박스를 눌러 진도를 저장하세요.