More 4-Way Handshake Fun
Rather than using Scapy to craft the 4-way handshake, which is old news, I decided to make an actual web server that would respond with the 4-way handshake.
To briefly describe the 4-way handshake again...
Client -> SYN -> Server
Client <- SYN <- Server
Client -> SYN-ACK -> Server
Client <- ACK <- Server
Client -> GET -> Server
The only way this would benefit a site, is to avoid a state tracker that happens to base to_server streams on which side of the conversation initiated with the first SYN packet.
Using some iptables rules first:
iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP
iptables -A OUTPUT -p ICMP --icmp-type port-unreachable -j DROP
Now the server no longer responds with RST packets or port unreachable, for UDP. We are free to listen for SYN packets and craft traffic with Scapy. Lets start with index.html, and have the script read that in.
======
self.index = f.read()
Listen for SYN packets to port 80...
sniff(filter="tcp dst port 80 && tcp[13] & 2 != 0", prn=self.procSyn)
Pull out useful information
self.srcIP = syn[IP].src
self.dstIP = syn[IP].dst
self.srcPort = syn[TCP].sport
self.dstPort = syn[TCP].dport
iplayer = IP(src=self.dstIP, dst=self.srcIP)
Make the server SYN
self.seq = 9001
p = iplayer/TCP(seq=self.seq, sport=self.dstPort, dport=self.srcPort, flags="S")
Send SYN and listen for the response
synack = sr1(p, timeout=1)
self.seq += 1
self.ack = synack.seq + 1
Send the ACK and Listen for GET request
p = iplayer/TCP(seq=self.seq, ack=self.ack, sport=self.dstPort, dport=self.srcPort, flags="A")
get = sr1(p, timeout=1)
Grab the length of the GET request for response and return ACK Number
data_len = len(get[Raw])
self.seq = get.ack
self.ack = get.seq + data_len
Craft HTTP Server Response
payload = "HTTP/1.1 200 OK\r\nDate: Mon, 08 Mar 2010 03:17:15 CMD\r\nServer: \r\nContent-Length: %s\r\nKeep-Alive: timeout=5, max=99\r\nConnection: Keep-Alive\r\nContent-Type: text/html; charset=utf-8\r\n\r\n%s" % (str(len(self.index)), self.index)
ACK the Client GET request first
p = iplayer/TCP(seq=self.seq, ack=self.ack, sport=self.dstPort, dport=self.srcPort, flags="A")
sendp(p)
Attach the payload
p = iplayer/TCP(seq=self.seq, ack=self.ack, sport=self.dstPort, dport=self.srcPort, flags="A")/payload
sendp(p)
=========
The result looks like this:

The client will still request the page, and the server responds as normal. Tested against snort, the result was not the same as the previously hand-crafted fake.pcap. Snort decided that this non-crafted 4-way handshake was "established,to_server" as it should be detected.
However, this pcap was submitted to our friends over at JsUnpack since the detection is based on who initially sent the SYN packet. In theory, the web server should not reply with a SYN but it is possible to set up with very little code.
The sample script can be downloaded here
Example:
python proxy.py index.html
