├── README.md └── geneva.py /README.md: -------------------------------------------------------------------------------- 1 | # 更新说明 2 | ## 1.1 2024-12-02 3 | **以80端口示例** 4 | 5 | IPTABLES: `iptables -t mangle -A OUTPUT -p tcp --sport 80 -m tcp --tcp-flags SYN,ACK,ACK SYN,ACK -j NFQUEUE --queue-num 100` 6 | 7 | python脚本: `python3 geneva.py -q 100 -w 1 -s 7 -c 7 -n 7` 8 | 9 | 参数说明: 10 | * -q: iptables标记 11 | * -w: window_size 最小分片尺寸(单位:字节) 12 | * -s: window_scale 调整混淆包的window_scale,倍率为2的n次方 13 | * -c: confusion_times 调整混淆包的发送次数,虽然不知道有啥用,但是确实多发几个过移动效果更好些,当然,随之而来的是更高的带宽与延迟开销 14 | * -n: split_number 数据包分片数量(一个请求的最多分片次数,达到此阈值的包不再分片) 15 | 16 | ## 1.0 2024-11-29 17 | Useage: `python3 geneva2.py -q 100 -w 1 -s 7 -c 7` 18 | 19 | 1. -w: window_size 20 | 2. -s: window_scale 21 | 3. -c: 混淆次数,建议7次,减少此值可提速(0最快) 22 | -------------------------------------------------------------------------------- /geneva.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # iptables: iptables -t mangle -A OUTPUT -p tcp --sport 80 -m tcp --tcp-flags SYN,ACK,ACK SYN,ACK -j NFQUEUE --queue-num 100 3 | 4 | import os 5 | import signal 6 | from scapy.all import * 7 | from netfilterqueue import NetfilterQueue 8 | import argparse 9 | import sys 10 | import threading 11 | import traceback 12 | import time 13 | 14 | 15 | window_size = 17 16 | edit_times = {} 17 | window_scale = 7 18 | confusion_times = 7 19 | split_number = 7 20 | 21 | 22 | def cleanup_edit_times(edit_times): 23 | while True: 24 | current_time = time.time() 25 | keys_to_delete = [] 26 | 27 | for key, value in list(edit_times.items()): 28 | created_time = value[0] 29 | if current_time - created_time >= 10: 30 | try: 31 | del edit_times[key] 32 | except: 33 | pass 34 | time.sleep(10) 35 | 36 | 37 | def clear_window_scale(ip_layer): 38 | if ip_layer.haslayer(TCP): 39 | tcp_layer = ip_layer[TCP] 40 | tcp_options = tcp_layer.options 41 | new_options = [] 42 | for i in range(len(tcp_options)): 43 | if tcp_options[i][0] == 'WScale': 44 | continue 45 | new_options.append(tcp_options[i]) 46 | tcp_layer.options = new_options 47 | return ip_layer 48 | 49 | 50 | def modify_window(pkt): 51 | global edit_times 52 | try: 53 | ip = IP(pkt.get_payload()) 54 | if ip.haslayer(TCP): 55 | key = f"{ip.dst}_{ip[TCP].dport}" 56 | 57 | if ip[TCP].flags == "SA": 58 | edit_times[key] = [time.time(), 1] 59 | ip = clear_window_scale(ip) 60 | ip[TCP].window = window_size 61 | del ip[IP].chksum 62 | del ip[TCP].chksum 63 | pkt.set_payload(bytes(ip)) 64 | 65 | thread = threading.Thread(target=send_payloads, args=(ip, )) 66 | thread.start() 67 | elif ip[TCP].flags == "A": 68 | if not key in edit_times: 69 | edit_times[key] = [time.time(), 1] 70 | if edit_times[key][1] < split_number: 71 | ip[TCP].window = window_size 72 | else: 73 | ip[TCP].window = 28960 74 | edit_times[key][1] += 1 75 | del ip[IP].chksum 76 | del ip[TCP].chksum 77 | pkt.set_payload(bytes(ip)) 78 | except Exception as e: 79 | # print(traceback.format_exc()) 80 | pass 81 | pkt.accept() 82 | 83 | 84 | 85 | def send_payloads(ip): 86 | if confusion_times < 1: 87 | return 88 | for i in range(1,confusion_times+1): 89 | _win_size = window_size 90 | if i == confusion_times: 91 | _win_size = 65535 92 | ack_packet = IP(src=ip.dst, dst=ip.src) / TCP(sport=ip[TCP].dport, dport=ip[TCP].sport, flags="A", ack=ip[TCP].seq +i, window=_win_size, options=[('WScale', window_scale)] + [('NOP', '')] * 5) 93 | send(ack_packet, verbose=False) 94 | 95 | def parsearg(): 96 | global window_size 97 | global window_scale 98 | global confusion_times 99 | global split_number 100 | parser = argparse.ArgumentParser(description='Description of your program') 101 | 102 | parser.add_argument('-q', '--queue', type=int, help='iptables Queue Num') 103 | parser.add_argument('-w', '--window_size', type=int, help='Tcp Window Size') 104 | parser.add_argument('-s', '--window_scale', type=int, help='Tcp Window Scale') 105 | parser.add_argument('-c', '--confusion_times', type=int, help='confusion_times') 106 | parser.add_argument('-n', '--split_number', type=int, help='Tcp Split Number') 107 | 108 | 109 | args = parser.parse_args() 110 | 111 | if args.queue is None or args.window_size is None: 112 | exit(1) 113 | 114 | window_size = args.window_size 115 | window_scale = args.window_scale 116 | confusion_times = args.confusion_times 117 | split_number = args.split_number 118 | 119 | return args.queue 120 | 121 | def main(): 122 | thread = threading.Thread(target=cleanup_edit_times, args=(edit_times, )) 123 | thread.start() 124 | queue_num = parsearg() 125 | nfqueue = NetfilterQueue() 126 | nfqueue.bind(queue_num, modify_window) 127 | 128 | try: 129 | print("Starting netfilter_queue process...") 130 | nfqueue.run() 131 | except KeyboardInterrupt: 132 | pass 133 | 134 | if __name__ == "__main__": 135 | signal.signal(signal.SIGINT, lambda signal, frame: sys.exit(0)) 136 | main() 137 | --------------------------------------------------------------------------------