Step 172. ★ 종합 시나리오 1 — 정찰부터 쉘까지

Step 172. ★ 종합 시나리오 1 — 정찰부터 쉘까지

Level 2 — 보안 입문과 공격 스킬 기초 | 난이도 ★★★★☆ | 예상 소요 시간 4시간

전제: Step 113~119(정찰, nmap, netcat, 쉘), Step 130(타임어택 모의 침투), Step 164(열거 자동화)를 마쳤다.

  • 준비물: 리눅스 랩(WSL 또는 Kali, nmap·nc·파이썬 포함), 타이머, 기록용 텍스트 파일. 취약 VM(Metasploitable2나 VulnHub Easy)이 있으면 본편 랩으로 씁니다.
  • ⚠️ 이 챕터의 실습은 내 랩·합법 플랫폼 전용입니다. 허가 없는 시스템에 적용하면 범죄입니다.
  • 성격 안내: 오늘은 [프로젝트] 챕터입니다. 새 기술이 없습니다 — 지금까지 배운 것을 하나의 흐름으로 잇는 것이 목표입니다.

지금까지 우리는 기술을 낱개로 배웠습니다 — nmap은 nmap, 쉘은 쉘. 그런데 대회와 모의해킹의 실제 형태는 다릅니다: IP 하나만 받고 시작해서, 쉘을 얻을 때까지 혼자 간다. 오늘은 그 전 과정을 시간을 재며 수행합니다. 기술보다 중요한 것은 "흐름을 잃지 않는 것" — 막혔을 때 다음 가설로 넘어가는 판단, 그리고 무엇을 언제 했는지 남기는 기록입니다. 먼저 여러분 컴퓨터 안에서 100% 재현 가능한 미니 체인으로 전체 흐름을 몸에 익히고, 그다음 진짜 랩 머신에 같은 흐름을 적용합니다.


1. 학습 목표

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

  • 정찰 → 스캔 → 열거 → 가설 → 검증 → 쉘의 킬 체인을 독립 수행한다
  • 서비스가 닫혀 있을 때와 열려 있을 때의 nmap 출력 차이를 읽는다
  • nmap의 버전 탐지가 대상에게 "말을 거는" 행위임을 서버 로그로 증명한다
  • 막혔을 때 체크리스트로 회귀하는 습관을 몸에 댄다
  • 각 단계의 시각과 한 일을 타임라인으로 기록한다

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

오늘의 도구 한눈에 보기

구분 내용
언어·환경 리눅스 쉘(WSL/Kali), 파이썬 3 (미니 취약 서비스용)
오늘의 명령 nmap -sV, nc -v 대상 포트, tee, date
필요한 개념 킬 체인, 공격 가설의 우선순위, 30분 규칙, 타임라인 기록
오늘의 산출물 미니 체인 완주 기록 + (랩 있으면) IP→쉘 타임라인 로그

2-1. 킬 체인 — 하나의 흐름으로 묶기

침투의 표준 흐름은 이렇습니다.

정찰(recon)   → 대상이 무엇을 열어 두었나 — nmap
열거(enum)    → 각 서비스의 정체와 버전 파악 — 배너, -sV
가설          → "이 서비스의 이 버전이라면, 이 공격이 통할 것"
검증          → 가장 유망한 가설부터 시도
쉘 획득       → 명령 실행 권한 확보 → 증거(id 출력) 확보
기록          → 전 과정의 시각·명령·결과를 타임라인으로

각 단계는 따로 배웠습니다. 오늘의 과제는 사이사이의 연결입니다 — 스캔 결과가 열거 질문을 만들고, 열거가 가설을 만들고, 가설이 다음 명령을 만드는 흐름입니다.

2-2. 가설의 우선순위와 30분 규칙

