Skip to content
This repository was archived by the owner on Sep 16, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 4 additions & 9 deletions malware/Xtreme RAT/xtrat_decrypt_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2014 FireEye, Inc. All rights reserved.
# Copyright (c) 2015 FireEye, Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
Expand Down Expand Up @@ -44,13 +44,8 @@
key = key[0:keylen]

f = args.i
rp = open(f, "rb")
ciphertxt = rp.read()
rp.close()
with open(f, 'rb') as fd:
ciphertxt = fd.read()

rc = ARC4.new(key)
print rc.decrypt(ciphertxt)




print(rc.decrypt(ciphertxt))
78 changes: 38 additions & 40 deletions malware/Xtreme RAT/xtrat_decrypt_keylog.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2014 FireEye, Inc. All rights reserved.
# Copyright (c) 2015 FireEye, Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
Expand Down Expand Up @@ -27,44 +27,42 @@
import argparse

def two_byte_xor(buf, key, preserve_unicode=True):
out = ''
for i in range(0,len(buf)/2):
c = struct.unpack(">H", buf[(i*2):(i*2)+2])[0]
if c == 0x0a00 or c == 0x0d00:
pass
else:
c ^= key
out += struct.pack(">H", c)
if preserve_unicode:
return out
else:
return out.replace("\x00","")
out = ''
for i in range(len(buf) / 2):
c = struct.unpack(">H", buf[(i * 2):(i * 2) + 2])[0]
if c not in (0x0a00, 0x0d00):
c ^= key
out += struct.pack(">H", c)

if preserve_unicode:
return out
return out.replace("\x00", "")

if __name__ == "__main__":
parser=argparse.ArgumentParser(description="decrypts and prints an Xtreme RAT keylog file")
parser.add_argument('i', metavar='Input', help='a path to an Xtreme RAT keylog file')
parser.add_argument('-u', action='store_true', help='Unicode output')
args = parser.parse_args()
preserve_unicode = args.u
keylog = args.i
if os.path.isfile(keylog):
rp = open(keylog, "rb")
buf = rp.read()
rp.close()
dec = two_byte_xor(buf, 0x3fa5, preserve_unicode)
if "---" in dec.replace("\x00","") or "---" in dec or "<br />" in dec.replace("\x00","") or "<br />" in dec:
print dec
else:
dec = two_byte_xor(buf, 0x5500, preserve_unicode)
if "---" in dec.replace("\x00","") or "---" in dec or "<br />" in dec.replace("\x00","") or "<br />" in dec:
print dec
else:
dec = two_byte_xor(buf, 0x1300, preserve_unicode)
if "---" in dec.replace("\x00","") or "---" in dec or "<br />" in dec.replace("\x00","") or "<br />" in dec:
print dec
else:
print "could not decrypt keylog.."
else:
print "argument supplied is not a file!"
parser=argparse.ArgumentParser(description="decrypts and prints an Xtreme RAT keylog file")
parser.add_argument('i', metavar='Input', help='a path to an Xtreme RAT keylog file')
parser.add_argument('-u', action='store_true', help='Unicode output')
args = parser.parse_args()
preserve_unicode = args.u
keylog = args.i
if not os.path.isfile(keylog):
print("argument supplied is not a file!")
sys.exit()
with open(keylog, 'rb') as fd:
buf = fd.read()

dec = two_byte_xor(buf, 0x3fa5, preserve_unicode)
if "---" in dec.replace("\x00", "") or "---" in dec or "<br />" in dec.replace("\x00","") or "<br />" in dec:
print(dec)
else:
dec = two_byte_xor(buf, 0x5500, preserve_unicode)
if "---" in dec.replace("\x00","") or "---" in dec or "<br />" in dec.replace("\x00","") or "<br />" in dec:
print(dec)
else:
dec = two_byte_xor(buf, 0x1300, preserve_unicode)
if "---" in dec.replace("\x00","") or "---" in dec or "<br />" in dec.replace("\x00","") or "<br />" in dec:
print(dec)
else:
print("could not decrypt keylog..")
198 changes: 93 additions & 105 deletions malware/Xtreme RAT/xtrat_find_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2014 FireEye, Inc. All rights reserved.
# Copyright (c) 2015 FireEye, Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
Expand Down Expand Up @@ -29,119 +29,107 @@
from pprint import pprint

