hello everyone
i hope you're all having a wonderful
village welcome to my talk
designing a c2 framework
uh so my name is daniel duggan um
otherwise known as rastamouse
i'm the director of zero point security
um you may have seen our
red team ops course i blog over
rastamast.me as well as on
offensivedefense
i'm on twitter github discord slack
all the things if you want to uh
get in touch with me after the talk by
all means
do so
so what inspired this talk well
it feels like to me prior to around
2018 there weren't really that many
um c2s or c2 frameworks available
um the main commercial offering was
probably called australia maybe a few
others
and there weren't that many open source
frameworks either we had
um powershell empire for a long time
we have uh posh t2 for a long time
and then covenant came along and some
others came along
and suddenly we just had this huge boom
in these um c2
tools um coming out
we've also had a lot more commercial
ones um
as well so it seems to be
an area of interest for sure and
it's not um infrequent that i get
approached and
people are asking me if i've got any
tips on how to
build c2 and specifically in c sharp
so i thought that this kind of talk
would be uh
helpful for those who were looking to
you know take on the process of trying
to
put such a tool together
now if you go over to uh the situate the
c2 matrix
um it's a a curated list of
uh commercial and open source frameworks
it now lists over 70 which is
pretty astounding really and more than
10 languages
everything from python
go rust c sharp ruby even power shell
there's no uh shortage of variety
and they all have different capabilities
so
some by default will be canova
https and we'll go over dns and we'll go
over
um completely custom channels and some
might
ride on legitimate services like
you know the dropbox is office 365
different google services and things
like that
um if you're interested in learning more
about
some of the frameworks or some of the c2
tools already out there
i highly suggest you check out the
matrix
it has a really useful like um
search tool i guess where you you plug
in your requirements
and it will recommend um some tools for
you
based on those requirements
so let's take a step back and talk about
c2
what is c2 um
well c2 is short for uh command and
control
you can imagine a scenario where you
have um us
cowboy operators and we have a target
and the operator will
deliver um some sort of implant or
payload
um sometimes also called a rat to that
target
and the operator needs to maintain some
control over that
over that implant somehow
the implant needs to talk to the
operator the operator needs to be able
to
give it commands and the implant needs
to
give the results back to the operator
and the the model that is
um used most i guess
is to have some sort of um
intermediary control server um often
called
a team server so the implant will
communicate to the um team server
over some sort of protocol again that
might be http
or dns or some other legit service
and the operator will have you know
some sort of admin interface
to that control server so the implant
will talk to the control server and it
will kind of
appear to the operator
and the operator will be able to give it
tasks
the implant will grab those tasks from
the server execute them
and send send the results back
it's worth noting that some
of these servers have the
admin interface kind of built into them
while others require the operators to
have
um a standalone client
that will connect to that um
to that server for them
so um conceptually not too complicated
however the point of this talk is about
designing
a c2 framework not just designing c2
and we need to understand specifically
for the purposes of this talk that c2
is not the same as a framework
so if you go into the matrix again for
example you'll see a lot of
c2 tools that don't
really readily provide that much
flexibility to the operator
um you know maybe a lot of those tools
were designed in mind with i want to
demonstrate being able to use c2 over
office 365 for example and that's pretty
much
all it's capable of
and to me that's not really a framework
and this is all about frameworks
so what does a framework provide well
they're quite clearly listed here um so
let's go through them
the first is inversion of control
now the overall flow of the program
or the uh the programs that are involved
in this whole process
and not strictly uh controlled by
the user so the flow
is that the implant is going to talk to
a server
and the operator is going to task that
implant and
you know you've got that back and forth
now that is a flow that's not controlled
by the user
you also have
on the server side and on the implant
side a lot of internal flows
so the implant will receive a job it'll
process it in some way and then send the
results back
that internal flow is not controlled by
the operator um and
a lot of flows
internal to the team server are not
necessarily going to be controlled by
the user
a framework also provides default
behaviors
but most importantly those are behaviors
that can be
overridden by the operator
so again we're talking about the
protocol that the
implant is talking over or the protocol
that teams here was listening on
a framework may provide a default
protocol for that
such as http but the operator should be
allowed to
override that in some way either
change the behaviors within that
protocol
or add their own complete custom
protocols
a framework also provides um
extensibility
and that is to introduce new
behaviors and capabilities that are not
currently within toolset so if you think
about
implants you might write your implant
with
a couple of commands but
it needs to be able to be customizable
for the operator they need to be able to
add their own commands if they want
their own capabilities their own
post exploitation capabilities and they
also need to be able to do that on the
server side as well
so if you have um something like
you want reverse port forwarding on your
implant
you need to be able to introduce that
capability to the implant
the implant needs to send that data to
the
somewhere probably the team server the
team server needs to
relay that traffic to wherever it needs
to go and then it needs to send that
traffic back
so both sides of that process
need to be extensible by the operator to
accommodate that
a framework also provides reusable
components which
i think is self-explanatory but they're
they're components that the framework
provides to
make the operators live easier
and we'll see an example of that on the
next slide
so this is an example i've taken from
the metaphor framework
metasploit is a very mature product at
this point and it's great to look at
um if we're looking for inspiration on
those
frameworky things
but if you're not familiar with maxploy
anybody can
write a module for it anybody can write
an
immersion module or an exploit module
for that framework for other people to
use
and being a framework it provides a lot
of helpers for you to
you know in writing those modules so
this example is taken from the ps
exec module and
the first thing you do in a module is to
define some module information
so this includes you know a name a
description
your an author or multiple authors
references and so on and so forth
and that information
from the module is picked up by the rest
of the framework
so that as the operator whilst you're
using the ui
and you search for a module you can you
know search it by name or whatever
and then it comes up and you can see the
name you can see its description and a
bunch of other things
uh you can also register options
so this being a um a ps exec module
the author here has said well you can
define
options for the service name um
paths and a bunch of other things that
are you know
important to that module but more
importantly
there are some options that you don't
have to
explicitly define in the module
so the framework knows that this is like
a remote exploit module or whatever it
knows that it needs
the r host or you know your targets
and the operator or the author of the
module doesn't need to specifically put
our host in as an option the framework
already knows that that's required
so that takes you know that burden off
the operator
or the author and you also have
includes and helpers which are down here
so
these includes are other exploit modules
that you can bring into your module
and because this module is
using you know smp is exec and smb
there's already a module for that
so you don't have to actually implement
an entire smb library in your module or
even
the ps exec process in your module
it's bringing in powershell and xs
because you know
you need to execute something so as the
module author you don't even have to
worry about the payload that you're
going to send the framework does it for
you
um and you can see here that uh
the uh service file name so this is um
service file name here is an option
if you haven't you know defined this
option it takes the defaults and so
these are the default behaviors
so if you haven't uh provided a name
it will pick it'll just make a random
one for you
and this rand text alpha is
um another module in the framework so
you don't have to worry about oh okay
well i want a random string now i have
to write a function for that
it's in the framework already and
those are the biggest strengths of
frameworks
is that as the module author they allow
you just to focus on
the task that you want and not worry
about
you know things that you don't want to
worry about
okay so where to start
well this is like it seems pretty uh
cliche but
the first thing you should really
understand is what are your motivations
um what does success look like and that
kind of sounds like
we're at some sort of management retreat
but um you kind of really need to think
about what you're actually trying to
achieve
because you need to build it
and you need to know what it's going to
look like at the end so you know
you might be doing this just for fun you
might be doing it just to teach yourself
some stuff you might want it to
teach other people um
you might be writing an internal tool if
you're like a pen tester or
a red teamer you might even want to sell
it you might want to open
source it um
and if i had to draw like some sort of
parallel i'd think about
if you were going to build a car it's
very easy to say i'm going to build a
car
but there are a lot of different types
of cart right if you
want something to take your family to
the
beach you probably don't want a mclaren
p1 and likewise if you want to go
around the nurburgring pretty quick you
probably don't want
i don't know some sort of absurd people
carrier
so even though they're both cars they
are quite different and they have
different
features to you know
make that goal a reality
and there are all sorts of things that
you you could think oh that would be
really cool to have in my framework that
would be
you know but if it doesn't
you know contribute towards
what you're actually trying to achieve
then it's kind of pointless
and if you
miss features that you need then you're
not going to achieve your goal and
you're going to end up with something
that you didn't want
so if you've never seen moscow
this is a pretty good way to try and
narrow down
what you think you want so this stands
for
must have could have oh sorry must have
should have
could have and won't have so your
must-haves
are like mandatory things right these
are things that
your framework absolutely has to have to
uh perform its function
uh should haves are important and they
they add significant value but they are
not
uh strictly mandatory um
to function could haves are
nice to haves but not really important
and won't haves are least critical
inappropriate or um undesirable
and like the won't have you can split
into
kind of two camps i guess you can have
won't haves like period and won't have
this time and i'll sort of expand on
this time
um in a minute
so what you really want to do is you
want to get your goals straight
and think about all the things that you
think you
might want in your tool
um you can also take inspiration from
other frameworks as well
and tooling that's perfectly okay i
don't think that's cheating
because you kind of want the best parts
of everything
and you know why
reinvent the wheel sometimes you can
take good ideas from
all sorts of places and that's perfectly
fine in my book
and then what you want to do is narrow
everything down to
an attainable first release
using that moscow
method and by attainable i mean
attainable within your current skill set
and your time budget
and i think uh a mistake that a lot of
people make
is to look at things that have been out
there for a long time so you look at
empire you look at mass block framework
and you look at covenant posh c2 and all
of those well-established
projects and they think that's what i
want to build
i'm going to build like my version of
that framework
but the thing is those projects they
didn't get there overnight they didn't
just
pop out of nowhere at the quality that
they are now
some of them are months or years old
so if you're trying to replicate that
straight off the bat
you know you've probably got easily six
or twelve months worth of work
and what you're going to do is you're
going to work on it for i don't know a
couple of months or however long you can
stand
you're going to get fed up with it
you're going to get demotivated and then
you're just going to
put it to the side
you'll come back to it maybe it's
important you look at it you'll look at
it and you'll think well
i've only done about 20 of what i hoped
to achieve
and you're probably not going to pick it
up again and it's going to end up in the
software graveyard so
small iterative releases are easily more
achievable
and far more likely to keep you
motivated
um and you're also going to grow your
project with your skill set i mean you
can you look at a lot of features in
a lot of advanced frameworks now and you
i mean they're pretty they're pretty
like advanced concepts so if you're uh
if you're doing this to teach yourself
um
you know coding it's probably not
realistic to shoot for
you know those kinds of um
you know features or whatever
so having a small project that's 100
complete
is a lot better and it's a lot more
satisfying than a large project that
that's you know 10 or 20 complete
um so
when i say attainable first release it's
gonna be like
probably the bare minimum of what will
make a c2
um framework function no bells or
whistles
but it's something to aim for right
so you're gonna set yourself a schedule
so you're gonna say i'm gonna target my
first release my initial release
in one month or whatever you think is
realistic so you've got your
moscow you've got your must-haves
and your should haves and you're
probably going to prioritize those the
most so
you could have you're probably not going
to um
really worry about too much because you
just want something that's going to
function that's going to work
and you need to be cognizant of scope
creep so it's really
easy to just think i'll just add this
i'll just add this
um people post things on like twitter
all the time or
just did you know you could do this or
you know new techniques blah blah blah
blah and it's really easy just to try
and add those in
when really what you want to do is just
stick to
what you had planned for you know this
release
and if you see you know cool stuff
coming into the public domain you can
say well okay well
i'm not going to do it now maybe i'll do
it in the next release
and for god's sake pace yourself so you
know
two hours a day for a month is not the
same as 12 hours on four fridays
in a month and maybe this is just a
personal thing for me
but little and often is
it's just a more enjoyable way to code
than having to sit at your desk for
however many hours
because you feel like you need to get
something out
so let's talk about languages for for a
sec
there are you know a billion different
languages out there
and you're gonna have to decide on
something for your server
and your implant and so depending on
your model you might
consider writing a client as well for
the operators
but in the world i'm just gonna sort of
focus on the server and the implant
for the server side i think you're
much better off building off a framework
that already exists some sort of
web framework
so you have um python ones like flask
and django
lots of different ones in the c sharp
you have blazer which provides you know
like a nice
um web ui you can have something that's
driven more by
apis or rpc and you have lots of others
like vue react and angular
and on the implant side you kind of have
to
think about maybe
well i mean this goes back to your goals
really what it what
what platform you really want to target
with your
framework i mean you can make your
framework
implants agnostic a lot of a lot of them
already do that like mystic
you can write your own implants for a
framework and that would be
you know really great if your framework
did that but you probably also want to
include an implant
just to make it easier for people to
pick up and use
and so you have os um specific languages
like um a c sharp
target.net framework and you have swift
on the mac os
you have languages that cross compile
like nim and go and rust
and then you have um actual proper
cross-platform languages like
net.net core and sort of python
but you certainly need to sort of
consider how these elements are going to
talk to each other and which language
facilitates that best so you know i've
already said that
the control server should provide a
means of
communicating with your implant over
any protocol or any means you want
so you have to consider
is the framework that i'm choosing gonna
be able to facilitate that
can i do that in python can i do that in
you know whatever
and then you kind of consider well if my
chosen language doesn't really do that
do i need to consider a different
language
and if you don't really know that
language is it worth
learning or is it worth
sticking to what you know and just
trying to make do the best you can
i think that's a decision only like you
can make based on
your goals and your priorities um
if you're learning if you're doing this
as a learning process then maybe it's
worth it
maybe you specifically want to
use this project as an opportunity to
learn
you know c-sharp for example i mean
that's pretty a pretty popular choice
then yeah by all means step out of your
comfort zone
and that kind of goes back to the
attainable first um
release thing is that if you're learning
something new
you've gotta like start small with it
so in terms of uh design patterns
there are two that i really um
go for the first is this command design
pattern
and i think this is pretty good for
picturing the
flow of stuff between the different
components
and by components i mean like separate
components such as the server and the
implant in the operator
not really internal
to any one of those
so we have the operator which is kind of
like the clients
and the operator wants to send a task
to an implant so you're probably going
to
send some information maybe it's over an
api you're going to post some
information
or post this data to your
team server which is kind of like the
director in
this design pattern nomenclature
so in this example i'm simply
i've got a simple task model that has a
command
and some arguments and i want to task an
implant that we're going to identify by
a guide
the server then takes that task
and sends it to the implant so that's
kind of the command
and then the implant which is a receiver
is going to execute that task
now i've highlighted task do it here
because it's in this model that the
server
um deals with but it's not in the model
that the um the operator sends
so the server if i want my server to
track
like task progress with the implant
it's going to need something so my
server
excuse me in this example adds a good to
all of the tasks
and then when the implant can when the
implant talks back to the server it can
report
it can use the same guide so that the
server can track
commands with the implant
and this kind of brings me on to the
subject of contracts
so you have contracts between the
different
elements within your the overall
solution so you have contracts between
the operator and the server
the server and the implant and maybe
even the server and any storage that you
want so if you're storing data so you
can
start and stop your team server without
losing data
and then what you really need
is different models
for each of those contracts don't try
and use the same model
between every element because you're
just going to get a little bit unstuck
so here's a code example of a task
request so this is what an operator
might post to the server
this is a request so it's got a command
an array of arguments and an artifact
so if this was like an execute assembly
um command the artifact would be like
the whole assembly so you're gonna push
like i don't know you're gonna push
rubeus down to your implant
and you're gonna tell it to execute with
these arguments
um the server will then
add on that task guide and give me back
that guide
so as the operator i can then use that
gui to check the status of that task
and when i'm asking for that i don't
necessarily i mean you might want to
it's kind of up to you
you might not want all of this original
data back
like you don't you might not i don't
need to see like the whole assembly
coming back i don't need to have rubius
just going backwards and forwards on the
wire between me and the server
all i really want maybe is just the
result
and the status
and you're going to find that you know
if you're using like
something like entity framework for
storage if you're using c sharp
you have to decorate your classes with
all sorts of things so you have to
have like attributes on your properties
that define
the like primary keys and stuff
and that information just doesn't need
to be coming back to the operator it
doesn't need to be going to the implant
so with every point you have to
try sort of like translate each model to
a different model
and then pass it along the chain
there's also this template method
pattern
and this is pretty good for planning you
know
plan more carefully planning your code
what's your actual code going to look
like
and i'm sorry that all of my code
examples are in c sharp
mainly because that's all i really know
but also that's what people
are kind of more interested in i think
so on the left i've got an abstract
class that's going to act as like
a building block to build custom
listeners on my server
i'm going to have a protected
field at the top which is an itask
manager
and that is an interface that has these
um methods on it
so q task is the method that an
operator would um
use to task an agent so it would take in
like a guide and i've just put a bite
array but this would be the um
the implant task model
and then get tasks and receive output
will be used like the listener side
so that when an implant is talking to
the listener
it can just use this task manager just
to grab the tasks
and any tasks that are queued for it
and also give the server any output that
the implant is sending
and then the listener it just has this
init or initialized method to bring in
that task manager
and then just to start on a stop
so let's have a look at what that could
look like in c sharp so this is my
abstract class
you can see i've got the eye task
manager here and this
init just brings in the task manager and
just assigns it to that field
and then it has two abstract
methods start and stop
and when somebody comes along and
implements their own custom listener
they inherit
from this listener class
and this is the entire
class here it's obviously not very
functional it's just an example
but you can see i've highlighted where
it would use
the task manager and
as the author of
the custom listener you don't have to
worry
about where the task manager is coming
from or how it works
because you've implemented this abstract
class
the framework is taking care of that for
you
and all you have to do is just the task
manager
is there is a field for you to use
as appropriate so to get tasks you just
call
get tasks and to send any output
into the server to
like process you just call receive
output so abstraction
and interfaces are you know just they're
just so useful
um in terms of any implant that you're
going to write
base primitives are better in my
view than i call it commands uh
proliferation and you know you can see
some um ct tools just have like a basili
you type like help whatever you just get
a bazillion um commands that you can
execute
and like me i find it a bit overwhelming
because i don't know it's just a lot but
it's also not that
um like flexible for the operator
so let's use mimikatz
as an example here you could build in a
command
um to your framework that will
automatically push moomin cats down to
the implant
um load it up in some way execute it and
send the results back
you could do that for seat belt and for
rubius
and it's very you know okay it's very
nice
just to have an automated way just to
push all of these assemblies down but
then as soon as the user
well you know the operator says well i
want to push down something custom
you've not made it very easy to do that
um so the base primitives
are more about what allows these
commands to actually happen
so mimikats is tied to manual mapping
in um like c sharp anyway so
instead of providing like a mimikats
command you could just
um provide some sort of means of just
manual mapping in your implant
and that will allow the user just to
send down an arbitrary
dll or executable arbitrary
commands
just map it into the implant execute it
and send the results back
you can also you know expose reflective
dlls
dot net reflection power shell sockets
you know whatever you want but the
closer
or the more easily you expose these base
primitives to your operator
the more easily they can
write custom commands for your implant
and in terms of commands this
is something that i see quite often not
even not just in like
c2 tools but all sorts of tools that
bring in some sort of user input
this you know the command is a string
and they're just well this is a switch
statement but it could easily be like
if else if else if else if if the
command equals this do this
and it's just not good um it's not very
flexible
obviously it's difficult to expand and
maintain
you know if you want to add another
one in here it's gonna be like massive
and if you've got
a more complicated method
than these it's just
just don't um it's difficult to handle
exceptions you could wrap this whole
thing in like a try catch
in which case you're only catching like
maybe like generic
exceptions or you could wrap each one of
these in a try catch
and that just makes it even bigger you
can see we've got code duplication
so we're requesting this like get
current directory a whole bunch of times
which isn't really a problem for
something so short but if it's something
more complicated then
it that just becomes untenable
it's not particularly performant because
most the time i think especially if it's
uh an if else if else if
it always starts from the top and you go
down
um we're also
forcing everything to be a string
and it's just you know it's just ugly
this is not a good way to
um code something
so what's a better um example perhaps
is again to implement those abstracts
so i've got an abstract class here which
is called
implant command um
it has a string which is called command
i probably should have called it name or
something but
this is like the name of the command
and it's got an abstract
method called execute that'll bring in
the task that's been sent down to it and
it has another
in it which brings in a class in this
case in case it's called
implant but implant has
several public methods you can see over
on this right-hand side here for
sending results back sending an error
back and all sorts of things
so the implant class again is not
something the operator will
care about but you can expose public
methods
on it for them to do useful things
so like the listener example we want to
create our own command
that will inherit from implant command
we give it a name in this case it's just
ls and i've also thrown like sharpsploit
in here as an example
um as an example of like decoupling
um a lot of like the back end execution
from the actual command
and that means that as a user if i want
to implement another command that uses
like sharp floyd they can do that really
easily
um you know again we're just
making it as flexible as we can
and of course um abstracts
you are forced to implement so you have
to um
you know put some sort of implementation
in when you override
the this method and you can as the
author you can just put whatever
whatever you want in there and again you
don't have to worry about the task
it automatically is brought into the
command for you you don't have to worry
about
where implant is coming from it's
automatically done for you
you just call the methods that you want
um and then you can
this is within that implant um
class is there at some point we call
load commands and we can use
uh reflection to automatically
instantiate
every type of implement command
and initialize them
so they're ready to be used and then
that handle task
method where in the previous example was
that big old switch case
this is what it would look like so all
we need to do is
find the class that has the name that
we're looking for
you know in the actual um task that
comes down
if we didn't find it we send an error
back saying that
well the command isn't found otherwise
we just
execute it
i got another example here using
attributes but i'm actually running at a
time
so i have to skip to the summary
so to start with absolutely know your
goals
know what you're trying to build and why
you're trying to build it
only by knowing your goals will you
really understand what features you need
to put into your framework but i'd
also encourage you to focus on framework
features rather than
c2 features so by c2 features
i don't know um i guess i'm referring to
command
proliferation again but i would
definitely focus
especially in the early days of your of
your framework is
is focus on those framework um elements
you really want to provide the operators
the means to customize and expand your
framework
the way they want to do it prioritize
those base primitives on your implant
and provide an easy means for the
operators to interact with them
abstracts and interfaces are incredibly
useful
i can't think
really of a a better way to provide
that extensibility um
to the operators
plan small attainable releases don't try
and do
like a big big bang release for your you
know your first one
and if this is something that you want
to maintain over the long term
i would also say to limit each release
to only one
like big feature so if you look at
usually if you look at release notes for
for software most of them the vast
majority of the changes are bug fixes
you'll then get other types of um minor
improvements
and you'll probably only really see like
one
or maybe two like big new features
um so that is a kind of software design
thing that i would really encourage
don't try and change too much
in one go
and yeah i think that's pretty much it
um i hope the talk was useful and if
you've got any questions please let me
know
i'm going to try and be around for a q a
during the
village if not feel free to hit me up on
any of those
um socials i shared the beginning
i hope you enjoy the rest of the
conference thanks very much