diff --git a/.gitignore b/.gitignore index 40c64083..85cfca11 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,14 @@ # Project Files # ################# *.userprefs -WebGoat/WebGoat.NET.pidb -WebGoat/bin -WebGoat/obj +*.pidb +*swp +bin +obj WebGoat/App_Data/*.txt -WebGoat/App_Data/.DS_Store -WebGoat/App_Data/*.sqlite +*.sqlite* WebGoat/Configuration/*.config # Trash Files # ############### .DS_Store -DB/.DS_Store -WebGoat/DB_Scripts/.DS_Store diff --git a/README b/README index 9c86601e..a5ce616c 100644 --- a/README +++ b/README @@ -1,22 +1,64 @@ - - From the prompt, cd into the WebGoat.NET DB directory +***************************** Webgoat.NET ********************************** +* Source Code: https://github.com/jerryhoff/WebGoat.NET +* Download zip: https://github.com/jerryhoff/WebGoat.NET/zipball/master +**************************************************************************** - % cd /WebGoat.NET/DB +This web application is a learning platform that attempts to teach about +common web security flaws. It contains generic security flaws that apply to +most web applications. It also contains lessons that specifically pertain to +the .NET framework. The excercises in this app are intented to teach about +web security attacks and how developers can overcome them. - Start the mysql utility, giving the name (and password, if needed) of a user permission to create databases. For example, to use the default root user: +WARNING: THIS WEB APPLICATION CONTAINS NUMEROUS SECURITY VULNERABILITIES +WHICH WILL RENDER YOUR COMPUTER VERY INSECURURE WHILE RUNNING! IT IS HIGHLY +RECOMMENDED TO COMPLETELY DISCONNECT YOUR COMPUTER FROM ALL NETWORKS WHILE +RUNNING! - % mysql --user=root +Notes: + - Google Chrome performs filtering for reflected XSS attacks. These attacks + will not work unless chrome is run with the argument + --disable-xss-auditor. +- Some (but not all!) of the lessons require a working SQL database. Setup + guidelines are shown below. - Create the webgoat_coins database and load the schema. (Loading the schema the schema the first time will give error messages as it attemps to empty any existing tables, just ignore these.) +How To Build And Run under Mac OS X and Linux: + 1. Prerequisites + a. Mono framework for your respective OS. It can be downloaded at + http://www.go-mono.com/mono-downloads/download.html. Make sure + that ALL components get installed, including GTK and xsp. + b. A DB for some of the lessions. Sqlite3 is recommended as it's + faster and easier to use for the purposes of these lessions. + Binaries can be found here: http://www.sqlite.org/download.html + 2. Install the mono framework and sqlite3 binaries. + 3. IMPORTANT: Make sure that the the mono executable is in your PATH. + 4. Grab WebGoat.NET and cd into the root dir. + 5. Run 'xbuild'. There may be a few warnings but there should be no + errors! If there are please let us know. + 6. cd into the WebGoat project and run 'xsp4'. Then open your favorite + browser and go to http://localhost:8080 (or whatever port your + xsp4 is using if you're not using the default). Note: The first run + may take take some time as it's compiling everything on the fly. + 7. If you see the WebGoat.NET page that means you're almost there! Next + step is to click on 'Set Up Database!' + 8. You should see a form with a bunch of setup information for the + database. For 'Data Provider' choose Sqlite. For 'Data File Path' put + in 'db.sqlite3' and for 'Client Executable' put in the sqlite3 + executable of your OS (usually /usr/bin/sqlite3). + 9. Click on 'Test Configuration', followed by 'Rebuild Database' and + hopefully you should be good go! Enjoy your hackathon! - mysql> create database webgoat_coins; - mysql> use webgoat_coins; - mysql> source create_webgoatcoins.sql; - - Load the table contents: - - mysql> source load_webgoatcoins.sql; - - Exit from mysql: - - mysql> quit; +How to build and run under Windows: + 1. Prerequisites: + a. Visual Studio 2010 and above. + b. Mysql database that's up and running with at least one user + aleady setup with full permissions. + 2. Open WebGoat.sln file via Visual Studio, and click on debug. + 3. You should see the WebGoat.NET page at which point click on + 'Set Up Database'. + 3. You should see a form with a bunch of setup information for the + database. For 'Data Provider' choose MySql. You'll need to fill in + the respective data entries for your mysql db. 'Client Executable' + and 'Data File Path' are not necessary for MySql so you can leave + them empty. + 4. Click on 'Test Configuration', followed by 'Rebuild Database' and + hopefully you should be good go! Enjoy your hackathon! diff --git a/WebGoat/App_Code/CustomerLoginData.cs b/WebGoat/App_Code/CustomerLoginData.cs index 9d4a5e13..fa431889 100644 --- a/WebGoat/App_Code/CustomerLoginData.cs +++ b/WebGoat/App_Code/CustomerLoginData.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Web; namespace OWASP.WebGoat.NET @@ -31,4 +30,4 @@ public String Message } } -} \ No newline at end of file +} diff --git a/WebGoat/App_Code/DB/DbConstants.cs b/WebGoat/App_Code/DB/DbConstants.cs index 85351d09..69e86efb 100644 --- a/WebGoat/App_Code/DB/DbConstants.cs +++ b/WebGoat/App_Code/DB/DbConstants.cs @@ -1,4 +1,5 @@ -using System; +using System; +using System.IO; namespace OWASP.WebGoat.NET.App_Code.DB { @@ -18,10 +19,12 @@ public class DbConstants public const string DB_TYPE_MYSQL = "MySql"; public const string DB_TYPE_SQLITE = "Sqlite"; public const string CONFIG_EXT = "config"; - + //DB Scripts - public const string DB_CREATE_SCRIPT = "DB_Scripts/create_webgoatcoins.sql"; - public const string DB_LOAD_MYSQL_SCRIPT = "DB_Scripts/load_webgoatcoins.sql"; - public const string DB_LOAD_SQLITE_SCRIPT = "DB_Scripts/load_webgoatcoins_sqlite3.sql"; + private const string SCRIPT_DIR = "DB_Scripts"; + public static readonly string DB_CREATE_MYSQL_SCRIPT = Path.Combine(SCRIPT_DIR, "create_webgoatcoins.sql"); + public static readonly string DB_CREATE_SQLITE_SCRIPT = Path.Combine(SCRIPT_DIR, "create_webgoatcoins_sqlite3.sql"); + public static readonly string DB_LOAD_MYSQL_SCRIPT = Path.Combine(SCRIPT_DIR, "load_webgoatcoins.sql"); + public static readonly string DB_LOAD_SQLITE_SCRIPT = Path.Combine(SCRIPT_DIR, "load_webgoatcoins_sqlite3.sql"); } } diff --git a/WebGoat/App_Code/DB/MySqlDbProvider.cs b/WebGoat/App_Code/DB/MySqlDbProvider.cs index 6d4307e3..0bc79812 100644 --- a/WebGoat/App_Code/DB/MySqlDbProvider.cs +++ b/WebGoat/App_Code/DB/MySqlDbProvider.cs @@ -103,7 +103,7 @@ public bool RecreateGoatDb() log.Info("Running recreate"); - int retVal1 = Math.Abs(Util.RunProcessWithInput(_clientExec, args, DbConstants.DB_CREATE_SCRIPT)); + int retVal1 = Math.Abs(Util.RunProcessWithInput(_clientExec, args, DbConstants.DB_CREATE_MYSQL_SCRIPT)); int retVal2 = Math.Abs(Util.RunProcessWithInput(_clientExec, args, DbConstants.DB_LOAD_MYSQL_SCRIPT)); return Math.Abs(retVal1) + Math.Abs(retVal2) == 0; diff --git a/WebGoat/App_Code/DB/SqliteDbProvider.cs b/WebGoat/App_Code/DB/SqliteDbProvider.cs index ee3e6e41..0e88a6d8 100644 --- a/WebGoat/App_Code/DB/SqliteDbProvider.cs +++ b/WebGoat/App_Code/DB/SqliteDbProvider.cs @@ -1,6 +1,6 @@ using System; using System.Data; -using System.Data.SQLite; +using Mono.Data.Sqlite; using log4net; using System.Reflection; using System.IO; @@ -25,17 +25,20 @@ public SqliteDbProvider(ConfigFile configFile) _clientExec = configFile.Get(DbConstants.KEY_CLIENT_EXEC); _dbFileName = configFile.Get(DbConstants.KEY_FILE_NAME); + + if (!File.Exists(_dbFileName)) + SqliteConnection.CreateFile(_dbFileName); } public bool TestConnection() { try { - using (SQLiteConnection conn = new SQLiteConnection(_connectionString)) + using (SqliteConnection conn = new SqliteConnection(_connectionString)) { conn.Open(); - using (SQLiteCommand cmd = conn.CreateCommand()) + using (SqliteCommand cmd = conn.CreateCommand()) { cmd.CommandText = "SELECT date('now')"; @@ -54,9 +57,11 @@ public bool TestConnection() public DataSet GetCatalogData() { - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { - SQLiteDataAdapter da = new SQLiteDataAdapter("select * from Products", connection); + connection.Open(); + + SqliteDataAdapter da = new SqliteDataAdapter("select * from Products", connection); DataSet ds = new DataSet(); da.Fill(ds); @@ -67,16 +72,18 @@ public DataSet GetCatalogData() public bool IsValidCustomerLogin(string email, string password) { - //encode password + //encode password string encoded_password = Encoder.Encode(password); //check email/password string sql = "select * from CustomerLogin where email = '" + email + "' and password = '" + encoded_password + "';"; - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { - SQLiteDataAdapter da = new SQLiteDataAdapter(sql, connection); + connection.Open(); + + SqliteDataAdapter da = new SqliteDataAdapter(sql, connection); //TODO: User reader instead (for all calls) DataSet ds = new DataSet(); @@ -98,13 +105,24 @@ public bool IsValidCustomerLogin(string email, string password) } public bool RecreateGoatDb() - { - log.Info("Running recreate"); - - int retVal1 = Math.Abs(Util.RunProcessWithInput(_clientExec, _dbFileName, DbConstants.DB_CREATE_SCRIPT)); - int retVal2 = Math.Abs(Util.RunProcessWithInput(_clientExec, _dbFileName, DbConstants.DB_LOAD_SQLITE_SCRIPT)); - - return Math.Abs(retVal1) + Math.Abs(retVal2) == 0; + { + try + { + log.Info("Running recreate"); + string args = string.Format("\"{0}\"", _dbFileName); + string script = Path.Combine(Settings.RootDir, DbConstants.DB_CREATE_SQLITE_SCRIPT); + int retVal1 = Math.Abs(Util.RunProcessWithInput(_clientExec, args, script)); + + script = Path.Combine(Settings.RootDir, DbConstants.DB_LOAD_SQLITE_SCRIPT); + int retVal2 = Math.Abs(Util.RunProcessWithInput(_clientExec, args, script)); + + return Math.Abs(retVal1) + Math.Abs(retVal2) == 0; + } + catch (Exception ex) + { + log.Error("Error rebulding DB", ex); + return false; + } } //Find the bugs! @@ -116,9 +134,11 @@ public string CustomCustomerLogin(string email, string password) //get data string sql = "select * from CustomerLogin where email = '" + email + "';"; - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { - SQLiteDataAdapter da = new SQLiteDataAdapter(sql, connection); + connection.Open(); + + SqliteDataAdapter da = new SqliteDataAdapter(sql, connection); DataSet ds = new DataSet(); da.Fill(ds); @@ -144,7 +164,7 @@ public string CustomCustomerLogin(string email, string password) } } - catch (SQLiteException ex) + catch (SqliteException ex) { log.Error("Error with custom customer login", ex); error_message = ex.Message; @@ -163,10 +183,12 @@ public string GetCustomerEmail(string customerNumber) try { - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { + connection.Open(); + string sql = "select email from CustomerLogin where customerNumber = " + customerNumber; - SQLiteCommand command = new SQLiteCommand(sql, connection); + SqliteCommand command = new SqliteCommand(sql, connection); output = command.ExecuteScalar().ToString(); } } @@ -188,9 +210,11 @@ public DataSet GetCustomerDetails(string customerNumber) try { - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { - SQLiteDataAdapter da = new SQLiteDataAdapter(sql, connection); + connection.Open(); + + SqliteDataAdapter da = new SqliteDataAdapter(sql, connection); da.Fill(ds); } @@ -208,10 +232,12 @@ public DataSet GetCustomerDetails(string customerNumber) public DataSet GetOffice(string city) { - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { + connection.Open(); + string sql = "select * from Offices where city = @city"; - SQLiteDataAdapter da = new SQLiteDataAdapter(sql, connection); + SqliteDataAdapter da = new SqliteDataAdapter(sql, connection); da.SelectCommand.Parameters.AddWithValue("@city", city); DataSet ds = new DataSet(); da.Fill(ds); @@ -221,10 +247,12 @@ public DataSet GetOffice(string city) public DataSet GetComments(string productCode) { - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { + connection.Open(); + string sql = "select * from Comments where productCode = @productCode"; - SQLiteDataAdapter da = new SQLiteDataAdapter(sql, connection); + SqliteDataAdapter da = new SqliteDataAdapter(sql, connection); da.SelectCommand.Parameters.AddWithValue("@productCode", productCode); DataSet ds = new DataSet(); da.Fill(ds); @@ -240,9 +268,10 @@ public string AddComment(string productCode, string email, string comment) try { - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { - SQLiteCommand command = new SQLiteCommand(sql, connection); + connection.Open(); + SqliteCommand command = new SqliteCommand(sql, connection); command.ExecuteNonQuery(); } } @@ -262,9 +291,11 @@ public string UpdateCustomerPassword(int customerNumber, string password) try { - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { - SQLiteCommand command = new SQLiteCommand(sql, connection); + connection.Open(); + + SqliteCommand command = new SqliteCommand(sql, connection); int rows_added = command.ExecuteNonQuery(); @@ -287,9 +318,11 @@ public string[] GetSecurityQuestionAndAnswer(string email) string[] qAndA = new string[2]; - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { - SQLiteDataAdapter da = new SQLiteDataAdapter(sql, connection); + connection.Open(); + + SqliteDataAdapter da = new SqliteDataAdapter(sql, connection); DataSet ds = new DataSet(); da.Fill(ds); @@ -311,11 +344,13 @@ public string GetPasswordByEmail(string email) try { - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { + connection.Open(); + //get data string sql = "select * from CustomerLogin where email = '" + email + "';"; - SQLiteDataAdapter da = new SQLiteDataAdapter(sql, connection); + SqliteDataAdapter da = new SqliteDataAdapter(sql, connection); DataSet ds = new DataSet(); da.Fill(ds); @@ -339,10 +374,12 @@ public string GetPasswordByEmail(string email) public DataSet GetUsers() { - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { + connection.Open(); + string sql = "select * from CustomerLogin;"; - SQLiteDataAdapter da = new SQLiteDataAdapter(sql, connection); + SqliteDataAdapter da = new SqliteDataAdapter(sql, connection); DataSet ds = new DataSet(); da.Fill(ds); return ds; @@ -352,10 +389,12 @@ public DataSet GetUsers() public DataSet GetOrders(int customerID) { - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { + connection.Open(); + string sql = "select * from Orders where customerNumber = " + customerID; - SQLiteDataAdapter da = new SQLiteDataAdapter(sql, connection); + SqliteDataAdapter da = new SqliteDataAdapter(sql, connection); DataSet ds = new DataSet(); da.Fill(ds); @@ -369,18 +408,20 @@ public DataSet GetOrders(int customerID) public DataSet GetProductDetails(string productCode) { string sql = string.Empty; - SQLiteDataAdapter da; + SqliteDataAdapter da; DataSet ds = new DataSet(); - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { + connection.Open(); + sql = "select * from Products where productCode = '" + productCode + "'"; - da = new SQLiteDataAdapter(sql, connection); + da = new SqliteDataAdapter(sql, connection); da.Fill(ds, "products"); sql = "select * from Comments where productCode = '" + productCode + "'"; - da = new SQLiteDataAdapter(sql, connection); + da = new SqliteDataAdapter(sql, connection); da.Fill(ds, "comments"); DataRelation dr = new DataRelation("prod_comments", @@ -405,9 +446,11 @@ public DataSet GetOrderDetails(int orderNumber) "and OrderDetails.orderNumber = " + orderNumber; - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { - SQLiteDataAdapter da = new SQLiteDataAdapter(sql, connection); + connection.Open(); + + SqliteDataAdapter da = new SqliteDataAdapter(sql, connection); DataSet ds = new DataSet(); da.Fill(ds); @@ -420,10 +463,12 @@ public DataSet GetOrderDetails(int orderNumber) public DataSet GetPayments(int customerNumber) { - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { + connection.Open(); + string sql = "select * from Payments where customerNumber = " + customerNumber; - SQLiteDataAdapter da = new SQLiteDataAdapter(sql, connection); + SqliteDataAdapter da = new SqliteDataAdapter(sql, connection); DataSet ds = new DataSet(); da.Fill(ds); @@ -443,7 +488,7 @@ public DataSet GetProductsAndCategories(int catNumber) { //TODO: Rerun the database script. string sql = string.Empty; - SQLiteDataAdapter da; + SqliteDataAdapter da; DataSet ds = new DataSet(); //catNumber is optional. If it is greater than 0, add the clause to both statements. @@ -452,15 +497,16 @@ public DataSet GetProductsAndCategories(int catNumber) catClause += " where catNumber = " + catNumber; - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { + connection.Open(); sql = "select * from Categories" + catClause; - da = new SQLiteDataAdapter(sql, connection); + da = new SqliteDataAdapter(sql, connection); da.Fill(ds, "categories"); sql = "select * from Products" + catClause; - da = new SQLiteDataAdapter(sql, connection); + da = new SqliteDataAdapter(sql, connection); da.Fill(ds, "products"); @@ -480,9 +526,11 @@ public DataSet GetEmailByName(string name) string sql = "select firstName, lastName, email from Employees where firstName like '" + name + "%' or lastName like '" + name + "%'"; - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { - SQLiteDataAdapter da = new SQLiteDataAdapter(sql, connection); + connection.Open(); + + SqliteDataAdapter da = new SqliteDataAdapter(sql, connection); DataSet ds = new DataSet(); da.Fill(ds); @@ -499,10 +547,12 @@ public string GetEmailByCustomerNumber(string num) try { - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { + connection.Open(); + string sql = "select email from CustomerLogin where customerNumber = " + num; - SQLiteCommand cmd = new SQLiteCommand(sql, connection); + SqliteCommand cmd = new SqliteCommand(sql, connection); output = (string)cmd.ExecuteScalar(); } @@ -521,9 +571,11 @@ public DataSet GetCustomerEmails(string email) string sql = "select email from CustomerLogin where email like '" + email + "%'"; - using (SQLiteConnection connection = new SQLiteConnection(_connectionString)) + using (SqliteConnection connection = new SqliteConnection(_connectionString)) { - SQLiteDataAdapter da = new SQLiteDataAdapter(sql, connection); + connection.Open(); + + SqliteDataAdapter da = new SqliteDataAdapter(sql, connection); DataSet ds = new DataSet(); da.Fill(ds); diff --git a/WebGoat/App_Code/Encoder.cs b/WebGoat/App_Code/Encoder.cs index 5d792c51..99bb022e 100644 --- a/WebGoat/App_Code/Encoder.cs +++ b/WebGoat/App_Code/Encoder.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Web; using System.IO; using System.Text; @@ -242,4 +241,4 @@ public string EncodeTicket(string token) } } -} \ No newline at end of file +} diff --git a/WebGoat/App_Code/Settings.cs b/WebGoat/App_Code/Settings.cs index c72eb0de..b0873633 100644 --- a/WebGoat/App_Code/Settings.cs +++ b/WebGoat/App_Code/Settings.cs @@ -2,6 +2,12 @@ using OWASP.WebGoat.NET.App_Code.DB; using System.IO; using System.Web; +using log4net; +using System.Reflection; +using System.Diagnostics; +using log4net.Config; +using log4net.Appender; +using log4net.Layout; namespace OWASP.WebGoat.NET.App_Code { @@ -10,43 +16,66 @@ public class Settings public static readonly string DefaultConfigName = string.Format("Default.{0}", DbConstants.CONFIG_EXT); private const string PARENT_CONFIG_PATH = "Configuration"; private const string DATA_FOLDER = "App_Data"; - private const string DEFAULT_SQLITE_NAME = "webgoat_coins.sqlite"; + private const string DEFAULT_SQLITE_NAME = "webgoat_coins.sqlite"; + + private static object _lock = new object(); + private static bool _inited = false; + private static ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); public static void Init(HttpServerUtility server) - { - string configPath = Path.Combine(PARENT_CONFIG_PATH, DefaultConfigName); - DefaultConfigPath = server.MapPath(configPath); - - //By default if there's no config let's create a sqlite db. - string defaultConfigPath = DefaultConfigPath; - - string sqlitePath = Path.Combine(DATA_FOLDER, DEFAULT_SQLITE_NAME); - sqlitePath = server.MapPath(sqlitePath); - - if (!File.Exists(defaultConfigPath)) - { - ConfigFile file = new ConfigFile(defaultConfigPath); - - file.Set(DbConstants.KEY_DB_TYPE, DbConstants.DB_TYPE_SQLITE); - file.Set(DbConstants.KEY_FILE_NAME, sqlitePath); - file.Save(); - - CurrentConfigFile = file; - } - else - { - CurrentConfigFile = new ConfigFile(defaultConfigPath); - CurrentConfigFile.Load(); + { + lock (_lock) + { + if (Debugger.IsAttached) + BasicConfigurator.Configure(); + else + XmlConfigurator.Configure(); + + string configPath = Path.Combine(PARENT_CONFIG_PATH, DefaultConfigName); + DefaultConfigPath = server.MapPath(configPath); + + RootDir = server.MapPath("."); + + log.Debug("DYLD_FALLBACK_LIBRARY_PATH: " + Environment.GetEnvironmentVariable("DYLD_FALLBACK_LIBRARY_PATH")); + log.Debug("PWD: " + Environment.CurrentDirectory); + + //By default if there's no config let's create a sqlite db. + string defaultConfigPath = DefaultConfigPath; + + string sqlitePath = Path.Combine(DATA_FOLDER, DEFAULT_SQLITE_NAME); + sqlitePath = server.MapPath(sqlitePath); + + if (!File.Exists(defaultConfigPath)) + { + ConfigFile file = new ConfigFile(defaultConfigPath); + + file.Set(DbConstants.KEY_DB_TYPE, DbConstants.DB_TYPE_SQLITE); + file.Set(DbConstants.KEY_FILE_NAME, sqlitePath); + file.Save(); + + CurrentConfigFile = file; + } + else + { + CurrentConfigFile = new ConfigFile(defaultConfigPath); + CurrentConfigFile.Load(); + } + + CurrentDbProvider = DbProviderFactory.Create(CurrentConfigFile); + _inited = true; } - CurrentDbProvider = DbProviderFactory.Create(CurrentConfigFile); - } - + } + + public static string RootDir { get; private set; } + public static IDbProvider CurrentDbProvider { get; set; } public static string DefaultConfigPath { get; private set; } - public static ConfigFile CurrentConfigFile { get; set; } + public static ConfigFile CurrentConfigFile { get; set; } + + public static bool Inited { get { lock (_lock) { return _inited; } } } } } \ No newline at end of file diff --git a/WebGoat/App_Code/Util.cs b/WebGoat/App_Code/Util.cs index a074d7ef..a88fa9ff 100644 --- a/WebGoat/App_Code/Util.cs +++ b/WebGoat/App_Code/Util.cs @@ -15,6 +15,7 @@ public static int RunProcessWithInput(string cmd, string args, string input) { ProcessStartInfo startInfo = new ProcessStartInfo { + WorkingDirectory = Settings.RootDir, FileName = cmd, Arguments = args, UseShellExecute = false, @@ -27,7 +28,6 @@ public static int RunProcessWithInput(string cmd, string args, string input) { process.EnableRaisingEvents = true; process.StartInfo = startInfo; - process.Start(); process.OutputDataReceived += (sender, e) => { if (e.Data != null) @@ -47,16 +47,26 @@ public static int RunProcessWithInput(string cmd, string args, string input) Thread.Sleep(1000); are.Set(); log.Info("Process exited"); - }; - process.Start(); + }; - using (StreamReader reader = new StreamReader(new FileStream(input, FileMode.Open))) - { - string line; - - while ((line = reader.ReadLine()) != null) - process.StandardInput.WriteLine(line); + process.Start(); + + using (StreamReader reader = new StreamReader(new FileStream(input, FileMode.Open))) + { + string line; + string replaced; + while ((line = reader.ReadLine()) != null) + { + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + replaced = line.Replace("DB_Scripts/datafiles/", "DB_Scripts\\\\datafiles\\\\"); + else + replaced = line; + + log.Debug("Line: " + replaced); + + process.StandardInput.WriteLine(replaced); + } } process.StandardInput.Close(); diff --git a/WebGoat/App_Code/VeryWeakRandom.cs b/WebGoat/App_Code/VeryWeakRandom.cs new file mode 100644 index 00000000..ed70a3ce --- /dev/null +++ b/WebGoat/App_Code/VeryWeakRandom.cs @@ -0,0 +1,38 @@ +using System; + +namespace OWASP.WebGoat.NET.App_Code +{ + public class VeryWeakRandom + { + private uint _seed = 7; + private uint _helper = 1; + + public VeryWeakRandom() {} + + public VeryWeakRandom(uint seed) + { + _seed = seed; + } + + public uint Next(uint min, uint max) + { + _seed = Peek(min, max); + _helper++; + + return _seed; + } + + public uint Peek(uint min, uint max) + { + if (min >= max) + throw new Exception("Min must be smaller than max"); + + var seed = _seed + _helper; + + if (seed > max) + seed = min; + + return seed; + } + } +} diff --git a/WebGoat/App_Code/WeakRandom.cs b/WebGoat/App_Code/WeakRandom.cs new file mode 100644 index 00000000..f0b4ae2f --- /dev/null +++ b/WebGoat/App_Code/WeakRandom.cs @@ -0,0 +1,42 @@ +using System; + +namespace OWASP.WebGoat.NET.App_Code +{ + public class WeakRandom + { + private uint _seed = 7; + + public WeakRandom() {} + + public WeakRandom(uint seed) + { + _seed = seed; + } + + public uint Next(uint min, uint max) + { + if (min >= max) + throw new Exception("Min must be smaller than max"); + + unchecked //Just use next number from overflow + { + _seed = _seed * _seed + _seed; + } + + return _seed % (max - min) + min; + } + + public uint Peek(uint min, uint max) + { + if (min >= max) + throw new Exception("Min must be smaller than max"); + + unchecked //Just use next number from overflow + { + var seed = _seed * _seed + _seed; + + return seed % (max - min) + min; + } + } + } +} \ No newline at end of file diff --git a/WebGoat/App_Themes/.DS_Store b/WebGoat/App_Themes/.DS_Store deleted file mode 100644 index 73b840f1..00000000 Binary files a/WebGoat/App_Themes/.DS_Store and /dev/null differ diff --git a/WebGoat/Content/.DS_Store b/WebGoat/Content/.DS_Store deleted file mode 100644 index 5008ddfc..00000000 Binary files a/WebGoat/Content/.DS_Store and /dev/null differ diff --git a/WebGoat/Content/EncryptVSEncode.aspx.cs b/WebGoat/Content/EncryptVSEncode.aspx.cs index 16bdb328..aac8a197 100644 --- a/WebGoat/Content/EncryptVSEncode.aspx.cs +++ b/WebGoat/Content/EncryptVSEncode.aspx.cs @@ -13,54 +13,62 @@ namespace OWASP.WebGoat.NET { public partial class EncryptVSEncode : System.Web.UI.Page { - enum WG_Hash {Sha1=1, Sha256}; - - private string password = "123456"; + public string Password { get; set; } + + enum WG_Hash + { + Sha1=1, + Sha256 + }; + private string hardCodedKey = "key"; protected void Page_Load(object sender, EventArgs e) { - + Password = "123456"; } + protected void btnGO_Click(object sender, EventArgs e) { - //url encoded - //base64 - //sha1 - //encryption with password - - string secret = txtString.Text; - string key = String.IsNullOrEmpty(txtPassword.Text) ? hardCodedKey : txtPassword.Text; - - Table t = new Table(); - t.Width = new Unit("100%"); - + //url encoded + //base64 + //sha1 + //encryption with password + + string secret = txtString.Text; + string key = String.IsNullOrEmpty(txtPassword.Text) ? hardCodedKey : txtPassword.Text; + + Table t = new Table(); + t.Width = new Unit("100%"); + t.Rows.Add(MakeRow("Custom Crypto", CustomCryptoEncrypt(secret))); - t.Rows.Add(MakeRow("URL Encoded:", Server.UrlEncode(secret))); - t.Rows.Add(MakeRow("Base64 Encoded:", Base64(secret))); - t.Rows.Add(MakeRow("SHA1 Hashed:", SHA(secret, WG_Hash.Sha1))); - t.Rows.Add(MakeRow("SHA256 Hashed:", SHA(secret, WG_Hash.Sha256))); - t.Rows.Add(MakeRow("Rijndael Encrypted: ", Encypt(secret, key), Color.LightGreen)); + t.Rows.Add(MakeRow("URL Encoded:", Server.UrlEncode(secret))); + t.Rows.Add(MakeRow("Base64 Encoded:", Base64(secret))); + t.Rows.Add(MakeRow("SHA1 Hashed:", SHA(secret, WG_Hash.Sha1))); + t.Rows.Add(MakeRow("SHA256 Hashed:", SHA(secret, WG_Hash.Sha256))); + t.Rows.Add(MakeRow("Rijndael Encrypted: ", Encypt(secret, key), Color.LightGreen)); + + ContentPlaceHolder cph = (ContentPlaceHolder)this.Master.FindControl("BodyContentPlaceholder"); + cph.Controls.Add(new LiteralControl("

