📚 네트워크 · 패킷 분석 › 02. 포트 · 프로토콜 분석 — 75편
이전 글: 74. NFS · 다음 글: 76. RDP와 3389 포트 — 원격 접속 노출 위험
참고: 66. Telnet과 평문 프로토콜의 위험 — 평문 프로토콜 목록과 대체 프로토콜
SNMP(Simple Network Management Protocol)는 스위치·라우터·방화벽·서버·프린터의 상태를 조회하고 경보를 받는 표준 관리 프로토콜입니다. 네트워크 관리 시스템(NMS)이 트래픽 그래프를 그리고 장비 장애를 알려 주는 것도 대부분 SNMP 덕분입니다.
문제는 오래된 버전(v1, v2c)이 "Community 문자열"이라는 평문 비밀번호 하나로 접근을 통제한다는 점입니다.
public, private)을 바꾸지 않은 장비가 여전히 발견됩니다.그래서 관제에서는 "SNMP가 쓰이는가"보다 "어떤 버전으로, 누가, 어디서 조회하는가" 를 봅니다.
| 구성 요소 | 역할 | 포트 |
|---|---|---|
| Manager (NMS) | 장비에 조회 요청, Trap 수신 | Trap 수신 UDP 162 |
| Agent | 장비 안에서 요청에 응답 | 조회 수신 UDP 161 |
| MIB / OID | 조회 대상 정보의 이름표(트리 구조 번호) | — |
자주 보는 OID (MIB-2 system 그룹)
| OID | 이름 | 내용 |
|---|---|---|
| 1.3.6.1.2.1.1.1.0 | sysDescr | 장비·OS 설명(버전 정보 포함되는 경우 많음) |
| 1.3.6.1.2.1.1.3.0 | sysUpTime | 에이전트 가동 시간 |
| 1.3.6.1.2.1.1.4.0 | sysContact | 관리자 연락처 |
| 1.3.6.1.2.1.1.5.0 | sysName | 장비 이름 |
| 1.3.6.1.2.1.1.6.0 | sysLocation | 설치 위치 |
sysDescr 한 줄만으로도 OS 종류·버전을 알 수 있어, 공격자에게는 정찰 정보가 됩니다.
| 버전 | 인증 | 암호화 | 특징 |
|---|---|---|---|
| v1 | Community 문자열(평문) | 없음 | 최초 버전, 32비트 카운터 |
| v2c | Community 문자열(평문) | 없음 | GetBulk·Inform 추가, 64비트 카운터. 보안은 v1과 동일 |
| v3 | 사용자 기반(USM), HMAC 인증 | 선택(DES, AES) | 보안 수준 3단계 선택, VACM으로 조회 범위 제어 |
v3 보안 수준
| 보안 수준 | 인증 | 암호화 | 권장 |
|---|---|---|---|
| noAuthNoPriv | 사용자 이름만 | 없음 | 사용 지양 |
| authNoPriv | MD5 / SHA 계열 | 없음 | 내용은 평문으로 보임 |
| authPriv | MD5 / SHA 계열 | DES / AES | 권장 (SHA 계열 + AES 조합) |
구현에 따라 SHA-2 계열 인증을 지원하므로, 장비가 지원하는 가장 강한 조합을 선택합니다.
| PDU | 방향 | 의미 |
|---|---|---|
| GetRequest / GetNextRequest | Manager → Agent | 값 하나 / 다음 값 조회 (snmpwalk는 GetNext 반복) |
| GetBulkRequest (v2c 이상) | Manager → Agent | 여러 값을 한 번에 조회, 응답이 요청보다 훨씬 큼 |
| SetRequest | Manager → Agent | 값 변경 (쓰기 권한 필요) |
| Response | Agent → Manager | 응답 |
| Trap / InformRequest | Agent → Manager (162) | 장비가 먼저 보내는 이벤트 알림 (Inform은 수신 확인) |

