Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
vsftpd-deny-file-brace-child — vsftpd 3.0.5 - High - Remote - Privilege leftover - brace deny_file misses .private/secret | Kitploit
Tools/GitHubGitHub/abraxas/vsftpd-deny-file-brace-child
Vulnerability AnalysisExploitationWeb Application ExploitationInformation GatheringNetwork SecurityPenetration TestingLabs & Practice
GitHub
abraxas/vsftpd-deny-file-brace-child

vsftpd-deny-file-brace-child

vsftpd 3.0.5 - High - Remote - Privilege leftover - brace deny_file misses .private/secret

View Repository
76 days agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

Abraxas Labs - vsftpd-deny-file-brace-child

abraxaslabs.tech  ·  github.com/abraxas  ·  @abraxas_null  ·  [email protected]  ·  vsftpd-deny-file-brace-child

vsftpd-deny-file-brace-child

Class: Privilege leftover Reach: Remote

vsftpd 3.0.5 - Chris Evans

The man page (vsftpd.conf.5) example is deny_file={*.mp3,*.mov,.private}. Matching names "should not be accessible in any way," including "download, change into directory, affect something within directory." vsf_access_check_file (access.c:16-43) calls vsf_filename_passes_filter on the client path as given, then str_locate_str of the entire brace tunable. Filter matches last-component / prefix; leftover /secret fails; substring of {*.mp3,*.mov,.private} misses.

CWD .private is denied (basename hits). RETR .private/secret and RETR dir/.private succeed. That "within directory" is what this leftover breaks.

CVE-2015-1419 is a public distro realpath/basename patch. Official 3.0.5 never took it. Debian's brace branch still matches the full path, so this child walk remains on patched distro packages too. Do not re-file 2015-1419.

This leftover is a config-gated deny-list miss. It is not unauth RCE, not a chroot escape, and not a host /etc read.

IDno CVE yet
ClassPrivilege leftover
ReachRemote (authenticated FTP)
CWECWE-863, CWE-22
CVSSHigh: 7.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N
Productvsftpd (Chris Evans)
Affectedvsftpd 3.0.5 official tarball SHA-256 26b602ae454b0ba6d99ef44a09b6b9e0dfa7f67228106736df1f278c70bc91d3
Authauthenticated FTP USER/PASS (anonymous in the lab). deny_file set to a brace list (default unset)
LicenseGNU Affero GPL v3.0
Lab127.0.0.1 only. Anonymous read-only. Witness file.

What an attacker can do

Who: an authenticated FTP user (anonymous ftp in the lab). Session UID after the usual vsftpd drop. deny_file is the extra policy that was supposed to take capabilities away from that UID. Virtual-user recipes the man page names share guest_username, so Unix DAC does not separate them. Stock 3.0.5 with tunable_deny_file NULL is not this leftover.

Confidentiality (lab-proven)

Method + sinkPrivilege
RETR .private/secret with documented brace deny_file={*.mp3,*.mov,.private}handle_retr str_open of a file whose directory name is on the deny list, as the session uid. Lab: 150/226, 37 bytes, body VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS
RETR dir/.privatesame sink. A file named .private under another directory (must_match_at_current_pos rejects a match at index > 0). Lab: 150/226, body DIRDOT-VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS

Integrity (inferred from the same vsf_access_check_file gate; lab was read-only)

Method + sinkPrivilege
STOR / APPE the same path when write_enable=YEShandle_upload_common create / overwrite as the session uid
DELE / RNTO the same pathstr_unlink / rename of a name the denylist was meant to stop

Recon (inferred)

Method + sinkPrivilege
LIST .private/x (or LIST inside the denied tree)handle_dir_common access-checks the full arg (miss), then str_opendir of the .private prefix after the slash split. Names only. Unix DAC still applies

Lab-proven negatives (same run)

Method + sinkResult
CWD .private550 Permission denied. Basename .private hits the brace
RETR song.mp3550. *.mp3 is a last-component pattern and does match

What this leftover does not grant

  • Files the session uid cannot Unix-open
  • CWD .private itself (basename hits)
  • hide_file LIST hide of the dirent (basename from readdir; RETR of a hidden name is documented intended)
  • Host /etc from a chroot
  • Unauthenticated HTTP (http_enable default off; FTP-mode GET kills the session)
  • Non-brace deny_file=.private is saved by the substring fallback (str_locate_str of .private in .private/secret)
  • Unauth login skip, PORT bounce, root, chroot escape

How I found it

I pinned official vsftpd 3.0.5 (SHA-256 26b602ae...c91d3) rather than a GitHub mirror or a Debian/Fedora tree. Nineteen source hunts. Default compiled daemon has no unpublished Critical/High leftover. This one needs the operator to copy the man-page brace example.

vsf_filename_passes_filter (ls.c) matches * / ? / unnested {,} and only does useful work on a last-component pattern. For name .private/secret against {*.mp3,*.mov,.private}:

  1. Brace alts *.mp3, *.mov, .private are matched at the start of .private/secret. Leftover /secret fails unless the token was *.
  2. Substring fallback searches for the literal {*.mp3,*.mov,.private} and misses.

Wrong turn already public: CVE-2015-1419 is distro-only realpath. Official Changelog has no such fix. Even Debian's brace branch copies the full normalized path, so children still walk.

Lab

cd lab
./run.sh

Loopback control 127.0.0.1:18710, PASV 18711-18718. Compose project vsftpd-deny-file-brace-child. Official 3.0.5 tarball, anonymous read-only, deny_file={*.mp3,*.mov,.private}. Witness VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS. Last line:

SUCCESS vsftpd-deny-file-brace-child cwd-dotprivate=550 retr-child=yes retr-dir-dotprivate=yes mp3=550 VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS

Fix

Match brace alts against every path component, or realpath / basename before the filter (with the usual symlink caveats). The documented example should actually deny children.

Vendor intake is [email protected] (vsftpd). Do not open a public GitHub issue on any vsftpd mirror.

Contact

Abraxas Labs - abraxaslabs.tech - github.com/abraxas - @abraxas_null - [email protected]

Download Tool