Step 273. HTB Hard 도전 1 — 자세히 열거, 가설 검증

Step 273. HTB Hard 도전 1 — 자세히 열거, 가설 검증

Level 3 — CTF 실전과 공격 스킬 심화 | 난이도 ★★★★★ | 예상 소요 시간 1주일(타임박스)

전제: HTB Medium 5대 졸업 정리(Step 270)와 침투 플레이북 v1.0(Step 272)이 있다.

  • 준비물: HTB 계정과 VPN 연결, 플레이북, 그리고 이번에는 가설 관리표가 하나 더 필요합니다.
  • ⚠️ 이 챕터의 실습은 내 랩·합법 플랫폼 전용입니다. 허가 없는 시스템에 적용하면 범죄입니다. Hack The Box(hackthebox.com)는 운영자가 공격 연습용으로 공식 개방한 합법 학습 플랫폼입니다 — HTB 머신 외에는 오늘의 기술을 쓰지 않습니다.
  • 화면 안내: 이 챕터의 HTB 접속 화면과 명령 출력은 전부 화면 예시입니다. 실제 접속과 풀이는 여러분이 직접 합니다.
  • 목표 안내: 첫 Hard의 목표는 완주가 아니라 과정 학습입니다. 1주일 타임박스, 완주는 보너스입니다.

Hard는 Medium의 연장이 아닙니다. Medium까지의 루틴으로는 입구조차 안 보일 수 있습니다 — "모르는 기술 + 숨겨진 입구 + 다단계 체인"이 겹치기 때문입니다. 실제로 첫 Hard에서 사흘을 쓰고도 포트 스캔 화면만 보고 있는 것은 비극이 아니라 표준 경험입니다.

그래서 Hard의 핵심 스킬은 새로운 기술이 아니라 가설 관리입니다. 가능한 경로를 전부 열거하고, 확률 순으로 정렬하고, 하나씩 부수며 결과를 기록하는 — 기술이라기보다 과학의 방법입니다. 오늘은 그 방법을 들고 첫 Hard의 벽에 몸으로 부딪힙니다.


1. 학습 목표

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

  • Hard가 Medium과 다른 세 가지 특성(모르는 기술·숨겨진 입구·다단계 체인)을 설명한다
  • "자세히 열거"의 구체적 수법(UDP 풀스캔, 대형 워드리스트, vhost, 소스 리딩)을 실행한다
  • 가설 관리표(경로 목록 → 우선순위 → 검증 결과)를 작성하고 운용한다
  • 세션 종료 기록("부순 가설 / 남은 가설 / 내일 첫 행동")을 습관화한다
  • 1주일 공략 로그와 회고로 "Hard가 요구하는 것"을 문장으로 정리한다

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

오늘의 도구 한눈에 보기

구분 내용
언어·환경 HTB 플랫폼(VPN) + 공격 머신 + 플레이북(Step 272)
오늘의 명령 nmap -sU(UDP), 대형 워드리스트 스캔, ffuf vhost, 소스 리딩
필요한 개념 가설-검증 사이클, 가설 관리표, 확률 순 정렬, 열거 회귀
오늘의 산출물 1주일 공략 로그 + 가설 관리표 + 주간 회고(완주는 보너스)

2-1. Hard의 세 가지 특성

첫째, 오래된 패턴이 안 통합니다. Medium에서 먹혔던 "디렉터리 스캔 → 백업 파일" 같은 입구는 Hard 출제자도 압니다. 그래서 입구는 흔한 목록 바깥에 숨겨져 있습니다 — UDP만 여는 서비스, vhost 뒤의 도메인, 소스를 읽어야만 보이는 로직.

둘째, 가설의 수가 폭발합니다. Medium은 "가능한 경로"가 서너 개였지만 Hard는 열 개가 넘습니다. 머리로 관리하면 반드시 같은 것을 두 번 검증하거나, 중요한 것을 건너뜁니다.

셋째, 체인이 깁니다. Step 269의 2단 체인이 Hard에서는 4~5단이 되고, 중간 고리 하나가 여러분이 아직 모르는 기술일 수 있습니다. 그때 필요한 것은 포기가 아니라 "이 고리만 따로 공부하는 것"입니다.

2-2. "자세히 열거"의 구체적 방법

Hard에서 "열거를 더 열심히"는 구호가 아니라 구체적 명령의 목록입니다.

