Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Triconex protocol #525

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion conpot/core/attack_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,16 @@
logger = logging.getLogger(__name__)


# one instance per connection
NEW_CONNECTION = "NEW_CONNECTION"
CONNECTION_LOST = "CONNECTION_LOST"
CONNECTION_CLOSED = "CONNECTION_CLOSED"
CONNECTION_FAILED = "CONNECTION_FAILED"
CONNECTION_TERMINATED = "CONNECTION_TERMINATED"
CONNECTION_QUIT = "CONNECTION_QUIT"
CONNECTION_TIMEOUT = "CONNECTION_TIMEOUT"


# one instance per connection
class AttackSession(object):
def __init__(
self,
Expand Down
11 changes: 6 additions & 5 deletions conpot/protocols/IEC104/IEC104_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from .frames import struct, TESTFR_act, socket, errno
import logging
import conpot.core as conpot_core
from conpot.core import attack_session
from gevent.server import StreamServer
import gevent
from .errors import Timeout_t3
Expand Down Expand Up @@ -52,7 +53,7 @@ def handle(self, sock, address):
address[1],
session.id,
)
session.add_event({"type": "NEW_CONNECTION"})
session.add_event({"type": attack_session.NEW_CONNECTION})
iec104_handler = IEC104(self.device_data_controller, sock, address, session.id)
try:
while True:
Expand All @@ -65,7 +66,7 @@ def handle(self, sock, address):
request = sock.recv(6)
if not request:
logger.info("IEC104 Station disconnected. (%s)", session.id)
session.add_event({"type": "CONNECTION_LOST"})
session.add_event({"type": attack.session.CONNECTION_LOST})
iec104_handler.disconnect()
break
while request and len(request) < 2:
Expand Down Expand Up @@ -122,18 +123,18 @@ def handle(self, sock, address):
except gevent.Timeout:
logger.warning("T1 timed out. (%s)", session.id)
logger.info("IEC104 Station disconnected. (%s)", session.id)
session.add_event({"type": "CONNECTION_LOST"})
session.add_event({"type": attack_session.CONNECTION_LOST})
iec104_handler.disconnect()
break
except socket.timeout:
logger.debug("Socket timeout, remote: %s. (%s)", address[0], session.id)
session.add_event({"type": "CONNECTION_LOST"})
session.add_event({"type": attack_session.CONNECTION_LOST})
except socket.error as err:
if isinstance(err.args, tuple):
if err.errno == errno.EPIPE:
# remote peer disconnected
logger.info("IEC104 Station disconnected. (%s)", session.id)
session.add_event({"type": "CONNECTION_LOST"})
session.add_event({"type": attack_session.CONNECTION_LOST})
else:
# determine and handle different error
pass
Expand Down
3 changes: 2 additions & 1 deletion conpot/protocols/bacnet/bacnet_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import conpot.core as conpot_core
from conpot.protocols.bacnet.bacnet_app import BACnetApp
from conpot.core.protocol_wrapper import conpot_protocol
from conpot.core import attack_session
from conpot.utils.networking import get_interface_ip
import logging

Expand Down Expand Up @@ -69,7 +70,7 @@ def handle(self, data, address):
logger.info(
"New Bacnet connection from %s:%d. (%s)", address[0], address[1], session.id
)
session.add_event({"type": "NEW_CONNECTION"})
session.add_event({"type": attack_session.NEW_CONNECTION})
# I'm not sure if gevent DatagramServer handles issues where the
# received data is over the MTU -> fragmentation
if data:
Expand Down
9 changes: 5 additions & 4 deletions conpot/protocols/enip/enip_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from cpppo.server.enip import parser
from cpppo.server.enip import device
from conpot.core.protocol_wrapper import conpot_protocol
from conpot.core import attack_session
import conpot.core as conpot_core

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -133,7 +134,7 @@ def handle(self, conn, address, enip_process=None, delay=None, **kwds):
"enip", host, port, conn.getsockname()[0], conn.getsockname()[1]
)
logger.debug("ENIP server %s begins serving client %s", name, address)
session.add_event({"type": "NEW_CONNECTION"})
session.add_event({"type": attack_session.NEW_CONNECTION})

