* update gh actions versions
* update docker build/pub
* docker workflow update
* also update latest docker tag
* ruff has taken over from flake8
This commit is contained in:
Michel Oosterhof 2023-01-30 17:51:20 +08:00 committed by GitHub
parent 0001168382
commit bf55a591bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 249 additions and 247 deletions

View File

@ -1,3 +0,0 @@
[flake8]
ignore = E203, E501, W503
max-line-length = 79

View File

@ -1,94 +0,0 @@
---
name: Docker
on: # yamllint disable-line rule:truthy
push:
# Publish `master` as Docker `latest` image.
branches:
- master
# Publish `v1.2.3` tags as releases.
tags:
- v*
# Run tests for any PRs.
pull_request:
# Run manually
workflow_dispatch:
inputs:
logLevel:
description: 'Log level'
required: true
default: 'warning'
tags:
description: 'Build and publish Docker image'
env:
# TODO: Change variable to your image's name.
IMAGE_NAME: cowrie
jobs:
# Run tests.
# See also https://docs.docker.com/docker-hub/builds/automated-testing/
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run tests
run: |
if [ -f docker-compose.test.yml ]; then
docker-compose --file docker-compose.test.yml build
docker-compose --file docker-compose.test.yml run sut
else
docker build --file docker/Dockerfile .
fi
# Push image to GitHub Packages.
# See also https://docs.docker.com/docker-hub/builds/
push:
# Ensure test job passes before pushing image.
needs: test
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v2
- name: Build image
run: docker build --file docker/Dockerfile --tag $IMAGE_NAME .
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# TODO: Create a PAT with `read:packages` and `write:packages` scopes and save it as an Actions secret `CR_PAT`
# run: echo "${{ secrets.CR_PAT }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin
- name: Push image to GitHub Container Registry
run: |
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
# Change all uppercase to lowercase
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
# Strip git ref prefix from version
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
# Strip "v" prefix from tag name
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
# Use Docker `latest` tag convention
[ "$VERSION" == "master" ] && VERSION=latest
echo IMAGE_ID=$IMAGE_ID
echo VERSION=$VERSION
docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
docker push $IMAGE_ID:$VERSION

91
.github/workflows/docker.yml vendored Normal file
View File

@ -0,0 +1,91 @@
---
name: Docker Build and Publish
on: # yamllint disable-line rule:truthy
push:
# Publish `master` as Docker `latest` image.
branches:
- master
# Publish `v1.2.3` tags as releases.
tags:
- v*
# Run tests for any PRs.
pull_request:
# Run manually
workflow_dispatch:
inputs:
logLevel:
description: 'Log level'
required: true
default: 'warning'
tags:
description: 'Build and publish Docker image'
env:
IMAGE_NAME: cowrie
jobs:
# Push image to GitHub Packages.
# See also https://docs.docker.com/docker-hub/builds/
push:
# Ensure test job passes before pushing image.
needs: test
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- name: Checkout
uses: actions/checkout@v3
# Add support for more platforms with QEMU (optional)
# https://github.com/docker/setup-qemu-action
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
with:
platform: amd64,arm64
# - name: Login to Docker Hub
# uses: docker/login-action@v2
# with:
# registry: ghcr.io
# username: ${{ github.actor }}
# password: ${{ secrets.GITHUB_TOKEN }}
# # TODO: Create a PAT with `read:packages` and `write:packages` scopes and save it as an Actions secret `CR_PAT`
# # run: echo "${{ secrets.CR_PAT }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin
# $(DOCKER) buildx build --platform ${PLATFORM} -t ${IMAGE}:${TAG} --build-arg BUILD_DATE=${BUILD_DATE} -f docker/Dockerfile --push .
- name: Build
uses: docker/build-push-action@v3
with:
push: false
tags: cowrie/cowie:latest
file: docker/Dockerfile
# - name: Push image to GitHub Container Registry
# run: |
# IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
#
# # Change all uppercase to lowercase
# IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
#
# # Strip git ref prefix from version
# VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
#
# # Strip "v" prefix from tag name
# [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
#
# # Use Docker `latest` tag convention
# [ "$VERSION" == "master" ] && VERSION=latest
#
# echo IMAGE_ID=$IMAGE_ID
# echo VERSION=$VERSION
#
# docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
# docker push $IMAGE_ID:$VERSION

