📚 네트워크 · 패킷 분석 › 02. 포트 · 프로토콜 분석 — 98편
이전 글: 97. Port 기반 공격 · 다음 글: 99. 서버 1대의 포트 노출 현황 종합 분석
참고(리눅스 시스템 기초): 44. 프로세스 네트워크 연결 점검 — 프로세스 단위 연결 점검 절차
서비스별로 글을 나눠 공부하면 각 내용은 이해되지만, 막상 서버 한 대를 점검하려고 하면 "무엇부터, 어디까지 봐야 하는가" 가 흩어져 있습니다. 점검은 기억이 아니라 목록으로 해야 빠뜨리지 않습니다.
체크리스트가 관제에 주는 이점은 다음과 같습니다.
이 글은 01~22편 내용을 점검 항목 형태로 압축합니다. 각 항목의 원리는 해당 편 링크로 대신합니다. 다음 글(24편)에서는 이 체크리스트로 서버 한 대를 처음부터 끝까지 분석합니다.
좋은 점검 항목은 다음 네 가지를 가집니다.
| 요소 | 예 |
|---|---|
| 점검 대상 | SNMP 서비스 |
| 확인 방법(명령·설정 위치) | ss -ulnp로 161 확인, snmpd.conf의 community·버전 설정 |
| 판정 기준 | v1/v2c 사용 시 기본 community 미사용, 관리망만 허용. 가능하면 v3 |
| 근거 기록 | 명령 출력·설정 파일 해당 줄 |
"SNMP 안전한가? → 예"처럼 기준 없는 항목은 점검이 아니라 감상에 가깝습니다.
| 등급 | 의미 | 예 |
|---|---|---|
| 양호 | 기준 충족 | Telnet 미설치, 23 LISTEN 없음 |
| 취약 | 기준 미충족, 조치 필요 | DB 포트 0.0.0.0 바인드 + 방화벽 전체 허용 |
| 주의 | 기준은 충족하나 보완 권고 | SSH는 관리망만 허용되나 비밀번호 인증 허용 |
| 해당 없음 | 서비스가 존재하지 않음 | SMB 미사용 서버의 SMB 항목 |
| 확인 불가 | 권한·정보 부족 | 네트워크 방화벽 규칙 미열람 |
"확인 불가"를 따로 두는 이유는 확인하지 않은 것을 양호로 적지 않기 위해서입니다.
| 영역 | 핵심 점검 질문 | 관련 편 |
|---|---|---|
| 포트 체계·매핑 | LISTEN 포트마다 프로세스가 확인되는가 | 01·02·20 |
| 웹 | HTTP가 HTTPS로 전환되는가, TLS 버전·인증서가 적절한가 | 04·05·06 |
| DNS | 재귀 질의가 내부로 제한되는가, 외부 DNS 직접 질의가 통제되는가 | 07·08 |
| DHCP | 허가된 DHCP 서버만 응답하는가 | 09·10 |
| 평문 프로토콜 | Telnet·FTP 등 평문 서비스가 없는가 | 11·12 |
| 메일 | 오픈 릴레이가 아닌가, 인증 구간이 암호화되는가 | 13 |
| 원격·공유 | SMB·RDP가 외부에 노출되지 않는가 | 14·15 |
| 관리 프로토콜 | SNMP 버전·community, NTP 동기화 | 16·17 |
| 인증·DB | LDAP 평문 Bind 여부, DB 바인드·계정 허용 호스트 | 18·19 |
| 위장·정책 | 443 이상 통신, 노출 정책 준수 | 21·22 |
점검은 "넓게 → 좁게" 순서로 진행합니다.

