1*8feac640Sbluhm#!/usr/local/bin/python3 215b894fdSbluhm# send payload from client to relay before connecting to server 315b894fdSbluhm 415b894fdSbluhmimport os 5e1860033Sbluhmimport re 615b894fdSbluhmimport sys 715b894fdSbluhmimport threading 815b894fdSbluhmfrom addr import * 915b894fdSbluhmfrom scapy.all import * 1015b894fdSbluhm 1115b894fdSbluhmclient=os.getpid() & 0xffff 1215b894fdSbluhmrelay=int(sys.argv[2]) 1315b894fdSbluhmserver=int(sys.argv[1]) 1415b894fdSbluhm 1515b894fdSbluhmclass Sniff1(threading.Thread): 1615b894fdSbluhm filter = None 1715b894fdSbluhm captured = None 1815b894fdSbluhm packet = None 19925939b7Sbluhm def __init__(self): 20925939b7Sbluhm # clear packets buffered by scapy bpf 21925939b7Sbluhm sniff(iface=LOCAL_IF, timeout=1) 22925939b7Sbluhm super(Sniff1, self).__init__() 2315b894fdSbluhm def run(self): 2415b894fdSbluhm self.captured = sniff(iface=LOCAL_IF, filter=self.filter, 2515b894fdSbluhm count=1, timeout=5) 2615b894fdSbluhm if self.captured: 2715b894fdSbluhm self.packet = self.captured[0] 2815b894fdSbluhm 2915b894fdSbluhmip=IP(src=FAKE_NET_ADDR, dst=REMOTE_ADDR) 3015b894fdSbluhm 31*8feac640Sbluhmprint("Send SYN packet, receive SYN+ACK") 3215b894fdSbluhmsyn=TCP(sport=client, dport=relay, seq=0, flags='S', window=(2**16)-1) 3315b894fdSbluhmsynack=sr1(ip/syn, iface=LOCAL_IF, timeout=5) 3415b894fdSbluhm 3515b894fdSbluhmif synack is None: 36*8feac640Sbluhm print("ERROR: No matching SYN+ACK packet received") 3715b894fdSbluhm exit(1) 3815b894fdSbluhm 39*8feac640Sbluhmprint("Send ACK packet to finish handshake") 4015b894fdSbluhmack=TCP(sport=synack.dport, dport=synack.sport, 4115b894fdSbluhm seq=1, ack=synack.seq+1, flags='A') 4215b894fdSbluhmsend(ip/ack, iface=LOCAL_IF) 4315b894fdSbluhm 44*8feac640Sbluhmprint("Expect spliced SYN") 4515b894fdSbluhmsniffer = Sniff1(); 4615b894fdSbluhmsniffer.filter = "src %s and dst %s and tcp port %u " \ 4715b894fdSbluhm "and tcp[tcpflags] = tcp-syn" % (ip.dst, ip.src, server) 4815b894fdSbluhmsniffer.start() 4915b894fdSbluhmtime.sleep(1) 5015b894fdSbluhm 51*8feac640Sbluhmprint("Send 10 bytes payload") 5215b894fdSbluhmdata="0123456789" 5315b894fdSbluhmpayload=TCP(sport=synack.dport, dport=synack.sport, 5415b894fdSbluhm seq=1, ack=synack.seq+1, flags='APU')/data 5515b894fdSbluhmpayload_ack=sr1(ip/payload, iface=LOCAL_IF) 5615b894fdSbluhm 5715b894fdSbluhmif payload_ack is None: 58*8feac640Sbluhm print("ERROR: No payload ACK packet received") 5915b894fdSbluhm exit(1) 6015b894fdSbluhmif payload_ack.ack != len(data)+1: 61*8feac640Sbluhm print("ERROR: Expected ack %d, got %d in payload ACK" % 62*8feac640Sbluhm (len(data)+1, payload_ack.ack)) 6315b894fdSbluhm exit(1) 6415b894fdSbluhm 6515b894fdSbluhmsniffer.join(timeout=7) 6615b894fdSbluhmspliced_syn = sniffer.packet 6715b894fdSbluhm 6815b894fdSbluhmif spliced_syn is None: 69*8feac640Sbluhm print("ERROR: No spliced SYN packet received") 7015b894fdSbluhm exit(1) 7115b894fdSbluhm 72*8feac640Sbluhmprint("Expect spliced payload") 7315b894fdSbluhmsniffer = Sniff1(); 7415b894fdSbluhmsniffer.filter = "src %s and dst %s and tcp port %u " \ 7515b894fdSbluhm "and tcp[tcpflags] = tcp-ack|tcp-push" % (ip.dst, ip.src, server) 7615b894fdSbluhmsniffer.start() 7715b894fdSbluhmtime.sleep(1) 7815b894fdSbluhm 79*8feac640Sbluhmprint("Wait for splicing syscall, grep it in relay log") 80e1860033Sbluhmdef loggrep(file, regex, timeout): 81e1860033Sbluhm for i in range(timeout): 82e1860033Sbluhm for line in open(file, 'r'): 83e1860033Sbluhm if re.search(regex, line): 84e1860033Sbluhm return line 85e1860033Sbluhm time.sleep(1) 86e1860033Sbluhm return None 87e1860033Sbluhmif not loggrep("relay.log", "Spliced", 5): 88*8feac640Sbluhm print("ERROR: Relay did not splice") 89e1860033Sbluhm exit(1) 90e1860033Sbluhm 91*8feac640Sbluhmprint("Send spliced SYN+ACK packet to finish handshake") 9215b894fdSbluhmspliced_synack=TCP(sport=spliced_syn.dport, dport=spliced_syn.sport, 9315b894fdSbluhm seq=0, ack=spliced_syn.seq+1, flags='SA') 9415b894fdSbluhmspliced_ack=sr1(ip/spliced_synack, iface=LOCAL_IF) 9515b894fdSbluhm 9615b894fdSbluhmif spliced_ack is None: 97*8feac640Sbluhm print("ERROR: No spliced ACK packet received") 9815b894fdSbluhm exit(1) 9915b894fdSbluhm 10015b894fdSbluhmsniffer.join(timeout=7) 10115b894fdSbluhmspliced_payload = sniffer.packet 10215b894fdSbluhm 10315b894fdSbluhmif spliced_payload is None: 104*8feac640Sbluhm print("ERROR: No spliced payload packet received") 10515b894fdSbluhm exit(1) 10615b894fdSbluhmif spliced_payload.seq != spliced_ack.seq: 107*8feac640Sbluhm print("ERROR: Expected seq %d, got %d in spliced payload" % 108*8feac640Sbluhm (spliced_ack.seq, spliced_payload.seq)) 10915b894fdSbluhm exit(1) 11015b894fdSbluhmif spliced_payload.len-20-20 != len(data): 111*8feac640Sbluhm print("ERROR: Expected len %d, got %d in spliced payload" % 112*8feac640Sbluhm (len(data), spliced_payload.len-20-20)) 11315b894fdSbluhm exit(1) 11415b894fdSbluhm 115*8feac640Sbluhmprint("Kill connections with RST") 11615b894fdSbluhmspliced_rst=TCP(sport=spliced_ack.dport, dport=spliced_ack.sport, 11715b894fdSbluhm seq=1, ack=spliced_ack.seq, flags='RA') 11815b894fdSbluhmsend(ip/spliced_rst, iface=LOCAL_IF) 11915b894fdSbluhmrst=TCP(sport=synack.dport, dport=synack.sport, 12015b894fdSbluhm seq=payload_ack.ack, ack=synack.seq+1, flags='RA') 12115b894fdSbluhmsend(ip/rst, iface=LOCAL_IF) 12215b894fdSbluhm 12315b894fdSbluhmexit(0) 124