Skip to content

Commit

Permalink
Merge pull request #56 from fkie-cad/refactoring-base-class
Browse files Browse the repository at this point in the history
base class
  • Loading branch information
giga-a authored Feb 19, 2024
2 parents 403c06f + acddcea commit 89c8b21
Show file tree
Hide file tree
Showing 38 changed files with 879 additions and 4,049 deletions.
2 changes: 0 additions & 2 deletions honeypots/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
is_privileged,
clean_all,
close_port_wrapper,
disable_logger,
get_free_port,
get_running_servers,
kill_server_wrapper,
Expand Down Expand Up @@ -78,7 +77,6 @@
"is_privileged",
"clean_all",
"close_port_wrapper",
"disable_logger",
"get_free_port",
"get_running_servers",
"kill_server_wrapper",
Expand Down
123 changes: 123 additions & 0 deletions honeypots/base_http_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
from __future__ import annotations

from abc import ABC
from cgi import FieldStorage
from contextlib import suppress
from random import choice

from twisted.web.resource import Resource

from honeypots.base_server import BaseServer
from honeypots.helper import load_template, get_headers_and_ip_from_request, check_bytes


class BaseHttpServer(BaseServer, ABC):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.mocking_server = choice(
[
"Apache",
"nginx",
"Microsoft-IIS/7.5",
"Microsoft-HTTPAPI/2.0",
"Apache/2.2.15",
"SmartXFilter",
"Microsoft-IIS/8.5",
"Apache/2.4.6",
"Apache-Coyote/1.1",
"Microsoft-IIS/7.0",
"Apache/2.4.18",
"AkamaiGHost",
"Apache/2.2.25",
"Microsoft-IIS/10.0",
"Apache/2.2.3",
"nginx/1.12.1",
"Apache/2.4.29",
"cloudflare",
"Apache/2.2.22",
]
)

class MainResource(Resource):
isLeaf = True
home_file = load_template("home.html")
login_file = load_template("login.html")

def __init__(self, *args, hp_server=None, **kwargs):
super().__init__(*args, **kwargs)
self.hp_server = hp_server
self.headers = {}

def render(self, request):
client_ip, headers = get_headers_and_ip_from_request(request, self.hp_server.options)

with suppress(Exception):
log_data = {
"server": self.hp_server.NAME,
"action": "connection",
"src_ip": client_ip,
"src_port": request.getClientAddress().port,
"dest_ip": self.hp_server.ip,
"dest_port": self.hp_server.port,
}
if "capture_commands" in self.hp_server.options:
log_data["data"] = headers
self.hp_server.logs.info(log_data)

if self.hp_server.mocking_server != "":
request.responseHeaders.removeHeader("Server")
request.responseHeaders.addRawHeader("Server", self.hp_server.mocking_server)

if request.method in (b"GET", b"POST"):
self.hp_server.logs.info(
{
"server": self.hp_server.NAME,
"action": request.method.decode(),
"src_ip": client_ip,
"src_port": request.getClientAddress().port,
"dest_ip": self.hp_server.ip,
"dest_port": self.hp_server.port,
}
)

if request.method == b"GET":
if (
request.uri == b"/login.html"
and self.hp_server.username != ""
and self.hp_server.password != ""
):
request.responseHeaders.addRawHeader(
"Content-Type", "text/html; charset=utf-8"
)
return self.login_file

request.responseHeaders.addRawHeader("Content-Type", "text/html; charset=utf-8")
return self.login_file

if request.method == b"POST":
self.headers = request.getAllHeaders()
if (
request.uri in (b"/login.html", b"/")
and self.hp_server.username != ""
and self.hp_server.password != ""
):
form = FieldStorage(
fp=request.content,
headers=self.headers,
environ={
"REQUEST_METHOD": "POST",
"CONTENT_TYPE": self.headers.get(
b"content-type",
b"application/x-www-form-urlencoded",
),
},
)
if "username" in form and "password" in form:
username = check_bytes(form["username"].value)
password = check_bytes(form["password"].value)
self.hp_server.log_login(
username, password, client_ip, request.getClientAddress().port
)

request.responseHeaders.addRawHeader("Content-Type", "text/html; charset=utf-8")
return self.home_file
133 changes: 133 additions & 0 deletions honeypots/base_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
from __future__ import annotations

import inspect
from abc import ABC, abstractmethod
from os import getenv
from shlex import split
from subprocess import Popen
from uuid import uuid4

from honeypots.helper import (
setup_logger,
set_local_vars,
set_up_error_logging,
close_port_wrapper,
kill_server_wrapper,
get_free_port,
check_if_server_is_running,
)