차원 Medium 수준 Hard 수준
TCP 포트 -sV -sC + 전체 포트 전체 포트 결과의 모든 서비스를 각각 깊게
UDP 생략하거나 상위 20 -sU --top-ports 100 이상, SNMP·DNS 개별 점검
웹 목록 common.txt(약 4천) raft-medium 이상(수만), 확장자 조합
도메인 호스트 하나 vhost·서브도메인 퍼징
코드 응답만 봄 소스 입수 시 전체 리딩, JS 파일 정독

공통 원리는 하나 — "목록의 기본값을 쓰지 않는다." 출제자는 기본 목록에 없는 것을 숨깁니다.

2-3. 가설 관리표 — Hard의 항해일지

가설 관리표는 네 열이면 충분합니다.

| # | 가설(경로) | 근거 | 상태 |
|---|-----------|------|------|
| 1 | UDP 161 SNMP에서 커뮤니티 스트링 | UDP 스캔에서 열림 | 검증 중 |
| 2 | vhost 퍼징으로 숨은 도메인 | 80 응답에 도메인 힌트 | 부숨 — 3개 발견 |
| 3 | 웹 소스의 주석이 자격증명 | JS 파일에 이상한 문자열 | 기각 — 장난 문자열 |
| 4 | FTP 익명 로그인 | 21 열림 | 대기 |

규칙 세 가지. ① 가설은 발견 즉시 번호를 붙여 적습니다. ② 검증 결과는 "부숨/기각"으로 명확히 닫습니다 — "애매함"은 기각으로 처리하고 근거를 적습니다. ③ 새 정보가 나오면 표 전체의 우선순위를 다시 매깁니다.

2-4. 세션 종료 기록 — 내일의 나에게 넘기는 바통

Hard는 하루에 안 끝납니다. 여러 세션에 걸치는 공략에서 기억은 반드시 증발하므로, 매 세션 끝에 세 줄을 적습니다.

[Day 3 종료]
- 오늘 부순 가설: #2 vhost 3개 발견, #5 기각(응답 크기 동일)
- 남은 가설: #1(SNMP, 진행 중), #4, #7(신규)
- 내일 첫 행동: #1의 onesixtyone으로 커뮤니티 스트링부터

"내일 첫 행동"이 이 기록의 심장입니다. 이것이 있으면 다음 세션의 예열 시간이 30분에서 3분으로 줄고, 없으면 매 세션 "어디까지 했더라"로 시작합니다.

2-5. 같은 가설의 반복은 열거 회귀 신호

Hard에서 사흘 막히는 것은 정상입니다. 단, 구별이 필요합니다 — 새 가설을 검증하며 막히는 것은 전진이고, 같은 가설을 반복 검증하며 막히는 것은 정체입니다. 후자는 "가진 정보로는 더 이상 가설을 차별화할 수 없다"는 뜻이고, 처방은 하나 — 열거로 회귀해서 새 정보를 가져오는 것입니다.


3. 따라 하기

3-1. 머신 선정과 타임박스 선언

HTB에서 평가가 좋은(community rating이 높은) Hard 머신 1대를 고릅니다. 첫 Hard는 기술 전시용 머신보다 교훈이 잘 정리된 머신이 좋습니다 — 나중에 공식 write-up과 내 과정을 비교할 수 있으니까요.

그리고 달력에 선언합니다 — 1주일 타임박스. 매일 1~2시간이든 주말 몰아치기든 형태는 자유지만, "끝"을 정해 두어야 회고가 존재합니다.

3-2. Day 1 — 자세히 열거

첫 세션은 열거에 통째로 씁니다. Hard에서 첫날에 입구를 못 찾는 것은 실패가 아니라 설계입니다.

TCP와 UDP를 동시에 (화면 예시):

nmap -sV -sC 10.10.11.xx -oN tcp_default.txt
nmap -p- --min-rate 2000 10.10.11.xx -oN tcp_all.txt
sudo nmap -sU --top-ports 100 10.10.11.xx -oN udp_top100.txt
# udp_top100.txt (화면 예시)
PORT    STATE         SERVICE
161/udp open          snmp

웹이 보이면 목록을 키웁니다 (화면 예시):

gobuster dir -u http://10.10.11.xx \
  -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
ffuf -u http://10.10.11.xx -H "Host: FUZZ.대상도메인" \
  -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt

읽는 법: Medium에서는 common.txt로 나오던 것이 raft에서만 나오고, UDP를 열어야만 보이는 서비스(SNMP)가 체인의 첫 고리인 것 — 이것이 "자세히 열거"의 실체입니다. 오늘 발견한 모든 것은 자산 목록(Step 269)으로 가고, 가능한 경로는 전부 가설 관리표에 번호를 받습니다.