def getUnicodeString(buf,pos):
out = ""
for i in range(len(buf[pos:])):
if ord(buf[pos+i]) == 0 and ord(buf[pos+i+1]) == 0:
out += "\x00"
break
out += buf[pos+i]

if out == "":
return None
else:
return out

out = ""
for i in range(len(buf[pos:])):
if ord(buf[pos+i]) == 0 and ord(buf[pos+i+1]) == 0:
out += "\x00"
break
out += buf[pos+i]

if out == "":
return None
return out

def getMutex(buf, exitpos, persistpos):
#do a backwards comparison from PERSIST and EXIT and continue until there is a mismatch or two null bytes, calculate beginning of the mutex this way
cnt = 1
while 1:
exitc = buf[exitpos - cnt]
exitc2 = buf[exitpos - cnt - 1]
persistc = buf[persistpos - cnt]
persistc2 = buf[persistpos - cnt - 1]
if exitc != persistc:
if buf[persistpos - cnt + 1] == "\x00":
out = buf[persistpos - cnt + 2:persistpos]
else:
out = buf[persistpos - cnt + 1:persistpos]
return out
if (exitc == "\x00" and exitc2 == "\x00") or (persistc == "\x00" and persistc2 == "\x00"):
out = buf[persistpos - cnt + 1:persistpos]
return out
cnt+=1


#do a backwards comparison from PERSIST and EXIT and continue until there is a mismatch or two null bytes, calculate beginning of the mutex this way
cnt = 1
while 1:
exitc = buf[exitpos - cnt]
exitc2 = buf[exitpos - cnt - 1]
persistc = buf[persistpos - cnt]
persistc2 = buf[persistpos - cnt - 1]
if exitc != persistc:
if buf[persistpos - cnt + 1] == "\x00":
out = buf[persistpos - cnt + 2:persistpos]
else:
out = buf[persistpos - cnt + 1:persistpos]
return out
if (exitc == "\x00" and exitc2 == "\x00") or (persistc == "\x00" and persistc2 == "\x00"):
out = buf[persistpos - cnt + 1:persistpos]
return out
cnt+=1

def unicodifyre(s):
return "\\x00".join(s) + "\\x00"
return "\\x00".join(s) + "\\x00"
def unicodify(s):
return "\x00".join(s) + "\x00"
return "\x00".join(s) + "\x00"

def getConfig(f,buf):
persistre = unicodifyre("PERSIST")
persist = unicodify("PERSIST")
exit = unicodify("EXIT")
persistpattern = r"((?:[^\x00]\x00){4,})" + persistre
match = re.findall(persistpattern, buf)
if len(match) > 0:
configpos = None
lastfoundoffs = 0
for m in match:
print "possible xtrat config located in %s" % f
persistpos = string.find(buf[lastfoundoffs:],m)
persistoffs = string.find(buf[persistpos + lastfoundoffs:],persist)
persistpos += persistoffs + lastfoundoffs
lastfoundoffs = persistpos + len(persist)
exitpos = string.rfind(buf[:persistpos],exit)
#match last 3 characters of mutex as a sanity check
if exitpos != -1 and buf[exitpos-6:exitpos] == m[-6:]:
if persistpos - exitpos == 0x60:
print "possible version 1.3.6.x config block found.."
mutex = getMutex(buf, exitpos, persistpos)
print "mutex: %s" % mutex
configpos = persistpos - len(mutex) - 0x3c8
configlen = 0xe10
break

