리눅스 시스템 기초 · 입문편 — 본문의 "N편"은 입문 과정 번호다. 번호별 글과 전체 250편 구성은 통합 로드맵에서 확인할 수 있다.

리눅스 시스템 기초 42 / 50 · Part 5. 네트워크·보안·SOC
실습 환경: Rocky Linux 9 (10.0.0.200) · handshake 캡처와 ss 상태는 실습 컨테이너의 실제 출력
이전 글: 41. Linux 네트워크 구조

1. 들어가며

41편에서 패킷이 NIC → IP → TCP/UDP → 소켓 → 프로세스로 전달되는 전체 경로를 봤다. 이번 글은 그중 IP(L3)와 TCP/UDP(L4) 를 자세히 본다.

관제 로그의 대부분은 결국 다음 다섯 값으로 요약된다.

출발 IP · 출발 포트 · 목적지 IP · 목적지 포트 · 프로토콜 (5-tuple)

방화벽 로그, IDS 경보, ss 출력, sshd 로그 모두 이 값들을 담고 있다. 이 값의 의미와 TCP 연결 과정을 알아야 "이 연결은 누가 시작했는가", "연결이 실제로 성립했는가"를 판단할 수 있다.


2. 핵심 개념

2-1. IP 주소

구분대역의미
사설 IP10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16내부망. 인터넷에서 직접 라우팅되지 않음
루프백127.0.0.0/8자기 자신
문서용192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24예시·실습용 (이 시리즈의 외부 IP 예시)
공인 IP그 외인터넷 주소

/24 같은 CIDR 표기는 앞 24비트가 네트워크 부분이라는 뜻이다. 10.0.0.200/24는 10.0.0.0 ~ 10.0.0.255가 같은 네트워크다.

관제에서 출발지가 사설 IP인 공격 은 특히 중요하다. 외부 공격이 아니라 이미 내부에 들어온 공격자의 횡적 이동(Lateral Movement) 일 수 있기 때문이다(49·50편 시나리오의 10.0.0.128).

2-2. 포트

포트는 한 IP 안에서 어느 프로세스(서비스)로 보낼지 를 정하는 번호(0~65535)다.

범위이름예
0–1023잘 알려진 포트 (root만 바인딩 가능)22 SSH, 25 SMTP, 53 DNS, 80 HTTP, 443 HTTPS
1024–49151등록 포트3306 MySQL, 5432 PostgreSQL, 8080 대체 HTTP
32768–60999임시 포트 (Linux 기본)클라이언트가 접속할 때 자동 할당

cat /proc/sys/net/ipv4/ip_local_port_range로 임시 포트 범위를, /etc/services로 포트 이름을 확인할 수 있다. 포트 번호만으로 서비스를 단정하면 안 된다. 공격자는 443이나 53처럼 흔한 포트로 다른 프로토콜을 쓰기도 한다.

2-3. TCP와 UDP

항목TCPUDP
연결3-way handshake로 연결 수립연결 없음
신뢰성순서 보장, 손실 시 재전송보장 없음
속도·부하상대적으로 무거움가벼움
용도SSH, HTTP(S), DBDNS, NTP, syslog(514), 스트리밍
위조handshake 때문에 출발 IP 위조가 어려움출발 IP 위조 쉬움 (반사·증폭 공격)

3. 동작 원리

TCP 3-way handshake와 연결 상태 — 실제 캡처로 보기

실습 환경에서 curl http://127.0.0.1:8080/를 실행하며 tcpdump로 캡처한 실제 패킷이다(타임스탬프와 옵션 일부 생략).