그림 1. 조회·설정은 161, 이벤트 통보(Trap)는 162
NMS (192.168.10.5) 스위치 Agent (192.168.10.2)
│ │
│── GetRequest C="public" sysName.0 ─── UDP → :161 ──→│ ← v2c: Community 평문
│←─ Response sysName.0 = "sw-core-01" ────────────────│
│ │
│── GetBulkRequest ifTable ... ─────────── UDP → :161 ─→│
│←─ Response (인터페이스 목록·트래픽 카운터 다수) ──────────│ ← 응답이 큼
│ │
│ (포트 다운 발생) │
│←──────────── Trap linkDown ──────────── UDP → :162 ────│ ← 장비가 먼저 알림
↓
NMS: 그래프 갱신, 장애 알림
v2c 요청: [버전=1(v2c)] [Community="public"] [PDU: GetRequest sysName.0]
└─ 평문 ─┘ └──── 평문 ────┘
v3 authPriv 요청:
[버전=3] [USM: 사용자="monuser", 엔진ID, 인증 코드(HMAC)] [암호화된 ScopedPDU]
└─ 사용자 이름은 보임 ─┘ └─ OID·값 안 보임 ─┘
UDP는 출발지 주소를 검증하지 않습니다. 공격자가 출발지를 피해자 IP로 위조해 인터넷에 열린 SNMP Agent에 GetBulk를 보내면, 크기가 큰 응답이 피해자에게 쏟아집니다. 방어는 SNMP를 외부에 노출하지 않고, 조회 허용 IP를 제한하는 것입니다. DDoS 트래픽 분석은 (05. 네트워크 스캔 · 공격 징후 분석 시리즈에서 다룸)
실습 환경: 본인 소유 Linux VM (Rocky Linux 또는 Ubuntu), 인터페이스는 ens33을 예시로 사용합니다. net-snmp Agent를 설치해 루프백에서만 v2c와 v3 조회를 비교합니다.
| 항목 | Rocky Linux | Ubuntu |
|---|---|---|
| Agent / 도구 패키지 | net-snmp / net-snmp-utils | snmpd / snmp |
| 설정 파일 | /etc/snmp/snmpd.conf | /etc/snmp/snmpd.conf |
| v3 사용자 저장 파일 | /var/lib/net-snmp/snmpd.conf | /var/lib/snmp/snmpd.conf |
| 기본 리슨 주소 | 설정 파일 확인 필요 | 기본 설정이 localhost |
# Rocky
sudo dnf install -y net-snmp net-snmp-utils tcpdump
# Ubuntu
sudo apt install -y snmpd snmp tcpdump
/etc/snmp/snmpd.conf를 백업하고, 리슨 주소를 루프백으로 제한합니다(Ubuntu는 이미 agentaddress 항목이 localhost로 되어 있는지 확인만).
agentAddress udp:127.0.0.1:161
배포판 기본 설정에는 조회 범위가 제한된 읽기 전용 public Community가 들어 있는 경우가 많습니다. 설정 파일에서 public이 있는 줄(com2sec 또는 rocommunity)을 확인해 둡니다.
sudo systemctl stop snmpd
# v3 사용자 생성 정보 추가 (Ubuntu는 /var/lib/snmp/snmpd.conf)
echo 'createUser monuser SHA "AuthPass123" AES "PrivPass123"' | sudo tee -a /var/lib/net-snmp/snmpd.conf
# 권한 부여: 읽기 전용, authPriv 이상만 허용
echo 'rouser monuser priv' | sudo tee -a /etc/snmp/snmpd.conf
sudo systemctl start snmpd
sudo ss -ulnp | grep ':161'
createUser 줄은 snmpd가 시작될 때 읽은 뒤 키 값으로 변환되어 사라집니다. 비밀번호는 8자 이상이어야 하며, 실습용 값은 실제로 쓰는 비밀번호와 다르게 정합니다.
# 터미널 1
sudo tcpdump -i lo -nn -v -A 'udp port 161'
# 터미널 2: v2c 조회 (배포판 기본 public Community)
snmpget -v2c -c public 127.0.0.1 1.3.6.1.2.1.1.5.0
snmpwalk -v2c -c public 127.0.0.1 1.3.6.1.2.1.1
# v3 authPriv 조회
snmpget -v3 -l authPriv -u monuser -a SHA -A 'AuthPass123' -x AES -X 'PrivPass123' 127.0.0.1 1.3.6.1.2.1.1.5.0
# 틀린 Community로 조회 (응답 없이 타임아웃되는 것 확인)
snmpget -v2c -c wrongcomm -t 1 -r 0 127.0.0.1 1.3.6.1.2.1.1.5.0
📷 [실습 화면 삽입] tcpdump에서 v2c 요청의
C="public"과 OID가 보이는 부분 vs v3 요청에서 사용자 이름 외에는 알아볼 수 없는 부분
실습이 끝나면 v2c public 줄을 주석 처리하고 v3만 남기거나, snmpd를 중지합니다.
sudo systemctl disable --now snmpd
📷 [실습 화면 삽입] 수정한 snmpd.conf에서
public줄 주석 처리와rouser monuser priv줄
조회 결과 (형식 예시(값은 환경마다 다름))
$ snmpget -v2c -c public 127.0.0.1 1.3.6.1.2.1.1.5.0
SNMPv2-MIB::sysName.0 = STRING: rocky9-lab
$ snmpget -v2c -c wrongcomm -t 1 -r 0 127.0.0.1 1.3.6.1.2.1.1.5.0
Timeout: No Response from 127.0.0.1.
tcpdump -v 출력 (형식 예시(값은 환경·버전마다 다름))
127.0.0.1.41022 > 127.0.0.1.161: { SNMPv2c C="public" { GetRequest(28) R=1837461 .1.3.6.1.2.1.1.5.0 } }
127.0.0.1.161 > 127.0.0.1.41022: { SNMPv2c C="public" { GetResponse(40) R=1837461 .1.3.6.1.2.1.1.5.0="rocky9-lab" } }
127.0.0.1.52100 > 127.0.0.1.161: { SNMPv3 { F=apr } { USM B=3 T=812 U="monuser" } { ScopedPDU ...(암호화되어 OID·값 해석 불가, 표시 형식은 tcpdump 버전마다 다름)... } }
v2c는 Community·OID·값이 모두 보이고, v3 authPriv는 사용자 이름 외 PDU 내용이 암호화되어 해석되지 않습니다. 틀린 Community에는 응답 자체가 없다는 점도 확인합니다(오류 응답을 주지 않음).
점검 체크리스트
sysDescr에 OS·버전 정보가 포함되는지 확인했다public 비활성화 또는 snmpd 중지를 확인했다| 관찰 | 정상일 수 있는 경우 | 의심해야 하는 경우 |
|---|---|---|
| NMS → 장비 161 | 주기적(예: 1~5분 간격) 조회 | NMS가 아닌 일반 PC에서 조회 |
| 한 출발지 → 다수 장비 161 | NMS의 장비 탐색(Discovery) 설정 | 미등록 호스트가 대역 전체에 요청 = SNMP 스캔 (05. 네트워크 스캔 · 공격 징후 분석 시리즈에서 다룸) |
Community public·private 사용 | 없어야 함 | 기본값 그대로 운영 중인 장비 존재 |
| SetRequest | 승인된 설정 자동화 도구 | 미승인 출발지의 Set, 업무 외 시간 |
| 요청 대비 무응답 다수 | 장비 다운 | 여러 Community를 순차 시도(무응답이 계속 발생) |
| 외부 ↔ 161/162 | 없어야 함 | 인터넷에서 조회 가능 = 정보 노출·증폭 반사기 |
| 장비 → 외부 대량 UDP 응답(출발 포트 161) | 없어야 함 | 위조 요청에 응답 중 = 증폭 공격에 이용되는 중 |
# 이 호스트로 SNMP 요청을 보낸 출발지 집계 (게이트웨이·장비 측 캡처 시)
sudo tcpdump -i ens33 -nn -c 200 'udp dst port 161' \
| awk '{split($3,s,"."); print s[1]"."s[2]"."s[3]"."s[4]}' | sort | uniq -c | sort -rn
# v1/v2c 요청의 Community 문자열 확인 (평문이므로 보임)
sudo tcpdump -i ens33 -nn -v -c 50 'udp dst port 161' | grep -o 'C="[^"]*"' | sort | uniq -c
# SetRequest만 보기
sudo tcpdump -i ens33 -nn -v 'udp dst port 161' | grep -i setrequest
# snmpd가 남기는 로그 (배포판·설정에 따라 접속 기록 여부가 다름)
sudo journalctl -u snmpd --since today
흔적이 남는 곳
| 위치 | 남는 정보 |
|---|---|
| 방화벽 | 161/162 UDP 허용·차단, 외부 노출 여부 |
| IDS/IPS | 기본 Community 사용, SNMP 스캔, SetRequest 룰 (06. 방화벽 · IDS/IPS 분석 시리즈에서 다룸) |
| 네트워크 장비 로그 | SNMP 인증 실패 기록·authenticationFailure Trap(장비 설정에 따라) |
| NMS | 조회 실패·장비 응답 없음 경보, 수신한 Trap 이력 |
| 패킷 캡처 | v1/v2c의 Community·OID·값 전체 |
관제 시 핵심 포인트
한계와 오탐 주의
public·private 사용은 즉시 개선 대상입니다.다음 글: 17. NTP와 로그 시간 동기화