python黑帽子(第三章)
Windows/Linux下包的嗅探

根据os.name判断操作系统 下面是os的源码

posix是Linux nt是Windows
在windows中需要管理员权限、linux中需要root权限 因为是开启混杂模式(混杂模式允许我们嗅探网卡上流经的所有数据包,即使数据的目的地址不是本机)
import socket
import os # 监听的网卡 0.0.0.0表示所有网卡
host = "192.168.1.102" # Windows和Linux的区别是Windows允许我们嗅探所有协议的所有数据包,但Linux只能嗅探到ICMP数据。
if os.name == "nt":
socket_protocol = socket.IPPROTO_IP # 用于接收任何ip包
else:
socket_protocol = socket.IPPROTO_ICMP # 只接受icmp # SOCK_RAW是一种底层的SOCKET编程接口 可以处理ICMP、IGMP等网络报文、可以处理一些特殊协议报文以及操作IP层及其以上的数据
sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol) sniffer.bind((host, 21)) # 对网卡进行监听端口无所谓 # 设置在捕获的数据包中包含IP头
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) # 在Windows平台上,需要设置IOCTL以启动混杂模式,以允许我们嗅探网卡上经过的所有数据包(即使数据的目的地址不是本机)
if os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON) # 读取单个数据包
print(sniffer.recvfrom(65535)) # 在Windows平台上关闭混杂模式
if os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
解码IP头
上面只是捕获了包含ip头的数据包,现在我们来解码关于ip头的信息
ipv4头结构 每行32位

import socket
import os
import struct
from ctypes import *
# 监听的主机IP
host = "192.168.1.102"
# IP头定义
class IP(Structure):
    _fields_ = [
        ('ihl', c_ubyte, 4),            # 头长度
        ('version', c_ubyte, 4),        # 版本号
        ('tos', c_ubyte),               # 服务类型
        ('len', c_ushort),              # ip数据包总长
        ('id', c_ushort),               # 标识符
        ('offset', c_ushort),           # 片偏移
        ('ttl', c_ubyte),               # 生存时间
        ('protocol_num', c_ubyte),      # 协议类型区分上层协议
        ('sum', c_ushort),              # 头部校验
        ('src', c_ulong),               # 源IP   linux需要将c_ulong改为c_uint32
        ('dst', c_ulong)                # 目的IP
    ]
    def __new__(cls, socket_buffer=None):           # new()方法是在类准备将自身实例化时调用,将原始缓冲区中的数据填充到结构中
        return cls.from_buffer_copy(socket_buffer)
    def __init__(self, socket_buffer=None):
        # 协议字段与协议名称对应
        self.protocol_map = {1: 'ICMP', 6: 'TCP', 17: 'UDP'}
        # 可读性更强的IP地址,struct.pack()将数据解码为"<"小端,"L"无符号长型
        # inet_ntoa() 将32bit数值转换为IP地址
        self.src_address = socket.inet_ntoa(struct.pack("<L", self.src))
        self.dst_address = socket.inet_ntoa(struct.pack("<L", self.dst))
        # 匹配协议类型
        try:
            self.protocol = self.protocol_map[self.protocol_num]
        except:
            self.protocol = str(self.protocol_num)
if os.name == 'nt':
    socket_protocol = 0
else:
    socket_protocol = 1
sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
sniffer.bind((host, 0))
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
if os.name == 'nt':
    sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
try:
    while True:
        # 读取数据包
        raw_buffer = sniffer.recvfrom(65565)[0]
        # 前20个字节也就是前160位为ip头
        ip_header = IP(raw_buffer[0:20])
        # 输出协议和通信双方的IP地址
        print("protocol: %s %s -> %s" % (ip_header.protocol, ip_header.src_address, ip_header.dst_address))
# 处理ctrl+c
except KeyboardInterrupt:
    if os.name == 'nt':
        sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)

解码icmp
当发送一个UDP数据包到主机的某个关闭的UDP端口上时,目标主机通常会返回一个ICMP包指示目标端口不可达。这样的ICMP信息意味着目标主机是存活的,因为我们可以假设如果没有接受到发送的UDP数据的任何响应,目标主机应该不存在。

