【发布时间】:2015-06-01 03:20:18
【问题描述】:
import socket
import os
import struct
import sys
from ctypes import *
# host to listen on
host = sys.argv[1]
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 interface
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))
# we want the IP headers included in the capture
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
# if we're on Windows we need to send some ioctls
# to setup promiscuous mode
if 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)
这是来自 Black Hat Python 一书的代码。此代码应该嗅探原始套接字并显示来自 IP 标头的信息。它在 Windows 上运行良好(使用 Windows 8.1 64 位)。当我尝试在 linux (Kali linux 1.1.0-amd64) 上运行它时,我收到以下错误
ValueError: Buffer size too small (20 instead of at least 32 bytes)
为了解决这个问题,我像这样在缓冲区中添加了 12 个空格
ip_header = IP(raw_buffer[0:20]+' '*12)
当我这样做时,我得到以下错误
struct.error: 'L' format requires 0 <= number <= 4294967295
这样就行了
self.src_address = socket.inet_ntoa(struct.pack("<L",self.src))
我尝试将 L 之前的符号更改为 > 和 !我只用 L 试了一下,他们都给了我同样的问题。我也尝试像这样将 self.src 包装在 ntohs 中
self.src_address = socket.inet_ntoa(struct.pack("<L",socket.ntohs(self.src)))
我认为这与字节序有关,但我不确定。任何帮助将不胜感激。
注意:在 Windows 上,您必须以管理员身份运行,而在 linux 上,由于原始套接字,您必须以超级用户身份运行。如果您在 linux 上运行它,请打开另一个终端并 ping www.google.com,这样您就可以生成一些 ICMP 数据包以供其捕获。
编辑:我也尝试过使用
反转缓冲区ip_header = IP(raw_buffer[0:20][::-1]+' '*12)
编辑 2:在执行此处列出的任何其他项目之前,我确实在下一行尝试了 65535 和 65534。
raw_buffer = sniffer.recvfrom(65565)[0]
编辑 3:这在运行 python 2.7.6 的 ubuntu 机器上工作,我的 kali 发行版是 2.7.3,所以我决定在我的 kali 盒子上获取最新版本的 python,恰好是 2.7.9。还是没有运气。
我将以下代码放入结构中的 new 函数中以查看缓冲区大小
print sizeof(self)
在我的 Ubuntu 和 windows 机器上是 20,但在我的 kali 机器上是 32
【问题讨论】:
-
您的代码正在运行。 sys.version '2.7.6(默认,2014 年 3 月 22 日,22:59:38)\n[GCC 4.8.2]'。
uname -a'Linux 笔记本电脑 3.16.0-25-generic #33-Ubuntu SMP Tue Nov 4 12:05:25 UTC 2014 i686 i686 i686 GNU/Linux' -
尝试传递整个缓冲区
IP(raw_buffer)或IP(raw_buffer[:32]) -
有趣.. 看看我的 linux 机器上的 python 版本是 2.7.3,我的 windows 是 2.7.8... 我会尝试升级看看会发生什么。
-
我改变了这个。
host = 'localhost'并运行ping localhost -
hmmmm 我在 kali 机器上升级到 python 2.7.9 仍然遇到同样的错误。我尝试在我的 Ubuntu VM 上使用 2.7.6 运行相同的代码,它可以工作......一定是我的 kali 盒子上的东西正在这样做......
标签: python linux sockets networking