diff --git a/malware/Xtreme RAT/xtrat_decrypt_config.py b/malware/Xtreme RAT/xtrat_decrypt_config.py
index c539393..6db20d0 100644
--- a/malware/Xtreme RAT/xtrat_decrypt_config.py
+++ b/malware/Xtreme RAT/xtrat_decrypt_config.py
@@ -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
@@ -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))
diff --git a/malware/Xtreme RAT/xtrat_decrypt_keylog.py b/malware/Xtreme RAT/xtrat_decrypt_keylog.py
index a27350a..1bbad6c 100644
--- a/malware/Xtreme RAT/xtrat_decrypt_keylog.py
+++ b/malware/Xtreme RAT/xtrat_decrypt_keylog.py
@@ -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
@@ -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 "
" in dec.replace("\x00","") or "
" in dec:
- print dec
- else:
- dec = two_byte_xor(buf, 0x5500, preserve_unicode)
- if "---" in dec.replace("\x00","") or "---" in dec or "
" in dec.replace("\x00","") or "
" in dec:
- print dec
- else:
- dec = two_byte_xor(buf, 0x1300, preserve_unicode)
- if "---" in dec.replace("\x00","") or "---" in dec or "
" in dec.replace("\x00","") or "
" in dec:
- print dec
- else:
- print "could not decrypt keylog.."
- else:
- print "argument supplied is not a file!"
-
\ No newline at end of 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 "
" in dec.replace("\x00","") or "
" in dec:
+ print(dec)
+ else:
+ dec = two_byte_xor(buf, 0x5500, preserve_unicode)
+ if "---" in dec.replace("\x00","") or "---" in dec or "
" in dec.replace("\x00","") or "
" in dec:
+ print(dec)
+ else:
+ dec = two_byte_xor(buf, 0x1300, preserve_unicode)
+ if "---" in dec.replace("\x00","") or "---" in dec or "
" in dec.replace("\x00","") or "
" in dec:
+ print(dec)
+ else:
+ print("could not decrypt keylog..")
+
\ No newline at end of file
diff --git a/malware/Xtreme RAT/xtrat_find_config.py b/malware/Xtreme RAT/xtrat_find_config.py
index 43890cc..970d0e1 100644
--- a/malware/Xtreme RAT/xtrat_find_config.py
+++ b/malware/Xtreme RAT/xtrat_find_config.py
@@ -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
@@ -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)
diff --git a/malware/Xtreme RAT/xtrat_parse_config.py b/malware/Xtreme RAT/xtrat_parse_config.py
index 0b11a10..312f667 100644
--- a/malware/Xtreme RAT/xtrat_parse_config.py
+++ b/malware/Xtreme RAT/xtrat_parse_config.py
@@ -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
@@ -28,139 +28,128 @@
import argparse
def getString(buf,pos):
- out = ""
- for c in buf[pos:]:
- if ord(c) == 0:
- break
- out += c
-
- if out == "":
- return None
- else:
- return out
+ out = ""
+ for c in buf[pos:]:
+ if ord(c) == 0:
+ break
+ out += c
+
+ if out == "":
+ return None
+ return out
def getUnicodeString(buf,pos):
- out = ""
- for i in range(len(buf[pos:])):
- if not (ord(buf[pos+i]) >= 32 and ord(buf[pos+i]) <= 126) and not (ord(buf[pos+i+1]) >= 32 and ord(buf[pos+i+1]) <= 126):
- out += "\x00"
- break
- out += buf[pos+i]
-
- if out == "":
- return None
- else:
- return out.replace("\x00","")
-
+ out = ""
+ for i in range(len(buf[pos:])):
+ if not (ord(buf[pos+i]) >= 32 and ord(buf[pos+i]) <= 126) and not (ord(buf[pos+i+1]) >= 32 and ord(buf[pos+i+1]) <= 126):
+ out += "\x00"
+ break
+ out += buf[pos+i]
+
+ if out == "":
+ return None
+ return out.replace("\x00","")
+
def parseConfig(f,buf):
- #2.9.x
- if len(buf) == 0x1390:
- v = 3
- #3.x
- elif len(buf) == 0x7f0:
- v = 2
- #1.3.x
- elif len(buf) == 0xe10:
- v = 1
- else:
- print "unrecognized config.."
- return
- ftpserveroffs = None
- ftpuseroffs = None
- ftppassoffs = None
-
- if v == 1:
- idoffs = 0x1b4
- groupoffs = 0x1de
- versionoffs = 0x312
- mutexoffs = 0x33e
- installdiroffs = 0x234
- ftpserveroffs = 0x430
- ftpuseroffs = 0x4d4
- ftppassoffs = 0x526
-
- elif v == 2:
- idoffs = 0x1b4
- groupoffs = 0x1ca
- versionoffs = 0x2d8
- mutexoffs = 0x2f0
- installdiroffs = 0x1f8
- ftpserveroffs = 0x380
- ftpuseroffs = 0x424
- ftppassoffs = 0x476
- #delayoffs = 0x378
-
- elif v == 3:
- idoffs = 0x9e0
- groupoffs = 0xa5a
- versionoffs = 0xf2e
- mutexoffs = 0xfaa
- installdiroffs = 0xb50
-
-
- print f
- id = getUnicodeString(buf,idoffs)
- group = getUnicodeString(buf,groupoffs)
- version = getUnicodeString(buf,versionoffs)
- mutex = getUnicodeString(buf,mutexoffs)
- installdir = getUnicodeString(buf,installdiroffs)
- ftpuser = None
- ftppass = None
- ftpserver = None
-
- print "ID: %s" % id
- print "Group: %s" % group
- print "Version: %s" % version
- print "Mutex: %s" % mutex
- print "Install Dir: %s" % installdir
- if ftpserveroffs != None:
- ftpserver = getUnicodeString(buf,ftpserveroffs)
- if ftpserver != "ftp.ftpserver.com".join("\x00"):
- print "FTP Server: %s" % ftpserver
- ftpuser = getUnicodeString(buf,ftpuseroffs)
- ftppass = getUnicodeString(buf,ftppassoffs)
- print "FTP User: %s" % ftpuser
- print "FTP Pass: %s" % ftppass
-
- print "\n"
- return (id,group,version,mutex,installdir,ftpserver,ftpuser,ftppass)
-
+ #2.9.x
+ if len(buf) == 0x1390:
+ v = 3
+ #3.x
+ elif len(buf) == 0x7f0:
+ v = 2
+ #1.3.x
+ elif len(buf) == 0xe10:
+ v = 1
+ else:
+ print("unrecognized config..")
+ return
+ ftpserveroffs = None
+ ftpuseroffs = None
+ ftppassoffs = None
+
+ if v == 1:
+ idoffs = 0x1b4
+ groupoffs = 0x1de
+ versionoffs = 0x312
+ mutexoffs = 0x33e
+ installdiroffs = 0x234
+ ftpserveroffs = 0x430
+ ftpuseroffs = 0x4d4
+ ftppassoffs = 0x526
+ elif v == 2:
+ idoffs = 0x1b4
+ groupoffs = 0x1ca
+ versionoffs = 0x2d8
+ mutexoffs = 0x2f0
+ installdiroffs = 0x1f8
+ ftpserveroffs = 0x380
+ ftpuseroffs = 0x424
+ ftppassoffs = 0x476
+ #delayoffs = 0x378
+ elif v == 3:
+ idoffs = 0x9e0
+ groupoffs = 0xa5a
+ versionoffs = 0xf2e
+ mutexoffs = 0xfaa
+ installdiroffs = 0xb50
+
+ print(f)
+ _id = getUnicodeString(buf,idoffs)
+ group = getUnicodeString(buf,groupoffs)
+ version = getUnicodeString(buf,versionoffs)
+ mutex = getUnicodeString(buf,mutexoffs)
+ installdir = getUnicodeString(buf,installdiroffs)
+ ftpuser = None
+ ftppass = None
+ ftpserver = None
+
+ print("ID: %s" % _id)
+ print("Group: %s" % group)
+ print("Version: %s" % version)
+ print("Mutex: %s" % mutex)
+ print("Install Dir: %s" % installdir)
+ if ftpserveroffs != None:
+ ftpserver = getUnicodeString(buf,ftpserveroffs)
+ if ftpserver != "ftp.ftpserver.com".join("\x00"):
+ print "FTP Server: %s" % ftpserver
+ ftpuser = getUnicodeString(buf,ftpuseroffs)
+ ftppass = getUnicodeString(buf,ftppassoffs)
+ print "FTP User: %s" % ftpuser
+ print "FTP Pass: %s" % ftppass
+
+ print("\n")
+ return (_id,group,version,mutex,installdir,ftpserver,ftpuser,ftppass)
+
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="parses Xtreme RAT config and prints config data")
- parser.add_argument('i', metavar='Input', help='a path to a config dump or directory of config dumps')
- parser.add_argument('-csv', metavar="CSV", help='write results to CSV in addition to printing to console')
-
- args = parser.parse_args()
-
- if os.path.isfile(args.i):
- f = sys.argv[1]
- buf = getFile(f)
- parseConfig(f,buf)
- elif os.path.isdir(args.i):
- if args.csv:
- csv = open(args.csv,"w")
- headers = "file,id,group,version,mutex,installdir,ftpserver,ftpuser,ftppass\n"
- csv.write(headers)
- else:
- csv = None
- d = args.i
- for f in os.listdir(d):
- path = os.path.join(d, f)
- if os.path.isfile(path):
- buf = getFile(path)
- res = parseConfig(path,buf)
- if csv is not None:
- if res is not None:
- csv.write("%s,%s,%s,%s,%s,%s,%s,%s,%s\n" % (f, res[0], res[1], res[2], res[3], res[4], res[5], res[6], res[7]))
-
- if csv is not None:
- csv.close()
-
+ parser=argparse.ArgumentParser(description="parses Xtreme RAT config and prints config data")
+ parser.add_argument('i', metavar='Input', help='a path to a config dump or directory of config dumps')
+ parser.add_argument('-csv', metavar="CSV", help='write results to CSV in addition to printing to console')
+ args = parser.parse_args()
+ if os.path.isfile(args.i):
+ f = sys.argv[1]
+ buf = getFile(f)
+ parseConfig(f,buf)
+ elif os.path.isdir(args.i):
+ if args.csv:
+ csv = open(args.csv,"w")
+ headers = "file,id,group,version,mutex,installdir,ftpserver,ftpuser,ftppass\n"
+ csv.write(headers)
+ else:
+ csv = None
+ d = args.i
+ for f in os.listdir(d):
+ path = os.path.join(d, f)
+ if os.path.isfile(path):
+ buf = getFile(path)
+ res = parseConfig(path,buf)
+ if csv and res is not None:
+ csv.write("%s,%s,%s,%s,%s,%s,%s,%s,%s\n" % (f, res[0], res[1], res[2], res[3], res[4], res[5], res[6], res[7]))
+
+ if csv is not None:
+ csv.close()