mirror of https://github.com/cowrie/cowrie.git
Devops (#1811)
* 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:
parent
0001168382
commit
bf55a591bf
|
@ -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
|
|
@ -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
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
2
Makefile
2
Makefile
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
[pytype]
|
||||
inputs = src/cowrie
|
||||
keep_going = True
|
||||
|
||||
[flake8]
|
||||
ignore = E203,E501,W503
|
||||
count = True
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -36,7 +36,7 @@ class CustomParser(argparse.ArgumentParser):
|
|||
):
|
||||
self.protocol = protocol
|
||||
if parents is None:
|
||||
parents=[]
|
||||
parents = []
|
||||
super().__init__(
|
||||
prog=prog,
|
||||
usage=usage,
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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]:
|
||||
"""
|
||||
|
|
|
@ -65,4 +65,4 @@ class CowrieSSHConnection(connection.SSHConnection):
|
|||
if wantReply:
|
||||
d.addCallback(self._cbChannelRequest, localChannel)
|
||||
d.addErrback(self._ebChannelRequest, localChannel)
|
||||
return d
|
||||
return d
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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""
|
||||
|
||||
|
|
Loading…
Reference in New Issue