Skip to content

Repo containing source files for the QA application for workshops

Notifications You must be signed in to change notification settings

putrequest/PUTcyberCONF-CTF_QA

Repository files navigation

PUTcyberCONF-CTF_QA

Repo containing source files for the QA application for Forensic workshops and others.

Current dependencies

Current dependencies can be found in requirements.txt file.

Running standalone app (release)

  1. Unpack the application from .zip archive
  2. Create configuration file (in JSON format) with the contents and follow either way:
    1. Name it config.json and paste it into the home folder of the app
    2. Name it as you wish and run the application with command-line options:
      1. -c <path_to_config>
      2. --config <path_to_config>
      3. --config=<path_to_config>

Installation

The program utilizes Python 3.12.1 and PyQT6. The required dependencies can be found in requirements.txt file.

⚠️As of 09.05.2024: The program itself can run on Python 3.10+ (match case clause use)

  1. Program can run by installing dependencies and executing main.py via Python.
  2. Program executable for Windows was generated and can be found under Releases.
    1. Script for generating the executable: pyinstaller --add-data 'path/to/file' --add-data 'path/to/other/file' main.py -F -w -n CTF-QA
      1. --add-data - append external assets to the file
      2. -F - create one-file bundle
      3. -D - create one-folder bundle
      4. -w - windowed, noconsole file
      5. -n - custom name of the app
    2. The settings for pyinstaller can also be wrote to file with .spec extension and then the script can be executed appropriately:
      pyinstaller CTF-QA.spec
      
      1. Example specification can be found in folder config_standalone and will be used in later releases due to the increasing number of dependencies.
    3. Versions before v1.0 were created with switch -D instead of -F and are available only for Windows.

Program reads the data for tasks from configuration file called config.json. The file itself should be stored within programs root directory.

Running the program via python with configuration file can be proceeded in the same way as presented in 2. point of Running standalone app (release)

Layout editing

The main layout file is CTF_QA_gui.ui, generated by QT Designer app. Next, the file needs to be converted into .py module with command:

pyuic6 .\CTF_QA_gui.ui -o gui.py

Which then is utilized by the application.

Creating config

In folder config_example_preparation there is a script for creating a configuration.

You need to edit config_strings.py file with appropriate data and order. You can fill out it with new tasks and questions.

Each task has possible arguments:

task_name - task name

task_desc - (optional argument) task description

Each question has possible arguments:

q_desc - (optional argument) question description

q_answer - (optional argument) questions answer

q_hint - (optional argument) question hint

q_answer_case_sensitive - (optional argument) boolean value, by default all answers are checked in case insensitive manner (to minimize mistakes when inserting answer with diferent character sizes)

The module helpers.py stores the necessary classes used in config.json configuration and creation.

If you want the answers to be encrypted, set encrypted key to true:

  • The config file stores the answers encrypted with combination of Base64 and ROT13 - this ensures the basic safety against nosy contestants.

Template JSON configuration

{
    "workshop": "Nazwa warsztatu",
    "encrypted": true, // default: null
    "tasks": [
        {
            "task_id": "ID zadania",
            "task_name": "Nazwa_zadania/tytuł",
            "task_desc": "Opis zadania [default: null]",
            "questions": [
                {
                    "q_id": "ID pytania",
                    "q_desc": "Opis pytania [default: null]",
                    "q_answer": "Odpowiedź [default: null]",
                    "q_hint": "Podpowiedź [default: null]",
                    "q_answer_case_sensitive": false,
                },
                {
                    "q_id": "ID pytania",
                    "q_desc": "Opis pytania [default: null]",
                    "q_answer": "Odpowiedź [default: null]",
                    "q_hint": "Podpowiedź [default: null]",
                    "q_answer_case_sensitive": true,
                }
            ]
        },
        {
            "task_id": "ID zadania",
            "task_name": "Nazwa_zadania/tytuł",
            "task_desc": "Opis zadania [default: null]",
            "questions": [
                {
                    "q_id": "ID pytania",
                    "q_desc": "Opis pytania [default: null]",
                    "q_answer": "Odpowiedź [default: null]",
                    "q_hint": "Podpowiedź [default: null]",
                    "q_answer_case_sensitive": false,
                }
            ]
        }
    ]
}