import threading
import socket
import os
import struct
from ctypes import *
import time
from netaddr import IPNetwork, IPAddress
host = "192.168.1.102"
# 目标网段
subnet = "192.168.1.0/24"
# 自定义字段,用于辨别收到的包是否是响应我们的UDP请求
magic_message = b'PYTHONRULES!'
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__(cls, socket_buffer=None):
        return cls.from_buffer_copy(socket_buffer)
    def __init__(self, socket_buffer=None):
        self.protocol_map = {1: 'ICMP', 6: 'TCP', 17: 'UDP'}
        self.src_address = socket.inet_ntoa(struct.pack("<L", self.src))
        self.dst_address = socket.inet_ntoa(struct.pack("<L", self.dst))
        try:
            self.protocol = self.protocol_map[self.protocol_num]
        except:
            self.protocol = str(self.protocol_num)
# ICMP包头定义
class ICMP(Structure):
    _fields_ = [
        ("type", c_ubyte),          # 类型
        ("code", c_ubyte),          # 代码值
        ("checksum", c_ushort),     # 头部校验和
        ("unused", c_ushort),       # 未使用
        ("next_hop_mtu", c_ushort)  # 下一跳的MTU
    ]
    def __new__(cls, socket_buffer=None):
        return cls.from_buffer_copy(socket_buffer)
    def __init__(self, socket_buffer=None):
        pass
# 批量发送UDP请求包
def udp_sender(subnet, magic_message):
    time.sleep(2)
    sender = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    for ip in IPNetwork(subnet):
        try:
            # 设置端口为大于1023的端口号,尽量使用不常用端口
            sender.sendto(magic_message, (str(ip), 65212))
        except:
            pass
if os.name == 'nt':
    socket_protocol = socket.IPPROTO_IP
else:
    socket_protocol = socket.IPPROTO_ICMP
sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
sniffer.bind((host, 0))
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
if os.name == 'nt':
    sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
# 启用多线程发送UDP请求包
t = threading.Thread(target=udp_sender, args=(subnet, magic_message, ))
t.start()
try:
    while True:
        raw_buffer = sniffer.recvfrom(65535)[0]
        ip_header = IP(raw_buffer[0:20])
        # print("protocol: %s %s -> %s" % (ip_header.protocol, ip_header.src_address, ip_header.dst_address))
        # 如果协议为ICMP,则进行下一步处理 ip协议的
        if ip_header.protocol == 'ICMP':
            # 计算真实IP头长度 --> 计算公式:ihl(4位二进制换算十进制) * 4 = ip头长度(字节)
            offset = ip_header.ihl * 4
            buf = raw_buffer[offset:offset + sizeof(ICMP)]
            # 结构ICMP头数据
            icmp_header = ICMP(buf)
            # print("ICMP -> Type: %d Code: %d" % (icmp_header.type, icmp_header.code))
            # 收到检查类型为3,代码为3的ICMP包则说明目标主机存在
            if icmp_header.type == 3 and icmp_header.code == 3:
                # 确认响应的主机在我们的目标子网内
                if IPAddress(ip_header.src_address) in IPNetwork(subnet):
                    # 确认ICMP数据中包含我们发送的自定义字符串
                    if raw_buffer[len(raw_buffer)-len(magic_message):] == magic_message:
                        print("Host Up: %s" % ip_header.src_address)
except KeyboardInterrupt:
    if os.name == 'nt':
        sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
												
											python黑帽子(第三章)的更多相关文章
- python黑帽子(第五章)
		
对开源CMS进行扫描 import os import queue import requests # 原书编写时间过于久远 现在有requests库对已经对原来的库进行封装 更容易调用 import ...
 - python黑帽子(第四章)
		
Scapy窃取ftp登录账号密码 sniff函数的参数 filter 过滤规则,默认是嗅探所有数据包,具体过滤规则与wireshark相同. iface 参数设置嗅探器索要嗅探的网卡,默认对所有的网卡 ...
 - 读书笔记 ~ Python黑帽子  黑客与渗透测试编程之道
		
Python黑帽子 黑客与渗透测试编程之道 <<< 持续更新中>>> 第一章: 设置python 环境 1.python软件包管理工具安装 root@star ...
 - 2017-2018-2 20179204 PYTHON黑帽子 黑客与渗透测试编程之道
		