elif persistpos - exitpos == 0x38:
print "possible version 3.x config block found.."
mutex = getMutex(buf, exitpos, persistpos)
print "mutex: %s" % mutex
configpos = persistpos - len(mutex) - 0x33e
configlen = 0x7f0
break

elif persistpos - exitpos == 0x7a:
print "possible version 2.x config block found.."
mutex = getMutex(buf, exitpos, persistpos)
print "mutex: %s" % mutex
configpos = persistpos - len(mutex) - 0x109e
configlen = 0x1390
break

if configpos is not None:
print "config located at %08X" % configpos
wp = open(f + ".cfg", "wb")
wp.write(buf[configpos:configpos+configlen])
wp.close()

else:
print "could not locate xtrat config"
persistre = unicodifyre("PERSIST")
persist = unicodify("PERSIST")
exit = unicodify("EXIT")
persistpattern = r"((?:[^\x00]\x00){4,})" + persistre
match = re.findall(persistpattern, buf)
if len(match) > 0:
configpos = None
lastfoundoffs = 0
for m in match:
print("possible xtrat config located in %s" % f)
persistpos = string.find(buf[lastfoundoffs:],m)
persistoffs = string.find(buf[persistpos + lastfoundoffs:],persist)
persistpos += persistoffs + lastfoundoffs
lastfoundoffs = persistpos + len(persist)
exitpos = string.rfind(buf[:persistpos],exit)
#match last 3 characters of mutex as a sanity check
if exitpos != -1 and buf[exitpos-6:exitpos] == m[-6:]:
if persistpos - exitpos == 0x60:
print("possible version 1.3.6.x config block found..")
mutex = getMutex(buf, exitpos, persistpos)
print("mutex: %s" % mutex)
configpos = persistpos - len(mutex) - 0x3c8
configlen = 0xe10
break
elif persistpos - exitpos == 0x38:
print("possible version 3.x config block found..")
mutex = getMutex(buf, exitpos, persistpos)
print("mutex: %s" % mutex)
configpos = persistpos - len(mutex) - 0x33e
configlen = 0x7f0
break
elif persistpos - exitpos == 0x7a:
print("possible version 2.x config block found..")
mutex = getMutex(buf, exitpos, persistpos)
print("mutex: %s" % mutex)
configpos = persistpos - len(mutex) - 0x109e
configlen = 0x1390
break

if configpos is not None:
print("config located at %08X" % configpos)
with open(os.path.join(f, '.cfg'), 'wb') as fd:
fd.write(buf[configpos:configpos+configlen])
else:
print("could not locate xtrat config")

def getFile(f):
rp = open(f, "rb")
buf = rp.read()
rp.close()
return buf
with open(f, 'rb') as fd:
return fd.read()

if __name__ == "__main__":
parser=argparse.ArgumentParser(description="scans for Xtreme RAT config in memory dumps and writes them to a file of the same name with '.cfg' appended")
parser.add_argument('i', metavar='Input', help='a path to a memory dump or directory of memory dumps')

args = parser.parse_args()

if os.path.isfile(args.i):
f = args.i
buf = getFile(f)
getConfig(f,buf)
elif os.path.isdir(args.i):
d = args.i
for f in os.listdir(d):
path = os.path.join(d, f)
if os.path.isfile(path):
buf = getFile(path)
getConfig(path,buf)

parser = argparse.ArgumentParser(description="scans for Xtreme RAT config in memory dumps and writes them to a file of the same name with '.cfg' appended")
parser.add_argument('i', metavar='Input', help='a path to a memory dump or directory of memory dumps')

args = parser.parse_args()

if os.path.isfile(args.i):
f = args.i
buf = getFile(f)
getConfig(f,buf)
elif os.path.isdir(args.i):
d = args.i
for f in os.listdir(d):
path = os.path.join(d, f)
if os.path.isfile(path):
buf = getFile(path)
getConfig(path,buf)
Loading