$ sudo tcpdump -i lo -nn 'tcp port 8080'
127.0.0.1.55972 > 127.0.0.1.8080: Flags [S],  seq 2106989631, win 65495, length 0
127.0.0.1.8080 > 127.0.0.1.55972: Flags [S.], seq 1862633251, ack 2106989632, length 0
127.0.0.1.55972 > 127.0.0.1.8080: Flags [.],  ack 1, length 0
127.0.0.1.55972 > 127.0.0.1.8080: Flags [P.], seq 1:78, ack 1, length 77: HTTP: GET / HTTP/1.1
127.0.0.1.8080 > 127.0.0.1.55972: Flags [P.], seq 1:158, ack 78, length 157: HTTP: HTTP/1.0 200 OK
...
127.0.0.1.8080 > 127.0.0.1.55972: Flags [F.], seq 4614, ack 78, length 0
줄의미
[S]클라이언트(임시 포트 55972)가 연결 요청. 초기 순서 번호 2106989631
[S.]서버가 수락(SYN+ACK). ack 2106989632 = 상대 번호 + 1
[.]클라이언트가 확인. 여기서 연결 수립(ESTABLISHED)
[P.]데이터 전송 (HTTP 요청 77바이트 → 응답)
[F.]서버가 먼저 종료 요청 (HTTP/1.0 서버라 응답 후 바로 닫음)

tcpdump는 handshake 이후 순서 번호를 상대값 (ack 1, seq 1:78)으로 보여준다.

TCP 상태 전이. 연결 직후 ss로 본 실제 상태다.

$ ss -tan '( sport = :8080 or dport = :8080 )'
State     Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN    0      5          127.0.0.1:8080      0.0.0.0:*
TIME-WAIT 0      0          127.0.0.1:8080    127.0.0.1:38102

먼저 연결을 닫은 쪽 에 TIME-WAIT이 약 60초 남는다(늦게 도착하는 패킷을 처리하기 위함). 이번에는 서버가 먼저 닫았으므로 서버 포트 8080 쪽에 남았다.

상태의미관제에서
LISTEN접속 대기열린 서비스 목록 (44편)
SYN-SENT요청 보냄, 응답 대기외부로 계속 SYN만 → 스캔·C2 연결 실패
SYN-RECVSYN 받고 SYN+ACK 보냄대량이면 SYN flood
ESTABLISHED연결 수립실제 통신 중
TIME-WAIT먼저 닫은 쪽이 대기대량이면 짧은 연결이 많음
CLOSE-WAIT상대가 닫았는데 내가 안 닫음대량이면 애플리케이션 버그

닫힌 포트에 SYN을 보내면 커널이 RST로 응답한다. 방화벽이 조용히 버리면(DROP) 응답이 없다. 포트 스캐너는 이 차이로 포트 상태(open / closed / filtered)를 판단한다.


4. 실습

# 1) 잘 알려진 포트 이름
grep -wE '^(ssh|http|https|domain|ntp|syslog)' /etc/services

# 2) 임시 포트 범위
cat /proc/sys/net/ipv4/ip_local_port_range

# 3) handshake 관찰 (터미널 2개)
sudo tcpdump -i lo -nn 'tcp port 8080'          # 터미널 A
python3 -m http.server 8080 --bind 127.0.0.1 &  # 터미널 B
curl -s -o /dev/null http://127.0.0.1:8080/

# 4) TCP 상태별 개수
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c

# 5) 닫힌 포트에 대한 응답 (RST) 관찰
sudo tcpdump -i lo -nn 'tcp port 9999' &
curl -s http://127.0.0.1:9999/ ; echo "exit=$?"   # exit=7 (연결 거부)

# 6) UDP 대기 소켓
ss -ulnp

5. 결과 분석

아래 출력은 형식 설명용 예시다.

① 포트 스캔 흔적 (tcpdump)

10.0.0.128.41022 > 10.0.0.200.21:   Flags [S]
10.0.0.200.21 > 10.0.0.128.41022:   Flags [R.]      ← 닫힘
10.0.0.128.41022 > 10.0.0.200.22:   Flags [S]
10.0.0.200.22 > 10.0.0.128.41022:   Flags [S.]      ← 열림
10.0.0.128.41022 > 10.0.0.200.22:   Flags [R]       ← 연결 완성 없이 끊음
10.0.0.128.41022 > 10.0.0.200.23:   Flags [S]
...

