Introduction

Bareos is an open-source enterprise backup software solution:

Bareos provides centralized backup and recovery for Linux, Windows, macOS and FreeBSD systems. The same platform can protect physical servers, virtual machines, databases and application data across mixed IT environments.

Bareos provides centralized backup and recovery for Linux, Windows, macOS, and FreeBSD systems. With over 1,200 stars on GitHub and 100,000 downloads for its Docker image. It is written mainly in C++ for its daemon components, and PHP for the WebUI dashboard.

There is a daemon named Director which acts as a central coordinator. Bareos is split into three daemons, and the Director is the one that dictates how the others operate:

  • Director daemon (tcp/9101)
  • File daemon (tcp/9102) – runs on each machine being backed up
  • Storage daemon (tcp/9103) – manages the actual backup media

The bareos-director service does as follows:

  • Holds all configuration that defines which clients to back up, what filesets, schedules, and retention policies
  • Owns the catalog database connection (PostgreSQL)
  • Schedules and runs jobs through the File daemon
  • Serves the console (bconsole) and the web UI


Since the Director is managing other components, it is a prime candidate for a single point of failure. If the Director gets damaged or misbehaves, so do the remaining components.

This blog post shows a stack-based buffer overflow vulnerability identified in bareos-director, which can be triggered by any authenticated user, even if read-only, in addition to a proof-of-concept exploit to cause a crash.



Installation and Lab Setup

The installation is straightforward and can be done by following the available documentation. For this assessment, Bareos was installed on a Debian-based Linux virtual machine.


After installation, the services can be started and should bind to their respective ports.



Starting From the Start

The main focus of the assessment was to spot vulnerabilities that could be exploited remotely. Knowing that Bareos has different services running and bound to different ports, the focus was put on those. The Director daemon’s functionality can be found at core/src/dird/which contains many different files for each feature.

On dird/dird.cc:371, the Director’s listening socket is started.


The port value is inherited from the CMAKE file.


The beginning of the flow is at dird/socket_server.cc, where the daemon defines the listener and individual connection dispatchers.


The actual source is in the command loop defined at dird/ua_server.cc:

  • Line 106: wait for the user to send a command. Bareos will accept a single command up to a megabyte long (more on this later).
  • Line 108: copy the text received into the session’s own storage. Note that there is no length check so far.
  • Line 109: chop the value into words to become a list of name/value pairs.
  • Line 110: Look up the first word in a table of known commands, check if the user is allowed to run it, and call the function that handles it.



The Do_a_command function handles the command provided by the user, directing it to its appropriate handler. There is a big table mapping each and every command that Director supports at dird/ua_cmds.cc.


From this point, if the value provided by the user has a match on an existing command, there will be a check to determine if the user is allowed to run the command, and if so, it calls the handler.



About Buffers and Sizes

The Bvfs::GetAllFileVersions function declares three fixed-size escape buffers and fills them from its arguments.


The path overload has the same characteristic.


One can note the definitions in the header file, where MAX_ESCAPE_NAME_LENGTH is 2*MAX_NAME_LENGTH+1, which would be 257. This value should be enough for a Bareos resource name, capped at 127 characters.


The EscapeString function performs no bounds checking of its own, it hands the caller’s buffer straight to libpq (C language API for PostgreSQL), which expands each input byte to at most two output bytes plus a terminator.


The arguments then arrive as unbounded console strings for the Bareos Director. The DotBvfsVersionsCmd function takes the variables verbatim out of the parsed command line and passes them through with no length check.


The BvfsParseArgVersion simply records the pointers.


The fallback size limitation would be bounded to the socket’s maximum packet size, which is 1,000,000 bytes, so the provided values can be up to roughly one megabyte.



Authorization and Reachability

This issue can particularly be deemed relevant due to not requiring any special access, as even read-only access is enough to trigger the vulnerability. Reaching the .bvfs_versions command requires only that the console’s profile permit it, and this is shipped with the solution by default.


The webui-admin grants the command as well, and the default *UserAgent* console has no Console resource, so ACL checks are bypassed.


The issue can also be triggered through Bareos WebUI, which passes the user-supplied filename into the same command.



Exploitation and Proof of Concept

A Console bound to the read-only profile shipped was created, defining dummy username and password credentials for demonstration.


By leveraging a debugger, one can replicate the issue directly from the machine hosting the Bareos Director service.


After attaching the debugger to the respective process, the Bareos Console utility can be used to interact with its features. This can be done by running the bconsole command.


A sample payload can be delivered through this channel, as shown below.

.bvfs_versions jobid=1 pathid=1 client=x fname=<trash_goes_here>


By checking the debugger, one will note that a crash has happened, and it makes the bug visible in a single frame.

At the top of the stack, the console command is visible, still sitting in memory, one fragment can be seen per row.

The registers pane shows how far it got. The RBP and R12-R14 registers are all holding repetitions of 0x58, which equates to the uppercase letter “X” ASCII code.


A proof-of-concept exploit was developed to automate the attack, leveraging user-supplied credentials to authenticate and cause a crash. The script was delivered to the Bareos team, attached to the original e-mail sent when reporting the vulnerability, and will be published to ExploitDB once the CVE is assigned by MITRE.

The screenshot below shows an example of executing the exploit, leveraging the read-only access aforementioned.



Timeline

  • August 27, 2026: Vulnerability reported to Bareos security team via e-mail
  • August 28, 2026: Vendor acknowledged the issue and deployed a PR with a fix
  • September 19, 2026: Pending CVE assignment from MITRE



References