포트가 다섯 개 열려 있으면 가설도 다섯 개입니다. 전부 동시에 검증할 수 없으니 순서를 정합니다 — 기준은 "알려진 취약점이 있는가, 인증이 없는가, 낡았는가". 그리고 하나에 얼마나 매달릴지의 규칙이 필요합니다: 한 가설에 30분 이상 묶이지 않기. 30분이 지나면 메모를 남기고 다음 가설로 갑니다. 막힌 곳에 갇히는 것이 타임어택의 최대 원인입니다.

2-3. 막히면 정찰로 회귀 — 90%는 놓친 단서

침투가 안 풀릴 때 원인의 대부분은 익스플로잇이 아니라 정찰에서 놓친 것입니다. 회귀 체크리스트:

□ 포트를 전부 봤나? (-p- 로 65535개)
□ UDP는 봤나? (-sU)
□ 웹이면 경로 스캔을 했나? (gobuster/dirb)
□ 서비스 버전으로 취약점 검색을 했나? (searchsploit)
□ 배너가 거짓말을 하지는 않나? (직접 접속해 확인)

이 다섯 질문으로 풀리는 문제가 경험상 절반 이상입니다.

2-4. 오늘의 랩 구조 — 두 개의 단계

1단계는 미니 체인입니다 — 여러분의 리눅스 랩에 직접 만드는 "취약 서비스"를 상대로 정찰부터 명령 실행까지 전 흐름을 20분 안에 돌립니다. 외부 대상이 없어도 체인의 모양은 같습니다. 2단계는 본편 랩입니다 — 취약 VM이 있는 분은 같은 흐름을 실제 머신에 적용하고 타임라인을 기록합니다. 없는 분은 1단계의 기록을 완성하고, 본편 구간은 계획서로 작성합니다.


3. 따라 하기

3-1. 미니 "취약 서비스" 만들기

훈련용 표적을 직접 만듭니다. 127.0.0.1에만 귀를 여는, 허가된 안전 명령 네 개만 실행하는 작은 서버입니다 — 실제 취약 서비스의 "인증 없이 명령을 받는다"는 성격만 흉내 냅니다.

입력: minivuln.py:

# 127.0.0.1 전용 훈련 서비스 — 허가된 안전 명령만 실행
import socket, subprocess

ALLOWED = ["whoami", "id", "hostname", "uname"]

srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(("127.0.0.1", 9000))
srv.listen(5)
srv.settimeout(120)
print("mini-vuln listening on 127.0.0.1:9000", flush=True)

while True:                                   # 스캐너의 탐지 연결도 받고 다음을 기다림
    try:
        conn, addr = srv.accept()
    except socket.timeout:
        break
    conn.settimeout(3)
    conn.sendall(b"MiniVulnService 1.0 ready\n$ ")
    try:
        data = conn.recv(1024).decode(errors="ignore").strip()
    except socket.timeout:
        data = ""
    print("received:", repr(data), flush=True)   # 서버 측 로그 — 누가 무엇을 물었나
    cmd = data.split()[0] if data else ""
    if cmd in ALLOWED:
        out = subprocess.run(data.split(), capture_output=True, text=True).stdout
        conn.sendall(out.encode())
    else:
        conn.sendall(b"command not allowed\n")
    conn.close()
srv.close()

읽는 법: print("received:", ...)가 오늘의 숨은 주인공입니다 — 서버 측에서 누가 무슨 짓을 했는지 전부 보이게 하는 로그입니다. 공격 실습이면서 동시에 방어자의 눈 실습입니다.

3-2. 정찰 — 닫힌 문과 열린 문

먼저 서비스를 켜기 전에 스캔해 봅니다.

입력 (리눅스 랩):

nmap -p 9000 127.0.0.1

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

Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-09-09 16:52 KST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.000059s latency).

PORT     STATE  SERVICE
9000/tcp closed cslistener

Nmap done: 1 IP address (1 host up) scanned in 0.06 seconds

이제 서비스를 켜고 버전 탐지까지 걸어 봅니다.

입력:

python3 minivuln.py > server.log 2>&1 &
sleep 1
nmap -p 9000 -sV 127.0.0.1