View File

@ -27,7 +27,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Hadolint Action
uses: hadolint/hadolint-action@v3.0.0
with:

View File

@ -22,9 +22,9 @@ jobs:
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
- run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
- name: Check out repository code
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Install Python tools

View File

@ -22,9 +22,9 @@ jobs:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "pypy-3.8", "pypy-3.9"]
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies

View File

@ -84,7 +84,7 @@ TAG=$(shell git rev-parse --short=8 HEAD)
docker-build: docker/Dockerfile ## Build Docker image
-$(DOCKER) buildx create --name cowrie-builder
$(DOCKER) buildx use cowrie-builder
$(DOCKER) buildx build --platform ${PLATFORM} -t ${IMAGE}:${TAG} --build-arg BUILD_DATE=${BUILD_DATE} -f docker/Dockerfile --push .
$(DOCKER) buildx build --platform ${PLATFORM} -t ${IMAGE}:${TAG} -t ${IMAGE}:latest --build-arg BUILD_DATE=${BUILD_DATE} -f docker/Dockerfile --push .
.PHONY: docker-run
docker-run: docker-start ## Run Docker container

View File

@ -1,7 +1,64 @@
[build-system]
requires = ["setuptools >= 65.63"]
[project]
name = "cowrie"
version = "2.4.0"
version = "2.5.0"
description="Cowrie SSH/Telnet Honeypot."
license.text="BSD-3-Clause"
authors = [ {name = "Michel Oosterhof", email="michel@oosterhof.net"}, ]
maintainers = [ {name = "Michel Oosterhof", email="michel@oosterhof.net"}, ]
keywords=["ssh", "telnet", "honeypot"]
requires-python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*, <4"
readme="README.rst"
classifiers=[
"Development Status :: 5 - Production/Stable",
"Environment :: No Input/Output (Daemon)",
"Framework :: Twisted",
"Intended Audience :: Developers",
"Intended Audience :: System Administrators",
"License :: OSI Approved :: BSD License",
"Operating System :: MacOS :: MacOS X",
"Operating System :: POSIX :: Linux",
"Operating System :: POSIX",
"Programming Language :: Python",
"Topic :: Security"
]
dependencies = [
"twisted==22.10.0",
"cryptography>=0.9.1",
"configparser",
"pyopenssl",
"pyparsing",
"incremental",
"packaging",
"appdirs>=1.4.0",
"python-dateutil",
"service_identity>=14.0.0",
]
[project.urls]
homepage = "https://www.cowrie.org/"
repository = "https://github.com/cowrie/cowrie"
[project.scripts]
fsctl = "bin/fsctl"
asciinema = "bin/asciinema:main"
cowrie = "bin/cowrie:main"
creatfs = "bin/createfs:main"
playlog = "bin/playlog:main"
[project.optional-dependencies]
csirtg = ["csirtgsdk==1.1.5"]
dshield = ["requests"]
elasticsearch = ["pyes"]
mysql = ["mysqlclient"]
mongodb = ["pymongo"]
rethinkdblog = ["rethinkdb"]
s3 = ["botocore"]
slack = ["slackclient"]
influxdb = ["influxdb"]
[tool.isort]
profile = "black"

View File

@ -1,8 +1,6 @@
Sphinx==5.3.0
build==0.9.0
coverage==7.0.3
flake8-bugbear==22.12.6
flake8==6.0.0
mypy-extensions==0.4.3; platform_python_implementation=='CPython' and python_version>'3.8'
mypy-zope==0.3.11; platform_python_implementation=='CPython' and python_version>'3.8'
mypy==0.981; platform_python_implementation=='CPython' and python_version>'3.8'

View File

@ -1,7 +1,3 @@
[pytype]
inputs = src/cowrie
keep_going = True
[flake8]
ignore = E203,E501,W503
count = True

61
setup.py Normal file → Executable file
View File

