1. 前言

如果只需要研究Linux的tcp协议栈行为,只需要使用packetdrill就能够满足我的所有需求。packetdrill才是让我随心所欲地撩tcp协议栈。packetdrill的简单使用手册。

然而悲剧的是,除了要研究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。其次是官方的参考手册

  • 基本语法

    1. ip/tcp/http数据包操纵
>>> IP()
<IP  |>
>>>> IP()/TCP()
<IP  frag=0 proto=tcp |<TCP  |>>
>>>> IP(proto=55)/TCP()
<IP  frag=0 proto=55 |<TCP  >> >>>> Ether()/IP()/TCP()
<Ether  type=IPv4 |<IP  frag=0 proto=tcp |<TCP  |>>>
>>>> IP()/TCP()/"GET /HTTP/1.0\r\n\r\n"     数据部分可以直接使用字符串
<IP  frag=0 proto=tcp |<TCP  |<Raw  load='GET /HTTP/1.0\r\n\r\n' |>>>
>>>> Ether()/IP()/UDP()
<Ether  type=IPv4 |<IP  frag=0 proto=udp |<UDP  |>>>
>>>> Ether()/IP()/IP()/UDP()
<Ether  type=IPv4 |<IP  frag=0 proto=ipencap |<IP  frag=0 proto=udp |<UDP  |>>>>>>> str(IP())
'E\x00\x00\x14\x00\x01\x00\x00@\x00|\xe7\x7f\x00\x00\x01\x7f\x00\x00\x01'
>>> IP(_)
<IP  version=4L ihl=5L tos=0x0 len=20 id=1 flags= frag=0L ttl=64 proto=hopopt chksum=0x7ce7 src=127.0.0.1 dst=127.0.0.1 |>
>>> 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..a
0020   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 64 65 78    ..u..GET /index
0040   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
"\x00\x03\x0f\x19jI\x08\x00'\xfe\xd8\x12\x08\x00E\x00\x00C\x00\x01\x00\x00@\x06px\xc0\xa8s\xc6\xb4a!l\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\xb3u\x00\x00GET /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",ttl=(1,4)),iface="eth0")

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 / Padding
0001 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 / Padding
0002 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
<IP  version=4L ihl=5L tos=0x0 len=32 id=26000 flags= frag=0L ttl=128 proto=icmp chksum=0x6c79 src=192.168.115.188 dst=192.168.115.198 options=[] |<ICMP  type=echo-reply code=0 chksum=0x1826 id=0x0 seq=0x0 |<Raw  load='test' |<Padding  load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |>>>>
>>> p.show()
###[ IP ]###version= 4Lihl= 5Ltos= 0x0len= 32id= 26000flags= frag= 0Lttl= 128proto= icmpchksum= 0x6c79src= 192.168.115.188dst= 192.168.115.198\options\
###[ ICMP ]###type= echo-replycode= 0chksum= 0x1826id= 0x0seq= 0x0
###[ Raw ]###load= 'test'
###[ Padding ]###load= '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
  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/python
from scapy.all import *# VARIABLES
src = 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].sport
SeqNr=a[0].seq
AckNr=a[0].seq+1# Generating the IP layer:
ip=IP(src="192.168.1.1", dst="192.168.1.2")
# Generating TCP layer:
TCP_SYNACK=TCP(sport=80, dport=ValueOfPort, flags="SA", seq=SeqNr, ack=AckNr, options=[('MSS', 1460)])#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",count=1,prn=lambda x:x.sprintf("{IP:%IP.src%: %TCP.dport%}"))
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\x0d\x0aDate: Wed, 29 Sep 2010 20:19:05 GMT\x0d\x0aServer: Testserver\x0d\x0aConnection: Keep-Alive\x0d\x0aContent-Type: text/html; charset=UTF-8\x0d\x0aContent-Length: 291\x0d\x0a\x0d\x0a<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\"><html><head><title>Testserver</title></head><body bgcolor=\"black\" text=\"white\" link=\"blue\" vlink=\"purple\" alink=\"red\"><p><font face=\"Courier\" color=\"blue\">-Welcome to test server-------------------------------</font></p></body></html>"# Generate TCP data
data1=TCP(sport=80, dport=ValueOfPort, flags="PA", seq=SeqNr, ack=AckNr, options=[('MSS', 1460)])# 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", seq=SeqNr, ack=AckNr, options=[('MSS', 1460)])send(ip/Bye)# The End

这个服务器只需要使用wget或者curl就可以实现验证了。

4. 参考资料

  1. http://www.secdev.org/projects/scapy/doc/usage.html#starting-scapy

  2. https://akaljed.wordpress.com/2010/12/12/scapy-as-webserver/

  3. http://lost-and-found-narihiro.blogspot.com/2012/12/scapy-simple-web-server-with-scapy.html

