您好,欢迎来到微智科技网。
搜索
您的当前位置:首页PythonScapy随心所欲研究TCP协议栈

PythonScapy随心所欲研究TCP协议栈

来源:微智科技网
PythonScapy随⼼所欲研究TCP协议栈

1. 前⾔

如果只需要研究Linux的tcp协议栈⾏为,只需要使⽤packetdrill就能够满⾜我的所有需求。packetdrill才是让我随⼼所欲地撩tcp协议栈。。然⽽悲剧的是,除了要研究Linux的TCP协议栈⾏为,还需要研究Windows的tcp协议栈的⾏为,Windows不开源,感觉⾥⾯应该有挺多未知的坑。

为了能够重现Windows的tcp协议栈的⼀些⽹络⾏为,这⾥使⽤python的scapy进⾏包构造撩撩Windows的tcp协议栈。scapy在tcp数据报⽂注⼊会有⼀点的时延,这个⼯具在要求时延严格的场景⽆法使⽤(还是packetdrill好⽤,囧)。针对⽬前遇到的场景,勉强能⽤,再则已经撸惯了python,上⼿起来⽐较容易。2. 基本语法

安装scapy

在Centos 7.2中直接使⽤yum install 来安装。

yum install scapy.noarch

help 能解决⼤部分问题

[root@localhost ~]# scapy

INFO: Can't import python gnuplot wrapper . Won't be able to plot.INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().WARNING: No route found for IPv6 destination :: (no default route?)Welcome to Scapy (2.2.0)>>> help(send)

在⼤部分时候,如果看到不明⽩的地⽅,请⽤help。其次是官⽅的参考⼿册

基本语法ip/tcp/http数据包操纵

>>> IP()

>>>> IP()/TCP()

>>>>> IP(proto=55)/TCP()

> >>>> Ether()/IP()/TCP()

>>

>>>> IP()/TCP()/\"GET /HTTP/1.0\\r\\n\\r\\n\" 数据部分可以直接使⽤字符串>> >>>> Ether()/IP()/UDP()

>>>>>> Ether()/IP()/IP()/UDP()

>>>>>> str(IP())

'E 00 00 14 00 01 00 00@ 00| e7 7f 00 00 01 7f 00 00 01'>>> IP(_)