같은 출발 포트에서 목적지 포트만 바뀌며 SYN 이 이어지고, 열린 포트에는 handshake를 끝내지 않고 RST로 끊는다. 전형적인 SYN 스캔 이다. 출발지가 사설 IP(10.0.0.128)이므로 내부 호스트가 이미 장악되었을 가능성을 함께 본다.

② 상태 분포

  1520 SYN-RECV
    38 ESTAB
     6 LISTEN

SYN-RECV가 비정상적으로 많다 → handshake를 끝내지 않는 대량 요청(SYN flood) 의심. sysctl net.ipv4.tcp_syncookies(기본 1)가 켜져 있는지 확인한다.


6. 보안 관점

관찰의미대응
한 IP → 여러 포트 SYN포트 스캔 (T1046)출발지 확인, 방화벽 차단
여러 IP → 한 포트 SYN 대량SYN floodsyncookies, 상위 장비 차단
내부 IP 출발 스캔횡적 이동 준비출발 호스트 침해 조사
서버 → 외부 비표준 포트 ESTABC2 통신 가능성프로세스 식별 (44편)
흔한 포트로 다른 프로토콜탐지 회피 (예: 443으로 비 TLS)포트가 아닌 프로세스 로 판단
UDP 출발 IP위조 가능UDP 로그의 IP는 신뢰도 낮음

7. SOC / 보안관제 활용

7-1. 방화벽 로그 한 줄 읽기

SRC=10.0.0.128 DST=10.0.0.200 PROTO=TCP SPT=41022 DPT=23 FLAGS=SYN ACTION=DROP
필드해석
SRC / SPT누가 (임시 포트)
DST / DPT어디의 어떤 서비스 (23 = telnet)
FLAGS=SYN연결 시도 (성립 여부는 아직 모름)
ACTION=DROP차단됨

SYN만 있는 기록은 "시도"다. 실제 연결이 성립했는지는 ESTABLISHED 기록이나 서버 측 로그(sshd Accepted, 웹 로그)로 확인해야 한다.

7-2. 분석 흐름

[Alert]   IDS: 10.0.0.128 → 10.0.0.0/24 다수 호스트 · 다수 포트 SYN (02:05)
   ↓
[판단 1]  사설 IP 출발 → 외부 공격이 아니라 내부 호스트의 스캔
   ↓
[서버]    10.0.0.200 에서 22번만 SYN+ACK → 노출 서비스는 SSH
   ↓
[후속]    02:10부터 secure 에 10.0.0.128 Failed password 급증 (49편)
   ↓
[Response] 10.0.0.128 격리·조사, 22번 접근을 관리망으로 제한 (46편)

8. 핵심 정리

  • 관제 로그의 기본 단위는 5-tuple: 출발 IP·포트, 목적지 IP·포트, 프로토콜.
  • 사설 IP 출발 공격은 내부 횡적 이동 을 의심한다.
  • 포트는 서비스를 가리키지만, 포트 번호만으로 서비스를 단정하지 않는다.
  • TCP는 SYN → SYN+ACK → ACK로 연결되고, FIN(정상)·RST(강제)로 끝난다.
  • 먼저 닫은 쪽에 TIME-WAIT이 남는다(실습 확인). SYN-RECV 급증은 SYN flood.
  • UDP는 연결이 없어 출발 IP 위조가 쉽다.
  • SYN 기록 = 시도, 성립 여부는 ESTABLISHED나 서버 로그로 확인한다.

9. 다음 글

다음 글 「43. Socket 이해」 에서는 애플리케이션과 커널 네트워크를 잇는 소켓 을 다룬다. 소켓이 파일 디스크립터라는 의미(/proc/PID/fd의 socket:[inode]), socket → bind → listen → accept 흐름, 그리고 리버스 쉘 이 소켓 관점에서 어떻게 보이는지를 정리한다.


참고 자료

profile
코드에 숨겨진 위협을 읽고 AI로 보안의 미래를 설계합니다. 프론트엔드 개발 경험을 자산 삼아 더 견고하고 지능적인 보안 운영 시스템을 구축해 나가는 과정을 기록합니다

0개의 댓글