Skip to content

Single-threaded event-driven low-interaction SSH honeypot based on libassh

License

Notifications You must be signed in to change notification settings

sjinks/tiny-ssh-honeypot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tiny-ssh-honeypot

Build Docker CI/CD CodeQL Scan Static Code Analysis

tiny-ssh-honeypot is a lightweight, low-interaction SSH honeypot. It is a spin-off of ssh-honeypotd with fewer features but lower resource consumption.

Unlike ssh-honeypotd, tiny-ssh-honeypot is a single-threaded event-driven application. Its architecture allows for handling much more connections while consuming much less memory. tiny-ssh-honeypot uses libassh 1.1 and libev 4.x under the hood.

Compilation

tiny-ssh-honeypot uses CMake as its build system.

The project has two optional dependencies:

  1. libassh 1.1
  2. libev 4.x

If those are not present, the build script will try to download and build them.

The download locations are:

NOTE: the build script builds static versions of the downloaded libraries.

The build script defines the following command-line options:

  • BUILD_STATIC_BINARY (OFF by default): whether to build a static binary;
  • FORCE_EXTERNAL_LIBEV (OFF by default): whether to ignore the system libev;
  • FORCE_EXTERNAL_LIBASSH (OFF by default): whether to ignore the system libassh.

To build the program, you will need cmake, a C compiler (say, clang or gcc), and a make tool (make). The program builds on Linux and may (or may not) build on other systems (like Windows).

cmake -S . -B build
cmake --build build

Build Docker Image

If you have Buildx installed:

docker buildx build --pull --tag wildwildangel/tiny-ssh-honeypot .

Otherwise, if you have BuildKit enabled:

docker build --pull --tag wildwildangel/tiny-ssh-honeypot .

Or, for Docker versions earlier than 23.0,

DOCKER_BUILDKIT=1 docker build --pull --tag wildwildangel/tiny-ssh-honeypot .

Note: BuildKit is the default builder for users on Docker Desktop and Docker Engine v23.0 and later.

Usage

tiny-ssh-honeypot [options]

Mandatory arguments for long options are mandatory for short options, too.

  • -k, --host-key FILE: the file containing the private host key (RSA, DSA, ECDSA, ED25519). As a fallback mechanism, the program will try to generate the RSA and ED25519 keys automatically.
  • -b, --address ADDRESS: the IP address to bind to (default: 0.0.0.0). You can specify this option multiple times.
  • -p, --port PORT: the port to bind to (default: 22).
  • -h, --help: display the help screen and exit.
  • -v, --version: output version information and exit.

Log Format

Unlike ssh-honeypotd, tiny-ssh-honeypot does not try to mimic the output of sshd but logs its messages differently. The reason behind this decision is that some developers find it hard to write a robust regular expression for a failed SSH login, and thus leave their systems open to a possible Denial of Service attack.

All actionable messages generated by tiny-ssh-honeypot have the following format:

[source_ip:source_port => target_ip:target_port]: message

tiny-ssh-honeypot generates the following messages:

  • incoming connection: there is a new incoming connection.
  • closing connection: the client has disconnected. If there are no messages about failed login attempts between these two messages, it could mean that someone is scanning your server's ports (reading service identification strings).
  • did not receive identification string: the client has failed to identify itself and disconnected. This message may indicate a scanner.
  • login attempt for user: [user] (password: [password]): failed login attempt.
  • connection closed by authenticating user: the client has identified itself and passed the KEX (key exchange) stage, but disconnected before the user has identified themselves.
  • SSH error: [error]: protocol error occurred. For example, errors can happen when the client unexpectedly disconnects (IO error).
  • input overflow: should not happen. This means that the length of the username or password exceeds the value of the INT_MAX constant.

Usage with Docker

docker run -d \
    --network=host \
    --cap-drop=all \
    --cap-add=NET_BIND_SERVICE \
    --restart=always \
    --read-only \
    --user=10001:10001 \
    wildwildangel/tiny-ssh-honeypot:latest -t

These variables make it easy to have several honeypots running on the same machine, should the need arise.

Usage with Kubernetes

tiny-ssh-honeypot.yaml:

---
apiVersion: v1
kind: Namespace
metadata:
  name: honeypots
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: tiny-ssh-honeypot
  namespace: honeypots
