scapy:发送数据包时不允许进行操作

问题描述 投票:0回答:5

我正在尝试学习一些使用 scapy 生成数据包的知识。看起来很酷。根据一些文档,我正在这样做:

l3=IP(dst="192.168.0.1", src="192.168.0.2", tos=(46 << 2))

但只是得到错误消息:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/scapy/sendrecv.py", line 251, in send
    __gen_send(conf.L3socket(*args, **kargs), x, inter=inter, loop=loop, count=count,verbose=verbose, realtime=realtime)
  File "/usr/lib/python2.7/dist-packages/scapy/arch/linux.py", line 307, in __init__
    self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type))
  File "/usr/lib/python2.7/socket.py", line 187, in __init__
    _sock = _realsocket(family, type, proto)
error: [Errno 1] Operation not permitted

以 root 身份运行 scapy 解决了问题。但这不是我想要的。是因为普通用户无法创建RAW套接字吗?如果是的话有解决办法吗?

python scapy
5个回答
12
投票

Scapy 需要 root 权限才能创建原始套接字,因为它使用 Python 套接字库。根据 Linux 原始手册页,仅允许使用“有效用户 ID 为 0 或 CAP_NET_RAW 功能”的原始套接字。

我找不到关于设置

CAP_NET_RAW
功能的可靠文档,但如果您正在寻找一种解决方法来运行无需 root 用户的原始套接字的 Scapy 脚本,那么这就是您需要做的。


8
投票

仅使用

cap_net_raw
权限运行 Scapy...

我知道的最安全、最简单的方法是,按顺序:

  1. 制作 python 二进制文件的个人副本:

    $ sudo cp /usr/bin/python2.7 ~/python_netraw

  2. 拥有它:

    $ sudo chown

    your user name
    ~/python_netraw

  3. 不要让其他人运行它:

    $ chmod -x,u+x ~/python_netraw

  4. 赋予它 cap_net_raw 功能:

    $ sudo setcap cap_net_raw=eip /usr/bin/python_netraw

  5. 用它运行 scapy:

    $ ~/python_netraw -O /usr/bin/scapy

(或者每次需要以原始权限运行 Scapy 时使用

sudo
。)


5
投票

一种肮脏的方法,可能不安全:直接为 Python 提供 CAP_NET_RAW 功能:

sudo setcap cap_net_raw=eip $(readlink -f $(which python))

0
投票

要使用 cap_net_raw 运行临时 python 环境(例如 scapy),我发现这有效:

sudo -E capsh --caps="cap_setpcap,cap_setuid,cap_setgid+ep cap_net_raw+eip" --keep=1 --user="$USER" --addamb="cap_net_raw" -- -c /usr/bin/python3

改编自Arch Wiki


0
投票

我自己还没有尝试过,但我想这可能是一个选择(来自 scapy 教程“Scapy in 15 分钟”):

或者,Scapy 可以使用操作系统套接字发送和接收数据包。 以下示例将 UDP 套接字分配给 Scapy StreamSocket, 然后用于查询 www.example.com IPv4 地址。与其他不同 Scapy 套接字,StreamSockets 不需要 root 权限

import socket

sck = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # create an UDP socket
sck.connect(("8.8.8.8", 53))  # connect to 8.8.8.8 on 53/UDP

# Create the StreamSocket and gives the class used to decode the answer
ssck = StreamSocket(sck)
ssck.basecls = DNS

# Send the DNS query
ssck.sr1(DNS(rd=1, qd=DNSQR(qname="www.example.com")))
© www.soinside.com 2019 - 2024. All rights reserved.