[IT실습] 스니핑 도구 만들기 실습
Python의 raw socket 기능을 활용해 직접 패킷 스니퍼를 socket과 struct 모듈을 이용해 TCP/UDP 패킷을 실시간으로 캡처하고, 간단한 필터링하는 과정입니다
준비물
- 리눅스 환경 (WSL, Ubuntu 등)
- Python 3.x
- 루트 권한 (sudo)
요약
- Raw Socket: 운영체제의 네트워크 스택을 우회해, 이더넷 프레임부터 직접 접근할 수 있는 소켓.
- Ethernet Header: MAC 주소와 프로토콜 정보를 담고 있음.
- IP Header: 송수신 IP, 프로토콜(TCP/UDP) 정보 포함.
- TCP/UDP Header: 포트 번호, 시퀀스 번호 등 전송 계층 정보 포함.
코드 설명
- AF_PACKET: 이더넷 프레임 단위로 수신
- SOCK_RAW: 원시 패킷 수신
- 0x0003: 모든 프로토콜 수신
- 이더넷 헤더는 14바이트
- !6s6sH: 목적지 MAC, 출발지 MAC, 프로토콜
- IP 헤더에서 프로토콜 번호 추출
- 6은 TCP, 17은 UDP
- TCP 헤더에서 포트, 시퀀스, ACK 번호 추출
실행 방법
- 파일 저장: packet_sniffer.py
- 실행:
- 출력 예시:
[IP] From: 192.168.0.10 To: 192.168.0.1 Protocol: 6
[TCP] Src Port: 443 Dst Port: 52344 Seq: 123456 Ack: 654321
[Data] b'GET / HTTP/1.1\r\nHost: example.com\r\n'...
[소스코드]
import socket
import struct
def capture_packets(interface):
sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003))
sock.bind((interface, 0))
while True:
packet = sock.recvfrom(65565)[0]
eth_length = 14
eth_header = packet[:eth_length]
eth = struct.unpack('!6s6sH', eth_header)
eth_protocol = socket.ntohs(eth[2])
if eth_protocol == 8: # IP 패킷
ip_header = packet[eth_length:eth_length+20]
iph = struct.unpack('!BBHHHBBH4s4s', ip_header)
version_ihl = iph[0]
ihl = version_ihl & 0xF
iph_length = ihl * 4
protocol = iph[6]
s_addr = socket.inet_ntoa(iph[8])
d_addr = socket.inet_ntoa(iph[9])
print(f'[IP] From: {s_addr} To: {d_addr} Protocol: {protocol}')
if protocol == 6: # TCP
t = eth_length + iph_length
tcp_header = packet[t:t+20]
tcph = struct.unpack('!HHLLBBHHH', tcp_header)
source_port = tcph[0]
dest_port = tcph[1]
sequence = tcph[2]
acknowledgment = tcph[3]
doff_reserved = tcph[4]
tcph_length = doff_reserved >> 4
print(f'[TCP] Src Port: {source_port} Dst Port: {dest_port} Seq: {sequence} Ack: {acknowledgment}')
h_size = eth_length + iph_length + tcph_length * 4
data = packet[h_size:]
print(f'[Data] {data[:64]}...') # 처음 64바이트만 출력
elif protocol == 17: # UDP
u = eth_length + iph_length
udp_header = packet[u:u+8]
udph = struct.unpack('!HHHH', udp_header)
source_port = udph[0]
dest_port = udph[1]
length = udph[2]
print(f'[UDP] Src Port: {source_port} Dst Port: {dest_port} Length: {length}')
h_size = eth_length + iph_length + 8
data = packet[h_size:]
print(f'[Data] {data[:64]}...') # 처음 64바이트만 출력
if __name__ == "__main__":
capture_packets("eth0") # 실제 사용하는 인터페이스 이름으로 변경
~
'실습 > IT실습' 카테고리의 다른 글
[IT실습] Traceroute 할때의 패킷은 어떤 모습일까 ? (0) | 2022.08.22 |
---|---|
[IT실습] IT 실습 환경 구현 -! (2) (0) | 2022.08.21 |
[IT실습] IT 실습 환경 구현 -! (1) (0) | 2022.08.21 |
[IT실습] Reverse TCP를 이용한 백도어[backdoor] 실습 (0) | 2017.11.30 |