python代码见码云:20179204_gege 参考博客Python黑帽子--黑客与渗透测试编程之道.关于<Python黑帽子:黑客与渗透测试编程之道>的学习笔记 第2章 网络基础 t ...
 - python学习心得第三章
		
python学习心得第三章 1.三元运算 变量=值1 if 条件 else 值2 由图如果条件成立则赋值1给变量,如果条件不成立则赋值2给变量. 2.数据类型 集合:set() class set(o ...
 - python学习笔记——第三章 串
		
第三章 字符串学习 1.字符串不灵活, 它不能被分割符值 >>> format = "hello, %s. %s enough for ya?" >> ...
 - 《零压力学Python》 之 第三章知识点归纳
		
第三章(第一个程序)知识点归纳 编程犹如写剧本.Python函数与剧本差别不大,你可以反复调用函数,而它每次都执行预定的“脚本”(脚本也可以指整个程序). 在Python IDLE中,真正的编程是从编 ...
 - 跟着高淇学Python——第一到第三章总结
		
2019/10/26 第一章:Python介绍 Python是一种解释型,面向对象的语言.特点是: 可读性强 简洁,简洁 面向对象 免费开源 可移植性和跨平台性 丰富的库 可扩展性 应用范围:1.人工 ...
 - 路飞学城-Python爬虫集训-第三章
		
这个爬虫集训课第三章的作业讲得是Scrapy 课程主要是使用Scrapy + Redis实现分布式爬虫 惯例贴一下作业: Python爬虫可以使用Requests库来进行简单爬虫的编写,但是Reque ...
 
随机推荐
- 【ASP.NET Core】MVC模型绑定——实现同一个API方法兼容JSON和Form-data输入
			
在上一篇文章中,老周给大伙伴们大致说了下 MVC 下的模型绑定,今天咱们进行一下细化,先聊聊模型绑定中涉及到的一些组件对象. ------------------------------------- ...
 - Key-Value存储系统简介
			
Redis是一个Key-Value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合)和zset(有序集合).这些数据类 ...
 - java 学习笔记(一)
			
书 head first java 1. 2.加强版的FOR循环 3. 通过super引用父类 4.多态 5.接口和抽象类 接口 6.多线程锁 7.JDBC
 - Linux Centos7使用ping命令ping不通网络的解决方案
			
本解决方案不配置dns,都是ping的IP地址,所以如果想ping域名,则加上DNS项的配置后自行尝试吧 我使用的虚拟机系统信息: Linux:Centos7 Network:虚拟机设置的桥接模式(自 ...
 - super.getClass()方法调用?
			
下面程序的输出结果是多少? import java.util.Date; public class Test extends Date{ public static void main(String[ ...
 - innodb和myisam
			
在Mysql数据库中,常用的引擎主要就是2个:Innodb和MyIASM.这篇文章将主要介绍这两个引擎,以及该如何去选择引擎,最后在提一下这2种引擎所使用的数据结构是什么. 首先介绍一下Innodb引 ...
 - char 和 varchar 的区别是什么?float 和 double 的区别是什么?
			
char 和 varchar 的区别是什么? char(n) :固定长度类型,比如订阅 char(10),当你输入"abc"三个字符的时候,它们占的空间还是 10 个字节,其他 7 ...
 - Dubbo 如何停机?
			
Dubbo 是通过 JDK 的 ShutdownHook 来完成优雅停机的,所以如果使用 kill -9 PID 等强制关闭指令,是不会执行优雅停机的,只有通过 kill PID 时,才 会执行.
 - 学习k8s(三)
			
一.Kubernetes核心概念 1.Kubernetes介绍 Kubernetes(k8s)是自动化容器操作的开源平台,这些操作包括部署,调度和节点集群间扩展.如果你曾经用过Docker容器技术部署 ...
 - 学习GlusterFS(四)
			
基于 GlusterFS 实现 Docker 集群的分布式存储 以 Docker 为代表的容器技术在云计算领域正扮演着越来越重要的角色,甚至一度被认为是虚拟化技术的替代品.企业级的容器应用常常需要将重 ...