-
Notifications
You must be signed in to change notification settings - Fork 460
How to Create a Web Shepherd Level
This wiki page will attempt to guide new Shepherd contributors in the effort of creating a Web Based level with View, Controller and Model type functionality. Where each piece operates the following type functionality;
- View
The view can be a web page, a mobile application or both. You could write an entire level that is made up of only one View, which stores a hard coded key for the user to find. Most mobile levels have two views, the Web page with instructions on the Shepherd Web Server and the Android Application.- Controller
The Controller is a Java Servlet that operates on the Shepherd Application Server. They are accessed by clients via url-mapping defined in the Shepherd Server's web.xml file. Many levels are made up of a View/Controller combo, with hardcoded base-keys which are made user specific when players complete the level.- Model
Not all levels in Security Shepherd offer model functionality, but it can be done. If a level needs a database, the schema is written and added to the moduleSchemas.sql file and a user defined for it. This user has READ ONLY access to the specified schema. It's not recommended to give any other permissions to the user without great care.
This wiki page will detail how to craft all these aspects of a level in a step by step guide.
Follow this Dev Environment Creation Guide
- Open a console to your database instance
- Run this command;
-- theModuleName \- The Name You want your module to have
-- lesson/challenge \- Do you want this to be grouped with Lessons or Challenges?
-- moduleCategory \- Defined by you. This groups levels together in the UI. If the Category already exists, use it (Case Sensitive).
-- true/false \- Is the key hard coded into the level or not? This should only be true if the key must be hard coded.
-- theModuleSolution \- Set this to null with no single quotes to have the database generate your solution. Or enter your hard coded expected result key
call moduleCreate('theModuleName', 'lesson/challenge', 'moduleCategory', true/false, 'theModuleSolution');
- The procedure will return a hash, the stored moduleSolution, the ModuleName Translation Key and the ModuleCaegory Translation Key. Make note of the Hash (referred to as level hash) as well as the Translation Keys.
- If you left the moduleSolution as null when executing, the output also returns the new value that now the key for your module. You'll want this when creating your level so keep it handy.
- Open the src/main/resources/i18n/moduleGenerics/moduleNames.properties file and add the Translation keys followed by the English Text for your level. If the Category Key does not already exist in the file, add it. The category translation key should be preceded by "category.". So like this:
sql.injection = SQL Injection
category.injection = Injection
- Copy src/main/webapp/webLevelTemplate.jsp into src/main/webapp/lessons or src/main/webapp/challenges based on the type you chose in the database procedure
- Rename the file as levelHash.jsp (The levelHash value returned by the database procedure)
- Save it as levelHash.jsp in SecurityShepherdCore/src/jsp/lesson or SecurityShepherdCore/src/jsp/challenge based on the type you chose in the procedure
- Now, if you open your Dev environment and clicked on your level in the UI, you should be presented with the template level
Every level in Security Shepherd needs a .jsp page and Strings in a i18n.properties file. Right now your view is the renamed web template JSP file. The JSP page does the following;
- Informs a user on what they have to do
- Reveals hints if the level is a lesson (i.e. First time a user encounters this type of security risk)
- Contains a description of the vulnerability.
- Contains i18n references that correspond to text in the properties files.
The .properties holds all the text that you display to your user on the webpage. You can append your strings to a i18n file or make a new one if you prefer (There are plans to merge as many as these together). They are in the form of key value pairs used for translating your level. The default properties file should be in English for example text.properties
where corrisponding languages are a copy of this file with an underscore and language code e.g. for Irish text_ga.properties
.
To find your language use this [ISO 639-1 Codes] (https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes). The keys in the properties file should remain the same where the values are the translation of the English text.
Use These Steps to Create your Level View
- In your JSP, Fill in the
levelName
parameter which is the name that will be entered into the logs as players access it. This should be in English. - Put the level hash value noted earlier into the
levelHash
string variable. - It's suggested you put the key / value pairs for your Strings into src/main/resources/i18n/lessons/lessons.properties or src/main/resources/i18n/challenges/challenges.properties. Each entry should be preceeded by your level's translation key (eg: sql.injection from above)
- Update the thei18nFileWithTheStrings string to the path of the i18n properties file eg:
i18n.challenges.challenges
- If your .jsp is going to call a Controller on the web server, you can uncomment the form/javascript examples on how to do so starting at line 69
- When calling a Servlet take a note of what URL you are defining the javascript ajax call. You will need to use this in the servlet-mapping stage. This URL is recommended to be {levelHash}{optionalExtra} so it cannot be guessed.
- All the text in your level should be stored in the corresponding properties file. Your JSP should contain the .properties file key e.g.
bundle.getString("injection.title.question")
which references the text value that will be displayed to the user please refer to this wiki page for information
The controller of a level is the brain of a level. This is most likely going to be the logic which the users will be attempting to exploit. To create this, use the following steps;
- Open the Directory src/main/java/servlets/module
- Open the file ModuleServletTemplate.java
- Update the
moduleName
,moduleHash
andmoduleResult
to match the database procedure output. - Skip down to line 76, and add in the code you need to get the data submitted by the user in from the View portion of this level
- If there is any text you want to display to the user please add it to the i18n/servlets files where appropriate.
.properties
file under. All text that will be displayed to the user should be stored in that file. - If you wish to return user specific keys (Recommended wherever possible) use the template example.
- Once you have finished coding and your logic is sound, open the src/main/webapp/WEB-INF/web.xml directory
- Add the following information to the XML file, updating the
levelhash
to the module level hash,ServletClassName
to the servlet class name and "challenges" to "lessons" if necessary;
<servlet>
<servlet-name>/challengeslevelhash</servlet-name>
<servlet-class>servlets.module.challenge.ServletClassName</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>/challenges/levelhash</servlet-name>
<url-pattern>/challenges/levelhash</url-pattern>
</servlet-mapping>
- After adding this information you can now test your Servlet. If you get a 404 error when trying to access the servlet please verify the values you entered in the web.xml match the resource your browser is trying to call.
Model is the server side database. This is where you will store any database information your level requires or even stored procedures if you prefer. Follow these steps to make one and get your level to access it
- Open the src/main/resources/database/moduleSchemas.sql file
- Add a mySql Schema to it containing your level's database structure
- At the end of the file add a user with READ ONLY access like so;
DROP USER `creativeName`@'localhost';
CREATE USER `creativeName`@'localhost' IDENTIFIED BY `somePasswordHere`;
-- Only grant the permissions required for your schema tables ONLY.
-- If you are overly permissive it may be possible for a player to find information for other levels
-- Do not grant UPDATE/DELETE in SQL Injection challenges as players could use this to update/delete critical level information
GRANT SELECT ON `challengeSchemaName`.`challengeTableName` TO `creativeName`;
- Then open the src/main/webapp/WEB-INF/challenges directory and create a .properties file (You will have to call this properties file in your controller)
- Enter the following information into the file;
databaseConnectionURL=challengeSchemaName
databaseUsername=creativeName
databasePassword=somePasswordHere
- Run the moduleSchemas.sql file on your database server
- Your controller can now interact with your schema
IF YOU MUST HAVE UPDATE PRIVILEGES ON YOUR SCHEMA FOR PLAYERS, PRACTISE EXTREME CAUTION AND BE AWARE OF RACE CONDITIONS
If you're stuck and unsure how to contribute please create a github issue so we can update this documentation