This week saw the publication of 576 new CVE IDs. Of those, 80 have not yet been assigned official CVSS scores, however, of the ones that were,...
In modern cyberattacks, threat actors will often begin their attacks against enterprises by obtaining low-privileged access to a single system in the internal IT environment through phishing, VPN access, or successful exploits against perimeter systems. Once they’ve gained a foothold into the secure environment, these threat actors will often perform local-system privilege escalation, which is the process of elevating their permission beyond those of their compromised user account, to expand their access and accomplish their objectives. Local-system privilege escalation will typically be performed by exploiting missing operating system patches (which address critical vulnerabilities), system misconfigurations, or vulnerable third-party applications installed on the target machine. In this article, we’ll explore how a simple oversight in a third-party application installer can compromise the security of a local system, allowing a threat actor or attacker to escalate their privileges and obtain complete system compromise. During a cyberattack, such a compromise would allow attackers to pivot and escalate their access to other systems and potentially privileged domain accounts within a corporate IT environment. This article should be of particular interest to IT administrators as this type of vulnerability affects many enterprise software products and is trivial to exploit.
The third-party application installer we’ll be examining in this article is associated with a product called Sage 300. This product caught our attention during a penetration test in 2021 where we used a vulnerability in a local Sage 300 installation to escalate our privileges on a workstation we had obtained low-privileged access to. Given the nature of the vulnerability, we assumed that our customer had made a mistake during installation or subsequent configuration, but after some research, we discovered that the vulnerability we exploited lay in the product itself, and likely affected Sage 300 installations going back several years. Following responsible disclosure, we alerted the Sage security team and worked with them towards a fix for over a year to address the vulnerability we discovered, which is now described in CVE-2021-45492
Sage 300 is a well established, closed-source enterprise resource planning (ERP) solution designed to facilitate business administration. The Sage 300 product can trace its lineage back to a solution called EasyBusiness Systems that was sold for the CP/M operating system back in the 1970’s before being ported to MS-DOS in the 1980’s. The company behind that solution was acquired, and the product evolved into a solution called Accpac for Windows in the late 1990’s and early 2000’s. In 2004, Sage Software acquired the product and continued developing it under the name Sage Accpac ERP, then Sage 300 ERP, and finally, starting in the 2016 release, just Sage 300.
ERP systems have become increasingly sophisticated over the years and Sage 300 is no exception: it started life as a simple terminal application and evolved into a suite that, according to the online product page, provides support for the management of multiple companies and currencies, inventory management, finance automation, cost management, order tracking, vendor relationships, and sales insights. Sage advertises that its Sage 300 product is now used by over 40,000 customers across 150 countries.
To deploy Sage 300 in a corporate environment with multiple users, an IT administrator is expected to install Sage 300 and its prerequisites on a server that end-users could access from their workstations. After the initial server setup, the IT administrator could then provision user accounts and roles for all workstation users within Sage. Workstations would be equipped with a workstation edition of the Sage 300 program and be configured to have access to the database and “SharedData” folder that would reside on the server.
Diagram of the “Windows Peer-to-Peer Network” configuration for Sage 300, taken from the Sage 300 2021 Installation and Administration guide. This is on of the common network configurations for the product.
In this configuration, regular users could open the Sage 300 program on their workstations, login with their Sage 300 user accounts, and perform work that would be ultimately saved on the server. There are, of course, multiple ways to configure Sage 300, like using a feature called “Web Screens” to allow workstation users to access the server via a web portal instead of via a desktop application.
Note: Sage offers a software-as-a-service product called Sage 300 Cloud, which is a managed cloud deployment instead of an on-premises solution; we will only be addressing the classic Sage 300 on-premises version in this article.
To use Sage 300 after it is installed in the environment, a typical workstation user would run their local installation of Sage 300, select or “open” a company, and then log in with their username and password, as pictured below:
Screenshot of the Sage 300 client login screen.
Past the login screen users have access to the various functionalities of Sage 300 including accounting, sales, and inventory tools. Under the hood, the Sage 300 product communicates with the server and underlying Microsoft SQL (MSSQL) database to store data and reflect changes.
Screenshot of the Sage 300 interface with sample data loaded.
To demonstrate the issues discovered in Sage 300, we will download and install a trial version of the product on a virtual machine running Windows 10 Enterprise. When we initially discovered and reported our findings to Sage in May 2021, Sage was providing trial downloads for all supported Sage 300 versions through their website, but it seems that practice has since changed and those trials are no longer available. For the purposes of this demonstration, we will be using a trial version of Sage 300 2021 that we were able to download when we performed our initial research.
Following the official Installation and Administration Guide document, we begin the installation processes by installing prerequisites, the first of which is Microsoft’s Internet Information Services (IIS). IIS is technically an optional prerequisite, but we will want to enable all optional Sage 300 features, including Web Screens, so we install it now. Continuing with our prerequisites, we will run the Sage 300 installer and use it to install Microsoft SQL Server 2017 Express.
Screenshot of the Sage 300 installer UI.
Once our prerequisites have been installed, we will proceed with the installation of Sage 300 and all of its optional features (except the language packs). We do this to account for the widest range of deployed configurations that may exist. Note that the screenshot on the right depicts the default installation location and data directory, which we will use.
Screenshot of selecting all Sage 300 features (left) and the default installation folders (right).
After clicking “Next” on the remaining prompts and waiting for the installation to conclude, we restart our machine. As we’re using a trial version, we must load the sample data, as outlined in the installation guide, as a final step. Once complete we can run the Sage 300 application to verify everything works as expected.
Screenshot of the default Sage 300 login prompt. Note the password field is disabled by default.
After opening Sage 300 we see everything appears to work as planned, except that we are not being prompted for a password. Sage 300 will only enforce a password for regular use if “Application Security” is enabled, which we will explore in the second part of this blog series. For now, we will consider everything functional.
The Sage 300 installation makes a few notable system modifications:
The first notable, and somewhat unusual choice made by the Sage 300 installer is that it opts to use a folder off the root of “C:\” as the default installation path instead of the more conventional “C:\Program Files\” or “C:\Program Files (x86)\”.
The “Program Files” folder (for 64-bit applications) and the “Program Files (x86)” folder (for 32-bit applications) are the default directories on Microsoft Windows operating systems where non-default programs (i.e. programs that do not ship with Windows) are conventionally installed. These folders have their default permissions configured so that only system administrators can modify files and folders within these directories. We can view these folder permissions by browsing to one of the two “Program Files” directories in Windows Explorer, right-clicking it, selecting “Properties”, and then selecting the “Security” tab.
Screenshot of the basic security settings on the “Program Files (x86)” folder.
We see that regular users have permissions to navigate through the folder and execute files, while administrative users have special permissions which allow them to modify the folder and have full control over all subfolders and files. This permission scheme provides a level of system integrity because it means that regular, non-administrative users can run programs from these directories without fear that other, non-administrative users have modified or swapped the programs to do something malicious. The described scenario is often called a cross-user attack. This permission scheme also makes developer’s jobs easier because if they use the “Program Files” folders, they don’t have to worry about explicitly setting permissions; their program installation folders can simply inherit permissions from the parent folder (aka the “Program Files” folder).
Examining the security permissions on “C:\”, we see it is a bit different than the “Program Files” folders in that the “Authenticated Users” group has “Special Permissions”. “Authenticated Users” is a group that contains all users of the system, minus built-in, service, and guest accounts. This group would include all regular, non-administrator users.
Screenshot of the basic security settings on the “C:\” folder, with the “Advanced” button highlighted.
We can get a more detailed view of these special permissions by clicking on the “Advanced” button.
Screenshot of the advanced security settings on the “C:\” folder.
In the advanced security settings view, we see that “C:\” allows members of the “Authenticated Users” group to create folders with data in them and allows them to modify subfolders. In Windows, “modify” means reading, writing, and deleting files and folders. This means that members of the “Authenticated Users” group will be able to modify data in any folder that is created on “C:\”, as it will inherit these permissions unless inheritance is disabled and explicit permissions set.
It is noteworthy when programs opt for an install location other than “Program Files” because instead of writing to the conventional folder, where they can rely on the operating system to enforce secure permissions, the developers have chosen to take responsibility for explicitly setting secure folder permissions. As we demonstrated, relying on permissions from other folders, like “C:\”, would be insecure by default.
Now looking at the default Sage 300 installation folder, “C:\Sage\Sage300”, we can see that it has naively inherited the security permissions from “C:\”, as it would for “Program Files”.
Screenshot of the advanced security settings on the “C:\Sage\Sage300” folder.
Unfortunately, as we demonstrated, this naïve inheritance means that any member of the “Authenticated Users” group can modify the contents of the Sage 300 installation folder and its subfolders.
There are several ways a user could abuse their “modify” permissions over Sage 300 files and the folders they reside in. Let’s assume the system we installed Sage 300 on is shared by two users: “Admin”, an administrator on our test machine, and “Joe”, a mischievous or potentially disgruntled, non-administrative user.
If Joe has “modify” permissions over Sage 300 files and folders, he can simply replace one or more of the Sage binaries his own binaries. For example, the Sage 300 shortcut created during installation points to “C:\Sage\Sage300\Runtime\accpac.exe”, which Joe could redirect to his own (malicious) binary such that the next time the Admin user runs Sage 300, Joe’s malicious binary will be executed instead of the legitimate Sage program file that the Admin user meant to execute. Instead of swapping a shortcut, Joe could also just replace legitimate application files like the “accpac.exe” file, or every single executable related to Sage 300 in the application folder. This would guarantee that the next time the Admin user runs anything related to Sage 300, Joe’s malicious binary will run instead.
Joe’s attacks on the Admin user could be fairly benign, like forcing everyone’s wallpaper to change, or setting the default search engine to Bing instead of Google, but these attacks could just as easily be used by Joe to obtain new, and perhaps higher privileges. For example, Joe could craft a binary that is designed to add his account to the “Local Administrators” group, and then use his newfound privileges to delete all other users or hold for ransom all the sensitive data on the machine. This is possible because when the modified binary is run by the Admin user, it will execute under the Admin user’s context (privileges) instead of Joe’s. Since the Admin user has full administrator privileges, Joe’s binaries will be able to execute any action that administrators are capable of.
Cross-user attacks can be dangerous, but in order to for them to be a successful privilege escalation vector, at least one privileged account must be in-use on the system. What if there was no Admin user in this example? Could Joe use the Sage installer’s permission mistake to escalate his privileges?
In short, yes. There are other ways to exploit this vulnerability to perform privilege escalation, including via the services that were created during the Sage 300 installation. We’ll leverage the Windows “services.msc” snap-in to review these installed services.
Screenshot of two Sage 300 services running as “Local System”.
All three of the services installed by Sage 300 (GlobalSearchService not pictured above) appear to be running as “Local System”. The Local System account, or “NT AUTHORITY\SYSTEM”, represents one of the most privileged accounts on Windows, even more powerful than a local administrator. If we can execute code under the “Local System” context, we would have complete control of the machine.
We can examine the permission on these services in more detail using the AccessChk utility from the Sysinternals collection. AccessChk is a simple console program which will report the effective permissions on objects and show us to what extent various users can control these services. Running this utility on each of the three Sage services reveals that unprivileged users cannot start, stop, restart, or modify these services. This means that Joe cannot simply update the service details to point to a malicious executable.
Screenshot of AccessChk output showing that our low-privileged user does not
have permissions to modify the service or interact with it in a meaningful way.
Switching back to the “services.msc” snap-in, we can expand each of the three services to see where their service binaries reside. Interestingly, we find that two of the services, GlobalSearchService and Sage.CNA.WindowsService, both call executables located in “C:\Sage\Sage300”, a folder which, thanks to the naïve installer, regular, unprivileged users have “modify” access over.
Screenshot of the “Sage.CNA.WindowsService” service details.
Armed with this information, the most obvious way to subvert these services would be to replace the legitimate service executable with a malicious executable that, for example, adds Joe to the local administrators group. Let’s use the “GlobalSearchService.exe” service binary located in “C:\Sage\Sage300\GS\GlobalSearchWindowService” folder as an example.
The first complication with this approach is that we cannot delete or replace the legitimate binary while it is being run by the service, and we do not have the permissions to stop the service from running. To overcome this, we could simply rename the original “GlobalSearchService.exe” service binary to something like “GlobalSearchService.exe.bak”. Interestingly, while Windows will not allow you to remove or replace running executables, it does allow you to rename them. Once renamed, we could copy a new, malicious “GlobalSearchService.exe” service binary to the “C:\Sage\Sage300\GS\GlobalSearchWindowService” folder.
Once our malicious service binary has been planted, we just need to restart the service somehow, so our binary is executed. The service is not configured to automatically restart after a crash, so in order to get our planted binary executed by the “Local System” account, we have to force a restart of the system, which would trigger all services configured with the “Automatic” start-up type to run, including our Sage 300 services. While not ideal, this should be feasible for most low privileged users on Windows workstations. On Windows server editions, however, a restart may not be possible on demand, forcing a low-privileged malicious user to wait for a scheduled maintenance window.
While exploiting the privileged services for privilege escalation works, it would require a system restart, which is hardly ideal. We’ll re-examine the Sage 300 features in search of a more elegant and immediate escalation vector.
Recall that when we installed Sage 300, we chose to install all optional features, which included the Web Screens functionality. Web Screens allows users to interact with Sage hosted on a local server using the browser instead of the desktop application.
Screenshot of the Sage 300 Web Screens login page.
Sage 300 Web Screens uses Microsoft .NET and Internet Information Services (IIS) to deliver the web experience, which is why we had to install IIS as a prerequisite. Opening the IIS Manager, we can see three non-default application pools that Sage has created.
Screenshot of the Sage 300 web application pools in the IIS Manager.
Interestingly, the Sage 300 application pools seem to be configured to run as “Local System”. IIS application pools can be though of like application containers. All the applications (think URLs) in one pool are served by one or more worker processes which provide application isolation by ensuring that they are not affected by applications running in other pools. A worker process is a Windows process: when we see that an application pool is configured to run as “Local System”, we know that there is a Windows process that is serving web content and running as “Local System”.
It is best practice to split large applications into multiple application pools in order to make them more resilient. For example, if we have our primary web application running in one pool, and our API application in another, the primary application could crash in the most catastrophic way (causing the worker processes to terminate) but our API application would remain available. If our two applications shared a pool, however, then when one crashed both would become unavailable.
The Sage 300 application pools running as “Local System” are of interest to us, so next we’ll check what sites are running in these application pools.
Screenshot of the Sage 300 pool details in the IIS Manager.
We see that there are three different sites: the default site being served on port 80, the Sage OAuth site on port 4433, and the Sage SIRC site on port 9133. Inspecting the settings of each site reveals that, predictably, the OAuth site is running in the “Sage 300 OAuth Pool”, the SIRC site is running in the “Sage300SIRC” pool, and the two applications in the default site are running in the “Sage 300 Pool”. We see that the Sage 300 applications all have physical paths in the installation folder, “C:\Sage\Sage300”, which, if you remember, is configured to be writable by low-privileged users.
Because these sites are running from the same folder with weak permissions, it is possible for us, and Joe, our low-privileged user, to add or modify web application code and have the worker process (aka the web server) execute it for us when it is called to serve the Web Screens functionality. Essentially, we can upload a webshell to escalate to root permissions using any of the Sage 300 sites installed as part of the Web Screens feature. To demonstrate this, let’s arbitrarily pick the SIRC site running on port 9133 and located in the “C:\Sage\Sage300\SIRC\site” directory.
Screenshot of the Sage 300 SIRC site directory.
As advertised, the Sage SIRC site appears to leverage .NET code. All we need to do now is to either acquire or craft a webshell to drop in this folder. For the purposes of demonstration, we’ll opt to employ a very simple open-source webshell by Dominic Chell to accomplish this.
The idea behind all webshells is to provide attackers some way to execute arbitrary commands on the system and read the output. In our webshell, the “ExcuteCmd” function on line 6 takes user input, passes it to a Command Prompt instance, and returns the command output. This webshell also features a basic visual input field and button to run our commands.
Source code for the basic ASP.NET webshell we’ll be using.
We’ll write our shell to the “C:\Sage\Sage300\SIRC\site” directory.
The Sage 300 SIRC application folder with our webshell added.
Finally, we can access our shell by navigating to “https://localhost:9113/shell.aspx” in a browser on our test machine. We’ll quickly verify that we’ve escalated our privileges by running a “whoami” command and then trying to access the Admin user’s files, which Joe, the low-privileged user, should not be able to do.
Webshell (left) demonstrating privileged code execution and Command Prompt (right) demonstrating low-privilege access.
Success! Using a Command Prompt, we verified we were running as Joe who could not access the Admin user’s folder, and then using the webshell we verified we could execute code as the “Local System” account that could access the Admin user’s folder. We can now execute any type of code or programs we wish with our newfound high-privileged access. We have successfully exploited a simple oversight in the Sage 300 installation process to achieve complete compromise over the underlying system without having to reboot the system.
It is worth mentioning that the webshell we used was far from covert; it is a well-known publicly available webshell that should alert any decent anti-virus solution that may exist on a production system. Bypassing anti-virus with a webshell is outside of this article’s scope, but we will note that there are several well-known webshells available online including community projects like SharPyShell and infamous, APT-grade shells like China Chopper that could be employed for greater success. If we were committed to roleplaying the disgruntled employee Joe, instead of creating a new web page called “shell.aspx”, we likely would have opted to embed a more discrete backdoor in a legitimate Sage 300 web application file that would allow someone like Joe to covertly maintain access. This access could even persist after Joe’s employment had been terminated.
Our webshell is such an elegant escalation vector that it feels like cheating. It should be noted that while Sage 300 Web Screens runs as the Local System account by default, the Sage Installation and Administration guide recommends configuring a separate user account for use with both the Sage.CNA.WindowsService service as well as the application pools.
An excerpt from the Sage 300 2021 Installation and Administration guide about recommended service configuration for increased security.
It has been our experience that default settings have a habit of persisting, regardless of official vendor guidance. For sake of completeness, we should ask ourselves “would it still be possible to escalate our privileges on an installation even if we followed all vendor documentation”?
In short, yes. Even following all of the vendor documentation we could still use the Web Screens functionality (assuming it was enabled) to trivially escalate and impersonate whatever Windows user account was used. The only difference is that instead of executing as “Local System” we would execute as different user. If we wanted to avoid that, we could fall back to abusing the “GlobalSearchService” which runs as “Local System” and has no official recommendation to change it to a different account. As we have “Modify” access to everything Sage, we could also target the services themselves or software components they rely on like code libraries or third-party services.
Due to the size and complexity of programs like Sage 300, we have a large attack surface to target when trying to exploit a writable folder vulnerability like this one. Given more time, it may be possible to find additional vectors that can be used for escalation.
In the case of this vulnerability, we aren’t limited to exploiting Sage 300 to perform our privilege escalation. Recall that during the Sage installation the “C:\Sage\Sage300\RUNTIME” folder is prepended to the system PATH. Because the Sage installation folder inherits weak permissions, and because that folder is then added to the trusted system PATH, the security posture of the entire system is compromised. To understand why a folder with weak permissions in the system PATH is so dangerous, we need to briefly talk about DLL hijacking.
A dynamic link library (DLL) is a library that contains code intended to be used by more than one program at the same time. DLLs are used to modularize programs and to promote code reuse and efficient memory usage. For example, if a developer had multiple products that work with a single database, it would make sense for them to write the database interface once and package it as a DLL for all of their products to use. This way, if the developer has to update that code, they can update only the DLL package instead of all the applications that use it. In order to use code found within a DLL, a program has to import the DLL at some point during runtime.
Sometimes programs will import DLLs using full paths (think of this like “my library code exists in the file C:\Windows\mylib.dll, please load it”), but more often programs will opt to import DLLs using only the DLL name (think of this like “my library code is in a fille called mylib.dll, please find and load it”). This is because DLL dependencies are often not stored in a predictable location on a machine. For example, consider a situation where a developer has multiple products, one of which is a “core” product that comes with all the DLLs that the other products need, but allows the user to specify an arbitrary install location for each product. How will the other products know where to find the “core” install folder with all of the dependencies that they need to function if the location is not guaranteed to be the same on each system?
When a DLL dependency is loaded using only the library name, Windows tries to find the file by searching locations along a predefined path called the DLL Search Order. This search order is (usually) as follows:
As outlined above, Windows checks the application directory first to see if the application brought the DLL it needed before checking a set of system folders, the current directory, and finally the folders in the PATH environment variable. As soon as a match is found for the DLL dependency, searching stops and whatever DLL was found is loaded.
Since DLLs are just code libraries that are eventually run by programs that rely on them, they can be used by attackers to execute code. Attackers can simply replace legitimate DLLs with malicious ones so that the next time a program tries to load that dependency and execute the code within, it ends up executing the attacker’s code in the malicious DLL instead. An attack where a legitimate DLL is replaced with a malicious one is often called DLL replacement.
DLL hijacking follows the same idea, but instead of replacing the legitimate DLL, an attacker plants their malicious DLL in a folder that is higher in the DLL Search Order than the legitimate DLL such that when a legitimate program attempts to resolve its dependencies it finds and loads the malicious library instead of the legitimate one. A special class of DLL hijacking is phantom DLL hijacking, which refers to when the legitimate DLL an application is trying to load doesn’t exist on the system. Phantom DLL hijacking is the easiest DLL hijack to perform because a malicious DLL can be placed anywhere along the DLL Search Order, and it is guaranteed to be loaded. It may seem strange that a program may depend on a library that doesn’t exist on the system, but this is surprisingly common. This can happen when programs rely on optional features that are excluded from production builds, like an untested or deprecated feature, or debugging functionalities.
For a more in-depth article about DLL Hijacking, please read: https://itm4n.github.io/windows-dll-hijacking-clarified/
When the Sage 300 installer prepended the “C:\Sage\Sage300\Runtime\” directory to the system PATH variable, it made that folder a part of the DLL Search Order. This means that any program that relies on this search order to resolve dependencies may end up searching this Sage 300 folder, which is writable by non-privileged users. This means that an attacker could plant malicious DLL files in this Sage 300 folder and escalate privileges by exploiting Windows and other third-party programs vulnerable to DLL hijacking. This functionally expands our attack surface to the entire system.
In recent years multiple default Windows programs have been found to be susceptible to phantom DLL hijacking, including the NetMan service, Task Scheduler, and the IKEEXT service. It may be possible for an attacker to perform DLL hijacking through the Sage 300 runtime folder that is in the system PATH environment variable to escalate their privileges. Note that in all the above cases, Microsoft’s position was that DLL hijacking is not a vulnerability as all these programs were operating as intended; to exploit any of these vulnerabilities for privilege escalation, an attacker would need to have a folder in the DLL Search Order that low-privilege users could write to, and that folder would constitute the “real” vulnerability. In other words, Microsoft expects all folders in the PATH variable in Windows to be properly protected to maintain the security integrity of the system, which Sage 300 failed to do.
In this article we covered several privilege escalation vectors, which may lead the reader to believe that Sage 300 is affected by multiple vulnerabilities. We want to be clear that all these escalations are simply exploitation avenues for a single vulnerability: weak permissions on the installation folder. These weak permissions could allow cross-user attacks and/or for the complete compromise of the underlying host. Of course, a compromised system in an enterprise environment could be used as a pivot point by attackers to continue attacking the rest of the internal environment. In this case we were able to demonstrate how a simple vulnerability has serious security implications.
Versions of Sage 300 between 2017 (6.4) and 2022 (6.9) are affected by the vulnerability, exactly as it has been described above because they all use “C:\Sage\Sage300” as the default installation directory. Versions of Sage 300 2016 (6.3) and older use “C:\Program Files\Sage\Sage 300 ERP” as the default installation folder and should not be affected, but likely are based on the installation guidance provided with those versions. The official installation instructions for Sage 300 2016 (6.3) and versions all the way back to Sage Accpac ERP 5.4 (2006) recommend that IT administrators change the default “C:\Program Files” installation folder to directories like “C:\Sage 300” or “C:\Sage300ERP”.
A screenshot of the Sage 300 2016 Installation and Administration Guide recommended
to change the default folder to something inherently insecure.
Documentation for Sage Accpac ERP 5.3 would suggest that, by default, it was set to install in the “C:\Sage\Sage Accpac” folder, which was likely vulnerable. In short, this product has likely been vulnerable for a very long time.
Sage declined to publish an official advisory to address this issue, citing complexities with partner modules that may lead to broken Sage 300 installations. Product users can either wait to upgrade to Sage 300 2023, which should be released in August this year, or manually modify the permissions at their own risk as described below.
Ensure that all Sage 300 data is properly backed-up prior to attempting any kind of remediation.
Our goal is to ensure that low-privileged users cannot modify the contents of the Sage 300 installation folder and its subfolders. To accomplish this, we’ll locate the topmost installation folder, which in our case is “C:\Sage”, right-click to open properties, navigate to the security tab, and then click the “Advanced” button.
A screenshot of the C:\Sage folder permissions that must be changed.
Next, we’ll disable inheritance and replace all child object permissions with entries from this object.
A screenshot of the prompt presented when disabling inheritance.
Now we can change the permissions on this folder and it should affect all of the Sage subfolders, which is exactly what we want. The next step is to remove any “Modify” permissions that low-privilege users may have. In our case the only low-privilege group with modify permissions is the “Authenticated Users” group, so we can simply remove their permissions completely.
A screenshot of the access control entry to be removed.
We can’t account for every installation configuration out there, but generally you want to look at groups like “Authenticated Users”, “Users”, and “Interactive Users” (if present) to ensure they have nothing more than “Read”, “Read & execute”, and “List folder contents” permissions. If your configuration only has the “Users” group with modify access, it may be necessary to use the “Edit” functionality to remove only the “Modify” permission. Remember, we want to prevent low-privilege users from modifying files, not from accessing and using the program. As a final “gotcha”, be sure to investigate any “Special Permissions” you may encounter to ensure a “Modify” or some equivalent isn’t hidden there.
Once we’re done modifying our permissions we can apply them, which will generate one final check that we can accept and wait as our permissions are propagated to all subfolders.
A screenshot of the prompt presented after removing the insecure access control entry.
To verify that everything worked as expected, we can check the properties on subfolders like the “C:\Sage\Sage300\runtime” folder that is in the system PATH to verify that our permissions have propagated.
A screenshot of the new C:\Sage\Sage300 folder permissions.
As a final step, always remember to check that all application functionality has been preserved before pushing changes to critical production systems.
It is important to clarify that while Sage 300 was the product being dissected in this article, it is certainly not the only product that suffers from weak folder permissions. We had intended to include a list of the other notable software we found to be affected by weak folder permission vulnerabilities (there were several), a tool to assess to the software installations on a given system, and guidance on how to write better installers, but we’ve opted to feature those topics in a separate, more comprehensive publication; look out for that later this year.
A vulnerability disclosure blog wouldn’t be complete if we didn’t include a timeline.
|May 14, 2021||Vulnerability first reported. Initial report stated Sage 300 2019 and older were vulnerable.|
|May 21, 2021||Sage flagged report as false positive claiming that Sage 300 2019 was unsupported. Support policy is current version plus two back, so 2019 should have been included, but we let that slide and instead asked where we could find the latest versions.|
|May 22, 2021||Sage provided links to up-to-date trial versions and changed their position to say Sage 300 2019 was a supported version.|
|May 25, 2021||Vulnerability reported again with update to reflect that all versions of Sage 300 were vulnerable, including 2021 release (latest at the time).|
|Jun 18, 2021||Sage acknowledged vulnerability but did not consider it a high priority and was unable to provide a resolution timeline.|
|Aug 24, 2021||Sage 300 2022 was released and was still (presumably) vulnerable. Support for Sage 300 2019 ends, Sage 300 2020 and 2021 remain supported.|
|Dec 20, 2021||I send a follow up and notice trial links no longer work so 2022 release couldn’t be tested.|
|Jan 12, 2022||Sage confirmed that the vulnerability is to be remediated in the August 2022 release and that an advisory will be published.|
|Feb 3, 2022||After some insistence, Sage agrees to publish their officially advisory prior to the August 2022 release.|
|Mar 1, 2022||Sent updated remediation recommendations based on further installer misconfiguration research.|
|Mar 6, 2022||Sage acknowledges new remediation guidance.|
|Mar 7, 2022||Asked for advisory publication timelines, Sage responds with something along the lines of “unknown, but we will let you know as soon as we get updates from the team”.|
|Apr 6, 2022||Sent follow up regarding official advisory and was told that it was being tested by the QA team and that I would be updated when timeline details became available.|
|Apr 12, 2022||Informed Sage that June 18 (about 65 days out) would be treated as the one-year mark for this issue and that we would make the vulnerability details and the CVE public.|
|Apr 27, 2022||After investigation Sage informs us that their official advisory will not be released due to difficulties accounting for partner modules. No advisory will be released before the official fix in the August 2022 product release.|
|Jun 18, 2022||Official one-year anniversary of Sage acknowledging the vulnerability.|
|Jul 14, 2022||CVE-2021-45492 and this article are published.|
|Aug 2022||Sage 300 2023 is expected to be released and (hopefully) contains a fix.|
There exist several secure software development frameworks and standards that, if followed, would have prevented the oversight described in this article, including the NIST Software Development Framework, PCI Secure Software Standard, and PCI Secure Software Lifecycle Standard.
This week saw the publication of 576 new CVE IDs. Of those, 80 have not yet been assigned official CVSS scores, however, of the ones that were,...
This week saw the publication of 449 new CVE IDs. Of those, 315 have not yet been assigned official CVSS scores, however, of the ones that were,...