spec:
  selector:
    matchLabels:
      name: tiny-ssh-honeypot
  template:
    metadata:
      labels:
        name: tiny-ssh-honeypot
    spec:
      hostNetwork: true
      containers:
        - name: tiny-ssh-honeypot
          image: wildwildangel/tiny-ssh-honeypot
          resources:
            limits:
              cpu: 100m
              memory: 8Mi
            requests:
              cpu: 50m
              memory: 8Mi
          securityContext:
            capabilities:
              drop:
                - all
              add:
                - NET_BIND_SERVICE
            readOnlyRootFilesystem: true
            runAsNonRoot: true
            runAsUser: 10001
            runAsGroup: 10001
            allowPrivilegeEscalation: false
          ports:
            - containerPort: 22
              hostPort: 22
              protocol: TCP
kubectl apply -f tiny-ssh-honeypot.yaml

Integration with Wazuh

tiny-ssh-honeypot_decoders.xml:

<decoder name="tiny-ssh-honeypot">
    <type>syslog</type>
    <program_name type="pcre2">^tiny-ssh-honeypot$</program_name>
</decoder>

<decoder name="tiny-ssh-honeypot">
    <type>firewall</type>
    <prematch type="pcre2">^tiny-ssh-honeypot(?:\[\d+\])?: </prematch>
</decoder>

<decoder name="tiny-ssh-honeypot">
    <type>syslog</type>
    <program_name type="pcre2">^[0-9a-f]{12}$</program_name>
    <prematch type="pcre2">tiny-ssh-honeypot(?:\[\d+\])?: </prematch>
</decoder>

<decoder name="tiny-ssh-honeypot-login">
    <parent>tiny-ssh-honeypot</parent>
    <regex type="pcre2" offset="after_parent">\[([0-9a-fA-F:.]+?):(\d+) => ([0-9a-fA-F:.]+?):(\d+)\]: login attempt for user: (.*?) \(password: </regex>
    <order>srcip, srcport, dstip, dstport, srcuser</order>
</decoder>

<decoder name="tiny-ssh-honeypot-scan">
    <parent>tiny-ssh-honeypot</parent>
    <regex type="pcre2" offset="after_parent">\[([0-9a-fA-F:.]+?):(\d+) => ([0-9a-fA-F:.]+?):(\d+)\]: did not receive identification string</regex>
    <order>srcip, srcport, dstip, dstport</order>
</decoder>

tiny-ssh-honeypot_rules.xml:

<group name="tiny-ssh-honeypot,">
    <rule id="101000" level="0">
        <decoded_as>tiny-ssh-honeypot</decoded_as>
        <match>login attempt for user</match>
        <description>Tiny SSH Honeypot: login attempt</description>
        <group>authentication_failed,</group>
    </rule>

    <rule id="101001" level="0">
        <if_sid>4100</if_sid>
        <decoded_as>tiny-ssh-honeypot</decoded_as>
        <match>login attempt for user</match>
        <description>Tiny SSH Honeypot: login attempt</description>
        <group>authentication_failed,</group>
    </rule>

    <rule id="101010" level="5">
        <if_sid>101000, 101001</if_sid>
        <user>\S+</user>
        <description>Tiny SSH Honeypot: login attempt for user $(srcuser)</description>
        <group>authentication_failed,</group>
    </rule>
    
    <rule id="101030" level="0" noalert="1">
        <if_sid>101000, 101001</if_sid>
        <srcip>127.0.0.1</srcip>
        <description>Tiny SSH Honeypot: ignore local testing</description>
        <options>no_log</options>
    </rule>

    <rule id="101100" level="10" frequency="10" timeframe="60">
        <if_matched_sid>101000, 101001</if_matched_sid>
        <same_source_ip />
        <description>Tiny SSH Honeypot: brute-force login attempts from $(srcip)</description>
        <group>bruteforce, authentication_failed,</group>
    </rule>

    <rule id="102000" level="4">
        <decoded_as>tiny-ssh-honeypot</decoded_as>
        <match>did not receive identification string</match>
        <description>Tiny SSH Honeypot: connection without SSH identification from $(srcip)</description>
        <group>scan, network,</group>
    </rule>

    <rule id="102100" level="8" frequency="5" timeframe="60">
        <if_matched_sid>102000</if_matched_sid>
        <same_source_ip />
        <description>Tiny SSH Honeypot: repeated probes from $(srcip)</description>
        <group>scan, network,</group>
    </rule>
</group>

About

Single-threaded event-driven low-interaction SSH honeypot based on libassh

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Contributors 4

  •  
  •  
  •  
  •