swlug/project

[Python] TCP/UDP 포트 스캔

Aapie 2024. 5. 9. 22:41

개념 정리

 

TCP(Transmission Control Protocol)란?

 
서버와 클라이언트간에 데이터를 신뢰성 있게 전달하기 위해 만들어진 프로토콜
데이터를 전송하기 전에 데이터 전송을 위한 연결을 만드므로 연결 지향적 (3-way handshake)
 
 

UDP(User Datagram Protocol)란?

 
비연결형, 신뢰성이 없는 전송 프로토콜
흐름제어를 하지 않기 때문에 TCP와는 달리, 빠른 전송이 가능하다. (UDP 사용 이유)
 
 

TCP와 UDP 통신 

아래 사진에서 볼 수 있듯이 TCP는 쌍방향 소통을 하는 연결 지향적인 모습을 확인할 수 있으며,
UDP는 Client에서 Server로만 데이터를 전송하는 일방향적인, 비연결형 전송 프로토콜임을 확인할 수 있다.
 
 

 
 
 

port란?

 
여러 관점에서 포트의 의미를 해석할 수 있으나, 인터넷 프로토콜(IP)에서의 포트는 통신의 종단점을 뜻한다.
 
그렇다면 port num이란 무엇인가?
데이터의 올바른 전송을 위해 수신 프로세스를 알아야 하는데, 이를 식별하기 위해 나온 식별자를 의미한다.
(e.g., HTTP port num : 80)
 
아래의 그림과 같이 클라이언트는 포트번호를 통해 서버에 접속하여 다양한 서비스를 이용할 수 있는 것이다. (물론 프로토콜은 사실 더 복잡하지만...)

 
 

포트스캐닝이란?


공격자가 침입 전, 대상 호스트에 어떤 포트(서비스)가 활성화 되어 있는지 확인하는 기법
프로토콜은 ICMP, TCP, UDP 등 다양하게 활용됨
 
 
 
 

TCP, UDP 포트 스캔

 

TCP 

 
http -> tcp 프로토콜 사용
www.naver.com  port : 80
 
import socket:
Python의 소켓 라이브러리를 가져온다. 네트워킹 기능을 제공하여, TCP/UDP 연결을 생성 및 관리할 수 있게 해준다.
 
with socket.socket() as s:
소켓 객체 생성
s는 생성된 소켓 객체에 대한 참조변수

addr = ("127.0.0.1", 8080):
스캔 대상의 IP 주소와 포트 번호를 튜플로 정의.
"127.0.0.1"는 로컬 호스트를 의미하며, 이는 스스로를 가리킨다. 8080은 확인하고자 하는 대상의 포트 번호

try:
try 블록은 예외(에러)가 발생할 가능성이 있는 코드를 실행하는 데 사용한다.
이 코드에서는 연결 시도 중 예외가 발생할 경우를 대비한다.

s.connect(addr):
소켓 s를 앞에서 정의한 주소 addr에 연결하려고 시도한다. 연결이 성공하면 포트가 열려있음을 의미.

print("8080 tcp socket is opened."):
s.connect(addr) 호출이 성공적으로 완료되면, 이 코드가 실행되어 사용자에게 포트(8080)가 열려 있다는 메시지를 출력

except:
연결 시도(s.connect(addr)) 중에 예외(에러)가 발생하면 except 블록이 실행된다.
이 코드에서는 예외의 유형을 지정하지 않고 모든 종류의 예외를 가정함.

print("8080 tcp socket is closed."):
예외가 발생하면 이 줄이 실행되어 사용자에게 포트( 8080)가 닫혀 있다는 메시지를 출력한다.
 

 
 

// addr() 값 변경
 

127.0.0.1 (localhost)
port : 8080

 
 

#tcp scan
import socket

with socket.socket() as s:
    addr = ("127.0.0.1", 8080)
    try:
        s.connect(addr)
        print("8080 tcp socket is opened.")
    except:
        print("8080 tcp socket is closed.")

 
 
 
열려있는 포트 확인

 

LISTENING : 응답(ACK) 대기 상태
ESTABLISTHED : 상호 연결 상태

 
 

UDP

DNS 서버 - UDP 기반
 
port = 500:
체크하고자 하는 UDP 포트 번호를 변수 port에 저장한다. 여기서는 500번 포트를 사용.

socket.setdefaulttimeout(2):
모든 소켓 연산에 대한 기본 타임아웃을 2초로 설정한다.
이는 recvfrom 같은 블로킹 소켓 연산이 최대 2초 동안만 대기하도록 지정합니다.
 
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
UDP 소켓을 생성한다.
socket.AF_INET =  인터넷 주소 패밀리(IPv4)
socket.SOCK_DGRAM = 데이터그램(UDP) 소켓 타입
with 구문은 소켓 사용이 끝나면 자동으로 소켓을 닫는다.

s.sendto("Data".encode(), addr):
"Data"라는 문자열을 UTF-8로 인코딩하고, 지정된 주소(addr)로 UDP 데이터그램을 보낸다.

s.recvfrom(1024):
소켓에서 최대 1024바이트를 수신하기 위해 대기한다.
UDP는 응답이 없을 수도 있기 때문에, 이 메소드는 타임아웃될 수 있다.

print("[+]{} udp port is opened.".format(port)):
데이터를 성공적으로 받으면, 해당 포트가 열려 있음을 의미하며 메시지를 출력한다.

except Exception as e:
예외가 발생했을 경우 이 블록이 실행된다. 예외 정보는 e 변수에 저장

if str(e) == "time out":
예외가 타임아웃인 경우, 여전히 포트가 열려 있을 가능성이 있음을 가정하고 포트가 열려 있다는 메시지를 출력한다.

else:
타임아웃 외의 다른 예외(예: 네트워크 에러)가 발생하면 포트가 닫혀 있다고 가정하고 해당 메시지를 출력.
 

 

import socket

port = 500
addr = ("127.0.0.1", 500) #DNS
socket.setdefaulttimeout(2)
#UDP
#소켓 오픈 : 응답 없음 (반응 없음)
#소켓 닫힘 : 응답 있음 (소켓 닫힘을 알림)

with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
        try:
            s.sendto("Data".encode(), addr) #데이터 전송
            s.recvfrom(1024)
            print("[+]{} udp port is opened.".format(port))
        except Exception as e:
            if str(e) == "time out":
                print("[+]{} udp port is opened.".format(port))
            else:
                 print("[-]{} udp port is closed".format(port))

 
 

 
 
 

참고

 

TCP 와 UDP의 특징과 차이

TCP와 UDP는 TCP/IP의 전송계층에서 사용되는 프로토콜이다. 전송계층은 IP에 의해 전달되는 패킷의 오류를 검사하고 재전송 요구 등의 제어를 담당하는 계층이다.TCP는 Transmission Control Protocol의 약

velog.io

 

 

포트 스캐너 개발

Port 포트 • 프로그램이 네트워크 통신을 위하여 소켓에 부여한 번호 Ex) FTP는 20, 21번 사용, SSH는 22번, Telnet은 23번 사용 등 • 포트를 열어 놓으면 언제든 통신이 가능하나, 공격자에게 취약점을

geniee-lamp.tistory.com