You want to contribute a module or two? Awesome! There are basically two steps:
- You have to write a module ;-) Chose a category (attack/defend) and create a file under it. To keep it consitent, please name the file the same name you will use in class variable
name
. - Register your module in
__init__.py
file of a given category (attack/defend)
Each module has to be contained in a single class containing four major components:
- A class which derives from ModuleBaseClass (abstract class to check everything was implemented)
- Three class variables:
name
(a str variable),description
(a str variable),safe
(a bool variable).
- One instance method named
run
taking four arguments:self
,sshclient
,args
,server
.
run
method must returnTrue
indicating it was executed correctly. Everything else will be treated as a fail.
sshclient
is just paramiko.client.SSHClient
object. It should be already connected to a given server. You can refer to paramiko documentation for further help. Paramiko for Dummies 101 when writing a module:
# To execute command
sshclient.exec_command("whoami")
# To upload a file
## Open SFTP channel
sftp = sshclient.open_sftp()
## The first argument is local location, the second one is remote location
sftp.put("./modules/defend/files/libsnoopy.so.2.4.8", "/usr/local/lib/libsnoopy.so")
## Close unused channel
sftp.close()
Basically it's argparse Namespace object. You can access here arguments provided to launch hyder with. Main usage predicted for module creators is to access args.env
which is a dictionary containing all key and values provided with -e
argument.
# Hyder launched like so
# ./hyder.py attack all -H hosts -e LHOST=127.0.0.1 -e LPORT=4444
#
# This is how you can access those LHOST and LPORT vars in two ways
# 1) Better way because you will get None if the key was not provided
args.env.get("LHOST")
# 2) If key does not exist, this will trigger exception
# You have to handle the exception. This way is not recommended
args.env["LHOST"]
This is dictionary file containing keys IP
, user
and password
. You have there information about currently server on which module runs.
It's easy as adding two lines of code and one comment. Here's the __init__.py
file from defend
directory:
import sys
sys.path.append('../..')
modules = []
# Register modules here
# Deploy Snoopy
from .deploy_snoopy import DeploySnoopy
modules.append(DeploySnoopy)
# (..)
# Your Module <---------------------------
from .yourmodule import YourModule # assumes your module file name is yourmodule.py
modules.append(YourModule)
Module:
import logging, datetime
from hyderaddons import ModuleBaseClass
class PrintTime(ModuleBaseClass):
name = "printtime"
description = "Module which prints time so operator know when hyder was run when viewing console history of any sort"
safe = True
def run(self, sshclient, args, server):
logging.debug(datetime.datetime.utcnow())
logging.debug("Server IP: " + server.get("IP", "Unknown"))
print(f"{server.get('IP')}: {datetime.datetime.utcnow()}")
return True
Defend __init__.py
file:
import sys
sys.path.append('../..')
modules = []
# Register modules here
(..)
# Print Time
from .printtime.py import PrintTime
modules.append(PrintTime)
Hyder is built in a way that by default it prints only module's print()
from the first server. For the rest of servers, a simple OK
or FAILED
is displayed (don't forget to return True
when everything was executed properly). Operator can change this behavior by providing -v
when executing hyder. logging
however is printed indepdently so it's crucial you use logging.error("Error message")
and logging.warning("Warning message")
when you can catch in the module something going sideways.