출력 (2026-09-09 실측, 핵심 부분):

PORT     STATE SERVICE     VERSION
9000/tcp open  cslistener?
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port9000-TCP:V=7.94SVN%I=7%D=9/9%...%r(NULL,1C,"MiniVulnService\x201\.0\x20ready\n\$\x20")...

읽는 법: closedopen으로 바뀌었습니다. 그리고 -sV가 서비스를 모르자 배너 지문을 통째로 보여 줍니다 — MiniVulnService 1.0 ready라는 우리가 심어 둔 문구가 그대로 읽혔습니다. 정찰의 수확입니다: 포트 9000, 열림, 정체 불명의 서비스, 배너 확보.

3-3. 스캐너의 발자국 — 서버 로그 열기

스캔이 끝난 뒤 서버 쪽 로그를 열어 봅니다.

입력:

head -20 server.log

출력 (2026-09-09 실측, 일부 발췌):

mini-vuln listening on 127.0.0.1:9000
received: ''
received: 'GET / HTTP/1.0'
received: 'OPTIONS / HTTP/1.0'
received: 'OPTIONS / RTSP/1.0'
received: 'HELP'
received: 'GET /nice%20ports%2C/Tri%6Eity.txt%2ebak HTTP/1.0'
received: 'OPTIONS sip:nm SIP/2.0\r\nVia: SIP/2.0/TCP nm;branch=foo...'

읽는 법: 놀랍지 않습니까? 우리는 스캔 한 번을 쳤는데, 서버가 받은 것은 수십 개의 서로 다른 인사입니다 — HTTP인 척, RTSP인 척, SIP인 척. nmap의 버전 탐지는 "너 누구니?"라고 하나로 묻는 게 아니라, 알려진 프로토콜마다 말을 걸어 보고 어떤 대답이 돌아오는가로 정체를 맞힙니다. 공격자 관점에서는 "정찰은 생각보다 시끄럽다"가, 방어자 관점에서는 "로그만 봐도 스캔이 보인다"가 되는 실측 장면입니다.

왜 하는가: 공격 기술 챕터에서 방어자의 눈을 얻는 것은 덤이 아니라 핵심입니다. 내 공격이 상대 로그에 어떻게 찍히는지 아는 사람만이 조용한 정찰과 요란한 정찰을 구분합니다.

3-4. 검증과 쉘 — nc로 명령 실행

정찰 결과 "인증 없이 명령을 받는 서비스"라는 가설이 섰습니다. 검증합니다.

입력:

printf "id\n" | nc -v -w 3 127.0.0.1 9000
printf "whoami\n" | nc -v -w 3 127.0.0.1 9000

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