tcp = conn.family == socket.AF_INET and conn.type == socket.SOCK_STREAM
udp = conn.family == socket.AF_INET and conn.type == socket.SOCK_DGRAM
Expand Down Expand Up @@ -332,7 +333,7 @@ def handle_tcp(
cpppo.timer() - begun,
delayseconds,
)
session.add_event({"type": "CONNECTION_CLOSED"})
session.add_event({"type": attack_session.CONNECTION_CLOSED})
except:
logger.error("Failed request: %s", parser.enip_format(data))
enip_process(address, data=cpppo.dotdict()) # Terminate.
Expand Down Expand Up @@ -491,7 +492,7 @@ def handle_udp(self, conn, name, enip_process, session, **kwds):
logger.debug(
"Transaction complete after %7.3fs", cpppo.timer() - begun
)
session.add_event({"type": "CONNECTION_CLOSED"})
session.add_event({"type": attack_session.CONNECTION_CLOSED})
stats["processed"] = source.sent
except:
# Parsing failure. Suck out some remaining input to give us some context, but don't re-raise
Expand All @@ -512,7 +513,7 @@ def handle_udp(self, conn, name, enip_process, session, **kwds):
where,
"".join(traceback.format_exception(*sys.exc_info())),
)
session.add_event({"type": "CONNECTION_FAILED"})
session.add_event({"type": attack_session.CONNECTION_FAILED})

def set_tags(self):
typenames = {
Expand Down
7 changes: 4 additions & 3 deletions conpot/protocols/ftp/ftp_base_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import gevent
import conpot.core as conpot_core
from conpot.core.filesystem import FilesystemError
from conpot.core import attack_session
import logging
import errno
import time
Expand Down Expand Up @@ -236,7 +237,7 @@ def setup(self):
self.client_address[0], self.client_address[1], self.session.id
)
)
self.session.add_event({"type": "NEW_CONNECTION"})
self.session.add_event({"type": attack_session.NEW_CONNECTION})
# send 200 + banner -- new client has connected!
self.respond(b"200 " + self.config.banner.encode())
# Is there a delay in command response? < gevent.sleep(0.5) ?
Expand Down Expand Up @@ -292,7 +293,7 @@ def handle_cmd_channel(self):
self.client_address, self.session.id
)
)
self.session.add_event({"type": "CONNECTION_LOST"})
self.session.add_event({"type": attack_session.CONNECTION_LOST})
self.finish()
return
socket_read, socket_write, _ = gevent.select.select(
Expand Down Expand Up @@ -349,7 +350,7 @@ def handle_cmd_channel(self):
self.client_address, self.session.id, se
)
)
self.session.add_event({"type": "CONNECTION_LOST"})
self.session.add_event({"type": attack_session.CONNECTION_LOST})
self.finish()

def respond(self, response):
Expand Down
11 changes: 7 additions & 4 deletions conpot/protocols/ftp/ftp_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import gevent
from gevent import socket
from conpot.core.filesystem import FilesystemError, FSOperationNotPermitted
from conpot.core import attack_session
from conpot.protocols.ftp.ftp_utils import FTPPrivilegeException, get_data_from_iter

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -113,7 +114,7 @@ def do_SYST(self, arg):

def do_QUIT(self, arg):
self.respond(b"221 Bye.")
self.session.add_event({"type": "CONNECTION_TERMINATED"})
self.session.add_event({"type": attack_session.CONNECTION_TERMINATED})
self.disconnect_client = True