class BaseServer(ABC):
NAME = "base"
DEFAULT_PORT = 0
DEFAULT_USERNAME = "test"
DEFAULT_PASSWORD = "test"

def __init__(self, **kwargs):
self.auto_disabled = None
self.process = None
self.uuid = f"honeypotslogger_{__class__.__name__}_{str(uuid4())[:8]}"
self.config = kwargs.get("config", "")
if self.config:
self.logs = setup_logger(__class__.__name__, self.uuid, self.config)
set_local_vars(self, self.config)
else:
self.logs = setup_logger(__class__.__name__, self.uuid, None)
self.ip = kwargs.get("ip", None) or (hasattr(self, "ip") and self.ip) or "0.0.0.0"
self.port = (
(kwargs.get("port", None) and int(kwargs.get("port", None)))
or (hasattr(self, "port") and self.port)
or self.DEFAULT_PORT
)
self.username = (
kwargs.get("username")
or (hasattr(self, "username") and self.username)
or self.DEFAULT_USERNAME
)
self.password = (
kwargs.get("password")
or (hasattr(self, "password") and self.password)
or self.DEFAULT_PASSWORD
)
self.options = (
kwargs.get("options", "")
or (hasattr(self, "options") and self.options)
or getenv("HONEYPOTS_OPTIONS", "")
or ""
)
self.logger = set_up_error_logging()

def close_port(self):
return close_port_wrapper(self.NAME, self.ip, self.port, self.logs)

def kill_server(self):
return kill_server_wrapper(self.NAME, self.uuid, self.process)

@abstractmethod
def server_main(self):
pass

def run_server(self, process: bool = False, auto: bool = False) -> bool | None:
status = "error"
run = False
if not process:
self.server_main()
return None

if auto and not self.auto_disabled:
port = get_free_port()
if port > 0:
self.port = port
run = True
elif self.close_port() and self.kill_server():
run = True

if run:
file = inspect.getfile(self.__class__)
command = (
f"python3 {file} --custom --ip {self.ip} " f"--port {self.port} --uuid {self.uuid}"
)
if self.options:
command += f" --options '{self.options}'"
if self.config:
command += f" --config '{self.config}'"
self.process = Popen(split(command))
if self.process.poll() is None and check_if_server_is_running(self.uuid):
status = "success"

self.logs.info(
{
"server": self.NAME,
"action": "process",
"status": status,
"src_ip": self.ip,
"src_port": self.port,
"dest_ip": self.ip,
"dest_port": self.port,
}
)

if status == "success":
return True
self.kill_server()
return False

def log_login(self, username: str, password: str, ip: str, port: int):
status = "success" if self._login_is_correct(username, password) else "failed"
self.logs.info(
{
"server": self.NAME,
"action": "login",
"status": status,
"src_ip": ip,
"src_port": port,
"username": username,
"password": password,
"dest_ip": self.ip,
"dest_port": self.port,
}
)

def _login_is_correct(self, username: str, password: str) -> bool:
return username == self.username and password == self.password
21 changes: 21 additions & 0 deletions honeypots/data/home.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<link rel='stylesheet' href='https://stackpath.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css' />
<link rel='stylesheet' href='https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css' />
<meta http-equiv='content-type' content='text/html;charset=utf-8' />
<title>Login</title>
<style>
body,html{height: 100%;text-align: center;}
</style>
</head>
<body>
<div class='container-fluid h-100'>
<div class='row justify-content-center h-100 align-items-center'>
<div class='col col-xl-3'>
<b>We'll back soon..</b>
</div>
</div>
</div>
</body>
</html>
29 changes: 29 additions & 0 deletions honeypots/data/login.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<link rel='stylesheet' href='https://stackpath.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css' />
<link rel='stylesheet' href='https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css' />
<meta http-equiv='content-type' content='text/html;charset=utf-8' />
<title>Login</title>
<style>body,html {height: 100%;}</style>
</head>
<body>
<div class='container-fluid h-100'>
<div class='row justify-content-center h-100 align-items-center'>
<div class='col col-xl-3'>
<form id='login' action='' method='post'>
<div class='form-group'>
<input class='form-control form-control-sm' name='username' type='text' placeholder='username' id='username'>
</div>
<div class='form-group'>
<input class='form-control form-control-sm' name='password' type='password' placeholder='password' id='password'>
</div>
<div class='form-group'>
<button class='btn btn-default btn-sm btn-block' type='submit'>login</button>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
Loading

0 comments on commit 89c8b21

Please sign in to comment.