Как подделать TCP-рукопожатие в scapy?

#python #linux #tcp #scapy

#python #linux #tcp #scapy

Вопрос:

Недавно я пытался написать скрипт Scapy, который выполняет полное рукопожатие TCP. Идея заключалась в том, что я подключаю две виртуальные машины Qemu с помощью -net socket пользовательского интерфейса (который, похоже, отлично обрабатывает необработанный IP / ethernet) и инструктирую машину B блокировать все входные данные от A (чтобы он не отправлял RSTS). Затем я использовал telnet для connect() перехода с компьютера A на компьютер B и запустил следующий скрипт на компьютере 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 amp; 0x10)
  

Проблема в том, что вместо получения подтверждения от A до B я, похоже, получаю повторную передачу SYN, как если бы SYN ACK не был интерпретирован правильно:

https://imgur.com/kv7A3Hr

tcp на компьютере A подтверждает, что SYN ACK достигли компьютера:

 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
  

Вот файл PCAP с точки зрения машины B в форме Base64:

1MOyoQIABAAAAAAAAAAAAP//AAABAAAAYlilUwieDgARAQAAEQEAAAEAXgAA 1JUABI0VggARQABA2UUQAD/ESrYCgAAAuAAAPsU6RTpAO/r/QAAAAAAAwAAAAUAAAE2ATUBNAEzATIBMQFlAWYBZgFmATABMAE0ATUBMAE1ATABMAEwATABMAEwATABMAEwATABMAEwATABOAFlAWYDaXA2BGFycGEAAP8AAQtkZWJpYW4tMTA5MwVsb2NhbAAA/wABATIBMAEwAjEwB2luLWFkZHLAUAD/AAHAWgANAAEAAAB4AAsESTY4NgVMSU5VWMBaAAEAAQAAAHgABAoAAALAcQAMAAEAAAB4AALAWsBaABwAAQAAAHgAEP6AAAAAAAAAUFQA//4SNFbADAAMAAEAAAB4AALAWmJYpVMJoA4AnAAAAJwAAAABAF4AAPtSVAASNFYIAEUAAI4GlEAA/xGJzgoAAAHgAAD7FOkU6QB6hFgAAIQAAAAAAQAAAAABNgE1ATQBMwEyATEBZQFmAWYBZgEwATABNAE1ATABNQEwATABMAEwATABMAEwATABMAEwATABMAEwATgBZQFmA2lwNgRhcnBhAAAMgAEAAAB4ABIKZGViaWFuLTQwNwVsb2NhbABnWKVTvIYIAEIAAABCAAAAUlQAEjRWUlQAEjRWCABFAAA0HdtAAEAGCOcKAAABCgAAAprbemmul/p8AAAAAIACOQhjsAAAAgQFtAEBBAIBAwMEZ1ilU5COCABCAAAAQgAAAFJUABI0VlJUABI0VggARQAANB3bQABABgjnCgAAAgoAAAF6aZrbrpf6fK6X n2AEjkIY7AAAAIEBbQBAQQCAQMDBGhYpVPTfggAQgAAAEIAAABSVAASNFZSVAASNFYIAEUAADQd3EAAQAYI5goAAAEKAAACmtt6aa6X nwAAAAAgAI5CGOwAAACBAW0AQEEAgEDAwRqWKVTrI4IAEIAAABCAAAAUlQAEjRWUlQAEjRWCABFAAA0Hd1AAEAGCOUKAAABCgAAAprbemmul/p8AAAAAIACOQhjsAAAAgQFtAEBBAIBAwME

И один с точки зрения A на B.:

1MOyoQIABAAAAAAAAAAAAP//AAABAAAAVVilU9NXCABCAAAAQgAAAFJUABI0VlJUABI0VggARQAANB3bQABABgjnCgAAAQoAAAKa23pprpf6fAAAAACAAjkIFCkAAAIEBbQBAQQCAQMDBFVYpVPIYAgAQgAAAEIAAABSVAASNFZSVAASNFYIAEUAADQd20AAQAYI5woAAAIKAAABemma266X nyul/p9gBI5CGOwAAACBAW0AQEEAgEDAwRWWKVT008IAEIAAABCAAAAUlQAEjRWUlQAEjRWCABFAAA0HdxAAEAGCOYKAAABCgAAAprbemmul/p8AAAAAIACOQgUKQAAAgQFtAEBBAIBAwMEWFilU4FfCABCAAAAQgAAAFJUABI0VlJUABI0VggARQAANB3dQABABgjlCgAAAQoAAAKa23pprpf6fAAAAACAAjkIFCkAAAIEBbQBAQQCAQMDBA==

Сначала я подумал, что это как-то связано с какой-то особенностью Linux TCP / IP, поэтому я экспериментировал с отключением временных меток TCP и SYN-файлов cookie. Я также попытался увеличить IP ID, что тоже не помогло. На обеих машинах работает Debian 7.5 с linux-image-3.2.0-4-686- pae в рамках qemu 1.6.2. Чего мне не хватает?

Ответ №1:

Это проблема с контрольной суммой.

На уровне IP все в порядке, поскольку вы просто меняете местами адреса источника и назначения, но на уровне TCP исходная контрольная сумма становится неправильной при изменении значения flags .

Лучший вариант — позволить Scapy вычислить правильное значение контрольной суммы для вас, добавив del(t[TCP].chksum) prepare_response() .

Комментарии:

1. Вау, Wireshark не проверил контрольные суммы TCP для меня! Теперь это работает как шарм.

2. Wireshark имеет возможность отключить проверку контрольной суммы, потому что множество стеков переносят вычисление контрольной суммы на оборудование. Вы должны иметь возможность включить их в настройках.