python Scapy 随心所欲撩tcp协议栈相关推荐

  1. python scapy 函数_【python|scapy】sprintf输出时raw_string转string

    最近在有python的scapy模块分析TCP报文,一直有一个关于转义字符的问题困惑着我,查找的很多资料后仍然百思不得其解,请大神指教. 请看代码: from scapy.all import * d ...

  2. [源码]python Scapy Ftp密码嗅探

    [源码]python Scapy Ftp密码嗅探 原理很简单,FTP密码明文传输的 截取tcp 21端口User和Pass数据即可 Scapy框架编译程序较大(一个空程序都25M),所以就不提供exe ...

  3. 从Linux内核角度看中间人攻击(ARP欺骗)并利用Python scapy实现

    邻居子系统与ARP协议 邻居子系统的作用就是将IP地址,转换为MAC地址,类似操作系统中的MMU(内存管理单元),将虚拟地址,转换为物理地址. 其中邻居子系统相当于地址解析协议(IPv4的ARP协议, ...

  4. python scapy使用教程_Scapy的基本使用

    关于Scapy Scapy是一个可以让用户发送.侦听和解析并伪装网络报文的Python程序.这些功能可以用于制作侦测.扫描和攻击网络的工具. 换言之,Scapy 是一个强大的操纵报文的交互程序.它可以 ...

  5. Python scapy抓包程序

    尝试使用Python scapy 包中 sniff 函数写个简单的抓包程序,sniff 抓取数据包并写入本地文件 1. 安装scapy,windows7 系统需要先安装 npcap,pip 之后 ,简 ...

  6. python 抓包 scapy udp,python+scapy 抓包與解析

    最近一直在使用做流量分析,今天把 scapy 部分做一個總結. python 的 scapy 庫可以方便的抓包與解析包,無奈資料很少,官方例子有限,大神博客很少提及, 經過一番嘗試后,總結以下幾點用法 ...

  7. Python Scapy

    Python Scapy Scapy介绍 Scapy主要功能 安装Scapy3 Scapy默认值 最简单Ping测试(1) 最简单Ping测试(2) 收发数据包介绍 提取返回包详细信息 测试Ping一 ...

  8. python网络编程自学_五分钟搞定Python网络编程实现TCP和UDP连接

    Python网络编程实现TCP和UDP连接, 使用socket模块, 所有代码在python3下测试通过. 实现TCP#!/usr/bin/env python3 # -*- coding: utf- ...

  9. linux协议栈劫持,Linux系统优化之TCP协议栈优化-基本篇1

    因为在做爬虫分布式系统的过程中,涉及到了一些linux系统优化方面的知识,所以来总结一下,我们会对linux的不同模块做相关的基本优化,这篇文章主要讲述的是关于tcp协议栈的参数优化. 1.机器环境 ...

最新文章

  1. Squid处理web数据请求
  2. 如何在保留订单的同时从列表中删除重复项?
  3. 多线程:volatile
  4. Azure已成为微软业绩的顶梁柱
  5. python 虚拟环境 django.db 报错_jumpserver一体化安装
  6. webview跟html通信的原理,1.iOS: webView与html的交互
  7. 智能手环和智能手表有啥区别啊?
  8. [翻译]RoboChamps城市挑战赛
  9. 事件代理与事件处理流程
  10. python条形图的间距_Matplotlib有间隙条形图
  11. matlab中 晶闸管整流桥导通角_逆变角如何设置,晶闸管2011-6-6
  12. python牛顿迭代公式_牛顿迭代法Python实现
  13. linux系统小红帽和ubuntu,Thinkpad trackpoint小红帽和中间键功能的实现。
  14. 顶级公司程序员,一天只写100行代码?
  15. 内存管理基础学习笔记 - 4.2 缺页中断处理 - do_page_fault
  16. 26进制(A到Z表示1到26,例27:AA,2019:BYQ)
  17. 案件被终本后,失信被执行人会从黑名单中移除吗?
  18. springboot项目扫描不到controller中的解决方法
  19. centos7 安装anaconda3,notebook,解决matplotlib 中文乱码
  20. 教师计算机培训心得体会2000,双师型教师计算机培训心得体会定稿(全文完整版)...

热门文章

  1. 用html5中canvas实现一个微信零钱余额生成器
  2. python 隐含波动率_什么是隐含波动率_隐含波动率的计算公式及平稳性
  3. 解决不能完全卸载solidworks2016的方法之一
  4. 计算机主板 安装系统,电脑更换主板不用重装系统的方法有哪些
  5. Jama Contour 轻量型企业需求管理工具
  6. TradeX使用注意事项?
  7. Qt实现长图片的放大缩小以及动态显示
  8. 字节出了一款设计神器,居然这么好用。外包又有icon、插画素材了
  9. 苹果笔记本充不了电怎么回事|苹果笔记本充不了电的修复方法
  10. java 离散_离散值计算方法JAVA实现