Python Scapy sniff without root
Asked Answered
L

2

11

I'm wondering if there is any possibility to run Scapy's 'sniff(...)' without root priveleges.

It is used in an application, where certain packages are captured. But I don't want to run the whole application with root permissions or change anything on scapy itselfe.

Thanks in advance!

EDIT:

For testing I use following code:

from scapy.all import *

def arp_monitor_callback(pkt):
    if ARP in pkt and pkt[ARP].op in (1,2): #who-has or is-at
        return pkt.sprintf("%ARP.hwsrc% %ARP.psrc%")

sniff(prn=arp_monitor_callback, filter="arp", store=0)

I'm only able to run it using sudo.

I tried to set capabilities with sudo setcap 'cap_net_admin=+eip' test.py. But it doesn't show any effects. Even the all capablity doesn't help.

Lubber answered 25/3, 2016 at 6:36 Comment(4)
sniff() needs to set promiscuous mode so capability CAP_NET_ADMIN should be enough for your program to run (see man capabilities(7))Tello
sorry, but I'm not very familiar with capabilities: do I have to set these on to my script, to the scapy lib or even somewhere else?Lubber
You can set the script capabilities with setcap(8) as root if you want regular users to use the program without privilege elevation (example here).Tello
Thanks for the guide, but it doesn't poses any reactions. I added some more information and the test I ran.Lubber
T
17

You need to set capabilities for binaries running your script i-e: python and tcpdump if you want to be able to just execute your script as ./test.py :

setcap cap_net_raw=eip /usr/bin/pythonX.X
setcap cap_net_raw=eip /usr/bin/tcpdump

Where X.X is the python version you use to run the script.

(note that path could be different on your system)

Please note that this allow anyone to open raw sockets on your system.

Tello answered 1/4, 2016 at 12:48 Comment(1)
I just tried it on a virtualenv python and it works as well. This somehow feels better to me than doing it for the global python command.Noahnoak
C
10

Although solution provided by @Jeff is technically correct, because of setting the file capabilities directly on binaries in /usr/bin, it has a drawback of allowing anyone in the system to open raw sockets.

Another way of achieving the desired outcome - script running with just the CAP_NET_RAW - is to use ambient capabilities. This can be done by leveraging a small helper binary that sets up ambient capabilities and exec()'s into python interpreter. For a reference please see this gist.

Using the reference implementation, assuming that that proper file capabilities are assigned to ./ambient:

$ sudo setcap 'cap_net_raw=p' ambient

your script would be launched as:

$ ./ambient -c '13' /usr/bin/python ./test.py

Please note that:

  • 13 is the integer value of CAP_NET_RAW as per capability.h
  • ambient capabilities are available since kernel 4.3
  • you can use pscap to verify if the process was launched with desired capabilities in its effective set

Why does this method work?

Ambient capabilities are preserved across exec() calls (hence passed to all subsequently created subprocesses) and raised in their effective set, e.g. a python interpreter invoked by the binary or tcpdump invoked by python script. This is of course a simplification, for a full description of transitions between capability sets see capabilities(7)

Cleveland answered 26/12, 2017 at 17:59 Comment(2)
This works great for my jupyter notebook setup (py 3.6.5, scapy 2.4.3, jupyter core 4.5.0, jupyter-notebook : 6.0.1)Oly
It didn't work for me $ uname -r 4.4.224-1.el7.elrepo.x86_64 maybe it needs so other specific versions of packages?Meras

© 2022 - 2024 — McMap. All rights reserved.