-
Notifications
You must be signed in to change notification settings - Fork 7
How to create new lessons
To create a lesson for PyGoat, you will need to write three things.
-
A yaml file in the lessons folder
-
An html file in the templates/content folder which can be formatted using jinja
-
Custom functions in the custom.py file
Important Note: Any changes to the lessons will not take effect unless the user deletes app/pygoat.db after making new lessons or expanding lessons. Users must also restart the python server for the changes to take effect
Required fields:
-
name - the name of your custom lesson. Will be displayed in the sidebar and as the title of the page. Needs to be unique
-
url - the url of the lesson. Make it similar to the name of the lesson, but without spaces or special characters. Needs to be unique
-
content - the name of the html file for this lesson. Should match a filename in the templates/content folder. use the same name as the custom lesson + .html
-
group - the group or category the lesson belongs to. This is used to group the lessons within the sidebar of the UI.
-
difficulty - an positive integer that corresponds to how difficult you think this lesson is.
-
numberOfPages - a positive integer that lists the number of pages in the lesson
-
completable - "true" or "false" (without the quotes) depending on whether or not the lesson has a challenge in it. If it does, then put true. Otherwise, false.
Optional fields:
-
load-script - the name of a function in the custom.py file to be run every time this lesson is loaded. If there is a load-script field in the lesson yaml, there must be a load-return field also. See below. Example:
load-script: $custom.loadComments(sql)- Where you would use this: If you want comments loaded in from a database, call a function that returns the comments from the database. See lessons/xss.yaml and its associated functions in custom.py for an example.
-
load-return - the name of the object returned from your load-script. Should match the name of the object that you're referencing in the html file. See the lessons/xss.yaml and templates/content/xss.html for an example.
-
success-condition - the name of a function in custom.py to be called every time the lesson page is loaded. If it returns true, the lesson is considered completed. Example:
success-condition: $custom.sqlValidator() -
db-tables - defines a table in the database. Recreated every time the application is restarted.
-
name - the name of the table. Needs to be unique
-
columns - defines the column names and types for the table
-
name - the name of the column
-
type - the SQLITE type for the column
-
-
rows - defines individual rows for the table. Should contain a list of key-value pairs that correspond to the columns defined earlier.
-
Defines two tables named "test" and "test2" with 2 columns each and 2 rows each
db-tables:
- name: test
columns:
- name: username
type: text
- name: password
type: text
rows:
- username: bob
password: 1234
- username: gary
password: ae394dff
- name: test2
columns:
- name: col1
type: blob
- name: col2
type: integer
rows:
- col1: \xe2aa@`\x53
col2: 15
- col1: aa28cn3\x12c**
col2: 123294-
routes - defines a custom route in the PyGoat webapp (e.g. /proxy) and what happens when the user navigates there
-
path - the url for this custom route
-
action - what should happen when this route is accessed. There are 4 different types of actions that are currently implemented: 'send-webrequest', 'sql-query', 'response', and run a custom script. To run a custom script, instead of placing a string in this field, write $custom.<name_of_script>( <params> ). The spaces between the parentheses and the params are required. You can also include form-fields and session variables as parameters using $form.<form_field> and $session.<session_variable> respectively.
-
success_if_true - if this is true, the action is a custom script, and that script returns true, consider the lesson completed.
-
webrequest - required if action is 'send-webrequest'. Defines a request to be sent when the route is accessed
-
url - required field. The url to send the request to. Only works for relative addresses (addresses from PyGoat) right now. Example:
url: /test -
method - the HTTP method to use to send the request. Only supports 'GET' and 'POST' right now
-
headers - the HTTP headers to include as key-value pairs. Can contain session and form data as well. See the action bullet point for more details on those.
-
body - can be either a string or a set of key-value pairs similar to headers. Both the string and the key-value set can contain session and form data.
-
-
query - required if action is 'sql-query'. Defines a SQLite query to be made when the route is accessed.
-
injectable - whether or not this should be vulnerable to SQL injection.
-
qstring - the query to be made. Can include session and form data using $session.<sess_data> and $form.<formdata>, just make sure to leave spaces around each use of $session and $form variables.
-
-
response - required if action is 'response'. Defines a response to send to whoever accessed this route.
-
headers - see webrequest headers above. Response headers have the exact same features
-
body - see web request body above. Response body has the exact same features.
-
-
Custom Route Examples:
routes:
- path: /testroute
action: send-webrequest
webrequest:
url: /test
method: POST
body:
name: bod
content: $session.name
- path: /testroute2
action: sql-query
query:
injectable: true
qstring: INSERT INTO testTable VALUES ( $session.username , 7, 3)
- path: /validateTest
action: $custom.validate_test()
success_if_true: true
- path: /responseTest
action: response
response:
headers:
content-type: xml
body:
'<?xml version="1.0"?>
<!--This is the request you want-->
<comment>
<text>
$form.content
</text>
</comment>'The HTML that the Flask server sends to the client is created using the jinja template engine.
All lesson templates must be split into pages with each page contained within a div with a class of 'page#' where number is the page number. the number of pages should match the number of pages property of the yaml file.
All styles are to be done inline or using unique classes and Ids. main.css in static/css contains all of the styles that are applied to the document, take care not to alter any that are there.
Do not include html, body, main, header, or footer elements in the lesson