Examples

Main scope should consists of:

{
    "workshop": "workshop name",
    "encrypted": true,
    "tasks": [
        {
            // task 1
        },
        {
            // task 2
        }
    ]
}
  1. Full task list:

task_full_list

There is a config:

{
   "workshop": "Warsztaty Forensics",
   "encrypted": true,
   "tasks": [
      {
         "task_id": 2,
         "task_name": "Task 2",
         "task_desc": null,
         "questions": [
            {
               "q_id": 1,
               "q_desc": "Just a thing to do...",
               "q_answer": "Zażółć",
               "q_hint": null
            },
            {
               "q_id": 2,
               "q_desc": "And here is one task to do without answer!",
               "q_answer": null,
               "q_hint": null
            }
         ]
      },
      {
         "task_id": 4,
         "task_name": "Task 3",
         "task_desc": null,
         "questions": [
            {
               "q_id": 1,
               "q_desc": null,
               "q_answer": "d1102305d817abafdd0981ed45aae236",
               "q_hint": null
            }
         ]
      },
      {
         "task_id": 5,
         "task_name": "Task 4",
         "task_desc": null,
         "questions": [
            {
               "q_id": 1,
               "q_desc": null,
               "q_answer": "19243ba33b323eb935f0cd5d5b329426",
               "q_hint": "Here is Johnny!"
            }
         ]
      },
      {
         "task_id": 6,
         "task_name": "Task 5",
         "task_desc": null,
         "questions": [
            {
               "q_id": 1,
               "q_desc": "Poczekaj kiedyś pojedzie!",
               "q_answer": "IC 2137",
               "q_hint": "Pociąg linii międzymiastowych"
            }
         ]
      }
   ]
}
  1. Task with all options:

huge_task

There is a config:

{
    "task_id": 1,
    "task_name": "Task 1",
    "task_desc": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed justo urna, volutpat ut dui id, feugiat varius mi. Nullam tincidunt diam eu risus commodo, non aliquam ligula pellentesque. Suspendisse potenti. Maecenas ut lobortis sem. Duis ut nisl vitae lorem pretium scelerisque lacinia eu dolor. Morbi sed congue diam. Aliquam a ex nisi.\n\nVivamus nulla diam, dapibus nec turpis fermentum, pellentesque fringilla eros. Donec consectetur vestibulum nisl, eget dictum nisi mollis id. Integer tincidunt, nisl quis sagittis porttitor, lorem dolor tempus purus, nec volutpat nisi risus et sem. Integer nec malesuada purus, ut condimentum sapien. Vivamus ac est at dolor varius. \n\n- One thing\n- **Bolded**\n- *Italic*\n\n1. List\n2. ddd\n",
    "questions": [
        {
            "q_id": 1,
            "q_desc": "Do that thing...",
            "q_answer": "this thing",
            "q_hint": "Do that!"
        },
        {
            "q_id": 2,
            "q_desc": "Do another thing!",
            "q_answer": "I have this one!",
            "q_hint": null
        },
        {
            "q_id": 3,
            "q_desc": "And here is one task to do without answer!",
            "q_answer": null,
            "q_hint": null
        }
    ]
},
  1. Task with one answer and a task step:

task_one_answer_task_step

There is a config:

{
    "task_id": 2,
    "task_name": "Task 2",
    "task_desc": null,
    "questions": [
        {
            "q_id": 1,
            "q_desc": "Just a thing to do...",
            "q_answer": "Zażółć",
            "q_hint": null
        },
        {
            "q_id": 2,
            "q_desc": "And here is one task to do without answer!",
            "q_answer": null,
            "q_hint": null
        }
    ]
}
  1. Task with only question:

task_only_question

There is a config:

{
    "task_id": 4,
    "task_name": "Task 3",
    "task_desc": null,
    "questions": [
        {
            "q_id": 1,
            "q_desc": null,
            "q_answer": "d1102305d817abafdd0981ed45aae236",
            "q_hint": null
        }
    ]
}