读书笔记 -《Python 黑帽子》 ( 二 )
来源:互联网 发布:nba1415赛季总决赛数据 编辑:程序博客网 时间:2024/04/29 21:12
读书笔记系列文章
一直都在读书,读了忘,忘了再读。不如把每次学到的东西都写下来
第三章 网络:原始套接字和流量嗅探
我的工作内容就是用C 语言写嗅探工具和 DPI。基本的工作原理和本章的内容是非常相似的。所以理解起来会比较容易一些。arp 欺骗和中间人攻击也玩过,所以对这些知识并不陌生。玩的时候用的也是别人的工具,arp 欺骗用的 dsniff 中的 arpspoof,中间人攻击用的 sslsplit,有空也把这些写下来。继续读书
这一章通过原始套接字来解析 IP 协议和 ICMP 协议的信息
开发 UDP 主机发现工具
这一节解释了利用 UDP 协议发现目标网络中的存活主机,其实用 nmap 工具就能实现,但毕竟这本书毕竟是教我们怎么开发自己的工具的,所以还是多懂一些原理比较好。基本原理可以概括为使用 UDP 向目标网络中所有 IP 地址的特定端口发送数据,如果 up 的主机收到这样的报文并且该端口是关闭的,那么就会返回一个 ICMP 报文,表示目标不可达。如果我们发送 UDP 报文后,接着抓到这些 ICMP 报文,那么就能确定哪些主机是 UP 状态了。
Windows 和 Linux 上的包嗅探
混杂模式就不用多介绍了,要想抓包,总是要打开网卡的混杂模式,抓取网卡上流经的所有的包。不过是 Windows还是 Linux 都是需要管理员权限打开。
这一节讲了一个有趣的事情,Windows 允许我们嗅探所有协议的所有数据包,但是 Linux 只能修改 ICMP 数据。
看一段这一节用到的代码吧。很简单,直接读注释就好了。
import socketimport os# host to listen onhost = "192.168.0.196"# create a raw socket and bind it to the public interfaceif os.name == "nt": socket_protocol = socket.IPPROTO_IPelse: socket_protocol = socket.IPPROTO_ICMPsniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol) sniffer.bind((host, 0))# we want the IP headers included in the capturesniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)# if we're on Windows we need to send an IOCTL# to setup promiscuous modeif os.name == "nt": sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)# read in a single packetprint sniffer.recvfrom(65565)# if we're on Windows turn off promiscuous modeif os.name == "nt": sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
解析 IP 层
一直是使用 C 语言来解析 IP 包的,C 语言处理这种数据其实更有优势,指针和数据类型更好使。作者使用 python 的 Ctype 来定义结构体,来完成一些 python 自身不好完成的东西。这也是 python 和 c 天生的血液相连啊。
这一节的代码还是比较简单的,看注释基本就能看懂,看不懂的地方估计就是 Ctype 的使用方法了,python 可读性这么好,还是比较好理解它背后的意思。
但是这个代码是有点问题的。作者使用的 kali 是32位的,我的是64位的,所以在使用 Ctype 的时候,c_ushort和 c_ulong的长度可能会和我的不一样。在我这里运行的时候,代码出错了。于是我把 c_ushort修改为 c_uint16,把 c_ulong修改为 c_uint32,这样就没有问题了。
import socketimport osimport structfrom ctypes import *# host to listen onhost = "192.168.0.187"class IP(Structure): _fields_ = [ ("ihl", c_ubyte, 4), ("version", c_ubyte, 4), ("tos", c_ubyte), ("len", c_ushort), ("id", c_ushort), ("offset", c_ushort), ("ttl", c_ubyte), ("protocol_num", c_ubyte), ("sum", c_ushort), ("src", c_ulong), ("dst", c_ulong) ] def __new__(self, socket_buffer=None): return self.from_buffer_copy(socket_buffer) def __init__(self, socket_buffer=None): # map protocol constants to their names self.protocol_map = {1:"ICMP", 6:"TCP", 17:"UDP"} # human readable IP addresses self.src_address = socket.inet_ntoa(struct.pack("<L",self.src)) self.dst_address = socket.inet_ntoa(struct.pack("<L",self.dst)) # human readable protocol try: self.protocol = self.protocol_map[self.protocol_num] except: self.protocol = str(self.protocol_num)# create a raw socket and bind it to the public interfaceif os.name == "nt": socket_protocol = socket.IPPROTO_IP else: socket_protocol = socket.IPPROTO_ICMPsniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)sniffer.bind((host, 0))# we want the IP headers included in the capturesniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)# if we're on Windows we need to send some ioctls# to setup promiscuous modeif os.name == "nt": sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)try: while True: # read in a single packet raw_buffer = sniffer.recvfrom(65565)[0] # create an IP header from the first 20 bytes of the buffer ip_header = IP(raw_buffer[0:20]) print "Protocol: %s %s -> %s" % (ip_header.protocol, ip_header.src_address, ip_header.dst_address)except KeyboardInterrupt: # if we're on Windows turn off promiscuous mode if os.name == "nt": sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
解码 ICMP
这一节的内容和上节的编写代码的方式是一样的,定义结构体解析 ICMP 的数据。ICMP 报文有两个比较关键的字段,分别是类型值和代码值。在『UDP 主机发现工具』这一节里面,说明了,要想嗅探存活的主机,需要截获返回的 ICMP 报文,目标不可达时,这两个值都是3,同时这个 ICMP 报文的最后8个字节指出了源 UDP 报文的ip 头的8个字节。所以分析返回的 ICMP 报文时,只需要判断这两个值就能判断主机是否存活了。
最后了,完成这个嗅探器
通过以上两节的内容,基本就可以确定嗅探器是怎么实现的了。
只需要开两个线程,一个发送 udp 报文给目标网路的特定端口;另一个线程抓去返回的 ICMP 包就可以了,捉到了哪一个,哪一个就是 UP 状态的。
这一节的代码也是比较好理解的,看代码注释就好了,这里面有一个比较好玩的第三方包 netaddr。这个包可以将「192.168.0.1/24」解析为192.168.0.1 ~ 192.168.0.255 这样的数组。
import socketimport osimport structimport threadingfrom netaddr import IPNetwork,IPAddressfrom ctypes import *# host to listen onhost = "192.168.0.187"# subnet to targetsubnet = "192.168.0.0/24"# magic we'll check ICMP responses formagic_message = "PYTHONRULES!"def udp_sender(subnet,magic_message): sender = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) for ip in IPNetwork(subnet): try: sender.sendto(magic_message,("%s" % ip,65212)) except: passclass IP(Structure): _fields_ = [ ("ihl", c_ubyte, 4), ("version", c_ubyte, 4), ("tos", c_ubyte), ("len", c_ushort), ("id", c_ushort), ("offset", c_ushort), ("ttl", c_ubyte), ("protocol_num", c_ubyte), ("sum", c_ushort), ("src", c_ulong), ("dst", c_ulong) ] def __new__(self, socket_buffer=None): return self.from_buffer_copy(socket_buffer) def __init__(self, socket_buffer=None): # map protocol constants to their names self.protocol_map = {1:"ICMP", 6:"TCP", 17:"UDP"} # human readable IP addresses self.src_address = socket.inet_ntoa(struct.pack("<L",self.src)) self.dst_address = socket.inet_ntoa(struct.pack("<L",self.dst)) # human readable protocol try: self.protocol = self.protocol_map[self.protocol_num] except: self.protocol = str(self.protocol_num)class ICMP(Structure): _fields_ = [ ("type", c_ubyte), ("code", c_ubyte), ("checksum", c_ushort), ("unused", c_ushort), ("next_hop_mtu", c_ushort) ] def __new__(self, socket_buffer): return self.from_buffer_copy(socket_buffer) def __init__(self, socket_buffer): pass# create a raw socket and bind it to the public interfaceif os.name == "nt": socket_protocol = socket.IPPROTO_IP else: socket_protocol = socket.IPPROTO_ICMPsniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)sniffer.bind((host, 0))# we want the IP headers included in the capturesniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)# if we're on Windows we need to send some ioctls# to setup promiscuous modeif os.name == "nt": sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)# start sending packetst = threading.Thread(target=udp_sender,args=(subnet,magic_message))t.start() try: while True: # read in a single packet raw_buffer = sniffer.recvfrom(65565)[0] # create an IP header from the first 20 bytes of the buffer ip_header = IP(raw_buffer[0:20]) #print "Protocol: %s %s -> %s" % (ip_header.protocol, ip_header.src_address, ip_header.dst_address) # if it's ICMP we want it if ip_header.protocol == "ICMP": # calculate where our ICMP packet starts offset = ip_header.ihl * 4 buf = raw_buffer[offset:offset + sizeof(ICMP)] # create our ICMP structure icmp_header = ICMP(buf) #print "ICMP -> Type: %d Code: %d" % (icmp_header.type, icmp_header.code) # now check for the TYPE 3 and CODE 3 which indicates # a host is up but no port available to talk to if icmp_header.code == 3 and icmp_header.type == 3: # check to make sure we are receiving the response # that lands in our subnet if IPAddress(ip_header.src_address) in IPNetwork(subnet): # test for our magic message if raw_buffer[len(raw_buffer)-len(magic_message):] == magic_message: print "Host Up: %s" % ip_header.src_address# handle CTRL-Cexcept KeyboardInterrupt: # if we're on Windows turn off promiscuous mode if os.name == "nt": sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
- 读书笔记 -《Python 黑帽子》 ( 二 )
- 读书笔记 -《Python 黑帽子》 ( 一 )
- 读书笔记 -《Python 黑帽子》 ( 三 )
- 读书笔记 -《Python 黑帽子》 ( 四 )
- 读书笔记 -《Python 黑帽子》 ( 五 )
- Python黑帽子开篇
- python黑帽子 pydasm 配置
- 《Python黑帽子》学习笔记
- Python黑帽子:取代netcat
- 灰帽子python 读书笔记 1
- 灰帽子python 读书笔记 2
- 《python 黑帽子》 示例 :TCP客户端
- 《python 黑帽子》 示例 :UDP客户端
- Python 黑帽子 snffer ip header decoder
- python黑帽子之netcat(chapter1)
- Python黑帽子学习笔记-----第二章
- Python黑帽子学习笔记-----第三章
- Python灰帽子笔记二
- poj 2251 Dungeon Master
- 自己总结的Xcode5和Xcode7的主要区别
- 内省调用JavaBean实现getXxx和setXxx的两种方式
- 钱宝订单查询 chaqb.com
- ui进阶第二天,一些琐碎的东西
- 读书笔记 -《Python 黑帽子》 ( 二 )
- java33.HTTP通信------使用Http的Post方式与网络交互通信
- 线程倒计时
- Android app引导页(背景图片切换加各个页面动画效果)
- 循序渐进学java基础笔记(1)——开山篇
- KVC 与 KVO 理解
- 生命之——松果体
- 读书笔记 -《Python 黑帽子》 ( 四 )
- 16-02-18 Java 方法应用 之 打印字母三角形