Discussion:
How to spoof a TCP handshake in scapy?
Jacek Wielemborek
2014-06-22 12:46:44 UTC
Permalink
Hello,

(This post is based on my StackOverflow question, which can be
found here: http://stackoverflow.com/q/24340455/1091116)

I was recently trying to write a Scapy script that performs a
full TCP handshake. The idea was that I connect two Qemu VMs
using `-net socket` userspace interface (which seems to handle
raw IP/ethernet fine) and instruct machine B to block all input
from A (to prevent it from sending the RSTs). Then, I used telnet
to `connect()` from machine A to B and ran the following script
on machine B:

#!/usr/bin/python

import scapy.all as scapy

filter = "port 31337"
iface = "eth0"

def prepare_response(t):
print("Received: %s" % repr(t))
t.src, t.dst = t.dst, t.src # swap ethernet addresses
ip = t.getlayer("IP")
ip.src, ip.dst = ip.dst, ip.src
t.dport, t.sport = t.sport, t.dport
t.ack = t.seq
t.ack += 1

syn = scapy.sniff(filter=filter, count=1, iface=iface)[0]
print(syn.sprintf('%TCP.flags%'))

syn_ack = syn
prepare_response(syn_ack)
syn_ack.getlayer("TCP").flags |= 0x10 # set the ACK flag
print(syn_ack.sprintf('%TCP.flags%'))

print("Sending: %s" % repr(syn_ack))
scapy.sendp(syn_ack, iface=iface, verbose=False)

ack = scapy.sniff(filter=filter, count=1, iface=iface)[0]
assert(ack.flags & 0x10)

The problem is that instead of receiving an ACK from A to B, I
seem to get a SYN retransmission as if SYN+ACK wasn't interpreted
correctly:

(A Wireshark screenshot can be found here:
https://imgur.com/kv7A3Hr )

tcp on machine A confirms that SYN+ACK reached the machine:

05:47:03.925100 IP 10.0.0.1.39634 > debian.31337: Flags [S],
seq 2426802888, win 14600, options [mss
1460,nop,nop,sackOK,nop,wscale 4], length 0
05:47:03.927515 IP debian.31337 > 10.0.0.1.39634: Flags [S.],
seq 2426802888, ack 2426802889, win 14600, options [mss
1460,nop,nop,sackOK,nop,wscale 4], length 0

Here's the PCAP file from machine B's perspective in Base64 form:

1MOyoQIABAAAAAAAAAAAAP//AAABAAAAYlilUwieDgARAQAAEQEAAAEAXgAA+1J
UABI0VggARQABA2UUQAD/ESrYCgAAAuAAAPsU6RTpAO/r/QAAAAAAAwAAAAUAAA
E2ATUBNAEzATIBMQFlAWYBZgFmATABMAE0ATUBMAE1ATABMAEwATABMAEwATABM
AEwATABMAEwATABOAFlAWYDaXA2BGFycGEAAP8AAQtkZWJpYW4tMTA5MwVsb2Nh
bAAA/wABATIBMAEwAjEwB2luLWFkZHLAUAD/AAHAWgANAAEAAAB4AAsESTY4NgV
MSU5VWMBaAAEAAQAAAHgABAoAAALAcQAMAAEAAAB4AALAWsBaABwAAQAAAHgAEP
6AAAAAAAAAUFQA//4SNFbADAAMAAEAAAB4AALAWmJYpVMJoA4AnAAAAJwAAAABA
F4AAPtSVAASNFYIAEUAAI4GlEAA/xGJzgoAAAHgAAD7FOkU6QB6hFgAAIQAAAAA
AQAAAAABNgE1ATQBMwEyATEBZQFmAWYBZgEwATABNAE1ATABNQEwATABMAEwATA
BMAEwATABMAEwATABMAEwATgBZQFmA2lwNgRhcnBhAAAMgAEAAAB4ABIKZGViaW
FuLTQwNwVsb2NhbABnWKVTvIYIAEIAAABCAAAAUlQAEjRWUlQAEjRWCABFAAA0H
dtAAEAGCOcKAAABCgAAAprbemmul/p8AAAAAIACOQhjsAAAAgQFtAEBBAIBAwME
Z1ilU5COCABCAAAAQgAAAFJUABI0VlJUABI0VggARQAANB3bQABABgjnCgAAAgo
AAAF6aZrbrpf6fK6X+n2AEjkIY7AAAAIEBbQBAQQCAQMDBGhYpVPTfggAQgAAAE
IAAABSVAASNFZSVAASNFYIAEUAADQd3EAAQAYI5goAAAEKAAACmtt6aa6X+nwAA
AAAgAI5CGOwAAACBAW0AQEEAgEDAwRqWKVTrI4IAEIAAABCAAAAUlQAEjRWUlQA
EjRWCABFAAA0Hd1AAEAGCOUKAAABCgAAAprbemmul/p8AAAAAIACOQhjsAAAAgQ
FtAEBBAIBAwME

And one from A to B's perspective:

1MOyoQIABAAAAAAAAAAAAP//AAABAAAAVVilU9NXCABCAAAAQgAAAFJUABI0VlJ
UABI0VggARQAANB3bQABABgjnCgAAAQoAAAKa23pprpf6fAAAAACAAjkIFCkAAA
IEBbQBAQQCAQMDBFVYpVPIYAgAQgAAAEIAAABSVAASNFZSVAASNFYIAEUAADQd2
0AAQAYI5woAAAIKAAABemma266X+nyul/p9gBI5CGOwAAACBAW0AQEEAgEDAwRW
WKVT008IAEIAAABCAAAAUlQAEjRWUlQAEjRWCABFAAA0HdxAAEAGCOYKAAABCgA
AAprbemmul/p8AAAAAIACOQgUKQAAAgQFtAEBBAIBAwMEWFilU4FfCABCAAAAQg
AAAFJUABI0VlJUABI0VggARQAANB3dQABABgjlCgAAAQoAAAKa23pprpf6fAAAA
ACAAjkIFCkAAAIEBbQBAQQCAQMDBA==

At first I thought that this is somehow related to some Linux
TCP/IP quirk, so I experimented with turning off TCP timestamps
and SYN cookies. I also tried increasing IP ID, which didn't help
either. Both machines are running Debian 7.5 with linux-
image-3.2.0-4-686-pae under qemu 1.6.2.

What am I missing?

Yours,
Jacek Wielemborek
Jacek Wielemborek
2014-06-23 09:22:55 UTC
Permalink
Post by Jacek Wielemborek
Hello,
(This post is based on my StackOverflow question, which can be
found here: http://stackoverflow.com/q/24340455/1091116)
I was recently trying to write a Scapy script that performs a
full TCP handshake. The idea was that I connect two Qemu VMs
using `-net socket` userspace interface (which seems to handle
raw IP/ethernet fine) and instruct machine B to block all input
from A (to prevent it from sending the RSTs). Then, I used
telnet to `connect()` from machine A to B and ran the
#!/usr/bin/python
import scapy.all as scapy
filter = "port 31337"
iface = "eth0"
print("Received: %s" % repr(t))
t.src, t.dst = t.dst, t.src # swap ethernet addresses
ip = t.getlayer("IP")
ip.src, ip.dst = ip.dst, ip.src
t.dport, t.sport = t.sport, t.dport
t.ack = t.seq
t.ack += 1
syn = scapy.sniff(filter=filter, count=1, iface=iface)[0]
print(syn.sprintf('%TCP.flags%'))
syn_ack = syn
prepare_response(syn_ack)
syn_ack.getlayer("TCP").flags |= 0x10 # set the ACK flag
print(syn_ack.sprintf('%TCP.flags%'))
print("Sending: %s" % repr(syn_ack))
scapy.sendp(syn_ack, iface=iface, verbose=False)
ack = scapy.sniff(filter=filter, count=1, iface=iface)[0]
assert(ack.flags & 0x10)
The problem is that instead of receiving an ACK from A to B, I
seem to get a SYN retransmission as if SYN+ACK wasn't
https://imgur.com/kv7A3Hr )
05:47:03.925100 IP 10.0.0.1.39634 > debian.31337: Flags
[S], seq 2426802888, win 14600, options [mss
1460,nop,nop,sackOK,nop,wscale 4], length 0
05:47:03.927515 IP debian.31337 > 10.0.0.1.39634: Flags
[S.], seq 2426802888, ack 2426802889, win 14600, options [mss
1460,nop,nop,sackOK,nop,wscale 4], length 0
Here's the PCAP file from machine B's perspective in Base64
1MOyoQIABAAAAAAAAAAAAP//AAABAAAAYlilUwieDgARAQAAEQEAAAEAXgAA+1J
UABI0VggARQABA2UUQAD/ESrYCgAAAuAAAPsU6RTpAO/r/QAAAAAAAwAAAAUAA
A
E2ATUBNAEzATIBMQFlAWYBZgFmATABMAE0ATUBMAE1ATABMAEwATABMAEwATAB
M
AEwATABMAEwATABOAFlAWYDaXA2BGFycGEAAP8AAQtkZWJpYW4tMTA5MwVsb2N
h
bAAA/wABATIBMAEwAjEwB2luLWFkZHLAUAD/AAHAWgANAAEAAAB4AAsESTY4Ng
V
MSU5VWMBaAAEAAQAAAHgABAoAAALAcQAMAAEAAAB4AALAWsBaABwAAQAAAHgAE
P
6AAAAAAAAAUFQA//4SNFbADAAMAAEAAAB4AALAWmJYpVMJoA4AnAAAAJwAAAAB
A
F4AAPtSVAASNFYIAEUAAI4GlEAA/xGJzgoAAAHgAAD7FOkU6QB6hFgAAIQAAAA
A
AQAAAAABNgE1ATQBMwEyATEBZQFmAWYBZgEwATABNAE1ATABNQEwATABMAEwAT
A
BMAEwATABMAEwATABMAEwATgBZQFmA2lwNgRhcnBhAAAMgAEAAAB4ABIKZGVia
W
FuLTQwNwVsb2NhbABnWKVTvIYIAEIAAABCAAAAUlQAEjRWUlQAEjRWCABFAAA0
H
dtAAEAGCOcKAAABCgAAAprbemmul/p8AAAAAIACOQhjsAAAAgQFtAEBBAIBAwM
E
Z1ilU5COCABCAAAAQgAAAFJUABI0VlJUABI0VggARQAANB3bQABABgjnCgAAAg
o
AAAF6aZrbrpf6fK6X+n2AEjkIY7AAAAIEBbQBAQQCAQMDBGhYpVPTfggAQgAAA
E
IAAABSVAASNFZSVAASNFYIAEUAADQd3EAAQAYI5goAAAEKAAACmtt6aa6X+nwA
A
AAAgAI5CGOwAAACBAW0AQEEAgEDAwRqWKVTrI4IAEIAAABCAAAAUlQAEjRWUlQ
A
EjRWCABFAAA0Hd1AAEAGCOUKAAABCgAAAprbemmul/p8AAAAAIACOQhjsAAAAg
Q FtAEBBAIBAwME
1MOyoQIABAAAAAAAAAAAAP//AAABAAAAVVilU9NXCABCAAAAQgAAAFJUABI0VlJ
UABI0VggARQAANB3bQABABgjnCgAAAQoAAAKa23pprpf6fAAAAACAAjkIFCkAA
A
IEBbQBAQQCAQMDBFVYpVPIYAgAQgAAAEIAAABSVAASNFZSVAASNFYIAEUAADQd
2
0AAQAYI5woAAAIKAAABemma266X+nyul/p9gBI5CGOwAAACBAW0AQEEAgEDAwR
W
WKVT008IAEIAAABCAAAAUlQAEjRWUlQAEjRWCABFAAA0HdxAAEAGCOYKAAABCg
A
AAprbemmul/p8AAAAAIACOQgUKQAAAgQFtAEBBAIBAwMEWFilU4FfCABCAAAAQ
g
AAAFJUABI0VlJUABI0VggARQAANB3dQABABgjlCgAAAQoAAAKa23pprpf6fAAA
A ACAAjkIFCkAAAIEBbQBAQQCAQMDBA==
At first I thought that this is somehow related to some Linux
TCP/IP quirk, so I experimented with turning off TCP timestamps
and SYN cookies. I also tried increasing IP ID, which didn't
help either. Both machines are running Debian 7.5 with linux-
image-3.2.0-4-686-pae under qemu 1.6.2.
What am I missing?
Yours,
Jacek Wielemborek
Apparently this is related to TCP checksums that I missed because
Wireshark doesn't check them by default. As StackOverflow Pierre
user helped me, the solution was to add del(t[TCP].chksum) in
prepare_response().

Loading...