def do_SITE_HELP(self, line):
Expand Down Expand Up @@ -878,7 +879,7 @@ def _process_command(self, cmd, *args, **kwargs):
if self.invalid_login_attempt >= self.max_login_attempts:
self.respond(b"421 Too many connections. Service temporarily unavailable.")
self.disconnect_client = True
self.session.add_event({"type": "CONNECTION_TERMINATED"})
self.session.add_event({"type": attack_session.CONNECTION_TERMINATED})
else:
try:
method = getattr(self, "do_" + cmd.replace(" ", "_"))
Expand Down Expand Up @@ -936,7 +937,9 @@ def process_ftp_command(self):
)
# TODO: what to respond here? For now just terminate the session
self.disconnect_client = True
self.session.add_event({"type": "CONNECTION_TERMINATED"})
self.session.add_event(
{"type": attack_session.CONNECTION_TERMINATED}
)
elif not (self.metrics.timeout() < self.config.timeout) and (
not self._data_channel
):
Expand All @@ -945,7 +948,7 @@ def process_ftp_command(self):
self.client_address, self.session.id
)
)
self.session.add_event({"type": "CONNECTION_TIMEOUT"})
self.session.add_event({"type": attack_session.CONNECTION_TIMEOUT})
self.respond(b"421 Timeout.")
self.disconnect_client = True
else:
Expand Down
5 changes: 3 additions & 2 deletions conpot/protocols/guardian_ast/guardian_ast_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import logging
import random
import conpot.core as conpot_core
from conpot.core import attack_session
from conpot.core.protocol_wrapper import conpot_protocol
from conpot.utils.networking import str_to_bytes

Expand Down Expand Up @@ -55,7 +56,7 @@ def handle(self, sock, addr):
logger.info(
"New GuardianAST connection from %s:%d. (%s)", addr[0], addr[1], session.id
)
session.add_event({"type": "NEW_CONNECTION"})
session.add_event({"type": attack_session.NEW_CONNECTION})
current_time = datetime.datetime.utcnow()
fill_start = self.fill_offset_time - datetime.timedelta(minutes=313)
fill_stop = self.fill_offset_time - datetime.timedelta(minutes=303)
Expand Down Expand Up @@ -507,7 +508,7 @@ def I20500():
logger.info(
"GuardianAST client disconnected %s:%d. (%s)", addr[0], addr[1], session.id
)
session.add_event({"type": "CONNECTION_LOST"})
session.add_event({"type": attack_session.CONNECTION_LOST})

def start(self, host, port):
connection = (host, port)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import conpot.core as conpot_core
from .command_responder import CommandResponder
from conpot.core.protocol_wrapper import conpot_protocol
from conpot.core import attack_session
from conpot.utils.networking import str_to_bytes

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -48,7 +49,7 @@ def handle(self, sock, address):
address[1],
session.id,
)
session.add_event({"type": "NEW_CONNECTION"})
session.add_event({"type": attack_session.NEW_CONNECTION})

try:
sock.send(
Expand All @@ -63,7 +64,7 @@ def handle(self, sock, address):
data = sock.recv(1024)
if not data:
logger.info("Kamstrup client disconnected. (%s)", session.id)
session.add_event({"type": "CONNECTION_LOST"})
session.add_event({"type": attack_session.CONNECTION_LOST})
break
request = data.decode()
logdata = {"request": request}
Expand All @@ -79,15 +80,15 @@ def handle(self, sock, address):
gevent.sleep(0.25) # TODO measure delay and/or RTT

if response is None:
session.add_event({"type": "CONNECTION_LOST"})
session.add_event({"type": attack_session.CONNECTION_LOST})
break
# encode data before sending
reply = str_to_bytes(response)
sock.send(reply)

except socket.timeout:
logger.debug("Socket timeout, remote: %s. (%s)", address[0], session.id)
session.add_event({"type": "CONNECTION_LOST"})
session.add_event({"type": attack_session.CONNECTION_LOST})

sock.close()

Expand Down
9 changes: 5 additions & 4 deletions conpot/protocols/kamstrup_meter/kamstrup_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from .request_parser import KamstrupRequestParser
from .command_responder import CommandResponder
from conpot.core.protocol_wrapper import conpot_protocol
from conpot.core import attack_session

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -64,7 +65,7 @@ def handle(self, sock, address):
address[1],
session.id,
)
session.add_event({"type": "NEW_CONNECTION"})
session.add_event({"type": attack_session.NEW_CONNECTION})

self.server_active = True

Expand All @@ -75,7 +76,7 @@ def handle(self, sock, address):

if not raw_request:
logger.info("Kamstrup client disconnected. (%s)", session.id)
session.add_event({"type": "CONNECTION_LOST"})
session.add_event({"type": attack_session.CONNECTION_LOST})
break

for x in raw_request:
Expand All @@ -84,7 +85,7 @@ def handle(self, sock, address):
while True:
request = parser.get_request()
if not request:
session.add_event({"type": "CONNECTION_LOST"})
session.add_event({"type": attack_session.CONNECTION_LOST})
break
else:
logdata = {
Expand Down Expand Up @@ -112,7 +113,7 @@ def handle(self, sock, address):

except socket.timeout:
logger.debug("Socket timeout, remote: %s. (%s)", address[0], session.id)
session.add_event({"type": "CONNECTION_LOST"})
session.add_event({"type": attack_session.CONNECTION_LOST})

sock.close()

Expand Down
19 changes: 12 additions & 7 deletions conpot/protocols/modbus/modbus_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from conpot.core.protocol_wrapper import conpot_protocol
from conpot.protocols.modbus import slave_db
import conpot.core as conpot_core
from conpot.core import attack_session

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -105,7 +106,7 @@ def handle(self, sock, address):
logger.info(
"New Modbus connection from %s:%s. (%s)", address[0], address[1], session.id
)
session.add_event({"type": "NEW_CONNECTION"})
session.add_event({"type": attack_session.NEW_CONNECTION})

try:
while True:
Expand All @@ -121,17 +122,17 @@ def handle(self, sock, address):

if not request:
logger.info("Modbus client disconnected. (%s)", session.id)
session.add_event({"type": "CONNECTION_LOST"})
session.add_event({"type": attack_session.CONNECTION_LOST})
break
if request.strip().lower() == "quit.":
logger.info("Modbus client quit. (%s)", session.id)
session.add_event({"type": "CONNECTION_QUIT"})
session.add_event({"type": attack_session.CONNECTION_QUIT})
break
if len(request) < 7:
logger.info(
"Modbus client provided data {} but invalid.".format(session.id)
)
session.add_event({"type": "CONNECTION_TERMINATED"})
session.add_event({"type": attack_session.CONNECTION_TERMINATED})
break
_, _, length = struct.unpack(">HHH", request[:6])
while len(request) < (length + 6):
Expand Down Expand Up @@ -169,7 +170,9 @@ def handle(self, sock, address):
logger.info(
"Modbus connection terminated with client %s.", address[0]
)
session.add_event({"type": "CONNECTION_TERMINATED"})
session.add_event(
{"type": attack_session.CONNECTION_TERMINATED}
)
sock.shutdown(socket.SHUT_RDWR)
sock.close()
break
Expand All @@ -179,13 +182,15 @@ def handle(self, sock, address):
"Modbus client ignored due to invalid addressing." " (%s)",
session.id,
)
session.add_event({"type": "CONNECTION_TERMINATED"})
session.add_event(
{"type": attack_session.CONNECTION_TERMINATED}
)
sock.shutdown(socket.SHUT_RDWR)
sock.close()
break
except socket.timeout:
logger.debug("Socket timeout, remote: %s. (%s)", address[0], session.id)
session.add_event({"type": "CONNECTION_LOST"})
session.add_event({"type": attack_session.CONNECTION_LOST})

def start(self, host, port):
self.host = host
Expand Down
Loading