Building mini c2c in Pascal – Part 1

Introduction

Over a while, the development of c2c has increased rapidly, including the number of new commercial frameworks, which I will not mention because I am not here to advertise any, and there are awesome open-sourced projects such as sliver, Covenant, and many more.

In this article, I will shed light on the uncovered offensive side of FreePascal for malware development and share insightful design and code snippets to build a mini command and control demo.
For you as a reader, I am going to divide the series into multiple parts, let’s consider it a workshop for now, and I will try my best to make the timeline relevant.

Requirements

you should have the following for the development environment

  • Lazarus-IDE x64 bit
  • Virtualbox/VM (windows for testing), 1GB RAM / 2 core
  • any Linux box for the team server development.(you need to install Lazarus-ide also )

The architecture design

I have divided the project into three parts.

  • TeamServer: it should handle the whole operation; for the current workshop, it will be for HTTP/HTTPS only. The team server will stand as JSON restful API high-performance server using FPC components and libraries.
  • Operator: a graphical interface to login into the Team server and manage the connected decoys.
  • Decoy: highly customized HTTP agent will work to communicate with a restful API end-point only.

Let’s look first into the whole workflow and then draw the needed basic end-points for communications between the three components.

As the previous figure shows, the agent will first connect to the heart-beat end-point to establish the initial verification with the server. After that, the server will assign a task created by the operator to the connected decoy, and then the decoy will execute the pending actions and exfiltrate the results to sever. So below is the execution playbook diagram of the demo.


Team server development

Let’s start focusing on building the team server; our goal is to achieve a functional team server that should be running over the HTTPS protocol type and using SQLite for storage. And support authentication for multiple registered users(Operators).

By using Multi-threading in Pascal, we could run two server instances simultaneously; one should be for operators and the second for C2 communications with decoys. Below is the suggested diagram for this method.

(Fig 3 )

in other words, our server will have the following classes

TChild = class(TThread)thread class to spawn a new thread for each listener and create threaded pools.
TPasserver = class(TCustomApplication)The main console application program execution flow, it will stand for our API server.
TMyHttpApplication = class(TCustomHTTPApplication)Custom HTTP Application with threading.

Let’s first declare the thread class and invoke TCustomHTTPApplication Class, which also supports threading, but since we developing the team server on Linux, we need to load both units cthreads,cmem


{ RESTful API application }

  TPasserver = class(TCustomApplication)
  protected
    procedure DoRun; override;
  public
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;     
end; 


{Child Servers }
 type
     TChild = class(TThread)
      type

       TMyListeners = class(TCustomHTTPApplication);   
end; 

{ Parent Server}
  type

  TMyHttpApplication = class(TCustomHTTPApplication)

  protected

  end;        
   Code language: Delphi (delphi)

This purpose is to create two functions with different HTTP routers and handlers for our API server, which will be useful to separate the operator’s instance from the decoy’s instance.

Databases

selecting and creating a database engine is required for our API server data storage, for this demonstration, i am going to use SQLite databases, which will have the following tables for now. and you can also use any other database technologies; I just found it easier using sqlite3.

Tasks to store created tasks information
Users this should be used for team server’s operators

SQL Worker

to ensure high server performance, I created the SQL connectivity and procedures in a new process thread. Which will help to handle errors and performance issues.
In other words, if the thread is closed or crashed, the main API server will still be active and create a new SQL worker if needed. The code below covers some of the functions we need for this stage of development.

unit SQL_Worker;

{$mode ObjFPC}{$H+}

interface

uses
  Classes,cthreads, SysUtils,sqlite3conn, sqldb, db,base64;
 type

  TSQL = Class(Tthread)


  SQLite3Connection: TSQLite3Connection;
  SQLTransaction : TSQLTransaction;
  SQL_Query : TSQLQuery;
  protected
 // procedure execute; virtual;
 public
   constructor Create;
   procedure connect;
   procedure add_task(UUID,task_name,task_data:string);
   procedure check_creds(username:string;password:string; out isvalid:boolean; out token:string);
   procedure isdecoy(UUID:string; out isvalid:string);

   end;

implementation
constructor TSQL.create;

begin

   SQLite3Connection := TSQLite3Connection.Create(nil);
   SQLTransaction := TSQLTransaction.Create(nil);
   SQL_Query := TSQLQuery.Create(nil);
   connect;


end;

procedure TSQL.connect;
var
  tmp : string;
begin

  SQLite3Connection.DatabaseName:=getcurrentdir+'/database/mydb.db';
  try
  SQLite3Connection.Open;
  writeln('[+] Successfully connected ');
   except
       on E: ESQLDatabaseError do
           writeln(E.Message);
   end;

  end;

