Debian Linux (and its derivatives like Ubuntu and Kali) has a system called alternatives that’s designed to manage having different version of some software, or aliasing different commands to different versions within the system. Most of the time, this is managed by the package management system. When you run apt install x, it may do some of this behind the scenes for you. But there are times when it is really useful to know how to interact with this yourself. For example, I’m currently working on a challenge that requires using an older version of Java to interact with a file. I’ll use update-altneratives to install the new Java version, and then to change what version java, javac, jar, etc utilize.

Example: nc

Background

nc is the Swiss Army knife of hacking at things. There’s a more powerful version, ncat, that brings in additional functionality, like SSL support, IPv6 support, and proxy support. If you’ve ever installed ncat, you may have noticed that running nc actually now runs ncat. This is managed by the alternatives system.

Before and After Install ncat

In a clean Kali install, nc is simply nc (actually nc.traditional, as I’ll show in a moment). If I run update-alternatives with the --display option, I can see that there is a symbolic link at /bin/nc, and it points currently to /bin/nc.traditional:

root@kali# update-alternatives --display nc
nc - auto mode
  link best version is /bin/nc.traditional
  link currently points to /bin/nc.traditional
  link nc is /bin/nc
  slave nc.1.gz is /usr/share/man/man1/nc.1.gz
  slave netcat is /bin/netcat
  slave netcat.1.gz is /usr/share/man/man1/netcat.1.gz
/bin/nc.traditional - priority 10
  slave nc.1.gz: /usr/share/man/man1/nc.traditional.1.gz
  slave netcat: /bin/nc.traditional
  slave netcat.1.gz: /usr/share/man/man1/nc.traditional.1.gz

I can run a listener, and connect to it and then exit:

root@kali# nc -lnvp 443
listening on [any] 443 ...
connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 46698

Now I’ll run apt install ncat. If I do the same thing, I get the ncat status strings:

root@kali# nc -lnvp 443
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 127.0.0.1.
Ncat: Connection from 127.0.0.1:46710.

The --display option now shows the new alternative added:

root@kali# update-alternatives --display nc
nc - auto mode
  link best version is /usr/bin/ncat
  link currently points to /usr/bin/ncat
  link nc is /bin/nc
  slave nc.1.gz is /usr/share/man/man1/nc.1.gz
  slave netcat is /bin/netcat
  slave netcat.1.gz is /usr/share/man/man1/netcat.1.gz
/bin/nc.traditional - priority 10
  slave nc.1.gz: /usr/share/man/man1/nc.traditional.1.gz
  slave netcat: /bin/nc.traditional
  slave netcat.1.gz: /usr/share/man/man1/nc.traditional.1.gz
/usr/bin/ncat - priority 40
  slave nc.1.gz: /usr/share/man/man1/ncat.1.gz
  slave netcat: /usr/bin/ncat
  slave netcat.1.gz: /usr/share/man/man1/ncat.1.gz

There’s a second alternative, ncat, and it has a higher priority than the previous option, and it is currently what /bin/nc points to.

To dig in one more level, I’ll look at what’s actually at /bin/nc. namei is a good utility to see this:

root@kali# namei /bin/nc
f: /bin/nc
 d /
 l bin -> usr/bin
   d usr
   d bin
 l nc -> /etc/alternatives/nc
   d /
   d etc
   d alternatives
   l nc -> /usr/bin/ncat
     d /
     d usr
     d bin
     - ncat

namei starts at / in the given path, and traces down what it finds, following links. Interestingly, this shows that /bin is actually a symbolic link to /usr/bin (I didn’t know that before working on this post). Then it reached /usr/bin/nc, which it finds is a link to /etc/alternatives/nc. It will then find that is a link to /usr/bin/ncat.

I can see those same links with ls is that’s more familier:

root@kali# ls -l /bin/nc
lrwxrwxrwx 1 root root 20 Feb 21 20:57 /bin/nc -> /etc/alternatives/nc
root@kali# ls -l /etc/alternatives/nc
lrwxrwxrwx 1 root root 13 Mar 20 09:29 /etc/alternatives/nc -> /usr/bin/ncat