그림 1. 수집 → 노출 판단 → 소유 확인 → 위험 요소 → 기록 순서로 점검합니다
① 인벤토리: 어떤 포트가 LISTEN 중인가 (ss -tulnp)
↓
② 식별: 각 포트의 프로세스·실행 파일·패키지·서비스 유닛 (20편 절차)
↓
③ 노출 범위: 바인드 주소(loopback / 특정 IP / 전체) + 호스트 방화벽 허용 범위
↓
④ 정책 대조: 22편 3분류(외부 공개 / 내부 전용 / 노출 금지)와 비교
↓
⑤ 프로토콜별 설정: 아래 체크리스트의 서비스별 항목 확인
↓
⑥ 로그·동기화: 인증 실패 로그 기록 여부, NTP 동기화, 원격 로그 전송
↓
⑦ 판정·기록: 양호 / 취약 / 주의 / 해당 없음 / 확인 불가 + 근거
①~④는 모든 서버에 공통이고, ⑤는 서버에 실제로 있는 서비스만 봅니다. 즉 ①의 결과가 ⑤의 범위를 결정합니다.
실습 환경: 본인 소유 Linux VM (Rocky Linux 또는 Ubuntu). 인터페이스 ens33은 예시입니다. 아래 스크립트는 설정을 바꾸지 않는 읽기 전용 점검 스크립트입니다.
#!/usr/bin/env bash
# port-audit.sh — LISTEN 포트를 읽기 전용으로 점검하는 실습용 스크립트
# 사용: sudo bash port-audit.sh
RISKY=" 21 23 69 111 135 137 138 139 161 445 1433 1521 2375 3306 3389 5432 5900 6379 9200 11211 27017 "
printf "%-5s %-26s %-16s %-10s %s\n" "PROTO" "LOCAL" "PROCESS" "SCOPE" "NOTE"
ss -H -tulnp | while read -r proto state recvq sendq local peer proc; do
port="${local##*:}"
addr="${local%:*}"
pname=$(printf '%s' "$proc" | grep -oP '\(\("\K[^"]+' | head -n1)
case "$addr" in
127.*|"[::1]"|*%lo) scope="loopback" ;;
0.0.0.0|"*"|"[::]") scope="ALL" ;;
*) scope="specific" ;;
esac
note=""
[[ "$RISKY" == *" $port "* ]] && note="위험 포트"
[[ "$scope" == "ALL" && -n "$note" ]] && note="$note / 모든 인터페이스 → 우선 확인"
printf "%-5s %-26s %-16s %-10s %s\n" "$proto" "$local" "${pname:--}" "$scope" "$note"
done
sudo bash port-audit.sh | tee "port-audit-$(hostname)-$(date +%F).txt"
-H(헤더 생략) 옵션은 비교적 최근 iproute2에 있으므로, 없다는 오류가 나면 ss -tulnp | tail -n +2로 대체합니다. 결과 파일을 날짜별로 저장해 두면 다음 점검 때 diff로 변화를 볼 수 있습니다.
# 호스트 방화벽 허용 목록
sudo firewall-cmd --list-all # Rocky
sudo ufw status verbose # Ubuntu
# 활성화된 서비스 유닛 목록 (LISTEN 포트와 대조용)
systemctl list-units --type=service --state=running --no-pager
# 평문 서비스 패키지 설치 여부
rpm -q telnet-server vsftpd 2>/dev/null # Rocky
dpkg -l | grep -E 'telnetd|vsftpd' # Ubuntu
# 시간 동기화
timedatectl | grep -E "synchronized|NTP service"
diff port-audit-web01-2026-09-01.txt port-audit-web01-2026-09-26.txt
📷 [실습 화면 삽입]
port-audit.sh실행 결과 (SCOPE와 NOTE 열이 표시된 화면)
📷 [실습 화면 삽입] 이전 점검 결과와의
diff출력 (새로 생긴 LISTEN 포트가 표시된 화면)
스크립트 출력 형식 예시(값은 환경마다 다름)
PROTO LOCAL PROCESS SCOPE NOTE
udp 127.0.0.53%lo:53 systemd-resolve loopback
udp [::1]:323 chronyd loopback
tcp 0.0.0.0:22 sshd ALL
tcp *:3306 mariadbd ALL 위험 포트 / 모든 인터페이스 → 우선 확인
tcp 127.0.0.1:6379 redis-server loopback 위험 포트
tcp 192.168.10.20:8081 python3 specific
스크립트는 1차 분류일 뿐입니다. 위험 포트라도 loopback이면 외부 노출 위험은 낮고, 반대로 목록에 없는 포트(8081)도 20편 절차로 정체를 확인해야 합니다.
공통
systemctl disable --now)했다원격 접속·관리
public/private) 미사용, 관리망만 허용한다파일·메일·웹
인증·데이터
%가 없다아웃바운드·이상 통신
| 점검 결과 | 정상일 수 있는 경우 | 의심해야 하는 경우 |
|---|---|---|
| 지난 점검 대비 새 LISTEN 포트 | 변경 요청에 따른 신규 서비스 배포 | 변경 기록 없음, 패키지 외 실행 파일 |
| 위험 포트가 loopback에만 바인드 | 로컬 전용 캐시·DB(정상 구성) | 방화벽 포워딩·프록시로 외부에 중계되고 있음 |
프로세스 이름 미표시(-) | 권한 없이 실행했거나 커널 소켓 | root로 실행해도 프로세스를 알 수 없는 LISTEN |
| 실행 중이지만 LISTEN 없는 서비스 | 클라이언트형 서비스(에이전트 등) | 이름과 달리 외부로 연결만 하는 알 수 없는 서비스 |
| 인증 실패 로그가 전혀 없음 | 실제로 실패가 없었음 | 로그 설정이 꺼져 있어 기록되지 않음 |
# 서비스별 최근 인증 실패 기록 여부 (예시)
sudo journalctl -u sshd --since "7 days ago" | grep -c "Failed password" # Rocky
sudo journalctl -u ssh --since "7 days ago" | grep -c "Failed password" # Ubuntu
# 현재 외부로 연결 중인 프로세스
sudo ss -tnp state established | grep -v "127.0.0.1"
"로그가 0건"과 "로그가 기록되지 않음"은 다른 결과입니다. 0건이라면 해당 서비스가 실패를 기록하도록 설정되어 있는지도 함께 확인해 근거에 남깁니다.
위험 포트 표시는 포트 번호 기반 1차 분류입니다. 02편에서 다룬 것처럼 번호만으로 결론 내리지 않고 프로세스로 확인합니다.diff로 변화를 추적합니다.