")); + cph.Controls.Add(t); - ContentPlaceHolder cph = (ContentPlaceHolder)this.Master.FindControl("BodyContentPlaceholder"); - cph.Controls.Add(new LiteralControl("

")); - cph.Controls.Add(t); - } + private TableRow MakeRow(string label, string val) { - TableRow row = new TableRow(); - - TableCell t1 = new TableCell(); - t1.Text = label; - row.Cells.Add(t1); - - TableCell t2 = new TableCell(); - t2.Text = val; - row.Cells.Add(t2); - return row; + TableRow row = new TableRow(); + + TableCell t1 = new TableCell(); + t1.Text = label; + row.Cells.Add(t1); + + TableCell t2 = new TableCell(); + t2.Text = val; + row.Cells.Add(t2); + return row; } + private TableRow MakeRow(string label, string val, Color color) { TableRow row = new TableRow(); @@ -76,29 +84,30 @@ private TableRow MakeRow(string label, string val, Color color) return row; } - private string Base64(string s) - { - byte[] bytes = System.Text.ASCIIEncoding.ASCII.GetBytes(s); - return System.Convert.ToBase64String(bytes); - } - - private string SHA(string s, WG_Hash hash) - { - byte[] bytes = System.Text.ASCIIEncoding.ASCII.GetBytes(s); - byte[] result; - HashAlgorithm sha; - switch(hash){ - case WG_Hash.Sha1: - sha = new SHA1Managed(); - break; - case WG_Hash.Sha256: - sha = new SHA256Managed(); - break; - } - result = sha.ComputeHash(bytes); - return System.Convert.ToBase64String(result); - } + { + byte[] bytes = System.Text.ASCIIEncoding.ASCII.GetBytes(s); + return System.Convert.ToBase64String(bytes); + } + + private string SHA(string s, WG_Hash hash) + { + byte[] bytes = System.Text.ASCIIEncoding.ASCII.GetBytes(s); + byte[] result; + HashAlgorithm sha = null; + + switch (hash) + { + case WG_Hash.Sha1: + sha = new SHA1Managed(); + break; + case WG_Hash.Sha256: + sha = new SHA256Managed(); + break; + } + result = sha.ComputeHash(bytes); + return System.Convert.ToBase64String(result); + } private string Encypt(string s, string key) { @@ -112,13 +121,13 @@ private string CustomCryptoEncrypt(String s) // needs work but you get the point for (int i = 0; i < bytes.Length; i++) { - if (i % 2 == 0) + if (i % 2 == 0) { - bytes[i] = (byte) (bytes[i] | 2); + bytes[i] = (byte)(bytes[i] | 2); } else { - bytes[i] = (byte) (bytes[i] & 2); + bytes[i] = (byte)(bytes[i] & 2); } } diff --git a/WebGoat/Content/HeaderInjection.aspx.cs b/WebGoat/Content/HeaderInjection.aspx.cs index ed691602..47b665ea 100644 --- a/WebGoat/Content/HeaderInjection.aspx.cs +++ b/WebGoat/Content/HeaderInjection.aspx.cs @@ -5,6 +5,7 @@ using System.Web.UI; using System.Web.UI.WebControls; using System.Collections; +using System.Collections.Specialized; namespace OWASP.WebGoat.NET { @@ -12,8 +13,24 @@ public partial class HeaderInjection : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { + if (Request.QueryString["Cookie"] != null) + { + HttpCookie cookie = new HttpCookie("UserAddedCookie"); + cookie.Value = Request.QueryString["Cookie"]; + + Response.Cookies.Add(cookie); + } + else if (Request.QueryString["Header"] != null) + { + NameValueCollection newHeader = new NameValueCollection(); + newHeader.Add("newHeader", Request.QueryString["Header"]); + Response.Headers.Add(newHeader); + } + + + //Headers - lblHeaders.Text = Request.Headers.ToString().Replace("&", "
");; + lblHeaders.Text = Request.Headers.ToString().Replace("&", "
"); //Cookies ArrayList colCookies = new ArrayList(); @@ -22,6 +39,9 @@ protected void Page_Load(object sender, EventArgs e) gvCookies.DataSource = colCookies; gvCookies.DataBind(); + + //possibly going to be used later for something interesting + } } } \ No newline at end of file diff --git a/WebGoat/Content/Random.aspx b/WebGoat/Content/Random.aspx new file mode 100644 index 00000000..0fb5b689 --- /dev/null +++ b/WebGoat/Content/Random.aspx @@ -0,0 +1,35 @@ +<%@ Page Title="" Language="C#" MasterPageFile="~/Resources/Master-Pages/Site.Master" AutoEventWireup="true" + Inherits="OWASP.WebGoat.NET.Content.Random" %> + + + + + + + +

