Windsurf编写一个检测本机通信数据

96 阅读7分钟

Windsurf

Windsurf 是由 Codeium 公司开发的,旨在提供一种简单、高效的方式来创建单页应用程序(SPA)。

codeium.com/windsurf 下载,目前还是免费

对话是交流

  • 拦截本电脑发出的所有请求信息
我将创建一个Python脚本来监控本机的网络请求。我们将使用`scapy`库来捕获和分析网络数据包。

Created packet_sniffer.py   +136-0 0

这个脚本需要使用sudo权限来运行,因为网络数据包捕获需要系统级权限。使用方法:

sudo python3 packet_sniffer.py

脚本功能:

1.  捕获所有经过本机网卡的网络数据包

1.  识别常见协议:TCPUDPHTTPHTTPSDNS1.  显示每个请求的详细信息:

    -   时间戳
    -   协议类型
    -   源IP和端口
    -   目标IP和端口
    -   数据包大小
    -   特殊信息(如DNS查询内容)

1.  自动将捕获的数据保存为JSON文件

1.Ctrl+C可以优雅地停止捕获

注意事项:

1.  需要root/管理员权限运行
1.  会显示所有网络请求,包括系统和应用程序的请求
1.  对于HTTPS请求,由于加密原因,只能看到基本连接信息,无法查看具体内容
1.  保存的JSON文件可以后续用于分析或处理
```js


```python
#!/usr/bin/env python3
from scapy.all import *
from datetime import datetime
import threading
import queue
import signal
import sys
import socket