3-3. Day 2 이후 — 가설-검증 루프

둘째 날부터는 리듬이 정해져 있습니다.

  1. 어제의 "내일 첫 행동"부터 시작
  2. 가설 관리표의 최상위 가설을 하나 골라 결정적 실험을 설계 — "이것이 보이면 부숨, 아니면 기각"을 미리 정합니다
  3. 결과를 표에 기록하고 우선순위를 다시 매김
  4. 정체 감지(같은 가설 반복) 시 열거로 회귀

결정적 실험의 예 (화면 예시) — SNMP 가설 #1의 검증:

onesixtyone -c /usr/share/seclists/Discovery/SNMP/common-snmp-community-strings.txt 10.10.11.xx
Scanning 1 hosts, 120 communities
10.10.11.xx [public] Linux web01 5.10.0 ...

public으로 응답이 왔으니 가설 #1은 "부숨" — 그리고 새 정보(호스트명 web01, 커널 버전)가 자산 목록에 입고되고, 이 정보에서 새 가설(#7: SNMP로 프로세스 목록 열거)이 파생됩니다. 가설이 가설을 낳는 이 순환이 Hard의 진짜 진행입니다.

3-4. 모르는 기술을 만났을 때 — 고리 분리 공부

체인 중간에 모르는 기술이 끼어 있으면(예: 경로가 "이 서비스의 CVE-2024-xxxx 익스플로잇"을 요구), 머신 공략을 잠시 멈추고 그 고리만 분리해 공부합니다.

  • 그 기술의 개념 문서를 위키에 한 장 작성 (Step 89의 세 칸 구조)
  • 가능하면 로컬 랩이나 THM의 관련 룸에서 그 기법만 연습
  • 플레이북(Step 272)에 미검증 카드로 적어 두고, 이번 머신에서 검증되면 링크 부착

Hard 1대가 요구하는 공부량이 Medium 3대보다 많은 것은 우연이 아닙니다 — Hard는 "모르는 것을 발견하는 장치"로 설계돼 있으니까요.

3-5. 매 세션의 종료 의식

세션을 닫기 전, 2-4의 세 줄을 공략 로그에 적습니다. 그리고 가설 관리표를 한 번 훑어 "오늘 새 정보가 생겼는데 우선순위는 그대로인가"를 점검합니다.

이 의식의 보상은 사흘째에 옵니다 — 다른 사람들이 "이틀 전에 뭘 봤더라"를 되짚는 시간에, 여러분은 로그의 마지막 줄을 읽고 바로 실험을 시작합니다.

3-6. Day 7 — 완주 여부와 무관한 주간 회고

타임박스가 끝나면 결과와 무관하게 회고합니다. 완주했다면 그 과정을, 못 했다면 공식 write-up과 내 가설 관리표를 나란히 놓고 비교합니다.

비교 질문 세 개:

  1. 정답 경로가 내 가설 관리표에 있었는가? — 있었다면 순서의 문제, 없었다면 열거의 문제입니다.
  2. 내가 기각한 가설이 정답이었는가? — 기각 근거가 성급했는지 봅니다. "애매함"을 기각한 것이 원인이면 기각 기준을 조정합니다.
  3. Hard가 요구한 것을 한 문장으로 말하면? — 예: "기본 워드리스트 너머", "UDP를 포기하지 않기", "소스를 끝까지 읽기".

이 문장들이 다음 Hard 도전(Step 274~)의 출발 지점이 됩니다.


4. 미션과 연습문제

미션 — 첫 Hard의 1주일

  1. 평가 좋은 Hard 머신 1대를 골라 1주일 타임박스를 선언한다
  2. Day 1에 "자세히 열거" 전 항목(UDP, 대형 워드리스트, vhost)을 실행한다
  3. 가설 관리표를 운용한다 — 모든 경로에 번호, 모든 검증에 부숨/기각 판정
  4. 매 세션 종료 기록("부순 가설 / 남은 가설 / 내일 첫 행동")을 남긴다
  5. Day 7에 주간 회고 — 정답 경로와 내 관리표 비교 + "Hard가 요구하는 것" 한 문장

연습문제

문제 1. Hard의 세 특성(모르는 기술·숨겨진 입구·다단계 체인) 각각이 요구하는 대응을 하나씩 말해 보세요.

문제 2. "자세히 열거"의 공통 원리인 "목록의 기본값을 쓰지 않는다"가 성립하는 이유를 출제자의 관점에서 설명해 보세요.