Weak Random Number Generators

+ +

A weak number generator can be the source of a system break-in, as it is used in many important situations + such as password salts, SSL handshakes etc.

+ +

In the following example, try to predict the next number in the sequence:

+ +

+ + + + + + +
+ +

The next number is: +

+ +

+ + + + + + diff --git a/WebGoat/Content/Random.aspx.cs b/WebGoat/Content/Random.aspx.cs new file mode 100644 index 00000000..501d7abc --- /dev/null +++ b/WebGoat/Content/Random.aspx.cs @@ -0,0 +1,77 @@ +using System; +using OWASP.WebGoat.NET.App_Code; +using System.Collections.Generic; +using System.Text; + +namespace OWASP.WebGoat.NET.Content +{ + public partial class Random : System.Web.UI.Page + { + private const uint MIN = 1; + private const uint MAX = 1000; + private const int INIT_NUMBERS = 5; + + public void Page_Load(object sender, EventArgs args) + { + if (Session["Random"] == null) + Reset(); + + IList numbers = (IList) Session["Numbers"]; + lblSequence.Text = "Sequence: " + Print(numbers); + } + + public void btnOneMore_Click(object sender, EventArgs args) + { + WeakRandom rnd = (WeakRandom) Session["Random"]; + IList numbers = (IList) Session["Numbers"]; + + numbers.Add(rnd.Next(MIN, MAX)); + + lblSequence.Text = "Sequence: " + Print(numbers); + } + + public void btnGo_Click(object sender, EventArgs args) + { + WeakRandom rnd = (WeakRandom) Session["Random"]; + + uint next = rnd.Peek(MIN, MAX); + + if (txtNextNumber.Text == next.ToString()) + lblResult.Text = "You found it!"; + else + lblResult.Text = "Sorry please try again."; + } + + public void btnReset_Click(object sender, EventArgs args) + { + Reset(); + + IList numbers = (IList) Session["Numbers"]; + lblSequence.Text = "Sequence: " + Print(numbers); + } + + private string Print(IList numbers) + { + StringBuilder strBuilder = new StringBuilder(); + + foreach(uint n in numbers) + strBuilder.AppendFormat("{0}, ", n); + + return strBuilder.ToString(); + } + + public void Reset() + { + Session["Random"] = new WeakRandom(); + + var rnd = (WeakRandom) Session["Random"]; + + IList numbers = new List(); + + for(int i=0; i +// This code was generated by a tool. +// Mono Runtime Version: 4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +namespace OWASP.WebGoat.NET.Content { + + + public partial class Random { + + protected System.Web.UI.WebControls.Content Content1; + + protected System.Web.UI.WebControls.Content Content2; + + protected System.Web.UI.WebControls.Label lblSequence; + + protected System.Web.UI.WebControls.Button btnOneMore; + + protected System.Web.UI.WebControls.Button btnReset; + + protected System.Web.UI.WebControls.TextBox txtNextNumber; + + protected System.Web.UI.WebControls.Button btnGo; + + protected System.Web.UI.WebControls.Label lblResult; + + protected System.Web.UI.WebControls.Content Content3; + } +} diff --git a/WebGoat/Content/RegexDoS.aspx b/WebGoat/Content/RegexDoS.aspx new file mode 100644 index 00000000..4d7dbbb9 --- /dev/null +++ b/WebGoat/Content/RegexDoS.aspx @@ -0,0 +1,12 @@ +<%@ Page Title="" Language="C#" MasterPageFile="~/Resources/Master-Pages/Site.Master" AutoEventWireup="true" CodeBehind="RegexDoS.aspx.cs" Inherits="OWASP.WebGoat.NET.RegexDoS" %> + + + + +
+Username:  +
+Password:  +
+ +
diff --git a/WebGoat/Content/RegexDoS.aspx.cs b/WebGoat/Content/RegexDoS.aspx.cs new file mode 100644 index 00000000..0941e992 --- /dev/null +++ b/WebGoat/Content/RegexDoS.aspx.cs @@ -0,0 +1,36 @@ +using System; +using System.Web; +using System.Web.UI; +using System.Text.RegularExpressions; + +namespace OWASP.WebGoat.NET +{ + public partial class RegexDoS : System.Web.UI.Page + { + protected void Page_Load(object sender, EventArgs e) + { + + } + + /// + /// Code from https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS + /// + protected void btnCreate_Click(object sender, EventArgs e) + { + string userName = txtUsername.Text; + string password = txtPassword.Text; + + Regex testPassword = new Regex(userName); + Match match = testPassword.Match(password); + if (match.Success) + { + lblError.Text = "Do not include name in password."; + } + else + { + lblError.Text = "Good password."; + } + } + } +} + diff --git a/WebGoat/Content/RegexDoS.aspx.designer.cs b/WebGoat/Content/RegexDoS.aspx.designer.cs new file mode 100644 index 00000000..9b81bb3e --- /dev/null +++ b/WebGoat/Content/RegexDoS.aspx.designer.cs @@ -0,0 +1,31 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Mono Runtime Version: 4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ +using System; +using System.Web; +using System.Web.UI; + +namespace OWASP.WebGoat.NET +{ + public partial class RegexDoS + { + protected System.Web.UI.WebControls.Content Content1; + + protected System.Web.UI.WebControls.Content Content2; + + protected System.Web.UI.WebControls.Label lblError; + + protected System.Web.UI.WebControls.TextBox txtUsername; + + protected System.Web.UI.WebControls.TextBox txtPassword; + + protected System.Web.UI.WebControls.Button btnUpload; + } +} + diff --git a/WebGoat/Content/Unsafe.aspx b/WebGoat/Content/Unsafe.aspx new file mode 100644 index 00000000..aac0f708 --- /dev/null +++ b/WebGoat/Content/Unsafe.aspx @@ -0,0 +1,31 @@ +<%@ Page Title="" Language="C#" MasterPageFile="~/Resources/Master-Pages/Site.Master" + AutoEventWireup="true" CodeBehind="MessageDigest.aspx.cs" Inherits="OWASP.WebGoat.NET.Content.Unsafe" %> + + + <%-- + Throw in some hints here. Many will have a hard time figuring it out: + -- Write a looong message + --%> + + + + + +

Unsafe blocks in .NET

+ +

In this lesson we'll take a look at .NET's unsafe block and how it can be exploited through user input. + When typing a string in the textbox below, the server will read it and compute its reverse. Try to exploit the + server by typing in a 'bad' input.

+ +

+ +

+ +

Result:

+ +
+ + + + diff --git a/WebGoat/Content/Unsafe.aspx.cs b/WebGoat/Content/Unsafe.aspx.cs new file mode 100644 index 00000000..bdc62557 --- /dev/null +++ b/WebGoat/Content/Unsafe.aspx.cs @@ -0,0 +1,37 @@ +using System; +using System.Text; + +namespace OWASP.WebGoat.NET.Content +{ + public partial class Unsafe : System.Web.UI.Page + { + public void Page_Load(object sender, EventArgs args) + { + } + + public unsafe void btnReverse_Click(object sender, EventArgs args) + { + const string msg = "passwor"; + const int INPUT_LEN = 256; + char[] fixedChar = new char[INPUT_LEN]; + + for (int i = 0; i < fixedChar.Length; i++) + fixedChar[i] = '\0'; + + fixed (char* revLine = fixedChar) + { + int lineLen = txtBoxMsg.Text.Length; + + for (int i = 0; i < lineLen; i++) + *(revLine + i) = txtBoxMsg.Text[lineLen - i - 1]; + + char* revCur = revLine; + + lblReverse.Text = string.Empty; + while (*revCur != '\0') + lblReverse.Text += (char)*revCur++; + } + } + } +} + diff --git a/WebGoat/Content/Unsafe.aspx.designer.cs b/WebGoat/Content/Unsafe.aspx.designer.cs new file mode 100644 index 00000000..be23d89a --- /dev/null +++ b/WebGoat/Content/Unsafe.aspx.designer.cs @@ -0,0 +1,28 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Mono Runtime Version: 4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +namespace OWASP.WebGoat.NET.Content { + + + public partial class Unsafe { + + protected System.Web.UI.WebControls.Content Content1; + + protected System.Web.UI.WebControls.Content Content2; + + protected System.Web.UI.WebControls.TextBox txtBoxMsg; + + protected System.Web.UI.WebControls.Button btnReverse; + + protected System.Web.UI.WebControls.Label lblReverse; + + protected System.Web.UI.WebControls.Content Content3; + } +} diff --git a/WebGoat/Content/VerbTampering.aspx b/WebGoat/Content/VerbTampering.aspx new file mode 100644 index 00000000..846e79a3 --- /dev/null +++ b/WebGoat/Content/VerbTampering.aspx @@ -0,0 +1,7 @@ +<%@ Page Title="" Language="C#" MasterPageFile="~/Resources/Master-Pages/Site.Master" AutoEventWireup="true" CodeBehind="VerbTampering.aspx.cs" Inherits="OWASP.WebGoat.NET.VerbTampering" %> + + + + + + diff --git a/WebGoat/Content/VerbTampering.aspx.cs b/WebGoat/Content/VerbTampering.aspx.cs new file mode 100644 index 00000000..1300a579 --- /dev/null +++ b/WebGoat/Content/VerbTampering.aspx.cs @@ -0,0 +1,19 @@ + +using System; +using System.Web; +using System.Web.UI; + +namespace OWASP.WebGoat.NET +{ + public partial class VerbTampering : System.Web.UI.Page + { + //Probably best if eventually connected to DB + public static string tamperedMessage = "This has not been tampered with yet..."; + + protected void Page_Load(object sender, EventArgs e) + { + lblTampered.Text = tamperedMessage; + } + } +} + diff --git a/WebGoat/Content/VerbTampering.aspx.designer.cs b/WebGoat/Content/VerbTampering.aspx.designer.cs new file mode 100644 index 00000000..5c96a5b3 --- /dev/null +++ b/WebGoat/Content/VerbTampering.aspx.designer.cs @@ -0,0 +1,22 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Mono Runtime Version: 4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +namespace OWASP.WebGoat.NET { + + + public partial class VerbTampering { + + protected System.Web.UI.WebControls.Content Content1; + + protected System.Web.UI.WebControls.Content Content2; + + protected System.Web.UI.WebControls.Label lblTampered; + } +} diff --git a/WebGoat/Content/VerbTamperingAttack.aspx b/WebGoat/Content/VerbTamperingAttack.aspx new file mode 100644 index 00000000..6f5defb5 --- /dev/null +++ b/WebGoat/Content/VerbTamperingAttack.aspx @@ -0,0 +1,5 @@ +<%@ Page Title="" Language="C#" MasterPageFile="~/Resources/Master-Pages/Site.Master" AutoEventWireup="true" CodeBehind="VerbTamperingAttack.aspx.cs" Inherits="OWASP.WebGoat.NET.VerbTamperingAttack" %> + + + + \ No newline at end of file diff --git a/WebGoat/Content/VerbTamperingAttack.aspx.cs b/WebGoat/Content/VerbTamperingAttack.aspx.cs new file mode 100644 index 00000000..2924d44f --- /dev/null +++ b/WebGoat/Content/VerbTamperingAttack.aspx.cs @@ -0,0 +1,19 @@ + +using System; +using System.Web; +using System.Web.UI; + +namespace OWASP.WebGoat.NET +{ + public partial class VerbTamperingAttack : System.Web.UI.Page + { + protected void Page_Load(object sender, EventArgs e) + { + if (Request.QueryString["message"] != null) + { + VerbTampering.tamperedMessage = Request.QueryString["message"]; + } + } + } +} + diff --git a/WebGoat/Content/VerbTamperingAttack.aspx.designer.cs b/WebGoat/Content/VerbTamperingAttack.aspx.designer.cs new file mode 100644 index 00000000..220e2fe2 --- /dev/null +++ b/WebGoat/Content/VerbTamperingAttack.aspx.designer.cs @@ -0,0 +1,20 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Mono Runtime Version: 4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +namespace OWASP.WebGoat.NET { + + + public partial class VerbTamperingAttack { + + protected System.Web.UI.WebControls.Content Content1; + + protected System.Web.UI.WebControls.Content Content2; + } +} diff --git a/WebGoat/Content/XMLInjection.aspx b/WebGoat/Content/XMLInjection.aspx index c3c23b4a..57af3799 100644 --- a/WebGoat/Content/XMLInjection.aspx +++ b/WebGoat/Content/XMLInjection.aspx @@ -2,4 +2,6 @@ + + diff --git a/WebGoat/Content/XMLInjection.aspx.cs b/WebGoat/Content/XMLInjection.aspx.cs index fdc67996..6f5e2674 100644 --- a/WebGoat/Content/XMLInjection.aspx.cs +++ b/WebGoat/Content/XMLInjection.aspx.cs @@ -6,14 +6,86 @@ using System.Xml; using System.Xml.XPath; using System.Data; +using System.IO; +using System.Text; namespace OWASP.WebGoat.NET { public partial class XMLInjection : System.Web.UI.Page { + List users; protected void Page_Load(object sender, EventArgs e) { + + ReadXml(); + + gvUsers.DataSource = users.ToArray(); + + gvUsers.DataBind(); + +/* + + + Todd Smith + todd@example.com + + + Al Thompson + al@example.com + + +*/ + + //Need to add lesson! + if (Request.QueryString["name"] != null && Request.QueryString["email"] != null) + { + users.Add(new XmlUser(Request.QueryString["name"], Request.QueryString["email"])); + WriteXML(); + } + } + + private void ReadXml() + { + users = new List(); + XmlDocument doc = new XmlDocument(); + doc.Load(Server.MapPath("/App_Data/XmlInjectionUsers.xml")); + foreach (XmlNode node in doc.ChildNodes[1].ChildNodes) + { + if (node.Name == "user") + { + users.Add(new XmlUser(node.ChildNodes[0].InnerText, node.ChildNodes[1].InnerText)); + } + } + } + + private void WriteXML() + { + string xml = ""+ Environment.NewLine +"" + Environment.NewLine; + foreach (XmlUser user in users) + { + xml += "" + Environment.NewLine; + xml += "" + user.Name + "" + Environment.NewLine; + xml += "" + user.Email + "" + Environment.NewLine; + xml += "" + Environment.NewLine; + } + xml += "" +Environment.NewLine; + + XmlTextWriter writer = new XmlTextWriter(Server.MapPath("/App_Data/XmlInjectionUsers.xml"), Encoding.UTF8); + writer.WriteRaw(xml); + writer.Close(); + } + } + + public class XmlUser + { + public string Name { get; set; } + public string Email { get; set; } + + public XmlUser(string name, string email) + { + Name = name; + Email = email; } } } diff --git a/WebGoat/Content/XMLInjection.aspx.designer.cs b/WebGoat/Content/XMLInjection.aspx.designer.cs index b60812f9..0da8dfa9 100644 --- a/WebGoat/Content/XMLInjection.aspx.designer.cs +++ b/WebGoat/Content/XMLInjection.aspx.designer.cs @@ -16,5 +16,7 @@ public partial class XMLInjection { protected System.Web.UI.WebControls.Content Content1; protected System.Web.UI.WebControls.Content Content2; + + protected System.Web.UI.WebControls.GridView gvUsers; } } diff --git a/WebGoat/DB_Scripts/create_webgoatcoins.sql b/WebGoat/DB_Scripts/create_webgoatcoins.sql index 36c54590..7c01d41b 100644 --- a/WebGoat/DB_Scripts/create_webgoatcoins.sql +++ b/WebGoat/DB_Scripts/create_webgoatcoins.sql @@ -49,7 +49,7 @@ DROP TABLE Comments; /* Create the full set of Classic Models Tables */ CREATE TABLE Customers ( - customerNumber INTEGER NOT NULL, + customerNumber INTEGER NOT NULL AUTO_INCREMENT, customerName VARCHAR(50) NOT NULL, logoFileName VARCHAR(100) NULL, contactLastName VARCHAR(50) NOT NULL, @@ -76,14 +76,14 @@ CREATE TABLE CustomerLogin ( ); CREATE TABLE SecurityQuestions ( - question_id SMALLINT NOT NULL, + question_id SMALLINT NOT NULL AUTO_INCREMENT, question_text VARCHAR(400) NOT NULL, PRIMARY KEY (question_id) ); CREATE TABLE Employees ( - employeeNumber INTEGER NOT NULL, + employeeNumber INTEGER NOT NULL AUTO_INCREMENT, lastName VARCHAR(50) NOT NULL, firstName VARCHAR(50) NOT NULL, extension VARCHAR(10) NOT NULL, @@ -117,7 +117,7 @@ CREATE TABLE OrderDetails ( ); CREATE TABLE Orders ( - orderNumber INTEGER NOT NULL, + orderNumber INTEGER NOT NULL AUTO_INCREMENT, orderDate DATETIME NOT NULL, requiredDate DATETIME NOT NULL, shippedDate DATETIME NULL, @@ -142,7 +142,7 @@ CREATE TABLE Payments ( ); CREATE TABLE Categories( - catNumber INTEGER NOT NULL, + catNumber INTEGER NOT NULL AUTO_INCREMENT, catName VARCHAR(50) NOT NULL, catDesc TEXT NOT NULL, PRIMARY KEY (catNumber) diff --git a/WebGoat/DB_Scripts/create_webgoatcoins_sqlite3.sql b/WebGoat/DB_Scripts/create_webgoatcoins_sqlite3.sql new file mode 100644 index 00000000..930b90cc --- /dev/null +++ b/WebGoat/DB_Scripts/create_webgoatcoins_sqlite3.sql @@ -0,0 +1,170 @@ +/****************************************************************************** + * Copyright (c) 2005 Actuate Corporation. + * All rights reserved. This file and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Actuate Corporation - initial implementation + * + * Classic Models Inc. sample database developed as part of the + * Eclipse BIRT Project. For more information, see http:\\www.eclipse.org\birt + * + *******************************************************************************/ +/******************************************************************************* +* Changes made Jan 2012 - Copyright 2012 +* Updated BIRT to be the webgoat coins database +* Images copyright US Mint and the Perth Mint +* Contributers: +* Jerry Hoff - Infrared Security, LLC +* +*******************************************************************************/ + + + +/* Recommended DATABASE name is classicmodels. */ + +/* CREATE DATABASE classicmodels; */ +/* USE classicmodels; */ + +/* DROP the existing tables. Comment this out if it is not needed. */ + +/* webgoat.net note: use name webgoat_coins" */ + + +DROP TABLE Customers; +DROP TABLE CustomerLogin; +DROP TABLE SecurityQuestions; +DROP TABLE Employees; +DROP TABLE Offices; +DROP TABLE OrderDetails; +DROP TABLE Orders; +DROP TABLE Payments; +DROP TABLE Products; +DROP TABLE Categories; +DROP TABLE Comments; + + +/* Create the full set of Classic Models Tables */ + +CREATE TABLE Customers ( + customerNumber INTEGER NOT NULL, + customerName VARCHAR(50) NOT NULL, + logoFileName VARCHAR(100) NULL, + contactLastName VARCHAR(50) NOT NULL, + contactFirstName VARCHAR(50) NOT NULL, + phone VARCHAR(50) NOT NULL, + addressLine1 VARCHAR(50) NOT NULL, + addressLine2 VARCHAR(50) NULL, + city VARCHAR(50) NOT NULL, + state VARCHAR(50) NULL, + postalCode VARCHAR(15) NULL, + country VARCHAR(50) NOT NULL, + salesRepEmployeeNumber INTEGER NULL, + creditLimit DOUBLE NULL, + PRIMARY KEY (customerNumber) +); + +CREATE TABLE CustomerLogin ( + email VARCHAR(100) NOT NULL, + customerNumber INTEGER NOT NULL, + password VARCHAR(40) NOT NULL, + question_id SMALLINT NULL, + answer VARCHAR(50) NULL, + PRIMARY KEY (email) +); + +CREATE TABLE SecurityQuestions ( + question_id SMALLINT NOT NULL, + question_text VARCHAR(400) NOT NULL, + PRIMARY KEY (question_id) +); + + +CREATE TABLE Employees ( + employeeNumber INTEGER NOT NULL, + lastName VARCHAR(50) NOT NULL, + firstName VARCHAR(50) NOT NULL, + extension VARCHAR(10) NOT NULL, + email VARCHAR(100) NOT NULL, + officeCode VARCHAR(10) NOT NULL, + reportsTo INTEGER NULL, + jobTitle VARCHAR(50) NOT NULL, + PRIMARY KEY (employeeNumber) +); + +CREATE TABLE Offices ( + officeCode VARCHAR(10) NOT NULL, + city VARCHAR(50) NOT NULL, + phone VARCHAR(50) NOT NULL, + addressLine1 VARCHAR(50) NOT NULL, + addressLine2 VARCHAR(50) NULL, + state VARCHAR(50) NULL, + country VARCHAR(50) NOT NULL, + postalCode VARCHAR(15) NOT NULL, + territory VARCHAR(10) NOT NULL, + PRIMARY KEY (officeCode) +); + +CREATE TABLE OrderDetails ( + orderNumber INTEGER NOT NULL, + productCode VARCHAR(15) NOT NULL, + quantityOrdered INTEGER NOT NULL, + priceEach DOUBLE NOT NULL, + orderLineNumber SMALLINT NOT NULL, + PRIMARY KEY (orderNumber, productCode) +); + +CREATE TABLE Orders ( + orderNumber INTEGER NOT NULL, + orderDate DATETIME NOT NULL, + requiredDate DATETIME NOT NULL, + shippedDate DATETIME NULL, + status VARCHAR(15) NOT NULL, + comments TEXT NULL, + customerNumber INTEGER NOT NULL, + PRIMARY KEY (orderNumber) +); + + +CREATE TABLE Payments ( + customerNumber INTEGER NOT NULL, + cardType VARCHAR(50) NOT NULL, + creditCardNumber VARCHAR(50) NOT NULL, + verificationCode SMALLINT NOT NULL, + cardExpirationMonth VARCHAR(3) NOT NULL, + cardExpirationYear VARCHAR(5) NOT NULL, + confirmationCode VARCHAR(50) NOT NULL, + paymentDate DATETIME NOT NULL, + amount DOUBLE NOT NULL, + PRIMARY KEY (customerNumber, confirmationCode) +); + +CREATE TABLE Categories( + catNumber INTEGER NOT NULL, + catName VARCHAR(50) NOT NULL, + catDesc TEXT NOT NULL, + PRIMARY KEY (catNumber) +); + +CREATE TABLE Products ( + productCode VARCHAR(15) NOT NULL, + productName VARCHAR(200) NOT NULL, + catNumber INTEGER NOT NULL, + productImage VARCHAR(100) NOT NULL, + productVendor VARCHAR(50) NOT NULL, + productDescription TEXT NOT NULL, + quantityInStock SMALLINT NOT NULL, + buyPrice DOUBLE NOT NULL, + MSRP DOUBLE NOT NULL, + PRIMARY KEY (productCode) +); + +CREATE TABLE Comments( + commentNumber INTEGER NOT NULL, + productCode VARCHAR(15) NOT NULL, + email VARCHAR(100) NOT NULL, + comment TEXT NOT NULL, + PRIMARY KEY (commentNumber) +); diff --git a/WebGoat/DB_Scripts/products/.DS_Store b/WebGoat/DB_Scripts/products/.DS_Store deleted file mode 100644 index 30264148..00000000 Binary files a/WebGoat/DB_Scripts/products/.DS_Store and /dev/null differ diff --git a/WebGoat/Global.asax.cs b/WebGoat/Global.asax.cs index 53a5cda8..e826ca68 100644 --- a/WebGoat/Global.asax.cs +++ b/WebGoat/Global.asax.cs @@ -32,6 +32,11 @@ protected void Application_BeginRequest(object sender, EventArgs e) } + void Application_PreSendRequestHeaders(Object sender, EventArgs e) + { + Response.AddHeader("X-XSS-Protection", "0"); + } + protected void Application_AuthenticateRequest(object sender, EventArgs e) { //get the role data out of the encrypted cookie and add to current context @@ -71,4 +76,4 @@ protected void Application_End(object sender, EventArgs e) } } -} \ No newline at end of file +} diff --git a/WebGoat/Resources/client-scripts/.DS_Store b/WebGoat/Resources/client-scripts/.DS_Store deleted file mode 100644 index 5008ddfc..00000000 Binary files a/WebGoat/Resources/client-scripts/.DS_Store and /dev/null differ diff --git a/WebGoat/TODO.txt b/WebGoat/TODO.txt index 327df519..ce46d772 100644 --- a/WebGoat/TODO.txt +++ b/WebGoat/TODO.txt @@ -3,19 +3,12 @@ Unassigned: + Entity SQLi + NHibernate SQLi -+ Httponly (cookie flag) -+ Secure (cookie) flag - * Flag for cookie to be sent only over HTTPS -+ Role manipulation (standard .net api for role (isInRole(request.getParameter("role"))) -+ Verb tampering (changing POST/GET etc. request to something different) - * Google verb tampering by author: Rshan + LDAP injection (research the APIs / point to the APIs) + Weak cryptographic cypher (mode & padding). * Find out the default behavior (mode & padding) * Find out an example where we specify bad values + Using an insecure protocol (web client / http client) (weak ssl algo) + Global error handling -+ Denial Of Service + Unpatched libraries @@ -27,14 +20,14 @@ Harry: * Amend Rebuild Page to easily switchout DBs (DONE) + Debugging leaks (DONE) + Insecure message digest (DONE) -+ Unsafe -+ Insecure random # gen -+ Hard coded seed (For when using random funcationality) -+ Not using SSL ++ Unsafe (DONE) ++ Not using SSL (DONE - already present when logging in) ++ Insecure random # gen (DONE) ++ Hard coded seed (For when using random functionality) (DONE) ++ Role manipulation (standard .net api for role (isInRole(request.getParameter("role"))) (WORKING) Ray: -+ XML Injection + LINQ SQLi + URL rewriting (e.g. session cookie in url. can rewrite) <-- might be an issue. Cookieless is sitewide and breaks site when set to true. + Basic Auth @@ -50,6 +43,12 @@ Ray: + Custom crypto (args have to use a byte array and do a bitwise operation) (Done) + Readline (denial of service) (Done) + Hard Code Passwords (PWD in source code) (Done) ++ Denial Of Service (RegEx) (Done) ++ Httponly (cookie flag) (Done) ++ Secure (cookie flag) (Done) ++ XML Injection(Done) ++ Verb tampering (changing POST/GET etc. request to something different) (Done) + + Session timeout (config setting) (Done) + Dir traversal (Done) diff --git a/WebGoat/Web.config b/WebGoat/Web.config index f1d1facf..ed1e0ab0 100644 --- a/WebGoat/Web.config +++ b/WebGoat/Web.config @@ -39,13 +39,16 @@ http://msdn2.microsoft.com/en-us/library/b5ysx397.aspx + + + + - + - @@ -68,7 +71,8 @@ http://msdn2.microsoft.com/en-us/library/b5ysx397.aspx - + + @@ -80,7 +84,6 @@ http://msdn2.microsoft.com/en-us/library/b5ysx397.aspx - @@ -158,4 +161,12 @@ http://msdn2.microsoft.com/en-us/library/b5ysx397.aspx --> - \ No newline at end of file + + + + + + + + + diff --git a/WebGoat/Web.sitemap b/WebGoat/Web.sitemap index 90e07be2..79f4e05d 100644 --- a/WebGoat/Web.sitemap +++ b/WebGoat/Web.sitemap @@ -38,6 +38,10 @@ + + + + diff --git a/WebGoat/WebGoat.NET.csproj b/WebGoat/WebGoat.NET.csproj index 03fa8e3b..c00501db 100644 --- a/WebGoat/WebGoat.NET.csproj +++ b/WebGoat/WebGoat.NET.csproj @@ -28,6 +28,14 @@ 4 false AllRules.ruleset + true + + + + + + + none @@ -37,6 +45,7 @@ 4 false AllRules.ruleset + true @@ -61,8 +70,8 @@ lib\log4net.dll - - lib\System.Data.SQLite.dll + + lib\Mono.Data.Sqlite.dll @@ -487,6 +496,11 @@ + + + + + @@ -911,7 +925,6 @@ - @@ -956,6 +969,38 @@ ReadlineDoS.aspx + + RegexDoS.aspx + + + RegexDoS.aspx + + + Unsafe.aspx + + + Unsafe.aspx + + + Random.aspx + + + Random.aspx + + + + VerbTampering.aspx + + + VerbTampering.aspx + + + VerbTamperingAttack.aspx + + + VerbTamperingAttack.aspx + + @@ -1009,6 +1054,7 @@ + diff --git a/WebGoat/WebGoatCoins/.DS_Store b/WebGoat/WebGoatCoins/.DS_Store deleted file mode 100644 index dba68dd5..00000000 Binary files a/WebGoat/WebGoatCoins/.DS_Store and /dev/null differ diff --git a/WebGoat/WebGoatCoins/images/.DS_Store b/WebGoat/WebGoatCoins/images/.DS_Store deleted file mode 100644 index 2b779894..00000000 Binary files a/WebGoat/WebGoatCoins/images/.DS_Store and /dev/null differ diff --git a/WebGoat/WebGoatCoins/images/products/.DS_Store b/WebGoat/WebGoatCoins/images/products/.DS_Store deleted file mode 100644 index 84ef6c93..00000000 Binary files a/WebGoat/WebGoatCoins/images/products/.DS_Store and /dev/null differ diff --git a/WebGoat/WebGoatCoins/images/products/other/.DS_Store b/WebGoat/WebGoatCoins/images/products/other/.DS_Store deleted file mode 100644 index 35360683..00000000 Binary files a/WebGoat/WebGoatCoins/images/products/other/.DS_Store and /dev/null differ diff --git a/WebGoat/lib/Mono.Data.Sqlite.dll b/WebGoat/lib/Mono.Data.Sqlite.dll new file mode 100644 index 00000000..0cd2565c Binary files /dev/null and b/WebGoat/lib/Mono.Data.Sqlite.dll differ diff --git a/WebGoat/libsqlite3.0.dylib b/WebGoat/libsqlite3.0.dylib new file mode 100755 index 00000000..eb3d1f19 Binary files /dev/null and b/WebGoat/libsqlite3.0.dylib differ