class PacketSniffer:
    def __init__(self):
        self.packet_queue = queue.Queue()
        self.is_running = False
        self.dns_cache = {}
        self.service_names = {
            21: 'FTP',
            22: 'SSH',
            23: 'Telnet',
            25: 'SMTP',
            53: 'DNS',
            80: 'HTTP',
            110: 'POP3',
            143: 'IMAP',
            443: 'HTTPS',
            465: 'SMTPS',
            587: 'SMTP(SSL)',
            993: 'IMAPS',
            995: 'POP3S',
            1080: 'SOCKS',
            1433: 'MSSQL',
            1521: 'Oracle',
            3306: 'MySQL',
            3389: 'RDP',
            5432: 'PostgreSQL',
            6379: 'Redis',
            8080: 'HTTP-Proxy',
            8443: 'HTTPS-Alt',
            27017: 'MongoDB'
        }

    def get_hostname(self, ip):
        """获取IP地址对应的域名"""
        if ip in self.dns_cache:
            return self.dns_cache[ip]
        
        try:
            hostname = socket.gethostbyaddr(ip)[0]
            self.dns_cache[ip] = hostname
            return hostname
        except (socket.herror, socket.gaierror):
            self.dns_cache[ip] = ip
            return ip

    def get_service_name(self, port):
        """获取端口对应的服务名称"""
        return self.service_names.get(port, str(port))
        
    def packet_callback(self, packet):
        """回调函数,处理每个捕获的数据包"""
        self.packet_queue.put(packet)

    def process_packet(self, packet):
        """处理数据包并提取详细信息"""
        packet_info = {
            'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f'),
            'protocol': None,
            'src_ip': None,
            'src_host': None,
            'dst_ip': None,
            'dst_host': None,
            'src_port': None,
            'src_service': None,
            'dst_port': None,
            'dst_service': None,
            'length': len(packet),
            'info': '',
            'payload': '',
            'payload_hex': '',
            'payload_ascii': '',
            'flags': [],
            'headers': {},
            'raw_layers': []
        }

        # 以太网层处理
        if Ether in packet:
            ether = packet[Ether]
            packet_info['mac_src'] = ether.src
            packet_info['mac_dst'] = ether.dst
            packet_info['raw_layers'].append({
                'layer': 'Ethernet',
                'type': hex(ether.type),
                'src': ether.src,
                'dst': ether.dst
            })

        # IP层处理
        if IP in packet:
            ip = packet[IP]
            # 解析IP和主机名
            src_ip = ip.src
            dst_ip = ip.dst
            packet_info.update({
                'src_ip': src_ip,
                'dst_ip': dst_ip,
                'src_host': self.get_hostname(src_ip),
                'dst_host': self.get_hostname(dst_ip),
                'ttl': ip.ttl,
                'ip_version': ip.version,
                'ip_ihl': ip.ihl,
                'ip_tos': ip.tos,
                'ip_len': ip.len,
                'ip_id': ip.id,
                'ip_flags': ip.flags,
                'ip_frag': ip.frag
            })
            
            packet_info['raw_layers'].append({
                'layer': 'IP',
                'version': ip.version,
                'ihl': ip.ihl,
                'tos': ip.tos,
                'len': ip.len,
                'id': ip.id,
                'flags': str(ip.flags),
                'frag': ip.frag,
                'ttl': ip.ttl,
                'proto': ip.proto,
                'src': ip.src,
                'dst': ip.dst
            })

            # TCP协议处理
            if TCP in packet:
                tcp = packet[TCP]
                packet_info['protocol'] = 'TCP'
                src_port = tcp.sport
                dst_port = tcp.dport
                packet_info.update({
                    'src_port': src_port,
                    'dst_port': dst_port,
                    'src_service': self.get_service_name(src_port),
                    'dst_service': self.get_service_name(dst_port),
                    'seq': tcp.seq,
                    'ack': tcp.ack,
                    'window': tcp.window
                })

                # TCP标志位
                flags = []
                if tcp.flags.F: flags.append('FIN')
                if tcp.flags.S: flags.append('SYN')
                if tcp.flags.R: flags.append('RST')
                if tcp.flags.P: flags.append('PSH')
                if tcp.flags.A: flags.append('ACK')
                if tcp.flags.U: flags.append('URG')
                packet_info['flags'] = flags

                # 应用层协议检测和处理
                # HTTP
                if tcp.dport == 80 or tcp.sport == 80:
                    packet_info['protocol'] = 'HTTP'
                    try:
                        if Raw in packet:
                            raw_data = packet[Raw].load
                            packet_info['payload'] = raw_data
                            try:
                                # 尝试解码为UTF-8文本
                                payload = raw_data.decode('utf-8', errors='ignore')
                                # 解析HTTP请求/响应
                                if payload.startswith(('GET', 'POST', 'PUT', 'DELETE', 'HTTP/')):
                                    lines = payload.split('\r\n')
                                    packet_info['info'] = lines[0]  # HTTP请求/响应行
                                    
                                    # 提取URL或文件名
                                    if ' ' in lines[0]:
                                        parts = lines[0].split(' ')
                                        if len(parts) > 1:
                                            path = parts[1]
                                            if '?' in path:
                                                path = path.split('?')[0]
                                            if '/' in path:
                                                packet_info['filename'] = path.split('/')[-1] or '/' 
                                            
                                    # 解析HTTPfor line in lines[1:]:
                                        if ': ' in line:
                                            key, value = line.split(': ', 1)
                                            packet_info['headers'][key] = value
                                            
                                            # 从Content-Disposition提取文件名
                                            if key.lower() == 'content-disposition':
                                                if 'filename=' in value:
                                                    filename = value.split('filename=')[-1].strip('"')
                                                    packet_info['filename'] = filename
                                
                                # 查找可能的文件名模式
                                import re
                                # 常见文件扩展名模式
                                file_pattern = r'[\w\-. ]+\.(jpg|jpeg|png|gif|pdf|doc|docx|xls|xlsx|zip|rar|txt|html|xml|json)'
                                found_files = re.findall(file_pattern, payload, re.IGNORECASE)
                                if found_files:
                                    packet_info['found_files'] = found_files
                                
                                # 查找URL模式
                                url_pattern = r'https?://[\w\-\.]+\.[a-zA-Z]{2,}[\w\-\./\?\=\&\%]*'
                                found_urls = re.findall(url_pattern, payload)
                                if found_urls:
                                    packet_info['found_urls'] = found_urls
                                    
                            except UnicodeDecodeError:
                                # 如果不是文本数据,检查是否是二进制文件格式
                                if raw_data.startswith(b'PK\x03\x04'):  # ZIP文件头
                                    packet_info['file_type'] = 'ZIP Archive'
                                elif raw_data.startswith(b'%PDF'):  # PDF文件头
                                    packet_info['file_type'] = 'PDF Document'
                                elif raw_data.startswith(b'\xff\xd8\xff'):  # JPEG文件头
                                    packet_info['file_type'] = 'JPEG Image'
                                elif raw_data.startswith(b'\x89PNG\r\n'):  # PNG文件头
                                    packet_info['file_type'] = 'PNG Image'
                                elif raw_data.startswith(b'GIF87a') or raw_data.startswith(b'GIF89a'):  # GIF文件头
                                    packet_info['file_type'] = 'GIF Image'
                    except Exception as e:
                        packet_info['parse_error'] = str(e)

                # HTTPS/TLS
                elif tcp.dport == 443 or tcp.sport == 443:
                    packet_info['protocol'] = 'HTTPS'
                    if Raw in packet:
                        try:
                            # 尝试检测TLS握手
                            if packet[Raw].load[0] == 0x16:  # TLS Handshake
                                packet_info['info'] = 'TLS Handshake'
                            elif packet[Raw].load[0] == 0x17:  # TLS Application Data
                                packet_info['info'] = 'TLS Application Data'
                            else:
                                packet_info['info'] = 'HTTPS Communication'
                        except:
                            packet_info['info'] = 'HTTPS Communication'

            # UDP协议处理
            elif UDP in packet:
                udp = packet[UDP]
                src_port = udp.sport
                dst_port = udp.dport
                packet_info.update({
                    'protocol': 'UDP',
                    'src_port': src_port,
                    'dst_port': dst_port,
                    'src_service': self.get_service_name(src_port),
                    'dst_service': self.get_service_name(dst_port),
                    'udp_len': udp.len
                })

                # DNS请求检测
                if udp.dport == 53 or udp.sport == 53:
                    packet_info['protocol'] = 'DNS'
                    if packet.haslayer(DNS):
                        dns = packet[DNS]
                        packet_info['dns_id'] = dns.id
                        if dns.qr == 0:  # DNS查询
                            packet_info['info'] = f"DNS Query: {dns.qd.qname.decode()}"
                            packet_info['dns_type'] = 'query'
                            packet_info['dns_qtype'] = dns.qd.qtype
                        else:  # DNS响应
                            packet_info['info'] = "DNS Response"
                            packet_info['dns_type'] = 'response'
                            packet_info['dns_rcode'] = dns.rcode
                            # 解析DNS应答
                            answers = []
                            for i in range(dns.ancount):
                                rr = dns.an[i]
                                if hasattr(rr, 'rdata'):
                                    answers.append({
                                        'name': rr.rrname.decode(),
                                        'type': rr.type,
                                        'data': str(rr.rdata)
                                    })
                            packet_info['dns_answers'] = answers

            # ICMP协议处理
            elif ICMP in packet:
                icmp = packet[ICMP]
                packet_info.update({
                    'protocol': 'ICMP',
                    'icmp_type': icmp.type,
                    'icmp_code': icmp.code
                })
                if icmp.type == 8:
                    packet_info['info'] = 'ICMP Echo Request (Ping)'
                elif icmp.type == 0:
                    packet_info['info'] = 'ICMP Echo Reply (Ping)'

        return packet_info

    def print_packet_info(self, packet_info):
        """打印数据包详细信息"""
        print("\n" + "="*80)
        print(f"时间: {packet_info['time']}")
        print(f"协议: {packet_info['protocol']}")
        
        # 显示文件名或URL信息
        if 'filename' in packet_info:
            print(f"\n检测到文件名: {packet_info['filename']}")
        
        if 'file_type' in packet_info:
            print(f"文件类型: {packet_info['file_type']}")
            
        if 'found_files' in packet_info:
            print("\n检测到的文件:")
            for file in packet_info['found_files']:
                print(f"  - {file}")
            
        if 'found_urls' in packet_info:
            print("\n检测到的URL:")
            for url in packet_info['found_urls']:
                print(f"  - {url}")
        
        # 网络层信息
        if 'mac_src' in packet_info:
            print(f"MAC地址: {packet_info['mac_src']} -> {packet_info['mac_dst']}")
        print(f"源地址: {packet_info['src_ip']} ({packet_info['src_host']}):{packet_info['src_port']} ({packet_info['src_service']})")
        print(f"目标地址: {packet_info['dst_ip']} ({packet_info['dst_host']}):{packet_info['dst_port']} ({packet_info['dst_service']})")
        
        # 分层协议详细信息
        print("\n分层协议信息:")
        for layer in packet_info['raw_layers']:
            print(f"\n  {layer['layer']} 层:")
            for key, value in layer.items():
                if key != 'layer':
                    print(f"    {key}: {value}")
        
        # 传输层信息
        if packet_info['protocol'] == 'TCP':
            print("\nTCP详细信息:")
            print(f"  序列号: {packet_info.get('seq', 'N/A')}")
            print(f"  确认号: {packet_info.get('ack', 'N/A')}")
            if packet_info['flags']:
                print(f"  TCP标志: {', '.join(packet_info['flags'])}")
        
        # 应用层信息
        print(f"\n数据包大小: {packet_info['length']} bytes")
        if packet_info['info']:
            print(f"协议信息: {packet_info['info']}")
        
        # HTTP头信息
        if packet_info['headers']:
            print("\nHTTP头信息:")
            for key, value in packet_info['headers'].items():
                print(f"  {key}: {value}")
        
        # DNS详细信息
        if packet_info['protocol'] == 'DNS':
            print("\nDNS详细信息:")
            print(f"  类型: {packet_info.get('dns_type', 'N/A')}")
            if 'dns_answers' in packet_info:
                print("  解析结果:")
                for answer in packet_info['dns_answers']:
                    print(f"    {answer['name']} -> {answer['data']}")
        
        # 显示原始负载
        if packet_info['payload'] and len(packet_info['payload']) > 0:
            print("\n负载内容:")
            try:
                # 尝试解码为UTF-8文本并美化显示
                text_content = packet_info['payload'].decode('utf-8', errors='ignore')
                if any(text_content.startswith(prefix) for prefix in ['GET ', 'POST ', 'PUT ', 'DELETE ', 'HTTP/', '{', '[']):
                    # 如果是HTTP请求/响应或JSON数据,保持原格式
                    print("  文本内容:")
                    for line in text_content.split('\n')[:20]:  # 限制显示前20print(f"    {line.strip()}")
                    if len(text_content.split('\n')) > 20:
                        print("    ...")
                else:
                    # 其他文本内容
                    print("  文本内容:")
                    preview = text_content[:200]
                    print(f"    {preview}" + ('...' if len(text_content) > 200 else ''))
            except UnicodeDecodeError:
                # 如果不是文本,显示十六进制格式
                print("  二进制内容 (HEX):")
                hex_payload = ' '.join(f'{b:02x}' for b in packet_info['payload'])
                print(f"    {hex_payload[:200]}" + ('...' if len(hex_payload) > 200 else ''))
        
        print("="*80)

    def packet_processor(self):
        """处理数据包队列的线程函数"""
        while self.is_running or not self.packet_queue.empty():
            try:
                packet = self.packet_queue.get(timeout=1)
                packet_info = self.process_packet(packet)
                if packet_info['protocol']:  # 只打印有效的数据包
                    self.print_packet_info(packet_info)
            except queue.Empty:
                continue

    def start_sniffing(self):
        """开始捕获数据包"""
        self.is_running = True
        
        # 启动数据包处理线程
        processor_thread = threading.Thread(target=self.packet_processor)
        processor_thread.start()

        print("开始捕获网络请求...")
        print("按 Ctrl+C 停止捕获")
        
        # 开始捕获数据包
        try:
            sniff(prn=self.packet_callback, store=0)
        except Exception as e:
            print(f"捕获错误: {e}")
        finally:
            self.stop_sniffing()
            processor_thread.join()

    def stop_sniffing(self):
        """停止捕获数据包"""
        self.is_running = False
        print("\n停止捕获...")

def main():
    sniffer = PacketSniffer()
    
    def signal_handler(sig, frame):
        print("\n正在优雅地停止...")
        sniffer.stop_sniffing()
        sys.exit(0)
    
    signal.signal(signal.SIGINT, signal_handler)
    sniffer.start_sniffing()

if __name__ == "__main__":
    main()

==========================================

时间: 2025-03-26 10:37:54.991109

协议: HTTPS

MAC地址: xxxx -> xxx

源地址: xxx:52375 (52375)

目标地址: xxxx:443 (HTTPS)

分层协议信息:

Ethernet 层:

    type: 0x800     src: xxxx     dst: xxx

  IP 层:

    version: 4     ihl: 5     tos: 0     len: 52     id: 0     flags: DF     frag: 0     ttl: 64     proto: 6     src: xxx     dst: xxx

数据包大小: 66 bytes

=======================================