I wanted a slightly cleaner way to visualize the links, so I creates a small function in my .bashrc file:

function tracelnk () {
    namei $1 | grep -E -e "^\s+l " -e "^f"
}

Running that just shows the root file and the links:

root@kali# tracelnk /bin/nc
f: /bin/nc
 l bin -> usr/bin
 l nc -> /etc/alternatives/nc
   l nc -> /usr/bin/ncat

Changing Alternative

Now that I have these options install, how do I change between them? I’ll use the --config option:

root@kali# update-alternatives --config nc
There are 2 choices for the alternative nc (providing /bin/nc).

  Selection    Path                 Priority   Status
------------------------------------------------------------
* 0            /usr/bin/ncat         40        auto mode
  1            /bin/nc.traditional   10        manual mode
  2            /usr/bin/ncat         40        manual mode

Press <enter> to keep the current choice[*], or type selection number: 1
update-alternatives: using /bin/nc.traditional to provide /bin/nc (nc) in manual mode

Above, it presents three options. The first is auto mode, saying take the option with the highest priority. The next two are manually setting which one I want. I entered 1, so it switched to nc.traditional. I can see the link in /etc has updated:

root@kali# tracelnk /bin/nc
f: /bin/nc
 l bin -> usr/bin
 l nc -> /etc/alternatives/nc
   l nc -> /bin/nc.traditional
     l bin -> usr/bin

I’ll run it again and select option 0 to go back to auto for nc.

Java

Background / Starting Status

The challenge that got me on this path involved a Java Jar file that was created with Java 8. I can see that I actually already have a version of Open JDK 8 on Kali:

root@kali# update-alternatives –display java 
java - auto mode
 link best version is /usr/lib/jvm/java-11-openjdk-amd64/bin/java
 link currently points to /usr/lib/jvm/java-11-openjdk-amd64/bin/java
 link java is /usr/bin/java
 slave java.1.gz is /usr/share/man/man1/java.1.gz 
/usr/lib/jvm/java-11-openjdk-amd64/bin/java - priority 1111
 slave java.1.gz: /usr/lib/jvm/java-11-openjdk-amd64/man/man1/java.1.gz 
/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java - priority 1081
 slave java.1.gz: /usr/lib/jvm/java-8-openjdk-amd64/jre/man/man1/java.1.gz

java is currently in auto, with the openjdk version 11 having the highest priority.

Install Oracle Java 8

I could tell update-alternatives to use that Open JDK 8, but I want to grab the actual Oracle Java version. I downloaded it here. It’s a tar archive. Given the folder structure that already exists, I’ll decompress is into /usr/lib/jvm with the others:

root@kali# ls /usr/lib/jvm/
default-java  java-1.11.0-openjdk-amd64  java-11-openjdk-amd64  java-1.8.0-openjdk-amd64  java-8-openjdk-amd64  jdk1.8.0_241

Now --install will create an alternative option for this version:

root@kali# update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk1.8.0_241/bin/java 1082

The arguments there are the link file to use, the name of the command, the path to the actual binary, and the desired priority.

This version now shows up as an alternative when I run --config:


t@kali:/# update-alternatives --config java
There are 3 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                                            Priority   Status
------------------------------------------------------------
* 0            /usr/lib/jvm/java-11-openjdk-amd64/bin/java      1111      auto mode
  1            /usr/lib/jvm/java-11-openjdk-amd64/bin/java      1111      manual mode
  2            /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java   1081      manual mode
  3            /usr/lib/jvm/jdk1.8.0_241/bin/java               1082      manual mode

Press <enter> to keep the current choice[*], or type selection number:

There are other binaries in the JDK that I’ll want to add as well, like jar and javac. Unfortunately, those each have to be managed independently.

Conclusion

update-alternatives is a neat little utility to understand if you have to work with some older versions of software. I hadn’t really understood how it worked before digging in for this challenge and this post, but now I see it as something I’ll use in the future.