@ -2,60 +2,25 @@
from setuptools import setup
try:
import twisted
except ImportError:
raise SystemExit("twisted not found. Make sure you "
"have installed the Twisted core package.")
setup(
name="Cowrie",
description="Cowrie SSH/Telnet Honeypot.",
long_description="Cowrie SSH/Telnet Honeypot.",
author="Michel Oosterhof",
author_email="michel@oosterhof.net",
maintainer="Michel Oosterhof",
maintainer_email="michel@oosterhof.net",
keywords="ssh telnet honeypot",
platforms="Unix, Mac OSX",
license="BSD",
url="https://www.cowrie.org/",
packages=["cowrie", "twisted"],
include_package_data=True,
package_dir={"": "src"},
package_data={"": ["*.md"]},
use_incremental=True,
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*, <4",
scripts=["bin/fsctl", "bin/asciinema", "bin/cowrie", "bin/createfs", "bin/playlog"],
classifiers=[
"Development Status :: 5 - Production/Stable",
"Environment :: No Input/Output (Daemon)",
"Framework :: Twisted",
"Intended Audience :: Developers",
"Intended Audience :: System Administrators",
"License :: OSI Approved :: BSD License",
"Operating System :: MacOS :: MacOS X",
"Operating System :: POSIX :: Linux",
"Operating System :: POSIX",
"Programming Language :: Python",
"Topic :: Security",
],
setup_requires=["incremental", "click"],
install_requires=[
"twisted==22.10.0",
"cryptography>=0.9.1",
"configparser",
"pyopenssl",
"pyparsing",
"incremental",
"packaging",
"appdirs>=1.4.0",
"python-dateutil",
"service_identity>=14.0.0",
],
extras_require={
"csirtg": ["csirtgsdk==1.1.5"],
"dshield": ["requests"],
"elasticsearch": ["pyes"],
"mysql": ["mysqlclient"],
"mongodb": ["pymongo"],
"rethinkdblog": ["rethinkdb"],
"s3": ["botocore"],
"slack": ["slackclient"],
"influxdb": ["influxdb"],
},
)
import sys
def refresh_plugin_cache():
from twisted.plugin import IPlugin, getPlugins
list(getPlugins(IPlugin))

View File

