由于 ACK 方式需要使用原始套接字,需要以管理员权限运行该程序。

import argparse
import socket
import struct

def scan_ports(target_ip, start_port, end_port):
    for port in range(start_port, end_port+1):
        try:
            # 创建原始套接字
            s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
            s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)

            # 构造 TCP 头部
            source_port = 12345  # 随便指定一个源端口
            dest_port = port
            seq_num = 0
            ack_num = 0
            data_offset = 5
            reserved = 0
            flags = 0x10  # ACK 标志位
            window_size = socket.htons(5840)
            checksum = 0
            urgent_pointer = 0
            tcp_header = struct.pack('!HHLLBBHHH', source_port, dest_port, seq_num, ack_num, data_offset, reserved, flags, window_size, checksum, urgent_pointer)

            # 构造 IP 头部
            source_ip = socket.gethostbyname(socket.gethostname())
            dest_ip = target_ip
            version = 4
            ihl = 5
            tos = 0
            total_length = 20 + 20
            id = 54321
            flags = 0
            ttl = 255
            protocol = socket.IPPROTO_TCP
            checksum = 0
            ip_header = struct.pack('!BBHHHBBH4s4s', (version << 4) + ihl, tos, total_length, id, flags, ttl, protocol, checksum, socket.inet_aton(source_ip), socket.inet_aton(dest_ip))

            # 计算 TCP 校验和
            pseudo_header = struct.pack('!4s4sBBH', socket.inet_aton(source_ip), socket.inet_aton(dest_ip), 0, socket.IPPROTO_TCP, len(tcp_header))
            pseudo_header = pseudo_header + tcp_header
            tcp_checksum = checksum_func(pseudo_header)

            # 将 TCP 校验和填入 TCP 头部
            tcp_header = struct.pack('!HHLLBBHHH', source_port, dest_port, seq_num, ack_num, data_offset, reserved, flags, window_size, tcp_checksum, urgent_pointer)

            # 将 IP 头部和 TCP 头部组合成一个完整的数据包
            packet = ip_header + tcp_header

            # 发送数据包
            s.sendto(packet, (dest_ip, 0))

            # 接收响应数据包
            s.settimeout(0.1)
            response = s.recvfrom(1024)[0]

            # 解析响应数据包
            tcp_header_length = (response[12] >> 4) * 4
            tcp_header = response[20:20+tcp_header_length]
            tcp_header = struct.unpack('!HHLLBBHHH', tcp_header)
            flags = tcp_header[5]

            # 判断端口是否开放
            if flags == 0x14:  # RST/ACK 标志位
                print('Port ' + str(port) + ' is open')
            s.close()
        except:
            pass

def checksum_func(data):
    if len(data) % 2 == 1:
        data += b'�'
    res = sum(struct.unpack('!{}H'.format(len(data) // 2), data))
    res = (res >> 16) + (res & 0xffff)
    res = res + (res >> 16)
    return (~res) & 0xffff

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Python port scanner using ACK scan')
    parser.add_argument('target', help='target IP address')
    parser.add_argument('-p', '--port', help='port number or range (e.g. 80 or 1-1024)', required=True)
    args = parser.parse_args()

    target_ip = args.target
    port_range = args.port.split('-')
    if len(port_range) == 1:
        start_port = end_port = int(port_range[0])
    else:
        start_port = int(port_range[0])
        end_port = int(port_range[1])

    scan_ports(target_ip, start_port, end_port)

使用示例:

sudo python3 ack_scan.py 192.168.0.1 -p 1-1024

该程序将扫描 192.168.0.1 主机的 1-1024 端口,输出开放的端口号。

Python ACK 端口扫描器:模拟 Nmap 扫描端口

原文地址: https://www.cveoy.top/t/topic/f0Aw 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录