> For the complete documentation index, see [llms.txt](https://simon-6.gitbook.io/simoncyber/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://simon-6.gitbook.io/simoncyber/cves/ghsa-vqjf-mvm9-x879.md).

# GHSA-vqjf-mvm9-x879

#### Summary

Looking at the logs system in Repomanger, Repomanger runs automated check on a schedule, creating logs of it. And it also allows you fetch these log files from a centralized system. However, what if it we edit the fetch request? If we use Burp suite to intercept that fetch request, and perhaps fetch something else, what will happen? The code needs to filter (input sanitization) that request, and if it does it wrong then it leads to possible RCE.&#x20;

The `get-unit-log` AJAX action accepts a `logfile` parameter that is concatenated directly into a filesystem path with no traversal check. Any authenticated user can read arbitrary files on the server that are readable by the web user (www-data), including repomanager's configuration, GPG signing-key passphrase, and source code.

Specifically, the parameter is passed through `Validate::string()`, which only escapes HTML (`htmlspecialchars(stripslashes(trim()))`) and leaves `../` completely untouched. This means instead of something like RCE it turns into "Authenticated Path Traversal allows arbitrary file read via service unit log viewer"

#### Steps

1. Navigate to the Status Page and scroll to "Service Units"
2. Load up Burpsuite (or any web interceptor like Devtools)
3. Turn on intercept
4. Click any "View" button in Service Units
5. On Burpsuite/Interceptor, replace the name of logfile with a path (ex: \&logfile=../../../../../../etc/passwd)
6. Send request

**Vulnerable file: www/controllers/ajax/status/service.php**

Line 7: Does not filter "." or "/", so "../" passes through unchanged.

```
if ($action == 'get-unit-log' and !empty($_POST['unit']) and !empty($_POST['logfile'])) {
    $logfile = \Controllers\Utils\Validate::string($_POST['logfile']);
```

Line 21: Attacker-controlled value is appended with no basename()/realpath() check.

```
$logfile = SERVICE_LOGS_DIR . '/' . $logDir . '/' . $logfile;
```

Line 29

```
`$content = file_get_contents($logfile);`
```

Line 36: file contents returned to the client.

```
`response(HTTP_OK, $content);`  
```

#### PoC

For example, since we know start somewhere like /var/lib/repomanager/logs/service/notifications/, we can estimate where to find certain files.

Replacing the prior log name with a path retrieves all users through /etc/passwd

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

Fetching the path towards the signing key (.gnupg/passphrase)

<figure><img src="/files/23nRas34UDsIM03YdhJC" alt=""><figcaption></figcaption></figure>

#### Remediation/Recommendations

The proper way to solve this vuln is to actually strip any directory component from the user-supplied value, and/or verify the resolved path stays inside the intended directory. Validate::string() is an HTML-output escaper for XSS and is not suitable for validating\
filesystem paths.

BEFORE (vulnerable) — www/controllers/ajax/status/service.php, line 7:

```
$logfile = \Controllers\Utils\Validate::string($_POST['logfile']);
```

AFTER (fixed):

```
$logfile = basename(\Controllers\Utils\Validate::string($_POST['logfile']));
```

basename() function in PHP is used to extract the filename from a given file path or URL, stripping away the directory structure. We can also use the realpath() function as an alternative to basename().

#### Impact

Arbitrary file disclosure/leak as the web user (www-data) by any authenticated account. Confirmed exposure includes:

* app.yaml - OIDC/SSO client secret on configured instances
* .gnupg/passphrase - passphrase protecting the repository GPG signing key
* application source code and system files such as /etc/passwd

This enables privilege escalation (a low-privilege user can harvest secrets belonging to the application and administrators/find more leaks within the source code)
