oSSH
… is a dirty mix of honey and tar, delivered by a fake SSH server.
Once running it will patiently wait for bots going after that sweet honey. When a bot tries to connect for the first time oSSH will check if username and password are already recorded. In that case it will kick the bot and wait for it to come back. If the bot has something new (either username or password), oSSH will gladly let the bot in and record the credentials. For bots that offer a username and a password that oSSH doesn’t know, oSSH will roll dice to decide whether to let the bot in. This applies to new hosts, known hosts will always be let it.
Once inside, oSSH will add some tar to the mix. The bot can run commands and access a filesystem, but it will be painfully slow and all data returned will be fake. Meanwhile oSSH will record what the bot is doing, fingerprint it and store it in a file for manual inspection.
In addition to being painfully slow, the bot will connect to a pretty broken system where many commands result in errors reminiscent of failing hardware, bad configuration and alike.
How oSSH behaves can be configured via a YAML config file, a fake file system and command templates.
oSSH can also sync with other oSSH nodes to share hosts, user names, passwords and fingerprints.
Installation
The following assumes that you will use /etc/ossh
as data directory. If you want something else you need to substitute accordingly and set path_data
in the config.
First of all you need to become root (or run everything with sudo
). Then get the repo and build the executable:
git clone https://github.com/Toxyl/ossh.git
cd ossh
CGO_ENABLED=0 go build
mv ossh /usr/local/bin/
Create directories and copy data from the repo:
mkdir -p /etc/ossh/{captures,commands,ffs}
cp -R commands/* /etc/ossh/commands/
cp -R ffs/* /etc/ossh/ffs/
cp ossh.service /etc/systemd/system/ossh.service
cp config.example.yaml /etc/ossh/config.yaml
Configure your instance:
nano /etc/ossh/config.yaml
And then enable the service:
systemctl enable ossh
Finally you can start trapping bots in that sweet tar:
service ossh start
You can monitor oSSHs operation using journalctl
:
journalctl -u ossh -f --output cat
Configuration
Sluggishness
oSSH slows down responses to simulate a slow machine and to waste the bots time. This ratelimit can be defined in the config (ratelimit
). Sometimes bots run commands with little output, so oSSH will add some penalty for every input character to slow things down a bit more for them. This can be defined in the config as well (input_delay
).
Sync operations between nodes are exempt from the restrictions.
Command Responses
The commands
section of the config allows you to customize oSSHs responses to commands. You can also create more elaborate responses using Golang templating, see the commands
directory for examples.
Commands are evaluated in the following order:
rewriters
(config)
These are pairs of regular expressions and replacements and will be executed in the given order on any user/bot input. Be aware that captures are made after rewriters have been applied.
my-little-pony
When this command is encountered oSSH will print a list with stats, such as amounts of collected user names and passwords. Consider it to be an admin-command which you can use to get stats. It cannot be configured and is included in this list for the sake of completeness.
exit
(config)
If a command matches this list the connection will be terminated with a time-wasting response:
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
simple
(config)
These are pairs with a command to match and a response. Responses can use some template variables so one can, e.g., simulate the whoami
command. Available variables are:
Variable | Effect |
---|---|
{{ .User }} |
User name the attacker logged in with |
{{ .IP }} |
IP of the attacker |
{{ .IPLocal }} |
IP of oSSH |
{{ .Port }} |
Port of the attacker |
{{ .PortLocal }} |
Port of oSSH |
{{ .HostName }} |
Host name of oSSH |
{{ .InputRaw }} |
Raw input line that matched the command |
{{ .Command }} |
Command that matched |
{{ .Arguments }} |
Array with the arguments |
permission_denied
(config)
If a command matches this list oSSH will respond with:
{{ .Command }}: permission denied
disk_error
(config)
If a command matches this list oSSH will respond with:
end_request: I/O error
command_not_found
(config)
If a command matches this list oSSH will respond with:
{{ .Command }}: command not found
file_not_found
(config)
If a command matches this list oSSH will respond with:
{{ .Command }}: No such file or directory
not_implemented
(config)
If a command matches this list oSSH will respond with:
{{ .Command }}: Function not implemented
Command templates
If none of the above steps matched, oSSH will look in the commands directory (see further below) for a matching response template and parse that.
Nothing defined anywhere
If there is still no match oSSH will simply return:
{{ .Command }}: command not found
Syncing
If you run multiple instances of oSSH, you might want them to share their knowledge. To do so you can create credentials, store them in the config of each instance and then restart the instances. Once done they will regularly sync up with all nodes defined in their config. Assuming you have nodes running on 192.168.0.10
, 192.168.0.20
and 192.168.0.30
, the config could look like this:
Node 1 (192.168.0.10
)
sync:
interval: 1 # in minutes
nodes:
- host: 192.168.0.20
port: 22
user: 078e5067ec45f123a11b0845b5ddba3fea63e243118454ce07f85d7639eb4ec4
password: 91ca82fc115605a4e21de7f9fc005b450ef6baa69fef56dbfbaf64375c21fd4f
- host: 192.168.0.30
port: 22
user: 8fe36196f2c4bb5a63f390c3e2e1152a3ababcd3f41c1295b86f773c9c53c632
password: ea5f6f80595c72c5e1ee8198a651f7584a3b293afbefcf228dd8b1659b6864c9
Node 2 (192.168.0.20
)
sync:
interval: 1 # in minutes
nodes:
- host: 192.168.0.10
port: 22
user: 42ba9f2b9b6e44a1b2744a243201d3147d174232de467899ab7e20df374101df
password: 8dd88f838d80197836c59ccdd8fbde1feed27688a443132be5c0cb0e999b603f
- host: 192.168.0.30
port: 22
user: 8fe36196f2c4bb5a63f390c3e2e1152a3ababcd3f41c1295b86f773c9c53c632
password: ea5f6f80595c72c5e1ee8198a651f7584a3b293afbefcf228dd8b1659b6864c9
Node 3 (192.168.0.30
)
sync:
interval: 1 # in minutes
nodes:
- host: 192.168.0.10
port: 22
user: 42ba9f2b9b6e44a1b2744a243201d3147d174232de467899ab7e20df374101df
password: 8dd88f838d80197836c59ccdd8fbde1feed27688a443132be5c0cb0e999b603f
- host: 192.168.0.20
port: 22
user: 078e5067ec45f123a11b0845b5ddba3fea63e243118454ce07f85d7639eb4ec4
password: 91ca82fc115605a4e21de7f9fc005b450ef6baa69fef56dbfbaf64375c21fd4f
Data directory
If you don’t want to keep data in the default location (/etc/ossh
), you can define an alternate location in the config like this:
path_data: /usr/share/ossh
Within that directory you will find bind a bunch of files with data collected by oSSH:
File | Description |
---|---|
hosts.txt |
List of attacker IPs |
users.txt |
List of user names |
passwords.txt |
List of passwords |
fingerprints.txt |
List of payload fingerprints |
Captures directory
The subdirectory captures
is the collection of payloads received from bots. Whenever a bot connects oSSH will record what it’s doing and then save that recording as an ASCIICast v2 (you can use asciinema
to play them back). Captures are saved per host, so you can, e.g., identify especially aggressive bots. The last part of the file name is the fingerprint of the sequence. Existing files will not be overwritten.
Fake File System (FFS)
The subdirectory ffs
contains the files and directories bots can browse. You can modify the directory content at runtime to react to new payloads. For example: if bots commonly cat
a specific file, you can create a very lengthy fake version of that file in the ffs
directory. Next time a bot cat
s it, it will be waiting for a long time 😀
Commands directory
The subdirectory commands
contains templates for commands that need more elaborate behavior. Like the ffs
directory it can be modified at runtime. These files are Golang templates, see this for more information in regards to the templating language.