Connection to 127.0.0.1 9000 port [tcp/*] succeeded!
MiniVulnService 1.0 ready
$ uid=0(root) gid=0(root) groups=0(root)
Connection to 127.0.0.1 9000 port [tcp/*] succeeded!
MiniVulnService 1.0 ready
$ root

읽는 법: 가설이 맞았습니다 — 인증 없이 id를 실행하고 결과를 돌려받았습니다. 이것이 "쉘"의 본질입니다: 원격에서 명령을 넣고 출력을 받는 통로. Step 118~119에서 배운 바인드/리버스 쉘과 모양은 달라도 의미는 같습니다. 그리고 uid=0(root) — 이 서버는 root로 돌고 있었습니다. 실제 랩이라면 이 한 줄이 최고 권한 획득의 증거입니다.

정리 명령 (실험 종료 후 서버 끄기):

pkill -f minivuln.py

3-5. 타임라인 기록 — 미니 체인의 모범 형태

방금 한 일을 타임라인으로 적습니다. 틀:

16:52:00  정찰 시작 — nmap -p 9000 127.0.0.1 → closed (서비스 미기동 확인)
16:52:30  재스캔 — nmap -p 9000 -sV → open, 배너 "MiniVulnService 1.0" 획득
16:53:00  가설 — 인증 없이 명령을 받는 서비스일 것
16:53:30  검증 — nc 접속, id 실행 → uid=0(root) 획득 확인
16:54:00  증거 저장 — 출력을 evidence/에 tee로 보관
16:54:30  종료 — 서버 정지, 타임라인 완성 (소요 2분 30초)

읽는 법: 각 줄은 "시각 + 한 일 + 결과"입니다. 이 형식이 그대로 Step 173 복기와 보고서의 뼈대가 됩니다. 기록은 침투의 부산물이 아니라 절반의 산출물입니다.

3-6. 본편 랩 — 실제 취약 VM에 적용

취약 VM이 있는 분은 타이머를 켜고 같은 흐름을 적용합니다.

0:00  풀스캔: nmap -p- -sV 대상IP -oN scan_full.txt
      → 열린 포트 전부와 버전 목록 확보 (이 파일이 정찰의 뼈대)
      열거: 포트별로 서비스 정체 확인 — 웹이면 경로 스캔까지
      가설: 버전별 알려진 취약점 검색(searchsploit), 우선순위 매기기
      검증: 가장 유망한 가설부터 — 30분 규칙 적용
      쉘:  획득 즉시 id / whoami 출력을 증거로 저장
      기록: 각 단계 시각을 타임라인에 계속 추가

랩이 없는 분은 각 칸에 "내 랩이라면 어떤 명령을 칠 것인가"를 계획서로 작성하고, 3-2~3-5의 미니 체인 실측 기록을 증거로 붙입니다. 출력을 꾸며 내지 마세요 — 계획은 계획, 실측은 실측으로 표시하는 것이 이 훈련의 정직성 규칙입니다.


4. 미션과 연습문제

미션 — IP에서 쉘까지, 타임라인과 함께

  1. 미니 체인(3-1~3-5)을 처음부터 끝까지 혼자 재현하고 타임라인을 완성합니다
  2. (랩 보유 시) 취약 VM 1대를 상대로 풀스캔 → 열거 → 가설 → 쉘까지 완주하고, 각 단계 시각을 기록합니다
  3. 타임라인에 "시간을 가장 많이 쓴 구간"과 그 이유를 한 줄로 적습니다
  4. 서버 로그(server.log)에서 nmap이 남긴 흔적을 세 줄 이상 인용합니다
  5. (랩 미보유 시) 본편 계획서를 작성하되, 실측이 아닌 부분에 [랩 실행 후 실측으로 교체 예정] 표시를 답니다

연습문제

문제 1. 정찰 없이 익스플로잇부터 시도하는 것이 왜 비효율적인지, 3-2의 스캔 출력 변화를 근거로 설명해 보세요.

문제 2. 3-3의 서버 로그가 보여 주듯 버전 탐지는 시끄럽습니다. 이 사실이 공격자와 방어자에게 각각 무엇을 의미하는지 설명해 보세요.

문제 3. 30분 규칙이 "포기하라"는 뜻이 아닌 이유를 설명해 보세요.

문제 4. 타임라인의 각 줄이 "시각 + 한 일 + 결과" 세 요소를 갖춰야 하는 이유를, Step 173의 복기와 연결해 설명해 보세요.


5. 모범 답안과 완료 기준

미션 모범 답안

완성된 타임라인의 실측 예시 (2026-09-09 미니 체인):

16:52  정찰 — 닫힘 확인 후 서비스 기동, 재스캔에서 open + 배너 획득
16:53  가설 수립 — "인증 없는 명령 실행 서비스"
16:53  검증 성공 — nc로 id 실행, uid=0(root) 확인
16:54  증거 저장 및 종료
시간을 가장 많이 쓴 구간: 첫 시도에서 nmap -sV가 서버의 단일 연결을 소모해
nc 접속이 실패 — 서버를 반복 수락 구조로 고치는 데 쓴 시간이 가장 김.

마지막 문장이 중요합니다 — 막힌 곳과 돌파 과정이 기록에 있어야 그것이 배움이 됩니다. 이 문장은 Step 173 보고서에서 "독자가 같은 함정을 피해 가는 문장"으로 재탄생합니다.

검증하는 법: ① 타임라인에 모든 단계의 시각이 있는가. ② 쉘 증거에 id 또는 whoami 출력이 있는가. ③ server.log 인용이 세 줄 이상인가. ④ 막힌 구간과 돌파가 기록돼 있는가. ⑤ 미실측 부분은 표시가 있는가. 전부 ‘예’이면 완주입니다.

연습문제 해답

문제 1 해답. 3-2에서 같은 포트가 서비스 기동 전에는 closed, 후에는 open으로 갈렸습니다 — 즉 두드려 볼 가치가 있는 문인지조차 정찰이 알려 줍니다. 정찰 없는 익스플로잇은 닫힌 문에 열쇠를 꽂는 격이고, 열려 있어도 버전을 모르면 어떤 공격이 맞는지 알 수 없습니다. 정찰은 시간을 쓰는 것이 아니라 시간을 아끼는 단계입니다.

문제 2 해답. 공격자에게는 "정찰 단계에서 이미 로그에 흔적이 남는다"는 경고입니다 — 수십 개 프로토콜 인사가 전부 기록됩니다. 방어자에게는 "로그를 읽으면 스캔이 보인다"는 기회입니다 — 정상 사용자는 SIP도 RTSP도 아닌 인사를 한 포트에 하지 않습니다. 같은 로그가 양쪽에 다른 교훈을 줍니다.

문제 3 해답. 30분 규칙은 그 가설을 버리는 것이 아니라 뒤로 미루는 것입니다. 메모를 남기고 다른 가설을 검증하는 동안 시야가 넓어지고, 나중에 새 단서를 들고 돌아올 수 있습니다. 타임어택에서의 적은 "못 푸는 문제"가 아니라 "한 문제에 갇힌 시간"입니다.

문제 4 해답. 복기는 기억이 아니라 기록으로 하는 것입니다. 시각이 있어야 "어디서 시간을 썼나"를 분석할 수 있고, 한 일과 결과가 있어야 "무엇이 통하고 무엇이 안 통했나"를 재구성할 수 있습니다. 세 요소가 갖춰진 타임라인은 그대로 보고서의 침투 경로 절의 초고가 됩니다 — 오늘의 기록이 내일의 문서입니다.

완료 기준 체크리스트

  • [ ] 킬 체인 여섯 단계를 순서대로 말할 수 있다
  • [ ] 서비스 on/off에 따른 nmap 출력 차이를 실측했다
  • [ ] -sV가 남긴 배너 지문 출력을 읽을 수 있다
  • [ ] 서버 로그에서 스캐너의 흔적을 찾아 인용했다
  • [ ] nc로 명령을 실행하고 id 출력을 확보했다
  • [ ] 미니 체인 타임라인을 완성했다
  • [ ] 30분 규칙과 회귀 체크리스트를 자기 말로 쓸 수 있다
  • [ ] (랩) IP→쉘 완주 또는 (무 랩) 계획서+표시 완료

6. 흔한 실수와 해결

벽 1. nc: connect to 127.0.0.1 port 9000 (tcp) failed: Connection refused가 난다

증상 (2026-09-09 실측, 서버 없이 접속한 경우):

nc: connect to 127.0.0.1 port 9000 (tcp) failed: Connection refused

원인: 듣는 서비스가 없습니다 — 3-2의 closed 상태 그대로입니다.
해결: 서버를 먼저 켜세요(python3 minivuln.py &). 실제 랩에서 이 메시지가 나오면 "그 포트는 문이 닫혔다"는 정찰 결과입니다 — 다른 포트로 가세요.

벽 2. 스캔 후에 nc 접속이 먹통이 된다

증상: nmap -sV 직후 nc로 접속하면 아무 응답이 없습니다.
원인 (2026-09-09 실측으로 확인): 서버가 연결을 하나만 받는 구조면, nmap의 버전 탐지가 그 연결을 먼저 써 버립니다.
해결: 3-1처럼 서버를 반복 수락(while True: accept()) 구조로 만드세요. 스캐너의 탐지 연결도 받고 다음 손님을 기다려야 합니다. 이 벽 자체가 "스캔이 대상에게 말을 건다"는 증거입니다.

벽 3. 풀스캔이 너무 오래 걸려 포기한다

증상: nmap -p-가 십 분째입니다.
원인: 65535개 포트 전수 조사는 원래 느립니다 — 특히 기본 옵션으로는.
해결: 두 단계로 나누세요 — 먼저 빠른 전체 조사(-p- 최소 속도 옵션)로 열린 포트만 찾고, 찾은 포트에만 -sV를 거는 것이 실무 패턴입니다. 처음부터 정밀 조사를 전 포트에 거는 것이 시간 도둑입니다.

벽 4. 쉘을 얻고 나서 무엇을 했는지 기억이 없다

증상: 완주했는데 타임라인이 비어 있습니다.
원인: 기록을 "나중에"로 미룬 것입니다 — 흥분 상태에서는 절대 안 써집니다.
해결: 명령을 칠 때마다 한 줄씩 바로 적으세요. tee로 출력을 파일에 남기는 습관(Step 126)이 증거를 자동으로 모아 줍니다. 기록 없는 완주는 반쪽짜리입니다 — Step 173에서 쓸 것이 없어집니다.

벽 5. 미니 체인을 "장난감"이라 건너뛴다

증상: 실제 VM만 하겠다며 3-1~3-5를 생략합니다.
원인: 목적 오해입니다 — 미니 체인은 대상이 아니라 흐름의 연습대입니다.
해결: 20분만 투자하세요. 실제 랩에서 막혔을 때 회귀할 "정상 동작의 기준"이 미니 체인의 실측 출력들입니다. 기준이 있어야 "뭐가 다른가"를 볼 수 있습니다.


7. 정리

오늘의 개념

개념 한 줄 설명
킬 체인 정찰→열거→가설→검증→쉘→기록 — 침투의 표준 흐름
공격 가설 "이 서비스의 이 버전이라면 이 공격" — 검증 전의 문장
30분 규칙 한 가설에 갇히지 않기 — 미루고 다음으로
회귀 체크리스트 막히면 정찰로 — 놓친 단서가 원인의 90%
타임라인 시각+한 일+결과의 기록 — 침투의 절반의 산출물
스캐너의 발자국 버전 탐지는 수십 번의 인사 — 대상 로그에 남는다

오늘의 명령어·도구

도구 하는 일
nmap -p- 대상IP 전 포트 조사 (느림 — 2단계 전략의 1단계)
nmap -p 포트 -sV 대상IP 버전 탐지 — 배너 지문 획득
nc -v 대상 포트 손으로 서비스와 대화하기
pkill -f 스크립트명 실험 서버 정리
tee 파일 출력을 화면과 파일에 동시에 — 증거 습관
minivuln.py 127.0.0.1 전용 훈련 서비스 — 체인 연습대

명령어보다 중요한 감각

오늘 여러분은 기술이 아니라 흐름을 연습했습니다. 정찰이 가설을 만들고, 가설이 다음 명령을 만들고, 모든 것이 기록으로 남는 사슬 — 이 사슬이 몸에 붙으면 낯선 머신을 만나도 할 일이 보입니다. 그리고 서버 로그가 보여 준 진실을 잊지 마세요: 공격의 첫 명령부터 대상은 보고 있었습니다. 조용한 정찰과 요란한 정찰의 차이를 아는 것, 그리고 자기 행동이 로그에 어떻게 찍히는지 아는 것 — 그것이 실력의 절반이고, 나머지 절반은 기록입니다.


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