>>> a=Ether()/IP(dst=\"www.baidu.com\")/TCP()/\"GET /index.html HTTP/1.0 \\n\\n\">>> hexdump(a)

0000 00 03 0F 19 6A 49 08 00 27 FE D8 12 08 00 45 00 ....jI..'.....E.0010 00 43 00 01 00 00 40 06 70 78 C0 A8 73 C6 B4 61 .C....@.px..s..a0020 21 6C 00 14 00 50 00 00 00 00 00 00 00 00 50 02 !l...P........P.0030 20 00 B3 75 00 00 47 45 54 20 2F 69 6E 65 78 ..u..GET /index0040 2E 68 74 6D 6C 20 48 54 54 50 2F 31 2E 30 20 0A .html HTTP/1.0 .0050 0A .>>> b=str(a)>>> b

\" 00 03 0f 19jI 08 00' fe d8 12 08 00E 00 00C 00 01 00 00@ 06px c0 a8s c6 b4a!l 00 14 00P 00 00 00 00 00 00 00 00P 02 00 b3u 00 00GET /index.html HTTP/1.0 \\n\\n\"

1.数据包发送

数据包的发送主要包括以下函数send/sendp/sr/sr1/srp 主要区别是:send函数⼯作在第三层

send(IP(dst=\"192.168.115.188\")/ICMP())

sendp函数⼯作在第⼆层,你可以选择⽹卡和协议

sendp(Ether()/IP(dst=\"192.168.115.188\

fuzz函数的作⽤:可以更改⼀些默认的不可以被计算的值(⽐如校验和checksums),更改的值是随机的,但是类型是符合字段的值的。

send(IP(dst=\"www.baidu.com\")/UDP()/NTP(version=4),loop=2) #未使⽤fuzz()

send(IP(dst=\" www.baidu.com\")/fuzz(UDP()/NTP(version=4)),loop=2) #使⽤fuzz()

SR()函数⽤来来发送数据包和接收响应。该函数返回有回应的数据包和没有回应的数据包;该函数也算得上是scapy的核⼼了,他会返回两个列表数据,⼀个是answer list 另⼀个是unanswered

>>> sr(IP(dst=\"192.168.115.1\")/TCP(dport=[21,22,23]))Begin emission:

Finished to send 3 packets.***

Received 3 packets, got 3 answers, remaining 0 packets

Results: TCP:3 UDP:0 ICMP:0 Other:0>, Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>>> ans,unans=_ 这也是scapy的核⼼了>>> ans.show()

0000 IP / TCP 192.168.115.198:ftp_data > 192.168.115.1:ftp S ==> IP / TCP 192.168.115.1:ftp > 192.168.115.198:ftp_data RA / Padding0001 IP / TCP 192.168.115.198:ftp_data > 192.168.115.1:ssh S ==> IP / TCP 192.168.115.1:ssh > 192.168.115.198:ftp_data RA / Padding0002 IP / TCP 192.168.115.198:ftp_data > 192.168.115.1:telnet S ==> IP / TCP 192.168.115.1:telnet > 192.168.115.198:ftp_data SA / Padding >>>sr(IP(dst=\"192.168.115.1\")/TCP(dport=[21,22,23]),inter=0.5,retry=-2,timeout=1) ⽹络环境不好时,也可以追加inter retry timeout等附加信息,

函数sr1()是sr()⼀个变种,只返回应答发送的分组(或分组集)。这两个函数发送的数据包必须是第3层数据包(IP,ARP等)。⽽函数SRP()位于第2层(以太⽹,802.3,等)。

>>> p=sr1(IP(dst=\"192.168.115.188\")/ICMP()/\"test\")Begin emission:

.....Finished to send 1 packets..*

Received 7 packets, got 1 answers, remaining 0 packets>>> p

###[ Padding ]###

load= ' 00 00 00 00 00 00 00 00 00 00 00 00 00 00'

1.数据包sniff

a=sniff(count=1,filter=\"tcp and host 192.168.1.1 and port 80\")

使⽤sniff主要是⽤于数据包的接收,根据filter设定的条件,将符合条件的数据包接收回来。3. 场景构造

scapy的缺点是,他只负责构造包,是单向的。不像packetdrill这么完美,packetdrill 不但可以构造包,还能实现系统调⽤构造不同的场景,还能帮你检查协议栈发出的数据包是否符合预期。撩协tcp协议栈的过程不外乎两端,⼀端使⽤系统调⽤模拟协议栈⾏为,另外⼀端则是我们构造的包。常见场景主要是:服务器场景、客户端场景。

服务器场景:

服务器场景使⽤系统调⽤(即⽤户态程序),⽽客户端则是scapy构造的包。

在这⾥构造⼀个简单的三次握⼿后向服务器端发送数据。为了防⽌Linux客户端rst。

iptables -A OUTPUT -p tcp --tcp-flags RST RST -s 192.168.56.1 -j DROP

#!/usr/local/bin/pythonfrom scapy.all import *# VARIABLESsrc = sys.argv[1]dst = sys.argv[2]

sport = random.randint(1024,65535)dport = int(sys.argv[3])# SYN

ip=IP(src=src,dst=dst)

SYN=TCP(sport=sport,dport=dport,flags='S',seq=1000)SYNACK=sr1(ip/SYN)# ACK

ACK=TCP(sport=sport, dport=dport, flags='A', seq=SYNACK.ack, ack=SYNACK.seq + 1)send(ip/ACK)

在这⾥可以安装⼀个nginx来验证。

客户端场景:

客户端场景使⽤系统调⽤(即⽤户态程序),⽽服务器端则是scapy构造包。

在这⾥使⽤scapy构造⼀个简单的http服务器。为了防⽌协议栈发送RST,需要对iptables进⾏设置。

iptables -A OUTPUT -p tcp --tcp-flags RST RST --sport 80 -j DROP

#!/usr/bin/python

from scapy.all import *

# Interacts with a client by going through the three-way handshake.

# Shuts down the connection immediately after the connection has been established.# Akaljed Dec 2010, http://www.akaljed.wordpress.com# Wait for client to connect.

a=sniff(count=1,filter=\"tcp and host 192.168.1.1 and port 80\")# some variables for later use.ValueOfPort=a[0].sportSeqNr=a[0].seqAckNr=a[0].seq+1

# Generating the IP layer:

ip=IP(src=\"192.168.1.1\# Generating TCP layer:

TCP_SYNACK=TCP(sport=80, dport=ValueOfPort, flags=\"SA\#send SYNACK to remote host AND receive ACK.ANSWER=sr1(ip/TCP_SYNACK)

# Capture next TCP packets with dport 80. (contains http GET request)

GEThttp = sniff(filter=\"tcp and port 80\AckNr=AckNr+len(GEThttp[0].load)SeqNr=a[0].seq+1

# Print the GET request

# (Sanity check: size of data should be greater than 1.)if len(GEThttp[0].load)>1: print GEThttp[0].load# Generate custom http file content.

html1=\"HTTP/1.1 200 OK 0d 0aDate: Wed, 29 Sep 2010 20:19:05 GMT 0d 0aServer: Testserver 0d 0aConnection: Keep-Alive 0d 0aContent-Type: text/html; charset=UTF-8 0d 0aContent-Length: 291 0d 0a 0d 0adata1=TCP(sport=80, dport=ValueOfPort, flags=\"PA\# Construct whole network packet, send it and fetch the returning ack.ackdata1=sr1(ip/data1/html1)# Store new sequence number.SeqNr=ackdata1.ack

# Generate RST-ACK packet

Bye=TCP(sport=80, dport=ValueOfPort, flags=\"FA\send(ip/Bye)# The End

这个服务器只需要使⽤wget或者curl就可以实现验证了。4. 参考资料总结

以上就是这篇⽂章的全部内容了,希望本⽂的内容对⼤家的学习或者⼯作具有⼀定的参考学习价值,谢谢⼤家对的⽀持。如果你想了解更多相关内容请查看下⾯相关链接

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- 7swz.com 版权所有 赣ICP备2024042798号-8

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务