[ << ALL_FEED ]

Really subtle interaction

More in Reverse engineering

Truly subtle interaction 🕊

During reverse engineering of the protocol of one of the Brazilian banking trojans, the use of an interesting network framework was discovered — RealThinClient. The communication process between client and server in this framework is built on serializing function call structures into a string format and their subsequent deserialization on the other side. This makes RTC not only a powerful development tool, but also a convenient platform for covert command exchange — for example, in the case of malicious behavior.

First, the client and server go through a custom handshake, during which encryption and decryption keys are established for both sides. After that, the framework provides the ability to execute functions on both the client and server sides.

Let’s go straight to an example and use it to understand the logic of how the tool works. The client wants to log in on the server and sends a request, as in the screenshot.

What’s happening here

1. The client forms a request:

• Sets the FC (function call) parameter to the value Login.

• Adds parameters: login, password, and id. They are passed as a dictionary structure RE=3 (record) containing the keys user, pwd, id, etc. An encrypted malicious request can be passed in user. RE denotes the rtc_Record type — it is a “key:value” structure, similar to a dictionary or JSON object.

• On the Delphi side it would look something like this:

with FunctionCall.Param do
begin
  asText['user'] := '...'; // rtc_Text
  asText['pwd'] := '';     // rtc_Text
  asString['id'] := '8DF313279CD34B81A3FB438708B4E8F1'; // rtc_String
end;

And during serialization all of this will turn into the following:

RE=3;
user:T=...;
pwd:T=...;
id:S=...

📁 When we call a remote function via the RTC SDK, we create a TRtcFunctionInfo object — this is a class that describes the remote callable function, its name, parameters, and execution result. It is used both on the client (to package the call) and on the server (to unpack and execute it). The TRtcFunctionInfo object is packed into a TRtcValue container and serialized into a string or byte stream.

TRtcValue can store any supported data type: string, number, array, record, date, nested function, etc. In fact, it is used everywhere data needs to be sent or received over the network, for example in remote function parameters (Param.asValue[...]) or function execution results (Result.asValue). This makes it flexible, but also potentially opaque, which is good for covert command transmission, especially if nested structures like rtc_Function are used.

• Before sending the request, the client registers the OnLoginResult handler to process the result of the function execution on the server.

2. The request is sent to the RTC server:

• The server receives the HTTP request and interprets the FC parameter as an instruction for which function needs to be called.

• On the server side, the handler for the Login function is called. The Delphi procedure associated with this name is executed.

3. The server responds:

• The function result is returned to the client, and it calls its OnLoginResult handler to process the received response.

• The server response is deserialized back into TRtcValue so that we can again access its structure. The server can return not just data, but a nested function call. This is a structure in which a field contains rtc_Function, rtc_Record, or rtc_Array, which the client deserializes and executes.

For example:

if xData.isType = rtc_Record then
  ExecuteRec(xData.asRecord)
else if xData.isType = rtc_Array then
  ExecuteArr(xData.asArray)

👾 This can be successfully used in malware: the server returns an encrypted description of the command that the client must execute. Thus, quite malicious behavior can be hidden within a legitimate RTC stream.

#reverse #hacktool
@ptescalator

More from global_author

More from global_author

More in Reverse engineering