리눅스 시스템 기초 · 입문편 — 본문의 "N편"은 입문 과정 번호다. 번호별 글과 전체 250편 구성은 통합 로드맵에서 확인할 수 있다.
리눅스 시스템 기초 44 / 50 · Part 5. 네트워크·보안·SOC
실습 환경: Rocky Linux 9 (10.0.0.200) ·ss·ip출력은 실습 컨테이너의 실제 출력 (실습용 서비스만 발췌)
이전 글: 43. Socket 이해
1편에서 서버 상태를 처음 확인할 때 ss -tulnp를 실행했다. 그때는 "열린 포트를 보는 명령" 정도로 넘어갔지만, 41~43편을 거친 지금은 그 출력의 각 칸이 무엇을 뜻하는지 설명할 수 있다.
bind()한 주소다(43편)./proc/PID/fd의 소켓 inode와 연결한 결과다(43편).이번 글은 ss와 ip를 관제 현장에서 쓰는 방식 으로 정리한다. 핵심 질문은 두 가지다.
| 옵션 | 의미 |
|---|---|
-t / -u / -x | TCP / UDP / Unix 소켓 |
-l | 대기(LISTEN) 소켓만. 없으면 연결된 소켓 |
-a | 전부 |
-n | 이름 변환 없이 숫자로 (빠르고 정확) |
-p | 프로세스 표시 (root로 실행해야 전체가 보임) |
-e | 추가 정보 (uid, inode) |
-o | 타이머 정보 (keepalive, TIME-WAIT 남은 시간) |
-s | 요약 통계 |
| Local Address | 접근 범위 | 판단 |
|---|---|---|
127.0.0.1:포트 / [::1]:포트 | 서버 내부에서만 | 외부 노출 없음 |
0.0.0.0:포트 / [::]:포트 / *:포트 | 모든 인터페이스 | 방화벽이 없으면 외부 노출 |
10.0.0.200:포트 | 해당 인터페이스만 | 그 네트워크에서 접근 가능 |
DB(3306, 5432), Redis(6379), Elasticsearch(9200) 같은 내부용 서비스가 0.0.0.0에 열려 있으면 대표적인 설정 취약점이다.
ss -tn state established # 상태
ss -tn '( dport = :22 or sport = :22 )' # 포트
ss -tn dst 203.0.113.50 # 상대 IP
ss -tn src 10.0.0.200 '( dport = :443 )' # 조합
state에는 established, listening, syn-sent, syn-recv, time-wait 등을 쓴다.
| 명령 | 내용 |
|---|---|
ip -br addr | 인터페이스별 IP 요약 |
ip route / ip route get <IP> | 라우팅 표 / 특정 목적지의 실제 경로 |
ip neigh | ARP 이웃 표 (IP ↔ MAC) |
ip -s link | 인터페이스 송수신·에러·드롭 통계 |
netstat, ifconfig, route, arp는 net-tools 패키지로 최신 배포판에는 기본 설치되지 않는다. 같은 정보를 ss와 ip로 볼 수 있다.