procedure TSQL.check_creds(username:string;password:string; out isvalid:boolean; out token:string);
var
sql,usr,pwd :string;
count: integer;
begin

isvalid := false;
  if SQLite3Connection.Connected then begin
     //database assignment
     SQL_query.DataBase:= SQLite3Connection;
     SQL_query.Transaction:= SQLtransaction;
     SQLtransaction.DataBase :=  SQLite3Connection;

     sql := 'SELECT * FROM users ';
     sql += 'WHERE username ='+'"'+username+'" ';
     sql += 'AND password ='+'"'+password+'"';

     SQL_query.SQL.Text := sql;
     //Count := 0;
           try
               SQL_query.Open;
           //  dbSQLQuery.First;
            //   while not dbSQLQuery.EOF do begin
             //      Inc(Count);
                   usr := SQL_query.FieldByName('username').AsString;
                   pwd :=  SQL_query.FieldByName('password').AsString;

               if ( trim(username) = usr) AND ( trim(password) = pwd) then begin
               isvalid := true;
               token := EncodeStringBase64(usr+':'+pwd);

          //   dbSQLQuery.Next;
            //   end;
               SQL_query.Close;

            end;
            except
               on E: ESQLDatabaseError do begin
                   writeln(E.Message);

           end;

            end;

  end;

end;

procedure TSQL.isdecoy(UUID:string; out isvalid:string);
var
   task,query :string;
   count:integer;
begin
if SQLite3Connection.Connected then begin
     //database assignment
     SQL_query.DataBase:= SQLite3Connection;
     SQL_query.Transaction:= SQLtransaction;
     SQLtransaction.DataBase :=  SQLite3Connection;
           // Create query
           Query := 'SELECT UUID FROM decoys WHERE UUID = '+'"'+UUID+'"';

           // Query the database
           SQL_query.SQL.Text := Query; Count := 0;
           try
               SQL_query.Open;
               SQL_query.First;
               while not SQL_query.EOF do begin
                   Inc(Count);
                  // task := dbSQLQuery.FieldByName('res_body').AsString;
                   UUID :=   SQL_query.FieldByName('UUID').AsString;

                  isvalid := UUID;

                  SQL_query.Next;
               end;
               SQL_query.Close;
           except
               on E: ESQLDatabaseError do begin
                   writeln(E.Message);
               end;
           end;

end;
end;
procedure TSQL.add_task(UUID,task_name,task_data:string);
var
   sql,task_status :string;
   task_id : integer;
begin
 Randomize;
 task_status := 'PENDING';
 task_id := random(100) + 10000;

 Sql := 'INSERT INTO tasks (UUID,task_name,task_data,task_status,task_id) ';
 Sql += 'VALUES ("' + UUID+'","' + task_name+ '","'+ task_data+'","'+ task_status+'","'+ inttostr(task_id)+'")';

 try
    SQL_query.DataBase:= SQLite3Connection;
    SQL_query.Transaction:= SQLtransaction;
    SQLtransaction.DataBase :=  SQLite3Connection;
    SQL_query.SQL.Text := Sql;
    SQL_query.ExecSQL;
    SQLtransaction.Commit;
  except
    on E: ESQLDatabaseError do
     writeln(E.Message);

  end;
end;

end.

Code language: Delphi (delphi)

Building the API

Now that we have a clear overview of the application architecture, let’s start building our server API and integrate it with our database. and will cover the remaining parts in the next blog post.

/authstands for a basic authentication mechanism
/decoys/list list all connected decoys
/listeners/createcreate listeners
/tasks/addadd new tasks
/tasks/updateupdate specific tasks

First, we need to create the HTTPS server application, which will handle the Team server API for operators, and for that reason, I have implemented the following code snippet, which will give the team server the functionality of JSON REST API.

function Team_server: TMyHttpApplication;

begin
    if not Assigned(_Parent) then
    begin

   _Parent := TMyHttpApplication.Create(nil);
   _Parent.Port := 8000;  // listening port 

// if using SSL, need self-sign or valid SSL cert 
   _Parent.UseSSL:=true;
   _Parent.CertificateData.HostName := 'zux0x3a-virtual-machine';
   _Parent.CertificateData.KeyPassword:='123456';  
   _Parent.CertificateData.PrivateKey.FileName := getcurrentdir+'/key.pem'; 
   _Parent.CertificateData.Certificate.FileName := getcurrentdir+'/cert.pem';


   with LAZ do begin
    try

  // authentication
  HTTPRouter.RegisterRoute('/auth/',@auth);

  // LAZ client will connect and assign a task for decoy (Protected)
  HTTPRouter.RegisterRoute('/tasks/add/', @add_task);

  _Parent.HostName:='192.168.33.135';
  _Parent.UseSSL:=true;

 _Parent.Threaded := True;
 _Parent.Initialize;