문제 3. 가설 관리표에서 "애매함" 상태를 허용하지 않고 부숨/기각으로 닫아야 하는 이유를 말해 보세요.

문제 4. "새 가설로 막히는 것"과 "같은 가설로 막히는 것"의 차이와, 후자의 처방을 설명해 보세요.


5. 모범 답안과 완료 기준

미션 모범 답안

완주 여부가 아니라 과정 산출물이 채점 대상입니다. 가설 관리표에 번호가 붙은 가설들, 각 가설의 판정, 세션별 종료 기록, Day 7의 비교 회고. 완주했다면 경로도(Step 269)까지 곁들이면 완벽합니다.

검증하는 법: ① 가설 관리표에 "대기/검증 중"으로 끝난 가설이 없이 전부 판정됐는가(마지막 날 미검증은 그 사실을 명시). ② 세션 종료 기록이 세션 수만큼 있는가. ③ 회고의 질문 1(정답이 내 표에 있었나)에 대한 답이 있는가. ④ "Hard가 요구하는 것" 문장이 구체적인가("더 열심히"가 아니라 "UDP 풀스캔을 기본값으로"처럼).

연습문제 해답

문제 1 해답. 모르는 기술에는 "고리 분리 공부" — 체인의 그 고리만 떼어 내 개념 문서를 만들고 연습합니다. 숨겨진 입구에는 "자세히 열거" — UDP·대형 워드리스트·vhost 등 기본 목록 바깥을 봅니다. 다단계 체인에는 "자산 목록과 가설 관리표" — 긴 체인의 부품과 경로를 기억이 아니라 문서로 관리합니다.

문제 2 해답. 출제자도 기본 목록을 압니다. common.txt에 있는 경로를 입구로 쓰면 그 머신은 Medium이 됩니다. Hard를 Hard답게 하려면 입구를 기본 목록에 없는 곳 — 큰 워드리스트에만 있는 경로, UDP 서비스, vhost 뒤 — 에 숨겨야 합니다. 따라서 공격자는 "기본값으로 안 나왔다"를 "없다"가 아니라 "아직 기본값만 봤다"로 읽어야 합니다.

문제 3 해답. "애매함"은 검증이 끝나지 않은 상태이므로 표에 남으면 나중에 다시 검증하게 되고, 그것이 "같은 가설의 반복" — Hard 최대의 시간 도둑 — 이 됩니다. 부숨/기각으로 닫아야 표의 남은 가설 수가 실제 남은 일의 양을 반영합니다. 근거가 약해 기각이 불안하면 "기각(근거 약함)"으로 닫고 근거를 적어 두면 됩니다.

문제 4 해답. 새 가설의 검증은 실패해도 표에서 가설이 하나씩 지워지므로 전진입니다. 같은 가설의 반복은 표가 줄지 않는 정체이며, "가진 정보로는 가설을 더 차별화할 수 없다"는 신호입니다. 처방은 가설을 더 짜내는 것이 아니라 열거로 회귀해 새 정보를 가져오는 것 — 새 정보가 새 가설(또는 기각 근거)을 낳습니다.

완료 기준 체크리스트

  • [ ] Hard의 세 특성과 각 대응을 설명할 수 있다
  • [ ] UDP 스캔, 대형 워드리스트, vhost 퍼징을 실제로 실행했다
  • [ ] 가설 관리표(번호·근거·부숨/기각 판정)를 1주일 운용했다
  • [ ] 매 세션 종료 기록 세 줄을 남겼다
  • [ ] 정체 시 열거 회귀 규칙을 실제로 한 번 이상 발동했다
  • [ ] 모르는 기술을 만나면 고리 분리 공부로 대응했다
  • [ ] 미션: 1주일 공략 로그 + 가설 관리표 + 주간 회고를 완성했다

6. 흔한 실수와 해결

벽 1. 첫날을 스캔만 하고 끝냈다는 자책

증상: Day 1에 입구를 못 찾아 "오늘 아무것도 못 했다"고 느낍니다.
원인: Hard의 진도를 Medium의 감각으로 재고 있습니다.
해결: Hard에서 열거 하루는 진도입니다 — 가설 관리표에 번호가 다섯 개 생겼다면 그것이 그날의 생산물입니다. 자책 대신 "내일 부술 가설이 다섯 개"로 읽으세요.

벽 2. vhost 퍼징에서 수백 개가 전부 걸린다