실습 환경에서 실습용 서비스 네 개를 띄우고 확인한 실제 출력이다.
$ sudo ss -tulnp
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 0.0.0.0:5514 0.0.0.0:* users:(("python3",pid=2041,fd=3))
tcp LISTEN 0 128 127.0.0.1:22 0.0.0.0:* users:(("sshd",pid=1788,fd=4))
tcp LISTEN 0 5 127.0.0.1:8080 0.0.0.0:* users:(("python3",pid=1790,fd=3))
tcp LISTEN 0 5 0.0.0.0:8081 0.0.0.0:* users:(("python3",pid=2043,fd=3))
| 줄 | 판단 |
|---|---|
udp 5514, 0.0.0.0 | UDP는 연결 상태가 없어 UNCONN. 모든 인터페이스에서 수신 → 외부 노출 |
tcp 22, 127.0.0.1 | sshd가 내부 전용으로 설정됨(실습용 ListenAddress 127.0.0.1) |
tcp 8080, 127.0.0.1 | 내부 전용 |
tcp 8081, 0.0.0.0 | 모든 인터페이스 에 노출. 방화벽 규칙으로 막고 있는지 확인 필요 |
LISTEN 줄의 Send-Q는 대기열(backlog) 최대 크기 다(sshd 128, 파이썬 5). 연결이 수립된(ESTAB) 소켓에서는 아직 상대가 받지 않은 데이터 양을 뜻한다.
ss는 커널의 netlink 인터페이스 로 소켓 정보를 직접 요청한다. /proc/net/tcp를 문자열로 파싱하던 netstat보다 빠르고, 연결이 수만 개인 서버에서도 쓸 수 있다.
# 1) 노출 서비스 목록 (root 로)
sudo ss -tulnp
# 2) 모든 인터페이스에 열린 것만
sudo ss -tulnp | awk 'NR==1 || $5 ~ /^(0\.0\.0\.0|\*|\[::\]):/'
# 3) 현재 수립된 연결 (프로세스 포함)
sudo ss -tnp state established
# 4) 외부(사설 대역이 아닌) 상대와의 연결
sudo ss -tnp state established | awk 'NR>1 {split($4,a,":"); ip=a[1];
if (ip !~ /^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.|127\.)/) print}'
# 5) SSH 접속 현황
ss -tn state established '( sport = :22 )'
who; last -n 5 # 로그인 기록과 대조 (10편)
# 6) 상태별 개수 · 요약
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c
ss -s
# 7) ip
ip -br addr; ip route; ip neigh; ip -s link show eth0
아래 출력은 형식 설명용 예시다.
① 기준값과 비교해 새로 생긴 포트
$ diff <(cut -c1-80 baseline_ss.txt) <(sudo ss -tulnp | cut -c1-80)
> tcp LISTEN 0 128 0.0.0.0:31337 0.0.0.0:* users:(("kworkerd",pid=7811,fd=5))
| 단서 | 해석 |
|---|---|
| 기준값에 없던 포트 31337 | 새로 열린 대기 포트 |
0.0.0.0 | 외부에서 접속 가능 |
이름 kworkerd | 커널 스레드 [kworker]를 흉내 낸 이름. 진짜 커널 스레드는 소켓을 열지 않는다(4·29편) |
→ 바인드 쉘(백도어 대기 포트) 의심. /proc/7811/exe, 부모, 실행 계정을 확인한다.
② 웹 서버 워커의 외부 연결
$ sudo ss -tnp state established dst 203.0.113.50
0 0 10.0.0.200:51844 203.0.113.50:4444 users:(("sh",pid=7900,fd=3))
웹 서버는 요청을 받는 쪽이다. 서버가 외부 IP의 비표준 포트로 먼저 연결 했다면 43편의 리버스 쉘이나 다운로더를 의심한다.
| 점검 | 위험 | 조치 |
|---|---|---|
내부용 서비스가 0.0.0.0 | DB·캐시 외부 노출 (무인증 접근, 랜섬) | bind-address=127.0.0.1 등 설정 + 방화벽 |
| 기준값에 없는 LISTEN | 백도어 | 프로세스 조사 (29·35편) |
| 서버 → 외부 ESTAB | C2, 데이터 유출 | 프로세스·계정 식별, 차단 |
-p 없이 본 결과 | 다른 계정 프로세스가 안 보임 | 반드시 sudo |
ss 결과 자체 | 변조 가능 | /proc/net/tcp 직접 대조 (43편), 외부 스캔과 비교 |
호스트 안의 ss 결과와 밖에서 본 결과는 다를 수 있다. ss는 대기 중인 포트를, 외부 스캔은 방화벽을 통과해 실제로 도달 가능한 포트를 보여준다. 둘 다 확인해야 정확하다.
{
date; ip -br addr; ip route
sudo ss -tulnp
sudo ss -tnp state established
sudo ss -tn state syn-sent # 나가는 연결 실패 (C2 재시도)
} > /root/evidence/net_$(hostname)_$(date +%Y%m%d_%H%M).txt
[Alert] 외부 스캔 결과: 10.0.0.200:31337 open (정기 점검)
↓
[ss] sudo ss -tulnp → 0.0.0.0:31337 kworkerd pid=7811
↓
[프로세스] /proc/7811/exe → /var/tmp/.cache/kworkerd (deleted) · PPID 1 · root
↓
[지속성] systemctl · cron · rc 스크립트 확인 (36·38편)
↓
[Response] STOP → 증적 → 차단·제거, 기준값 갱신
ss -tulnp = TCP·UDP·대기·숫자·프로세스. root로 실행 해야 전체가 보인다.127.0.0.1 = 내부 전용, 0.0.0.0·[::]·* = 모든 인터페이스 (실습 출력으로 비교).state established, '( dport = :22 )', dst <IP>.ip -br addr, ip route, ip neigh, ip -s link가 ifconfig, route, arp를 대체한다.다음 글 「45. SSH 구조 이해」 에서는 관제에서 가장 많이 다루는 원격 접속 서비스 SSH를 본다. 접속 흐름(키 교환 → 인증 → 세션), sshd의 권한 분리 프로세스 구조, 비밀번호와 공개키 인증, sshd_config 보안 설정, 그리고 실습 환경에서 남긴 실제 sshd 로그 를 읽는다.