This blog is for educational purpose only
Code repo for this blog: https://github.com/3santree/blogcode
Phase 1
We will use console library which aslo used by Sliver. I recommand go through the example it provides in the repo to get familiar with its usage, because I won’t explain setting up console in detail.
|
|
server/server.go
is the main function that will use packages inside folder server
|
|
The program will be look like this, no help menu as we haven’t add any commands yet. To exit the program, use Ctrl-C
and type y
to confirm exit
To save spaces for the blog, I put the code into github for you to test and play, for first time running, do
go mod tidy
in every folder to sync dependenies.
Phase 2
Now we need to add commands to this program, here’re the some functionality we gonna build:
listen
: start a tcp listener that waiting for connection, you can specify theip
andport
, a listener will be add to job queuejob
: print all background job
session
: print all sessions (along with the ip, os, username, hostname). You can interact will a session if you specify the session id after-i
listen
Let’s understand server/listen.go
code logic fisrt, which is called when we type listen
in the console. listen()
called in server/command,go
|
|
Dive into listen.go
where it’s implemented, it only do two things where the function name can explain for themselves
|
|
For tcpListen
, it does following things
Start listener
ln
onip:port
, accept the connection in the background which isgo acceptConnections(ln))
acceptConnections()
will send the established connection tohandleConncetion()
which implements the classic tcp read/write functionalityhandleConncetion()
will read the incoming data in the background, everytime we read some data, we will pass it toSend loop
, where themsgHandler()
will decide what to do based on the data we receviedIn
msgHandler()
, I use thetype
to differentiate the message
|
|
I use protobuf to package each message, you can find how I define a message structure in pb/message.proto
.
|
|
For example, if we receive an response that client send to us, contains the message SessionInfo
, we can unpack it and get the value which is what I do in case 2
of msfHandler()
|
|
session
In session.go
, if you want to interact with a session, it will switch to session menu for more action, such as ls()
to list current directory of the client. Other will print all sessions
|
|
After switching to the session’s menu, the command is implemented by SessionCmd()
in server/command.go
|
|
The ls()
implemented in server/commands/ls.go
is as an example of how to send command to the server. When the client recieves server’s message
- It checks the type is
1
meaning it’s an command from server - Read the Data which indicates the command
ls
, then prepare the output ofls
- Send the output back to server using type
1
, the server’smsfHandler()
recognize it as client’s response and print out the response
|
|
Phase 3
We add the client’s code which has following structure
|
|
For client.go
, the code logic is similar to server/listen.go
- Connect to a
ip:port
byclient()
client()
implement tcp read/write model and send any recieved message toclientHandler()
clientHandler()
is similar tomsgHandler()
in the server, which will make the action based on different message type, where case1
indicates the command from server
|
|
Final
Here’s what’s we implemented so far looks like. for ls()
now it’s only works for linux, anyway, we know the basic flow of the sending commands and get result back. Now We can build more functionality upon this rather than in part 1!