我正在尝试学习一些使用 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套接字吗?如果是的话有解决办法吗?
Scapy 需要 root 权限才能创建原始套接字,因为它使用 Python 套接字库。根据 Linux 原始手册页,仅允许使用“有效用户 ID 为 0 或 CAP_NET_RAW 功能”的原始套接字。
我找不到关于设置
CAP_NET_RAW
功能的可靠文档,但如果您正在寻找一种解决方法来运行无需 root 用户的原始套接字的 Scapy 脚本,那么这就是您需要做的。
仅使用
cap_net_raw
权限运行 Scapy...
我知道的最安全、最简单的方法是,按顺序:
制作 python 二进制文件的个人副本:
$ sudo cp /usr/bin/python2.7 ~/python_netraw
拥有它:
$ sudo chown
your user name
~/python_netraw不要让其他人运行它:
$ chmod -x,u+x ~/python_netraw
赋予它 cap_net_raw 功能:
$ sudo setcap cap_net_raw=eip /usr/bin/python_netraw
用它运行 scapy:
$ ~/python_netraw -O /usr/bin/scapy
(或者每次需要以原始权限运行 Scapy 时使用
sudo
。)
一种肮脏的方法,可能不安全:直接为 Python 提供 CAP_NET_RAW 功能:
sudo setcap cap_net_raw=eip $(readlink -f $(which python))
要使用 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
我自己还没有尝试过,但我想这可能是一个选择(来自 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")))