Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 39 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# ProSafeLinux (psl-cli.py)

If your interface is **not** eth0 please specify it, when you call *psl.py*.
Query and set data on GS105E and GS108E Netgear ProSafe switches.

These are known to work:
* GS105E 1.02.04
* GS108Ev2 1.00.12
* GS108Ev3 2.06.08EN (replies come via unicast)

# Using psl-cli.py

usage: psl-cli.py [-h] [--interface INTERFACE] [--debug]
[--timeout TIMEOUT]
{discover,exploit,query,query_raw,set} ...

* Older switch firmware (before 2018?) returns responses to the broadcast address.
* Newer switch firmware (after 2018?) return responses to the sender.
* If your interface is **not** eth0 please specify it, when you call *psl.py*.

# Examples

Expand All @@ -19,20 +35,38 @@ Query all ports for their 802.1Q VLAN port VID

./psl-cli.py query --mac B0:B9:8A:57:F6:56 vlan_pvid

# Dependencies

Required for cross-platform support of MacOS & Linux.
- pip install netifaces

# Supported Platforms

"discover" and "query" were recently tested on
* MacOS 10.15 with python 2.7
* Raspbian Linux 4.19.66-v7+ with python 2.7

# Known issues

Discovery only identifies the first switch that answers.

Newer switches that have web servers may have "Switch Management Mode" set to "Web browser only", which will result in the switch only responding to discovery requests. To use this software, you may login to the web UI and set "Switch Management Mode" to "Web browser and Plus Utility".

"query all" sometimes produces inconsistent results. More reliable responses seem to occur when you query one item at at time.

# Help wanted

Im sorry I am not active at this project anymore. It is open-source so perhabs you could find soneone who can help you.
Im sorry I am not active at this project anymore. It is open-source so perhaps you could find soneone who can help you.

I have found a security problem with this switch and was very disapointed in the answer from netgear. They need more than 6 Month to fix it and want the ethernet adress of it
I have found a security problem with this switch and was very disappointed in the answer from netgear. They need more than 6 Month to fix it and want the ethernet adress of it

Because of this, I do not use this switch anymore.

If you can read german, please read this two articles:

http://www.linux-magazin.de/Blogs/Insecurity-Bulletin/Gastbeitrag-Security-by-Obscurity-bei-Netgear-Switches
http://www.linux-magazin.de/Ausgaben/2012/10/Switch


Please feel free to fork the code and do any push request.

Please contact me if you like to do the new maintainer of the projekt Sven Anders <[email protected]>
Expand All @@ -48,6 +82,7 @@ https://github.com/Z3po/Netgearizer (We are merging code together.)
* Svenne Krap
* Shane Kerr
* Sven Anders
* Steven Bytnar

See also: http://git.asbjorn.biz/?p=gs105e.git;a=summary

Expand Down
52 changes: 24 additions & 28 deletions psl_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,17 @@
import psl_typ
import inspect
import errno
import select
import netifaces


def get_hw_addr(ifname):
"gives the hardware (mac) address of an interface (eth0,eth1..)"
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ifname = ifname.encode('ascii') # struct.pack requires bytes in Python 3
info = fcntl.ioctl(sock.fileno(), 0x8927, struct.pack('256s', ifname[:15]))
if type(info) is str:
return ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1]
else:
# Python 3 returns a list of bytes from ioctl, no need for ord()
return ''.join(['%02x:' % char for char in info[18:24]])[:-1]
return netifaces.ifaddresses(ifname)[netifaces.AF_LINK][0]['addr']

def get_ip_address(ifname):
"returns the first ip address of an interface"
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ifname = ifname.encode('ascii') # struct.pack requires bytes in Python 3
try:
# 0x8915 = SIOCGIFADDR
addr = socket.inet_ntoa(fcntl.ioctl(sock.fileno(), 0x8915,
struct.pack('256s',
ifname[:15]))[20:24])
return addr
except IOError as err:
if err.errno == errno.EADDRNOTAVAIL:
return None
raise
return netifaces.ifaddresses(ifname)[2][0]['addr']

def pack_mac(value):
"packs the hardware address (mac) to the internal representation"
Expand Down Expand Up @@ -142,18 +126,24 @@ def bind(self, interface):
return False
self.srcmac = pack_mac(get_hw_addr(interface))

# send socket
self.ssocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# send socket, can also be used to receive unicast!
self.ssocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
self.ssocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.ssocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
self.ssocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

self.ssocket.bind((self.myhost, self.RECPORT))
#self.ssocket.bind(('<broadcast>', self.RECPORT))
#self.ssocket.bind(('', self.RECPORT))

# receive socket
# separate broadcast receive socket
self.rsocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.rsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# self.rsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
self.rsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
self.rsocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
self.rsocket.bind(("255.255.255.255", self.RECPORT))
#self.rsocket.bind(("<broadcast>", self.RECPORT))
self.rsocket.bind(('', self.RECPORT))
#self.rsocket.bind(("255.255.255.255", self.RECPORT))

return True

Expand Down Expand Up @@ -194,15 +184,21 @@ def set_debug_output(self):

def recv(self, maxlen=8192):
"receive a packet from the switch"
self.rsocket.settimeout(self.timeout)

sel = select.select([self.ssocket.fileno(), self.rsocket.fileno()], [], [], self.timeout)
if sel[0] and sel[0][0] == self.ssocket.fileno():
rsock = self.ssocket
else:
rsock = self.rsocket
rsock.settimeout(self.timeout)
try:
message, address = self.rsocket.recvfrom(maxlen)
message, address = rsock.recvfrom(maxlen)
except socket.timeout:
return (None, None)
except socket.error as error:
# according to the Python documentation this error
# is system-specifc; this works on Linux
if error.errno == errno.EAGAIN:
if error.errno == errno.EAGAIN:
return (None, None)
raise
if self.debug:
Expand Down