@ -181,7 +181,7 @@ commands["echo"] = Command_echo
class Command_printf(HoneyPotCommand):
def call(self) -> None:
if not len(self.args):
if not self.args:
self.write("printf: usage: printf [-v var] format [arguments]\n")
else:
if "-v" not in self.args and len(self.args) < 2:
@ -232,7 +232,7 @@ commands["reset"] = Command_clear
class Command_hostname(HoneyPotCommand):
def call(self) -> None:
if len(self.args):
if self.args:
if self.protocol.user.username == "root":
self.protocol.hostname = self.args[0]
else:
@ -249,7 +249,7 @@ class Command_ps(HoneyPotCommand):
def call(self) -> None:
user = self.protocol.user.username
args = ""
if len(self.args):
if self.args:
args = self.args[0].strip()
(
_user,
@ -878,7 +878,7 @@ commands["passwd"] = Command_passwd
class Command_shutdown(HoneyPotCommand):
def start(self) -> None:
if len(self.args) and self.args[0].strip().count("--help"):
if self.args and self.args[0].strip().count("--help"):
output = [
"Usage: shutdown [-akrhHPfnc] [-t secs] time [warning message]",
"-a: use /etc/shutdown.allow ",
@ -959,7 +959,7 @@ commands["reboot"] = Command_reboot
class Command_history(HoneyPotCommand):
def call(self) -> None:
try:
if len(self.args) and self.args[0] == "-c":
if self.args and self.args[0] == "-c":
self.protocol.historyLines = []
self.protocol.historyPosition = 0
return
@ -990,7 +990,7 @@ class Command_yes(HoneyPotCommand):
self.y()
def y(self) -> None:
if len(self.args):
if self.args:
self.write("{}\n".format(" ".join(self.args)))
else:
self.write("y\n")
@ -1007,7 +1007,7 @@ commands["yes"] = Command_yes
class Command_sh(HoneyPotCommand):
def call(self) -> None:
if len(self.args) and self.args[0].strip() == "-c":
if self.args and self.args[0].strip() == "-c":
line = " ".join(self.args[1:])
@ -1087,7 +1087,7 @@ class Command_php(HoneyPotCommand):
VERSION = "PHP 5.3.5 (cli)\n" "Copyright (c) 1997-2010 The PHP Group\n"
def start(self) -> None:
if len(self.args):
if self.args:
if self.args[0] == "-v":
self.write(Command_php.VERSION)
elif self.args[0] == "-h":

View File

@ -374,14 +374,14 @@ class Command_curl(HoneyPotCommand):
self.protocol.logDispatch(
eventid="cowrie.session.file_download",
format="Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(filename)s",
format="Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s",
url=self.url.decode(),
outfile=self.artifact.shasumFilename,
shasum=self.artifact.shasum,
)
log.msg(
eventid="cowrie.session.file_download",
format="Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(filename)s",
format="Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s",
url=self.url.decode(),
outfile=self.artifact.shasumFilename,
shasum=self.artifact.shasum,
@ -401,7 +401,7 @@ class Command_curl(HoneyPotCommand):
log.msg(
eventid="cowrie.session.file_download.failed",
format="Attempt to download file(s) from URL (%(url)s) failed",
url=self.url,
url=self.url.decode(),
)
if response.check(error.DNSLookupError) is not None:

View File

@ -302,15 +302,15 @@ class Command_wget(HoneyPotCommand):
self.protocol.logDispatch(
eventid="cowrie.session.file_download",
format="Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(filename)s",
url=self.url,
format="Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s",
url=self.url.decode(),
outfile=self.artifact.shasumFilename,
shasum=self.artifact.shasum,
)
log.msg(
eventid="cowrie.session.file_download",
format="Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(filename)s",
url=self.url,
format="Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s",
url=self.url.decode(),
outfile=self.artifact.shasumFilename,
shasum=self.artifact.shasum,
)
@ -320,8 +320,6 @@ class Command_wget(HoneyPotCommand):
"""
handle errors
"""
log.err(response)
if response.check(error.DNSLookupError) is not None:
self.write(
f"Resolving no.such ({self.host})... failed: nodename nor servname provided, or not known.\n"
@ -330,6 +328,7 @@ class Command_wget(HoneyPotCommand):
self.exit()
return
log.err(response)
log.msg(response.printTraceback())
if hasattr(response, "getErrorMessage"): # Exceptions
errormsg = response.getErrorMessage()

View File

@ -40,7 +40,7 @@ class Artifact:
def __init__(self, label: str) -> None:
self.label: str = label
self.fp = tempfile.NamedTemporaryFile(dir=self.artifactDir, delete=False)
self.fp = tempfile.NamedTemporaryFile(dir=self.artifactDir, delete=False) # pylint: disable=R1732
self.tempFilename = self.fp.name
self.closed: bool = False

View File

@ -58,33 +58,31 @@ from cowrie.core.config import CowrieConfig
# cowrie.session.file_download
# cowrie.session.file_upload
"""
The time is available in two formats in each event, as key 'time'
in epoch format and in key 'timestamp' as a ISO compliant string
in UTC.
"""
# The time is available in two formats in each event, as key 'time'
# in epoch format and in key 'timestamp' as a ISO compliant string
# in UTC.
def convert(input):
def convert(data):
"""
This converts a nested dictionary with bytes in it to string
"""
if isinstance(input, str):
return input
if isinstance(input, dict):
return {convert(key): convert(value) for key, value in list(input.items())}
if isinstance(input, dict):
return {convert(key): convert(value) for key, value in list(input.items())}
elif isinstance(input, list):
return [convert(element) for element in input]
elif isinstance(input, bytes):
if isinstance(data, str):
return data
if isinstance(data, dict):
return {convert(key): convert(value) for key, value in list(data.items())}
if isinstance(data, dict):
return {convert(key): convert(value) for key, value in list(data.items())}
if isinstance(data, list):
return [convert(element) for element in data]
if isinstance(data, bytes):
try:
string = input.decode("utf-8")
string = data.decode("utf-8")
except UnicodeDecodeError:
string = repr(input)
string = repr(data)
return string
else:
return input
return data
class Output(metaclass=abc.ABCMeta):

View File

@ -44,7 +44,7 @@ class HoneyPotRealm:
def __init__(self) -> None:
pass
def requestAvatar(self, avatarId, mind, *interfaces):
def requestAvatar(self, avatarId, _mind, *interfaces):
user: IConchUser
if IConchUser in interfaces:
serv = shellserver.CowrieServer(self)
@ -54,3 +54,4 @@ class HoneyPotRealm:
serv = shellserver.CowrieServer(self)
user = session.HoneyPotTelnetSession(avatarId, serv)
return interfaces[0], user, user.logout
raise NotImplementedError

View File

@ -48,10 +48,10 @@ class Output(cowrie.core.output.Output):
"""
cuckoo output
"""
api_user: str
api_passwd: str
url_base: bytes
cuckoo_force: int
def start(self):
"""
@ -123,7 +123,8 @@ class Output(cowrie.core.output.Output):
"""
Send a file to Cuckoo
"""
files = {"file": (fileName, open(artifact, "rb").read())}
with open(artifact, "rb") as art:
files = {"file": (fileName, art.read())}
try:
res = requests.post(
urljoin(self.url_base, b"tasks/create/file"),

View File

@ -36,7 +36,7 @@ class CustomParser(argparse.ArgumentParser):
):
self.protocol = protocol
if parents is None:
parents=[]
parents = []
super().__init__(
prog=prog,
usage=usage,

View File

@ -102,7 +102,7 @@ class CowrieSFTPDirectory:
def __init__(self, server, directory):
self.server = server
self.files = server.fs.listdir(directory)
self.files = [".", ".."] + self.files
self.files = [".", "..", *self.files]
self.dir = directory
def __iter__(self):

View File

@ -432,9 +432,7 @@ class HoneyPotFilesystem:
return True
return False
"""
Below additions for SFTP support, try to keep functions here similar to os.*
"""
# Below additions for SFTP support, try to keep functions here similar to os.*
def open(self, filename: str, openFlags: int, mode: int) -> Optional[int]:
"""

View File

@ -65,4 +65,4 @@ class CowrieSSHConnection(connection.SSHConnection):
if wantReply:
d.addCallback(self._cbChannelRequest, localChannel)
d.addErrback(self._ebChannelRequest, localChannel)
return d
return d

View File

@ -9,6 +9,12 @@ from __future__ import annotations
import os
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import dsa
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from twisted.conch.ssh import keys
from twisted.python import log
@ -20,8 +26,6 @@ def getRSAKeys():
privateKeyFile: str = CowrieConfig.get("ssh", "rsa_private_key")
if not (os.path.exists(publicKeyFile) and os.path.exists(privateKeyFile)):
log.msg("Generating new RSA keypair...")
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa
rsaKey = rsa.generate_private_key(
public_exponent=65537, key_size=2048, backend=default_backend()
@ -45,8 +49,6 @@ def getDSAKeys():
privateKeyFile: str = CowrieConfig.get("ssh", "dsa_private_key")
if not (os.path.exists(publicKeyFile) and os.path.exists(privateKeyFile)):
log.msg("Generating new DSA keypair...")
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import dsa
dsaKey = dsa.generate_private_key(key_size=1024, backend=default_backend())
publicKeyString = keys.Key(dsaKey).public().toString("openssh")
@ -68,7 +70,6 @@ def getECDSAKeys():
privateKeyFile: str = CowrieConfig.get("ssh", "ecdsa_private_key")
if not (os.path.exists(publicKeyFile) and os.path.exists(privateKeyFile)):
log.msg("Generating new ECDSA keypair...")
from cryptography.hazmat.primitives.asymmetric import ec
ecdsaKey = ec.generate_private_key(ec.SECP256R1())
publicKeyString = keys.Key(ecdsaKey).public().toString("openssh")
@ -90,7 +91,6 @@ def geted25519Keys():
privateKeyFile: str = CowrieConfig.get("ssh", "ed25519_private_key")
if not (os.path.exists(publicKeyFile) and os.path.exists(privateKeyFile)):
log.msg("Generating new ed25519 keypair...")
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
ed25519Key = Ed25519PrivateKey.generate()
publicKeyString = keys.Key(ed25519Key).public().toString("openssh")

View File

@ -29,6 +29,7 @@ class HoneyPotSSHTransport(transport.SSHServerTransport, TimeoutMixin):
startTime: float = 0.0
gotVersion: bool = False
buf: bytes
transportId: str
ipv4rex = re.compile(r"^::ffff:(\d+\.\d+\.\d+\.\d+)$")
auth_timeout: int = CowrieConfig.getint(
"honeypot", "authentication_timeout", fallback=120
@ -57,7 +58,7 @@ class HoneyPotSSHTransport(transport.SSHServerTransport, TimeoutMixin):
"""
self.buf = b""
self.transportId: str = uuid.uuid4().hex[:12]
self.transportId = uuid.uuid4().hex[:12]
src_ip: str = self.transport.getPeer().host
ipv4_search = self.ipv4rex.search(src_ip)
@ -112,42 +113,39 @@ class HoneyPotSSHTransport(transport.SSHServerTransport, TimeoutMixin):
if not self.gotVersion:
if b"\n" not in self.buf:
return
self.otherVersionString = self.buf.split(b"\n")[0].strip()
otherVersion: bytes = self.buf.split(b"\n")[0].strip()
log.msg(
eventid="cowrie.client.version",
version=self.otherVersionString.decode(
version=otherVersion.decode(
"utf-8", errors="backslashreplace"
),
format="Remote SSH version: %(version)s",
)
m = re.match(rb"SSH-(\d+.\d+)-(.*)", self.otherVersionString)
m = re.match(rb"SSH-(\d+.\d+)-(.*)", otherVersion)
if m is None:
log.msg(
"Bad protocol version identification: {}".format(
repr(self.otherVersionString)
)
f"Bad protocol version identification: {repr(otherVersion)}"
)
# OpenSSH sending the same message
self.transport.write(b"Invalid SSH identification string.\n")
self.transport.loseConnection()
return
else:
self.gotVersion = True
remote_version = m.group(1)
if remote_version not in self.supportedVersions:
self._unsupportedVersionReceived(self.otherVersionString)
return
i = self.buf.index(b"\n")
self.buf = self.buf[i + 1 :]
self.sendKexInit()
self.gotVersion = True
remote_version = m.group(1)
if remote_version not in self.supportedVersions:
self._unsupportedVersionReceived(otherVersion)
return
i = self.buf.index(b"\n")
self.buf = self.buf[i + 1 :]
self.sendKexInit()
packet = self.getPacket()
while packet:
messageNum = ord(packet[0:1])
self.dispatchMessage(messageNum, packet[1:])
packet = self.getPacket()
def dispatchMessage(self, message_num: int, payload: bytes) -> None:
transport.SSHServerTransport.dispatchMessage(self, message_num, payload)
def dispatchMessage(self, messageNum: int, payload: bytes) -> None:
transport.SSHServerTransport.dispatchMessage(self, messageNum, payload)
def sendPacket(self, messageType: int, payload: bytes) -> None:
"""
@ -195,9 +193,7 @@ class HoneyPotSSHTransport(transport.SSHServerTransport, TimeoutMixin):
cencCS = ",".join([alg.decode("utf-8") for alg in encCS])
cmacCS = ",".join([alg.decode("utf-8") for alg in macCS])
ccompCS = ",".join([alg.decode("utf-8") for alg in compCS])
hasshAlgorithms = "{kex};{enc};{mac};{cmp}".format(
kex=ckexAlgs, enc=cencCS, mac=cmacCS, cmp=ccompCS
)
hasshAlgorithms = f"{ckexAlgs};{cencCS};{cmacCS};{ccompCS}"
hassh = md5(hasshAlgorithms.encode("utf-8")).hexdigest()
log.msg(

View File

@ -28,8 +28,8 @@ class HoneyPotSSHUserAuthServer(userauth.SSHUserAuthServer):
* IP based authentication
"""
bannerSent: bool = False
user: str
_pamDeferred: defer.Deferred | None
def serviceStarted(self) -> None:
@ -43,7 +43,6 @@ class HoneyPotSSHUserAuthServer(userauth.SSHUserAuthServer):
self.interfaceToMethod[
credentials.IPluggableAuthenticationModulesIP
] = b"keyboard-interactive"
self.bannerSent: bool = False
self._pamDeferred: defer.Deferred | None = None
userauth.SSHUserAuthServer.serviceStarted(self)
@ -57,10 +56,11 @@ class HoneyPotSSHUserAuthServer(userauth.SSHUserAuthServer):
self.bannerSent = True
try:
issuefile = CowrieConfig.get("honeypot", "contents_path") + "/etc/issue.net"
data = open(issuefile).read()
with open(issuefile, "rb") as issue:
data = issue.read()
except OSError:
return
if not data or not len(data.strip()):
if not data or not data.strip():
return
self.transport.sendPacket(userauth.MSG_USERAUTH_BANNER, NS(data) + NS(b"en"))
@ -84,7 +84,7 @@ class HoneyPotSSHUserAuthServer(userauth.SSHUserAuthServer):
# return defer.fail(error.ConchError("Incorrect signature"))
# return userauth.SSHUserAuthServer.auth_publickey(self, packet)
def auth_none(self, packet: bytes) -> Any:
def auth_none(self, _packet: bytes) -> Any:
"""
Allow every login
"""
@ -101,7 +101,7 @@ class HoneyPotSSHUserAuthServer(userauth.SSHUserAuthServer):
c = credentials.UsernamePasswordIP(self.user, password, srcIp)
return self.portal.login(c, srcIp, IConchUser).addErrback(self._ebPassword)
def auth_keyboard_interactive(self, packet: bytes) -> Any:
def auth_keyboard_interactive(self, _packet: bytes) -> Any:
"""
Keyboard interactive authentication. No payload. We create a
PluggableAuthenticationModules credential and authenticate with our
@ -142,7 +142,7 @@ class HoneyPotSSHUserAuthServer(userauth.SSHUserAuthServer):
elif kind in (3, 4):
return defer.fail(error.ConchError("cannot handle PAM 3 or 4 messages"))
else:
return defer.fail(error.ConchError("bad PAM auth kind %i" % (kind,)))
return defer.fail(error.ConchError(f"bad PAM auth kind {kind}" ))
packet = NS(b"") + NS(b"") + NS(b"")
packet += struct.pack(">L", len(resp))
for prompt, echo in resp:

View File

@ -102,7 +102,6 @@ class FrontendSSHTransport(transport.SSHServerTransport, TimeoutMixin):
b"none", b"none", b"none", b"none"
)
self.currentEncryptions.setKeys(b"", b"", b"", b"", b"", b"")
self.otherVersionString: bytes = b"Unknown"
log.msg(
eventid="cowrie.session.connect",
@ -212,20 +211,18 @@ class FrontendSSHTransport(transport.SSHServerTransport, TimeoutMixin):
if not self.gotVersion:
if b"\n" not in self.buf:
return
self.otherVersionString = self.buf.split(b"\n")[0].strip()
otherVersion = self.buf.split(b"\n")[0].strip()
log.msg(
eventid="cowrie.client.version",
version=self.otherVersionString.decode(
version=otherVersion.decode(
"utf-8", errors="backslashreplace"
),
format="Remote SSH version: %(version)s",
)
m = re.match(rb"SSH-(\d+.\d+)-(.*)", self.otherVersionString)
m = re.match(rb"SSH-(\d+.\d+)-(.*)", otherVersion)
if m is None:
log.msg(
"Bad protocol version identification: {}".format(
repr(self.otherVersionString)
)
f"Bad protocol version identification: {repr(otherVersion)}"
)
if self.transport:
self.transport.write(b"Protocol mismatch.\n")

View File

@ -28,6 +28,8 @@ class HoneyPotTelnetFactory(protocol.ServerFactory):
tac: IPlugin
portal: tp.Portal | None = None # gets set by Twisted plugin
banner: bytes
starttime: float
def __init__(self, backend, pool_handler):
self.backend: str = backend
@ -47,7 +49,8 @@ class HoneyPotTelnetFactory(protocol.ServerFactory):
try:
honeyfs = CowrieConfig.get("honeypot", "contents_path")
issuefile = honeyfs + "/etc/issue.net"
self.banner = open(issuefile, "rb").read()
with open(issuefile, "rb") as banner:
self.banner = banner.read()
except OSError:
self.banner = b""

View File

@ -32,7 +32,6 @@ allowlist_externals =
yamllint
commands =
ruff {toxinidir}/src
- flake8 --ignore E203,E501,W503 --count --statistics {toxinidir}/src
- yamllint {toxinidir}
- pylint {toxinidir}/src
basepython = python3.10