Jeff Bencteux Jeff Bencteux - 3 months ago 22
Python Question

Ack number to acknowledge data in scapy

I'm playing around with scapy, trying to do a nmap-like, I succeeded doing a three way handshake and I automatically receive data if I connect to a smtp server but I can't acknowledge it.

I have connected to it via netcat to see why it wouldn't work and nc actually send an ACK packet with the TCP ack field set to the length of the data segment received + 1.
So I am trying to do the same with scapy but I don't know where to find the length of a TCP segment. I tried a lsc(TCP) but I can not see the field.

Here is a wireshark capture of the netcat connection :

enter image description here

And the detail of the packet :

enter image description here

As you can see, the ack field of the packet just below the data is 37 + 1 = 38.

Does someone knows where or how it can be found ?

EDIT:

There is actually no field that gives the segment length but it can be calculated with two methods:

tcp_seg_len = len(rp.getlayer(Raw).load)
# or
ip_total_len = rp.getlayer(IP).len
ip_header_len = rp.getlayer(IP).ihl * 32 / 8
tcp_header_len = rp.getlayer(TCP).dataofs * 32 / 8
tcp_seg_len = ip_total_len - ip_header_len - tcp_header_len

ans_ack,unans_ack = sr(IP(dst=ip)/TCP(sport=pkt[1].dport, \
dport=pkt[1].sport, \
seq=rp[1].ack, \
ack=tcp_seg_len + 1, \
flags="A"), \
verbose=0, timeout=1)


However, when I print the values I get the good ack number but when I watch the wireshark capture, I have a huge ack number and the packet is marked as "ACKed unseen segment". When I look at the bytes in hexa, I got the right value though. Does anyone knows why that happens and how to solve it?

Answer

Wireshark uses relative numbers in its display so the right scapy line is :

    ans_ack,unans_ack = sr(IP(dst=ip)/TCP(sport=pkt[1].dport, \
                                      dport=pkt[1].sport, \
                                      seq=rp[1].ack, \
                                      ack=rp[1].seq + tcp_seg_len, \
                                      flags="A"), \
                       verbose=0, timeout=1)

And the following code (see EDIT in the question) does work :

ip_total_len = rp.getlayer(IP).len
ip_header_len = rp.getlayer(IP).ihl * 32 / 8
tcp_header_len = rp.getlayer(TCP).dataofs * 32 / 8
tcp_seg_len = ip_total_len - ip_header_len - tcp_header_len
ans_ack,unans_ack = sr(IP(dst=ip)/TCP(sport=pkt[1].dport, \
                                      dport=pkt[1].sport, \
                                      seq=rp[1].ack, \
                                      ack=rp[1].seq + tcp_seg_len, \
                                      flags="A"), \
                           verbose=0, timeout=1)