Advisory and Exploitation: The MELAG FTP Server
During an engagement in early 2021 my colleague nv1t and myself stumbled across an FTP server with a banner that we've never seen before, which said
MELAG FTP SERVER along with a version number.
As this banner was unknown to us and the existence of an FTP server at the specific network location itself seemed a little odd (since we did not expect to see an FTP server on the external network of this client), we decided to take a look into what this piece of software is and what we could find about it. Querying Google for the presented Banner, we found the source of this FTP Server and the company that had developed this with the first hit. Searching for known vulnerabilities, however, did not reveal any results. Luckily for us though the vendor did offer this exact FTP Server in the same version as we found it in our client's network for download.
We downloaded the FTP Server, set up a testing environment, began to dissect it and found 6x high impact vulnerabilities.
Summary and Mitigation Advice
In the following sections we will describe an attack chain that allows an attacker to escalate from an unauthenticated network position to gain authenticated host access, which could further be exploited to compromise and control the targeted host system running the vulnerable FTP server. This attack can as well be conducted from the internet against publicly accessible MELAG FTP server instances. After a long and fruitless disclosure process (see the following timeline) we decided to disclose our findings publicly, to allow affected organizations and companies to be aware of the vulnerabilities and protect themselves against attacks.
To mitigate exploitation of these attack we advise to disconnect MELAG FTP servers from untrusted (public) networks, especially from the public internet. While writing this blog post, the vendor has so far not provided any software update to mitigate the identified vulnerabilities, therefore the only mitigation against exploitation is preventing network level access to this FTP server.
- 27.05.2021: Initial Mail to MELAG informing about the found vulnerabilities
- 07.06.2021: Response from MELAG, details and report were handed over to MELAG
- 08.06.2021: Confirmation of Report received from MELAG
- 12.07.2021: 1st Update request from SSE to MELAG, asking if there are any questions on the report or update plans - no response
- 12.08.2021: 2nd Update request from SSE to MELAG, auto response indicating absence of contact - no further response
- 20.09.2021: 3rd Update request from SSE to MELAG - no response
- 20.09.2021: CVE Request to MITRE for 6x identified vulnerabilities, confirmation of submission by MITRE
- 06.12.2021: 1st Update request from SSE to MITRE, asking if there is any update on the process - no response
- 18.02.2022: 2nd Update request from SSE to MITRE - no response
- 04.04.2022: Vulnerability information submitted to CERT-Bund (BSI) - Confirmation of submission by CERT-Bund
- 25.04.2022: 1st Update request from SSE to CERT-Bund (BSI) - Response on 26.04.2022
- 25.04.2022: Informed MELAG and CERT-Bund (BSI) that this blog post will be published during the next two weeks. - Response on 26.04.2022
- 26.04.2022: CERT-Bund (BSI) confirmed the vulnerabilities and will contact MELAG - No statement from MELAG as of 05.05.2022.
- 05.05.2022: Public Disclosure, up to this point the software has not been updated and MELAG has not responded.
In the following sections the identified vulnerabilities will be described. Please note that these vulnerabilities will be described in order of a potential exploitation chain, not in order of their rated risk.
In total we identified the following 6 vulnerabilities:
- User Enumeration
- Authentication Bypass
- Path Traversal
- Storage of Cleartext Passwords
- Weak File Permissions
- High System Privileges
The FTP Server was found to be written in .NET, which allowed us to decompile and analyze the source code. dnSpy was used for this purpose. Snippets of this source code will be shown in the following sections to highlight the vulnerable code functions.
As an entry point into the application, we found a user enumeration vulnerability that allows an attacker to identify whether a given username is a registered FTP user or not. As with all user enumeration vulnerabilities, the vulnerability presents itself by returning different server response for valid and invalid usernames.
The FTP protocol defines the command
USER to submit the username used for logon, which is vulnerable to user enumeration, as shown below:
This vulnerability could easily be exploited using a brute-force style approach using an automated network scanner, such as hydra or by building a custom enumeration script.
As an example: Using a naive python-based network scanner the 10.000 name samples from SecLists could be tested in about 3mins on a local network.
This user enumeration vulnerability within the
USER command function can also be found in the application .NET code, as shown below:
Given a valid username we digged deeper into what happens within the implementation of the
USER command in case a valid username was submitted, which is shown below:
The important bit here is that the
RefUserAccount attribute of the
cc (ClientConnection) variable is set to the account that matches the given username if the identified account is active.
To get a better picture of what this means the server UI, which comes with the installation of the FTP server, is shown below:
This interface shows the identified user "ftpuser" along with a checked "active" box, showing that this FTP user is currently active and allowed to log in.
The interesting takeaway from the code snippet above is that the
RefUserAccount attribute has been set for the connection, although no password has been specified yet. So far only the
USER command has been sent to submit the username.
This gets interesting when inspecting other command implementations, for example the implementation of the
LIST command that is shown below (snippet):
This source code snippet shows the implementation of the FTP
LIST command, which can be used to list the contents of the current directory. As highlighted above this command used the
RefUserAccount attribute of the connection to resolve a user's base directory. The only requirement to make the highlighted call successful is that the
RefUserAccount attribute is set, which has been previously set by submitting a valid username. What's missing is any form of authentication verification, as no password has been provided for this user so far.
Looking at this code we were curious if any FTP functions could be called by only submitting a username, but no password. Testing this theory resulted in the following output:
The server response shows a "Login failed", however the
dir command seems to imply that the command was successful, although no output was received (We'll go into the details of this behaviour at the end of this section...).
This result let us into trying this manually and opening up a data connection ourselves (using the FTP
Using the FTP
PORT command we were able to specify our own endpoint for the passive FTP mode and successfully retrieved the directory listing of the user
ftpuser without specifying any password for this user.
Looking through the rest of the code, we were interested if this flaw is only present in the implementation of the
LIST command. We found that this flaw was present in all implemented FTP commands, which also allowed us to read the file "myfile.txt" that has been identified earlier using the FTP
Now that we proved that this vulnerability can be exploited, let's investigate why the
dir command did not returned any output when used from within the
ftp command line tool.
The reason for this is that the
ftp command line tool - like many other ftp clients - will always send a password with the
PASS command to the ftp server, even when this password is empty. In other words: Every ftp client expects the server to process a
USER command followed by a
PASS command. Looking at the source code of the MELAG FTP server for the
PASS command, we can find the following snippet:
refUserAccount variable is set - which it is in our case, as we send a valid username with the
USER command, but the password does not match with the password of the associated user, then
cc.RefUserAccount will be set to
Looking at the source code for the
LIST command, which is was is triggered when the command
dir is sent through the used ftp client, we'll see that a response with the status code of 150 FileStatusOK is send back to the client (which we also saw earlier) and then the
cc.List is called to handle the directory listing with the first argument of
BaseDirectory is called on
null, which causes an error and the termination of the command. We'll add another annotation to this at the end of the blog post.
So far we were able to "authenticate" to the FTP server by only using a valid and active username and reading a user's base directory indluding all files therein.
Our tour through the code and the various implemented FTP commands also revealed that the application is vulnerable to path traversal attacks, which we found within the implementation of the
This source code snippet shows the
ChangeDir command that is called when submitting the
CWD <PATH> command. The supplied sub-path of the
CWD command is passed as the 2nd argument ("subDir") to the
ChangeDir function. As highlighted above no sanity checks are performed to ensure the user is actually supplying a "sub directory", which allows an attacker to traverse through the entire host system, as shown below.
Consequently, this allows to read arbitrary files of the host system, as long as the user who is running the FTP server has the permission to read these files (which we'll later see could be all files). A proof of concept is shown below:
Storage of Cleartext Passwords
Being able to read through all files (that the user running the FTP server has permission to read) allowed us to look for potentially interesting configuration files that ship with this FTP server...and we found one.
The FTP server stores configurations in an XML file called "config.dat", which is stored under
%ProgramData%\ProgramData\MELAG Medizintechnik GmbH & Co. KG\FTP-Server\config.dat. Looking into this file we found - among other configuration settings - ftp user accounts with their respective password stored in plaintext:
Although so far we did not need to know the ftp user's password to run any of the above attacks it's certainly not good having these passwords stored in plaintext on disk.
Weak File Permissions
So far we had to specify that combining the authentication bypass and the path traversal attacks allows an attacker to read arbitrary files (and directories) on the target host, only if the user running the FTP Server had sufficient (host-level) permissions to read those files.
We found this caveat does not apply to the sensitive
config.dat file, which stores ftp user credentials in plain-text, as the default installation of the FTP server allows
Everyone full control over this file
This would also allow a local attacker on the host system to compromise all FTP users and their files, as an attacker can read (and change) all FTP users credentials and thereby login as any user.
High System Privileges
Lastly to weaken the "we can only read/write files that the user running the FTP server has permissions to read/write"-disclaimer even more we found that when installing the FTP server, the administrator is prompted with the following installation choices.
If the user chooses to install the FTP server "as Windows application" the server is installed like any other application and can be started by any user. If the user on the other hand chooses to install the FTP server "as Windows service", a service is created that runs the "NT Authority\SYSTEM" user, which has the highest system privileges.
A compromised MELAG FTP Server running as "SYSTEM" could then be used to compromise the entire host system.
When describing the "Authentication Bypass" vulnerability, we found that the default Linux
ftp command line client does not allow us to exploit the identified vulnerability. During our research we figured that many ftp clients, including Python's default ftplib, behave in the same manner of sending the
PASS command right after the
USER command, disallowing a user to step in without a password being send. During our analysis we patched the default Python ftplib to serve our needs, but for this blog post we figured it's worth noting that the "manual" approach, going through the protocol step-by-step, can also be fruitful.
Another interesting, but not exploitable (at least as far as we know) twist worth mentioning can be found in the following screenshot that was previously shown in the "Authentication Bypass" section:
As mentioned earlier this code does not check for an authenticated user session, but for our exploit a valid username was required. This requirement is only made necessary, due to the fact that in .NET calling an attribute of a
null object causes a run-time exception. If .NET would evaluate a call on
null to an empty string, we could have exploited this FTP server even without a valid username...
During our research we found several vulnerabilities within the MELAG FTP Server in version 126.96.36.199, which allows an attacker to chain some of these vulnerabilities to escalate privileges from an unauthenticated network position to the highest system privileges on a target host.
We think that these vulnerabilities are pretty severe, especially given that these vulnerabilities can be chained and that this vulnerable FTP server is - due to the market position of the vendor - likely to be found within companies of the medical business sector, such as hospitals, medical practices and so on.
We would have preferred to close all of these vulnerabilities with the vendor, but sadly we didn't receive any response, even after almost a year after we handed in our report describing all of the presented issues. However, we still are and always will be happy to support the mitigation process against the shown attacks.