증상: ffuf 결과가 전부 성공처럼 보입니다.
원인: 존재하지 않는 vhost에도 서버가 같은 응답(같은 크기)을 돌려주는 경우입니다. 퍼징의 상수입니다.
해결: 응답 크기로 걸러 내세요 — -fs 4242(크기 4242 제외)처럼, 대부분이 찍히는 크기를 제외하면 진짜 vhost만 남습니다. ffuf가 자동 보정(-ac)도 해 줍니다.

벽 3. UDP 스캔이 영원히 안 끝난다

증상: nmap -sU가 몇 시간째 진행 중입니다.
원인: UDP는 응답이 없으면 재전송하며 기다려서 TCP보다 훨씬 느립니다. 정상입니다.
해결: --top-ports 100으로 범위를 제한하고, 백그라운드로 돌린 채 TCP 쪽 작업을 병행하세요. SNMP(161), DNS(53), NTP(123)처럼 Hard에서 힌트가 되는 UDP 서비스는 몇 개로 정해져 있습니다.

벽 4. 사흘째 "정답이 있기는 한가"라는 의심

증상: 모든 가설이 기각되고 자신감이 무너집니다.
원인: Hard의 난이도 설계 자체가 그 의심을 유도합니다. 그리고 사흘 막히는 것은 이 책에서도 "정상"으로 명시된 구간입니다.
해결: 두 가지를 확인하세요 — ① 기각이 전부 "근거 있는 기각"인가(그렇다면 잘하고 있는 것) ② 열거 회귀를 발동했는가(안 했다면 지금). 그래도 정체면 커뮤니티의 무스포일러 힌트(공식 포럼의 방향 힌트)까지는 허용 범위입니다 — 답이 아니라 방향을 얻는 것과 답을 보는 것은 다릅니다.

벽 5. 공식 write-up을 보고 "이걸 어떻게 생각해 내지"라는 좌절

증상: Day 7 비교에서 정답 경로의 발상이 너무 비상식적으로 보입니다.
원인: write-up은 성공한 경로만 보여 줍니다 — 작성자가 버린 수십 개의 가설은 안 보입니다.
해결: 비교 기준을 바꾸세요 — "정답을 냈나"가 아니라 "정답 경로가 내 관리표의 후보에 있었나". 후보에 있었다면 여러분의 문제는 발상이 아니라 정렬(우선순위)이고, 그것은 경험으로 고쳐지는 종류입니다. 후보에조차 없었다면 열거 체계에 그 기법을 추가할 때입니다 — 그 추가가 오늘의 수확입니다.


7. 정리

오늘의 개념

개념 한 줄 설명
Hard의 세 특성 모르는 기술 + 숨겨진 입구 + 다단계 체인. Medium 루틴으로 입구조차 안 보일 수 있음
자세히 열거 UDP 풀스캔·대형 워드리스트·vhost·소스 리딩 — "목록의 기본값을 쓰지 않는다"
가설 관리표 경로 전체 목록 + 근거 + 부숨/기각 판정. Hard의 항해일지
결정적 실험 "이것이 보이면 부숨"을 미리 정한 검증. 애매함을 남기지 않는다
세션 종료 기록 부순 가설 / 남은 가설 / 내일 첫 행동 — 내일의 나에게 넘기는 바통
열거 회귀 같은 가설의 반복은 새 정보 부족의 신호 → 열거로 돌아가는 규칙
고리 분리 공부 체인 중간의 모르는 기술을 떼어 내 따로 공부하는 대응

오늘의 명령

명령 용도
nmap -p- --min-rate 2000 대상 TCP 전체 포트
sudo nmap -sU --top-ports 100 대상 UDP 상위 100 (백그라운드로)
gobuster dir -w raft-medium-directories.txt 대형 워드리스트 디렉터리 스캔
ffuf -H "Host: FUZZ.도메인" -w 워드리스트 -fs 크기 vhost 퍼징(크기 필터링 필수)
onesixtyone -c 목록 대상 SNMP 커뮤니티 스트링 점검

명령어보다 중요한 감각

Hard가 시험하는 것은 기술이 아니라 정체 속에서의 운영 능력입니다 — 가설을 표로 관리하고, 세션을 기록으로 잇고, 정체를 열거 회귀로 처리하는 체계가 있으면 Hard는 "어려운 문제"에서 "긴 문제"로 바뀝니다. 그리고 첫 Hard의 진짜 완료 조건은 root가 아닙니다. "정답 경로가 내 가설 관리표에 있었는가"라는 질문에 답할 수 있는 상태 — 그것이 이번 주의 수확이고, 그 답이 다음 Hard의 시작점입니다. 벽은 깨라고 있는 것이 아니라, 내 체계의 빈틈을 보여 주라고 있습니다.


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