Step 175. Level 2 종합 평가: 공격/방어 대응표 — 양면 사고의 완성
Level 2 — 보안 입문과 공격 스킬 기초 | 난이도 ★★★☆☆ | 예상 소요 시간 5시간(이틀 권장)
전제: Step 96~174를 마쳤습니다. 이 챕터는 새 공격 기법을 배우지 않는 Level 2의 졸업 시험입니다.
- 준비물: 노트(또는 빈 문서 파일), 지금까지의 실습 기록, 그리고 반나절의 시간.
- 주의: 오늘은 "만드는" 날입니다. 여러분만의 공격/방어 대응표를 완성하고, 흐릿한 스텝을 찾아 돌아갑니다.
⚠️ 이 챕터의 실습은 내 랩·합법 플랫폼 전용입니다. 허가 없는 시스템에 적용하면 범죄입니다.
수십 개의 공격 기법을 배웠습니다. 그런데 공격만 아는 사람은 반쪽입니다 — 모든 공격에는 대응하는 방어가 있고, 모든 방어에는 우회가 있습니다. 오늘은 Level 2 전체를 "공격 × 방어 × 우회"의 한 장짜리 표로 압축합니다. 이 표가 머릿속에 자리 잡으면, 공격을 볼 때 방어가, 방어를 볼 때 우회가 자동으로 떠오르는 양면 사고가 완성됩니다.
1. 학습 목표
이 챕터를 끝내면 다음을 할 수 있습니다:
- Level 2의 주요 공격 기법을 각각 짝이 되는 방어와 한 쌍으로 설명한다
- 각 방어의 우회 가능성을 한 줄로 말해 "방어 ≠ 절대 안전"을 체득한다
- 공격/방어 대응표를 직접 작성하고 계속 갱신하는 습관의 틀을 갖는다
- Level 2 기술 목록을 "설명 가능 / 실습 가능 / 흐릿함" 3단계로 자가 채점한다
- 흐릿한 항목만 골라 재실습하는 효율적인 복습을 한다
2. 배경 지식 — 오늘의 도구와 개념
오늘의 도구 한눈에 보기
| 구분 | 내용 |
|---|---|
| 언어·환경 | 노트와 펜 + 검증용으로 파이썬(Flask)과 curl 하나 |
| 오늘의 명령어 | 새 명령어 없음 — 검증 실측에 curl -sI(응답 헤더 보기)만 씁니다 |
| 필요한 개념 | 대응 사고(공격↔방어), 심층 방어, 우회 가능성, 3단 자가 채점 |
| 오늘의 산출물 | 공격/방어 대응표 1장 + 자가 채점표 + 재실습 목록 |
2-1. 왜 "표"인가
공격 기법은 낱개로 배우면 기술 목록이 되고, 방어와 짝지으면 구조가 됩니다. SQL 인젝션을 아는 것과 "SQL 인젝션 ↔ 준비된 문장, 우회: 인코딩·필터 우회"를 아는 것은 다릅니다. 후자는 면접에서도, 실무에서도, CTF에서도 바로 작동하는 지식입니다.
표의 힘은 또 있습니다 — 빈 칸이 보인다는 것. "이 공격의 방어가 뭐였지?"라고 막히는 칸이 바로 여러분의 빈 곳입니다.
2-2. 심층 방어 — 방어는 한 겹이 아니다
심층 방어(defense in depth)는 방어를 여러 겹으로 쌓는 원칙입니다. Step 174에서 확인했듯, 체인의 각 고리마다 방어가 있을 수 있고, 앞쪽 고리일수록 끊는 비용이 쌉니다. 대응표의 "방어" 칸에 하나만 적지 말고, 앞쪽 방어와 뒤쪽 방어를 함께 적는 습관을 들이세요.
2-3. 우회 가능성 — 방어가 완벽하지 않음을 아는 것
모든 방어 칸에는 "우회 가능성" 한 줄이 따라붙습니다. 필터가 있으면 우회 페이로드가 있고, MFA가 있으면 피로 공격(MFA fatigue)과 세션 탈취가 있습니다. 방어를 우습게 보자는 것이 아닙니다 — 방어의 한계를 아는 사람만이 방어를 올바른 위치에 놓을 수 있습니다.
2-4. 자가 채점의 3단계
Step 40에서 배운 원칙을 Level 2 규모로 확장합니다. 각 기술을 세 단계로 표시합니다:
- 설명 가능: 책 안 보고 남에게 설명할 수 있다
- 실습 가능: 명령어를 찾아보며라도 혼자 재현할 수 있다
- 흐릿함: 읽었는데 지금은 못 하겠다
"흐릿함"은 실패가 아니라 재실습 예약입니다.
3. 따라 하기
3-1. 대응표의 뼈대 — 먼저 함께 만드는 여덟 줄
아래 표는 Level 2 핵심 공격들의 대응표 뼈대입니다. 이것을 베껴 쓰는 것이 아니라, 이 형식으로 나머지를 직접 채우는 것이 오늘의 과제입니다.
| 공격 (스텝) | 원리 한 줄 | 방어 | 우회 가능성 |
|---|---|---|---|
| SQL 인젝션 (104, 135~137) | 입력이 쿼리 문법을 바꿈 | 준비된 문장(prepared statement), ORM | 필터 기반 방어는 인코딩·주석 우회 가능 |
| XSS (138~139) | 입력이 HTML/JS로 실행됨 | 출력 인코딩, CSP 헤더 | 필터 우회, DOM 기반 XSS |
| CSRF (140) | 브라우저가 대신 요청 보냄 | CSRF 토큰, SameSite 쿠키 | 토큰 누락 엔드포인트, GET 기반 상태 변경 |
| 파일 업로드 (141~142) | 업로드 파일이 실행됨 | 확장자 화이트리스트, 업로드 폴더 실행 금지 | 이중 확장자, MIME 검사만 하는 경우 |
| 명령어 인젝션 (143) | 입력이 쉘 명령에 붙음 | 쉘 호출 금지, 인자 배열 전달 | 필터 우회(공백 대체 ${IFS} 등) |
| LFI/RFI (144) | 경로 입력으로 파일 읽기/포함 | 경로 정규화, allowlist | ....//, 인코딩 우회 |
| 온라인 브루트포스 (122) | 로그인 무차별 대입 | 레이트 리밋, 계정 잠금, MFA | 스프레이(165), 분산 IP |
| ARP 스푸핑 (156~157) | 같은 동네에서 MAC 사칭 | 정적 ARP, 동적 ARP 검사(DAI) | 로컬 네트워크 신뢰 구조 자체의 한계 |
읽는 법: 네 칸의 관계를 보세요. "원리 한 줄"을 말할 수 있어야 공격을 안 것이고, "우회 가능성"을 말할 수 있어야 방어를 아는 것입니다. 이 여덟 줄이 감 잡기용입니다 — 아래 3-2에서 여러분이 나머지를 채웁니다.
3-2. 나머지 칸 채우기 — 여러분의 표
다음 항목들을 같은 네 칸 형식으로 채우세요. 막히는 칸은 비워 두지 말고 스텝 번호를 옆에 적어 두세요 — 그것이 재실습 목록이 됩니다.
- 패스워드 스프레이·크리덴셜 스터핑 (165)
- 오프라인 해시 크래킹 (123~124)
- SUID·권한 상승 (106, 125~126)
- PATH 인젝션 (108)
- DNS 스푸핑 (159)
- 세션·쿠키 공격 (134)
- IDOR·접근 제어 우회 (149)
- JWT 공격 (150)
- 사회공학 (167)
- OSINT 수집 (170~171)
작성 팁: 완벽한 표를 한 번에 만들려 하지 마세요. 공격 1개당 방어·우회 1쌍씩, 매일 몇 줄씩 누적하는 표가 목표입니다. 이 표는 오늘 끝나는 것이 아니라 Level 3 내내 커 가는 문서입니다.
3-3. 검증 실측 — 방어가 눈에 보이는지 확인하기
대응표가 문서에만 있으면 안 됩니다. 방어는 확인 가능해야 합니다. 3-1 표의 "XSS → CSP 헤더" 행을 손으로 검증해 봅니다.
먼저 방어 없는 서버(Step 174의 랩이 그대로 떠 있다면 그것, 아니면 아무 Flask 서버)의 헤더를 봅니다:
curl -sI http://127.0.0.1:8174/
HTTP/1.1 200 OK
Server: Werkzeug/3.1.8 Python/3.12.14
Date: Wed, 09 Sep 2026 08:04:04 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 240
Connection: close
(2026-09-09 실측.)
이제 같은 내용에 방어 헤더를 얹은 서버(step175_hardened.py)를 만들어 비교합니다:
입력 (step175_hardened.py)
from flask import Flask
app = Flask(__name__)
@app.after_request
def harden(resp):
resp.headers["X-Content-Type-Options"] = "nosniff"
resp.headers["X-Frame-Options"] = "DENY"
resp.headers["Content-Security-Policy"] = "default-src 'self'"
resp.headers["Server"] = "web" # 서버 버전 노출 지우기
return resp
@app.route("/")
def index():
return "<h1>하드닝된 사이트</h1>"
if __name__ == "__main__":
app.run(host="127.0.0.1", port=8175)
python step175_hardened.py
curl -sI http://127.0.0.1:8175/
HTTP/1.1 200 OK
Server: Werkzeug/3.1.8 Python/3.12.14
Date: Wed, 09 Sep 2026 08:04:26 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 31
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Content-Security-Policy: default-src 'self'
Server: web
Connection: close
(2026-09-09 실측.)
출력 읽는 법: 두 화면의 차이가 대응표의 실물입니다. 세 줄의 방어 헤더가 추가됐습니다 — 각각 MIME 스니핑 차단, 클릭재킹 차단, XSS 완화(CSP)에 대응합니다.
그런데 자세히 보세요 — Server: 헤더가 두 줄입니다. Werkzeug이 자기 버전을 먼저 써 버렸고, 우리의 web은 뒤에 추가된 것입니다. "헤더를 덮어썼다"와 "헤더가 사라졌다"는 다릅니다. 방어를 적용했다고 끝이 아니라, 공격자의 눈(curl)으로 다시 확인해야 비로소 방어입니다. 이 한 화면이 오늘 챕터의 축소판입니다.
예측: 실제 운영 서버에서는 Server 헤더 숨기기를 웹 서버 설정(nginx의
server_tokens off등)에서 합니다. 프레임워크 코드에서 지우려 하면 위처럼 두 줄이 되는 경우가 많습니다 — 방어의 "층위"도 대응표에 적을 만한 정보입니다.
3-4. Level 2 기술 목록 자가 채점
노트를 펴고 Level 2의 구간별 기술을 3단계(설명 가능/실습 가능/흐릿함)로 채점합니다. 구간 목록:
| 구간 | 스텝 | 핵심 기술 |
|---|---|---|
| 워게임 기초 | 96~105 | Bandit/Natas, XOR 분석, 첫 SQLi, 기법 목록화 |
| 리눅스 심화 | 106~110 | setuid, 로그, PATH 인젝션, 링크 |
| 침투 기초 | 111~121 | Kali, MS2, 정찰, 스캐너, Metasploit, 첫 쉘, 수동 익스플로잇 |
| 패스워드 | 122~124 | hydra, John, hashcat |
| 권한 상승 | 125~130 | SUID, linPEAS, 후속 침투, 타임어택 |
| 웹 공격 | 131~150 | Burp, SQLi, XSS, CSRF, 업로드, 웹쉘, 명령 인젝션, LFI, IDOR, JWT |
| 실전 웹 | 151~155 | 드림핵, 독립 공략 |
| 네트워크 | 156~166 | ARP/DNS 스푸핑, 스니핑, TLS, 방화벽, 터널링, 무선 |
| 인간·정보 | 167~171 | 사회공학, 악성코드 구조, OSINT |
| 종합 | 172~174 | 시나리오 1·2, 보고서, 체인 공격 |
각 구간에 "설명 가능 / 실습 가능 / 흐릿함" 중 하나를 적으세요. 열 개 구간을 채점하는 데 30분이면 충분합니다.
3-5. 흐릿한 것만 재실습 — 진짜 복습
채점에서 "흐릿함"이 나온 구간만 골라 해당 스텝으로 돌아갑니다. 재실습의 규칙은 Step 40과 같습니다:
- 개념이 흐릿: 그 스텝의 ‘배경 지식’을 읽고, 책을 덮고 내 말로 다시 설명해 본다
- 손이 흐릿: ‘따라 하기’만 다시 한다. 이번엔 출력 예시를 가리고 먼저 예측한다
- 둘 다 흐릿: 그 스텝을 처음부터 다시 한다 — 부끄러운 일이 아니라 가장 빠른 길입니다
재실습이 끝나면 대응표의 해당 칸을 다시 채웁니다. 비워 두었던 칸이 채워지는 것이 복습 완료의 증거입니다.
3-6. Level 3 미리보기 — 다음은 전문 트랙
Level 3(Step 176~)는 CTF 실전과 분야 심화입니다. 다섯 분야(Web, Pwn, Reversing, Crypto, Forensics)를 맛본 뒤 주력을 정합니다. Step 154에서 만든 약점/강점 분석이 있다면 꺼내 두세요 — 어떤 분야가 끌리는지의 첫 단서가 거기 있습니다.
지금 결정할 필요는 없습니다. 오늘의 과제는 Level 2를 닫는 것이니까요.
4. 미션과 연습문제
미션 — 나의 공격/방어 대응표 완성
3-2의 열 개 항목을 포함해, Level 2에서 배운 공격 총 18개 이상의 대응표를 완성하세요. 규칙:
- 네 칸(공격/원리/방어/우회 가능성)을 모두 채울 것 — 모르는 칸은 스텝 번호를 적고 재실습 후 갱신
- 방어 칸에는 앞쪽 방어(예방)와 뒤쪽 방어(탐지/대응)를 구분해 볼 것
- 표 맨 아래에 한 줄 요약: "이 표에서 내가 가장 약한 열(공격 또는 방어)은 무엇인가"
연습문제
문제 1. "완벽한 방어를 만들면 되지 않나요?"라는 질문에, 심층 방어와 우회 가능성 개념으로 답하세요.
문제 2. 3-3 실측에서 Server: 헤더가 두 줄 나왔습니다. 이것이 보여 주는 방어 적용의 교훈은 무엇인가요?
문제 3. 레이트 리밋(로그인 시도 제한)을 우회하는 공격 두 가지를 Level 2에서 배운 것으로 답하세요.
문제 4. 자가 채점에서 "흐릿함"으로 표시된 구간이 세 개 이상일 때, 권장 복습 순서는 무엇인가요? (힌트: 구간들의 의존 관계)
5. 모범 답안과 완료 기준
미션 모범 답안
3-2 항목의 참고 답 (여러분 표와 글자가 달라도 됩니다 — 네 칸이 채워졌는지가 기준):
| 공격 | 원리 한 줄 | 방어 | 우회 가능성 |
|---|---|---|---|
| 패스워드 스프레이 (165) | 흔한 비번 1개 × 계정 다수 | 전 계정 레이트 리밋, MFA, 유출 비번 차단 | 느린 스프레이, 분산 IP |
| 해시 크래킹 (123~124) | 유출 해시를 오프라인 대입 | 강한 해시(bcrypt/argon2), 솔트, 긴 비번 정책 | 약한 해시(MD5/SHA1), 사전에 있는 비번 |
| SUID 권한 상승 (106, 125) | SUID 프로그램 오용 | SUID 최소화, 파일시스템 감사, nosuid 마운트 | GTFOBins 대상 정상 명령 |
| PATH 인젝션 (108) | PATH 앞쪽 가짜 명령 실행 | 절대경로 호출, PATH 위생 | cron/스크립트의 관행적 상대경로 |
| DNS 스푸핑 (159) | 거짓 이름 해석 응답 | DNSSEC, HTTPS 강제(HSTS) | 내부망 신뢰, 다운그레이드 시도 |
| 세션·쿠키 공격 (134) | 세션 ID 탈취·고정 | HttpOnly/Secure/SameSite, 세션 회전 | XSS로 탈취, 사이드채널 |
| IDOR (149) | 객체 번호 바꿔 타인 자원 접근 | 서버 측 접근 제어, 간접 참조 | 인증은 있으나 인가 누락인 엔드포인트 |
| JWT 공격 (150) | alg=none, 약한 시크릿 | alg 고정, 강한 키, 만료 짧게 | 키 유출, 클레임 검증 누락 |
| 사회공학 (167) | 인간의 신뢰·급박함 이용 | 교육·훈련, 확인 절차, 보고 문화 | 새로운 미끼, 조직 경계 공략 |
| OSINT (170~171) | 공개 정보의 조합 | 정보 노출 최소화, 자산 인벤토리 | 공개 자체는 막을 수 없음 — 노출 관리만 가능 |
한 줄 요약의 예: "방어 열이 약하다 — 공격은 기억나는데 짝이 되는 방어가 안 나오는 칸이 네 개였다"처럼 솔직하게. 그 한 줄이 Level 3에서의 학습 우선순위가 됩니다.
검증하는 법: ① 18개 이상, ② 우회 가능성 칸이 전부 채워졌는가(비어 있으면 그 방어를 과신하고 있다는 뜻), ③ 재실습으로 갱신된 칸에 표시가 있는가.
연습문제 해답
문제 1 해답. 완벽한 방어는 없기 때문입니다. 모든 방어에는 우회 가능성이 있고(필터는 우회 페이로드가, 잠금은 스프레이가), 하나의 방어가 뚫리는 순간이 옵니다. 그래서 방어는 여러 겹으로 쌓습니다(심층 방어) — 한 겹이 뚫려도 다음 겹이 남고, 각 겹이 공격자의 비용을 올립니다. "완벽한 한 겹"보다 "불완전한 여러 겹"이 실전의 답입니다.
문제 2 해답. 방어는 적용했다는 사실이 아니라 검증된 결과로 판단해야 한다는 것입니다. 코드에서 헤더를 "덮어썼다"고 믿었지만, 공격자의 눈(curl -sI)으로 확인하니 프레임워크가 쓴 원래 헤더가 그대로 노출돼 있었습니다. 방어는 설정이 아니라 관측으로 완성됩니다 — Step 40의 "믿지 말고 확인하라"와 같은 계명입니다.
문제 3 해답. ① 패스워드 스프레이 — 계정별 시도 횟수 제한을 피하기 위해 비밀번호 하나를 계정 여러 개에 한 번씩만 시도. ② 크리덴셜 스터핑 — 다른 사이트에서 유출된 진짜 id/비번 쌍을 대입해 "추측" 자체를 하지 않음. 둘 다 Step 165의 주제이며, 대응은 전 계정 단위 제한과 MFA, 유출 비밀번호 차단입니다.
문제 4 해답. 의존 관계의 앞쪽부터 갑니다. 예: "권한 상승(125)이 흐릿"과 "시나리오 2(174)가 흐릿"이 함께 나왔다면 174는 125를 쓰는 종합이라 앞의 125부터 재실습해야 합니다. 이 책의 구조가 입구→발판→정착→지배의 사슬이므로, 사슬의 앞 고리부터 메우는 것이 항상 빠릅니다.
완료 기준 체크리스트
- [ ] 공격/원리/방어/우회 가능성 네 칸 형식의 대응표를 18개 이상 완성했다
- [ ] 각 방어의 우회 가능성을 한 줄씩 적었다
- [ ] 방어 헤더 실측으로 "방어는 관측으로 검증"을 확인했다
- [ ] Level 2 열 개 구간을 3단계로 자가 채점했다
- [ ] "흐릿함" 구간의 재실습 목록(스텝 번호)을 만들었다
- [ ] 흐릿한 구간 중 최소 한 개를 실제로 재실습하고 표를 갱신했다
- [ ] 표 맨 아래에 "나의 약한 열" 한 줄 요약을 적었다
6. 흔한 실수와 해결
벽 1. 표를 한 번에 완성하려다 지친다
증상: 18개를 한 자리에서 채우려다 중간에 손이 멈춥니다.
원인: 표는 시험이 아니라 살아있는 문서입니다.
해결: 오늘은 뼈대(3-1의 여덟 줄)와 자가 채점까지만 하고, 나머지는 재실습하면서 며칠에 걸쳐 채우세요. "계속 업데이트되는 표"가 "완벽한 표"보다 가치 있습니다.
벽 2. 방어 칸이 안 채워진다
증상: 공격은 기억나는데 방어가 떠오르지 않습니다.
원인: 정상적인 편향입니다 — 이 책은 공격 관점 책이라 방어는 공격을 뒤집어야 나옵니다.
해결: 공격의 원리 한 줄을 보고 "이 원리의 어느 고리를 끊으면 되는가"로 뒤집어 보세요. SQLi의 원리가 "입력이 쿼리 문법을 바꿈"이면, 끊는 법은 "입력과 문법을 분리(준비된 문장)"입니다. 방어는 공격의 거울입니다.
벽 3. 3-3에서 Server 헤더가 여전히 버전을 보여 준다
증상: 하드닝 코드를 넣었는데도 Server: Werkzeug/3.1.8 Python/3.12.14 줄이 남아 있습니다.
원인: 그것이 정상입니다 — Werkzeug이 자체 헤더를 먼저 쓰고, @after_request는 그 위에 다른 헤더를 추가합니다. 두 줄이 됩니다 (2026-09-09 실측).
해결: 고치려는 시도보다, 이 현상 자체가 오늘의 배움입니다. 운영 환경에서는 앞단 웹 서버(nginx 등)에서 헤더를 지웁니다. "방어를 어떤 층위에서 하느냐"도 대응표의 정보입니다.
벽 4. 자가 채점이 전부 "설명 가능"으로 나온다
증상: 너그러운 채점이 됩니다.
원인: 책을 보며 채점하면 다 아는 것 같습니다.
해결: 책을 덮고, 각 구간의 핵심 기술 하나를 소리 내어 60초 설명해 보세요. 막히면 그것은 "흐릿함"입니다. 엄격함이 이 시험의 전부입니다 — 너그러운 채점은 재실습 목록을 훔칩니다.
벽 5. 흐릿한 구간이 너무 많다
증상: 재실습 목록이 다섯 개를 넘습니다.
원인: 80개 스텝을 한 번에 다 기억하는 사람은 없습니다. 잊는 것은 기본 사양입니다.
해결: 목록을 "다음 스텝 계획표"로 이름 바꾸세요. 앞 고리부터(문제 4의 원칙) 하루 한 구간씩만. 재실습 다섯 번이면 Level 3 시작 전에 전부 메워집니다.
7. 정리
오늘의 개념
| 개념 | 한 줄 설명 |
|---|---|
| 공격/방어 대응표 | 공격·원리·방어·우회 가능성 네 칸 — Level 2의 압축 파일 |
| 양면 사고 | 공격을 보면 방어가, 방어를 보면 우회가 떠오르는 상태 |
| 심층 방어 | 불완전한 여러 겹 > 완벽한 한 겹 |
| 우회 가능성 | 모든 방어 칸에 붙는 꼬리표 — 한계를 아는 것이 전문가 |
| 3단 자가 채점 | 설명 가능 / 실습 가능 / 흐릿함 — 흐릿함은 재실습 예약 |
| 방어의 검증 | 설정했다 ≠ 막힌다 — 공격자의 눈(curl)으로 다시 본다 |
오늘의 명령어
| 명령 | 하는 일 |
|---|---|
curl -sI URL |
응답 헤더만 보기 — 방어(보안 헤더)의 검증 도구 |
명령어보다 중요한 감각
Level 2에서 여러분은 워게임의 첫 플래그부터, 첫 쉘, 웹 공격 전 유형, 네트워크 스푸핑, 그리고 어제의 체인 공격까지 지나왔습니다. 그 긴 목록이 오늘 한 장의 표가 됐습니다. 표가 짧아 보인다고 얕게 본 것이 아닙니다 — 압축됐다는 것은 언제든 다시 펼칠 수 있다는 뜻이고, 그것이 실력입니다.
그리고 이 표의 진짜 용도를 기억하세요. 모의해킹 보고서의 "대응 방안" 장, 면접의 "이 공격을 어떻게 막겠습니까", 방어 구축의 "우선순위" — 전부 이 표의 칸들입니다. 공격자로 배운 것이 방어자의 언어로 번역되는 순간, 여러분은 이 바닥의 양쪽 문법을 다 알게 됩니다.
Level 2, 졸업을 축하합니다. 여러분은 입문자가 아니라 준비된 학습자입니다.
전부 체크되면 Step 175 완료입니다. 사이드바의 체크박스를 눌러 진도를 저장하세요.