except on E : Exception do begin
    writeln(E.message);
end;
end;
end;
    Result := _Parent;
  end;

  end; Code language: PHP (php)

With blew two functions, we can magically implement REST JSON API with Authentication. I would like to thank Marcus Fernström for this article.

procedure TPasserver.jsonResponse(res: TResponse; JSON: TJSONObject; httpCode: integer);
  begin
  res.Content := JSON.AsJSON;
  res.Code := httpCode;
  res.ContentType := 'application/json';
  res.ContentLength := length(res.Content);
  res.SendContent;
  end;


procedure TPasserver.rerouteRoot(aRequest: TRequest; aResponse: TResponse);
  begin
    aResponse.Code := 301;
    //aResponse.SetCustomHeader('Location', fileLocation + '/index.html');
    aResponse.SendContent;
  end;



procedure TPasserver.validateRequest(aRequest: TRequest);
 var
   headerValue, b64decoded, username, password,usr,pwd,token: string;
   magic:string;
   isvalid:boolean;
 begin

   headerValue := aRequest.Authorization;
    writeln(headervalue);
   if length(headerValue) = 0 then
     raise Exception.Create('This endpoint requires authentication');


   if ExtractWord(1, headerValue, [' ']) <> 'Basic' then
     raise Exception.Create('Only Basic Authentication is supported');

   b64decoded := DecodeStringBase64(ExtractWord(2, headerValue, [' ']));
   username := ExtractWord(1, b64decoded, [':']);
   password := ExtractWord(2, b64decoded, [':']);
   magic := extractword(2,headervalue,[' ']);


   with DB do begin
   check_creds(username,password,isvalid,token); // will perform validation and output the token 
   end;

    if (token <> magic ) then  // if token match the submitted header, then hola 
   raise Exception.Create('Invalid API credentials'); 
end; Code language: JavaScript (javascript)

After that, I created the two required functions for adding tasks, and the authentication end-point, which the operator will use to log in and assign tasks into decoys.

procedure TPasserver.auth(req: TRequest; res: Tresponse);
var
jObject : TJSONobject;
username,password,token : string;
okay:boolean;
httpCode: integer;
begin
 okay := false;
 jObject := TJSONObject.Create;
try


username := req.contentfields.values['user'];
password := req.ContentFields.Values['pwd'];



with DB do  begin
check_creds(username,password,okay,token);
if (okay = true ) then begin
jObject.Add('token',token);
jsonresponse(res,Jobject,httpCode);
end;

end;
finally
 jobject.Free;
end;
end;  Code language: JavaScript (javascript)

As shown in the figure below, the server will respond with a token that will be used for authentication purposes; since the authentication bearer type is Basic, we may need to upgrade that in the upcoming series.

However, we can also protect any end-point with valid authentication, and that’s what I have done for the /tasks/add end-point.

procedure TPasserver.add_task(req: Trequest; res: TResponse);
 var
  jObject : TJSONobject;
  UUID,Res_str,task_name,task_data,validation:string;
  httpcode:integer;
begin
jObject := TJSONObject.Create;
try
try
validateRequest(req);
except on E: Exception do
begin
    jObject.Add('success', False);
    jObject.Add('reason', E.message);
    httpCode := 401;
end;
end;
jsonresponse(res,Jobject,httpcode);


UUID := req.contentfields.values['UUID'];
task_name := req.contentfields.values['task_name'];
task_data := req.contentfields.Values['task_data'];

with DB do  begin

isdecoy(UUID,validation);

if (validation = UUID) then begin

add_task(UUID,task_name,task_data);

end;

end;

jObject.Add('UUID',UUID);
jObject.Add('task_name',task_name);
Jobject.Add('task_data',task_data);

jsonresponse(res,Jobject,httpcode);
finally
jobject.Free;
end;

end;  Code language: PHP (php)


by adding a request validation code statement at the begining of the add_task API procedure, a request authentication mechanism is required to access the resources.

And in case the authorization token is invalid, the server will respond with invalid API credentials, as shown below.

What’s next?

As I don’t want the information to be too boring and long, I am going to divide the series into multiple parts, so in the next article, I will cover the following :

  • Complete the whole team server.
  • Start building the operator GUI interface.

Github repository

I will share the development stages for the PAS mini c2c project in workshop style, so each article will have a different folder to ensure enjoying the learning experience rather than getting the code and compiling it.

https://github.com/0xsp-SRD/PAS-mini-c2c-/tree/main/DEV-01

Please follow and like us: