From 6d6262b220f60a1110259ccf325a1931bb12b0bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20T=C3=B3th?= Date: Fri, 23 Mar 2018 15:27:42 +0100 Subject: [PATCH] Initial commit, first version of test TFW project --- config.yml | 11 +++++++ controller/Dockerfile | 1 + solvable/Dockerfile | 19 ++++++++++++ solvable/nginx/components/login.conf | 3 ++ solvable/nginx/components/terminal.conf | 6 ++++ solvable/src/demo/app.py | 21 ++++++++++++++ solvable/src/demo/event_handler_main.py | 21 ++++++++++++++ .../source_code_server/login_component.py | 27 ++++++++++++++++++ .../src/demo/source_code_server/server.py | 27 ++++++++++++++++++ solvable/src/demo/source_code_server/users.db | Bin 0 -> 16384 bytes solvable/src/demo/sql_injection_fsm.py | 26 +++++++++++++++++ .../supervisor/components/event_handlers.conf | 3 ++ solvable/supervisor/components/login.conf | 4 +++ 13 files changed, 169 insertions(+) create mode 100644 config.yml create mode 100644 controller/Dockerfile create mode 100644 solvable/Dockerfile create mode 100644 solvable/nginx/components/login.conf create mode 100644 solvable/nginx/components/terminal.conf create mode 100644 solvable/src/demo/app.py create mode 100644 solvable/src/demo/event_handler_main.py create mode 100644 solvable/src/demo/source_code_server/login_component.py create mode 100644 solvable/src/demo/source_code_server/server.py create mode 100644 solvable/src/demo/source_code_server/users.db create mode 100644 solvable/src/demo/sql_injection_fsm.py create mode 100644 solvable/supervisor/components/event_handlers.conf create mode 100644 solvable/supervisor/components/login.conf diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..df87455 --- /dev/null +++ b/config.yml @@ -0,0 +1,11 @@ +version: 'v2.0.0' +difficulty: 10 +enable_flag_input: false +name: 'test-tutorial-framework' +skills: [] +owners: ['kristof.toth@avatao.com'] +crp_config: + controller: + ports: ["4444/controller"] + solvable: + ports: ["8888/http"] diff --git a/controller/Dockerfile b/controller/Dockerfile new file mode 100644 index 0000000..2aa9563 --- /dev/null +++ b/controller/Dockerfile @@ -0,0 +1 @@ +FROM avatao/controller:ubuntu-16.04 diff --git a/solvable/Dockerfile b/solvable/Dockerfile new file mode 100644 index 0000000..85d23d7 --- /dev/null +++ b/solvable/Dockerfile @@ -0,0 +1,19 @@ +FROM baseimage-tutorial-framework + +ENV TFW_APP_DIR="/srv/app" \ + TFW_LOGIN_APP_DIR="/tmp/source_code_server" \ + TFW_WEBIDE_WD="/home/${AVATAO_USER}/workdir" \ + TFW_TERMINADO_WD="/home/${AVATAO_USER}/workdir" + +COPY solvable/src/demo ${TFW_APP_DIR}/ +COPY solvable/src/demo/source_code_server/server.py ${TFW_LOGIN_APP_DIR}/ +COPY solvable/src/demo/source_code_server/users.db ${TFW_LOGIN_APP_DIR}/ +COPY solvable/src/demo/source_code_server/login_component.py ${TFW_WEBIDE_WD}/ + +RUN chown -R ${AVATAO_USER} ${TFW_WEBIDE_WD} &&\ + chmod -R 755 ${TFW_WEBIDE_WD} + +VOLUME ["/home/${AVATAO_USER}"] +USER ${AVATAO_USER} +WORKDIR /home/${AVATAO_USER} + diff --git a/solvable/nginx/components/login.conf b/solvable/nginx/components/login.conf new file mode 100644 index 0000000..f8b1367 --- /dev/null +++ b/solvable/nginx/components/login.conf @@ -0,0 +1,3 @@ +location = /login { + proxy_pass http://127.0.0.1:${TFW_LOGIN_APP_PORT}; + } diff --git a/solvable/nginx/components/terminal.conf b/solvable/nginx/components/terminal.conf new file mode 100644 index 0000000..1d906a0 --- /dev/null +++ b/solvable/nginx/components/terminal.conf @@ -0,0 +1,6 @@ +location = /terminal { + proxy_pass http://127.0.0.1:${TFW_TERMINADO_PORT}; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } diff --git a/solvable/src/demo/app.py b/solvable/src/demo/app.py new file mode 100644 index 0000000..de73eee --- /dev/null +++ b/solvable/src/demo/app.py @@ -0,0 +1,21 @@ +import sys +import tornado +import zmq +from tornado.ioloop import IOLoop + +from sql_injection_fsm import SQLInjectionFSM +from tfw.networking.server.tfw_server import TFWServer +from tfw.config import tfwenv +from tfw.config.logs import logging +log = logging.getLogger(__name__) + + +if __name__ == '__main__': + server = TFWServer(SQLInjectionFSM) + server.listen(tfwenv.WEB_PORT) + log.debug('Python version: {}'.format(sys.version[:5])) + log.debug('Tornado version: {}'.format(tornado.version)) + log.debug('ZeroMQ version: {}'.format(zmq.zmq_version())) + log.debug('PyZMQ version: {}'.format(zmq.pyzmq_version())) + log.info('Tornado application listening on port {}'.format(tfwenv.WEB_PORT)) + IOLoop.instance().start() diff --git a/solvable/src/demo/event_handler_main.py b/solvable/src/demo/event_handler_main.py new file mode 100644 index 0000000..6cb9c8a --- /dev/null +++ b/solvable/src/demo/event_handler_main.py @@ -0,0 +1,21 @@ +from tornado.ioloop import IOLoop + +from tfw.components.source_code_event_handler import SourceCodeEventHandler +from tfw.components.terminado_event_handler import TerminadoEventHandler +from tfw.components.process_managing_event_handler import ProcessManagingEventHandler +from tfw.config import tfwenv +from tfw.config.logs import logging +log = logging.getLogger(__name__) + + +if __name__ == '__main__': + ide = SourceCodeEventHandler(key='webide', directory=tfwenv.WEBIDE_WD, exclude=['__pycache__']) + terminado = TerminadoEventHandler(key='shell') + terminado.historymonitor.subscribe_callback(callback=lambda hist: log.debug('User executed command: "{}"'.format(hist[-1]))) + processmanager = ProcessManagingEventHandler(key='processmanager', dirmonitor=ide.monitor) + + eventhandlers = {ide, terminado, processmanager} + try: + IOLoop.instance().start() + finally: + for eh in eventhandlers: eh.cleanup() diff --git a/solvable/src/demo/source_code_server/login_component.py b/solvable/src/demo/source_code_server/login_component.py new file mode 100644 index 0000000..3437d42 --- /dev/null +++ b/solvable/src/demo/source_code_server/login_component.py @@ -0,0 +1,27 @@ +import sqlite3 + + +def get_db(): + return sqlite3.connect('users.db') + + +def authorize_login(email, password): + """ + This method checks if a user is authorized and has admin privileges. + :param email: The email address of the user. + :param password: The password of the user. + :return: A tuple, the first element is the email address if the user exists, + and None if they don't; the second element is a boolean, which is True if + the user has admin privileges. + """ + conn = get_db() + sql_statement = '''SELECT email, is_admin FROM users + WHERE email="{}" AND password="{}"''' + # The problem with this approach is that it substitutes any value received + # from the user, even if it is a valid SQL statement! + result = conn.execute(sql_statement.format(email, password)).fetchone() + if result is None: + return None, False + else: + email, is_admin = result + return email, is_admin == 1 diff --git a/solvable/src/demo/source_code_server/server.py b/solvable/src/demo/source_code_server/server.py new file mode 100644 index 0000000..91f77d2 --- /dev/null +++ b/solvable/src/demo/source_code_server/server.py @@ -0,0 +1,27 @@ +import json, sys +from tornado.ioloop import IOLoop +from tornado.web import RequestHandler, Application + +from tfw.config import tfwenv + +sys.path.append(tfwenv.WEBIDE_WD) +from login_component import authorize_login + + +class LoginHandler(RequestHandler): + def post(self, *args, **kwargs): + request = json.loads(self.request.body) + email, is_admin = authorize_login( + request['email'], + request['password'] + ) + self.write({ + 'email': email, + 'is_admin': is_admin + }) + + +if __name__ == '__main__': + application = Application([(r'/login', LoginHandler)]) + application.listen(tfwenv.LOGIN_APP_PORT) + IOLoop.instance().start() diff --git a/solvable/src/demo/source_code_server/users.db b/solvable/src/demo/source_code_server/users.db new file mode 100644 index 0000000000000000000000000000000000000000..cde24ab8ce11ba9fa09b780a92d9c80f7f8c04b2 GIT binary patch literal 16384 zcmeI(zfRjg90%|_oBtBM4i#>NHLa^nm9H%m(WbsK@Q1M97CK4*7iyI z3f*`FmOeorp>w5Tn930^lc$7IQstZw zV(7A<%QUF&%#Wwne%Bgg_xb%g`%26w9|$wqN8KPG009U<00Izz00bZa0SG_<0)G}b zF_*0EZQ32l^S;Wj`}*xQ&eio;4KC(~3r^(P!sWs~@?AccyETxh+R-yhZ|ii~vMl;8 zE$%ta)i5tAb%*QE79?M>u45m+?J)%@HmaIdIl4Q_R zw-4);<55|@=HBD|g30%P%DxbNARqt%2tWV=5P$##AOHafKmY;|_@4w;scF&g Hzc_pYU}u|_ literal 0 HcmV?d00001 diff --git a/solvable/src/demo/sql_injection_fsm.py b/solvable/src/demo/sql_injection_fsm.py new file mode 100644 index 0000000..550fc00 --- /dev/null +++ b/solvable/src/demo/sql_injection_fsm.py @@ -0,0 +1,26 @@ +from tfw.fsm_base import FSMBase + + +class SQLInjectionFSM(FSMBase): + states = [ + 'start', + 'stripped_code', + 'sql', + 'commented_code', + 'sql_with_substitutions', + 'sql_output', + 'end', + ] + transitions = [ + {'trigger': 'webide', 'source': '*', 'dest': 'stripped_code'}, # TODO: delet this + {'trigger': 'webide', 'source': 'start', 'dest': 'stripped_code'}, + {'trigger': 'login', 'source': 'stripped_code', 'dest': 'sql'}, + {'trigger': 'logger', 'source': 'sql', 'dest': 'commented_code'}, + {'trigger': 'webide', 'source': 'commented_code', 'dest': 'sql_with_substitutions'}, + {'trigger': 'logger', 'source': 'sql_with_substitutions', 'dest': 'sql_output'}, + {'trigger': 'logger', 'source': 'sql_output', 'dest': 'end'}, + {'trigger': 'reset', 'source': 'end', 'dest': 'start'}, + ] + + def __init__(self): + super().__init__('start') diff --git a/solvable/supervisor/components/event_handlers.conf b/solvable/supervisor/components/event_handlers.conf new file mode 100644 index 0000000..a28afe5 --- /dev/null +++ b/solvable/supervisor/components/event_handlers.conf @@ -0,0 +1,3 @@ +[program:event_handler_main] +directory=%(ENV_TFW_APP_DIR)s +command=env python event_handler_main.py diff --git a/solvable/supervisor/components/login.conf b/solvable/supervisor/components/login.conf new file mode 100644 index 0000000..443b1af --- /dev/null +++ b/solvable/supervisor/components/login.conf @@ -0,0 +1,4 @@ +[program:login] +directory=%(ENV_TFW_LOGIN_APP_DIR)s +command=env python server.py +autostart=false