diff --git a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/SqlInjectionChallenge.java b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/SqlInjectionChallenge.java new file mode 100644 index 000000000..f47076500 --- /dev/null +++ b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/SqlInjectionChallenge.java @@ -0,0 +1,136 @@ +package org.owasp.webgoat.plugin; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.RandomStringUtils; +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentPath; +import org.owasp.webgoat.assignments.AttackResult; +import org.owasp.webgoat.session.DatabaseUtilities; +import org.owasp.webgoat.session.WebSession; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.sql.*; + +import static org.springframework.web.bind.annotation.RequestMethod.POST; + +/** + * @author nbaars + * @since 4/8/17. + */ +@AssignmentPath("SqlInjection/challenge") +@Slf4j +public class SqlInjectionChallenge extends AssignmentEndpoint { + + private static final String PASSWORD_TOM = "thisisasecretfortomonly"; + //Make it more random at runtime (good luck guessing) + private static final String USERS_TABLE_NAME = "challenge_users_6" + RandomStringUtils.randomAlphabetic(16); + + @Autowired + private WebSession webSession; + + public SqlInjectionChallenge() { + log.info("Challenge 6 tablename is: {}", USERS_TABLE_NAME); + } + + @PutMapping //assignment path is bounded to class so we use different http method :-) + @ResponseBody + public AttackResult registerNewUser(@RequestParam String username_reg, @RequestParam String email_reg, @RequestParam String password_reg) throws Exception { + AttackResult attackResult = checkArguments(username_reg, email_reg, password_reg); + + if (attackResult == null) { + Connection connection = DatabaseUtilities.getConnection(webSession); + checkDatabase(connection); + + String checkUserQuery = "select userid from " + USERS_TABLE_NAME + " where userid = '" + username_reg + "'"; + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery(checkUserQuery); + + if (resultSet.next()) { + attackResult = failed().feedback("user.exists").feedbackArgs(username_reg).build(); + } else { + PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO " + USERS_TABLE_NAME + " VALUES (?, ?, ?)"); + preparedStatement.setString(1, username_reg); + preparedStatement.setString(2, email_reg); + preparedStatement.setString(3, password_reg); + preparedStatement.execute(); + attackResult = success().feedback("user.created").feedbackArgs(username_reg).build(); + } + } + return attackResult; + } + + private AttackResult checkArguments(String username_reg, String email_reg, String password_reg) { + if (StringUtils.isEmpty(username_reg) || StringUtils.isEmpty(email_reg) || StringUtils.isEmpty(password_reg)) { + return failed().feedback("input.invalid").build(); + } + if (username_reg.length() > 250 || email_reg.length() > 30 || password_reg.length() > 30) { + return failed().feedback("input.invalid").build(); + } + return null; + } + + @RequestMapping(method = POST) + @ResponseBody + public AttackResult login(@RequestParam String username_login, @RequestParam String password_login) throws Exception { + Connection connection = DatabaseUtilities.getConnection(webSession); + checkDatabase(connection); + + PreparedStatement statement = connection.prepareStatement("select password from " + USERS_TABLE_NAME + " where userid = ? and password = ?"); + statement.setString(1, username_login); + statement.setString(2, password_login); + ResultSet resultSet = statement.executeQuery(); + + if (resultSet.next() && "tom".equals(username_login)) { + return success().build(); + } else { + return failed().feedback("NoResultsMatched").build(); + } + } + + private void checkDatabase(Connection connection) throws SQLException { + try { + Statement statement = connection.createStatement(); + statement.execute("select 1 from " + USERS_TABLE_NAME); + } catch (SQLException e) { + createChallengeTable(connection); + } + } + + private void createChallengeTable(Connection connection) { + Statement statement = null; + try { + statement = connection.createStatement(); + String dropTable = "DROP TABLE " + USERS_TABLE_NAME; + statement.executeUpdate(dropTable); + } catch (SQLException e) { + log.info("Delete failed, this does not point to an error table might not have been present..."); + } + log.debug("Challenge 6 - Creating tables for users {}", USERS_TABLE_NAME); + try { + String createTableStatement = "CREATE TABLE " + USERS_TABLE_NAME + + " (" + "userid varchar(250)," + + "email varchar(30)," + + "password varchar(30)" + + ")"; + statement.executeUpdate(createTableStatement); + + String insertData1 = "INSERT INTO " + USERS_TABLE_NAME + " VALUES ('larry', 'larry@webgoat.org', 'larryknows')"; + String insertData2 = "INSERT INTO " + USERS_TABLE_NAME + " VALUES ('tom', 'tom@webgoat.org', '" + PASSWORD_TOM + "')"; + String insertData3 = "INSERT INTO " + USERS_TABLE_NAME + " VALUES ('alice', 'alice@webgoat.org', 'rt*(KJ()LP())$#**')"; + String insertData4 = "INSERT INTO " + USERS_TABLE_NAME + " VALUES ('eve', 'eve@webgoat.org', '**********')"; + statement.executeUpdate(insertData1); + statement.executeUpdate(insertData2); + statement.executeUpdate(insertData3); + statement.executeUpdate(insertData4); + } catch (SQLException e) { + log.error("Unable create table", e); + } + } + +} + diff --git a/webgoat-lessons/sql-injection/src/main/resources/css/challenge.css b/webgoat-lessons/sql-injection/src/main/resources/css/challenge.css new file mode 100644 index 000000000..6a8635ae6 --- /dev/null +++ b/webgoat-lessons/sql-injection/src/main/resources/css/challenge.css @@ -0,0 +1,96 @@ +.panel-login { + border-color: #ccc; + -webkit-box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.2); + -moz-box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.2); + box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.2); +} +.panel-login>.panel-heading { + color: #00415d; + background-color: #fff; + border-color: #fff; + text-align:center; +} +.panel-login>.panel-heading a{ + text-decoration: none; + color: #666; + font-weight: bold; + font-size: 15px; + -webkit-transition: all 0.1s linear; + -moz-transition: all 0.1s linear; + transition: all 0.1s linear; +} +.panel-login>.panel-heading a.active{ + color: #029f5b; + font-size: 18px; +} +.panel-login>.panel-heading hr{ + margin-top: 10px; + margin-bottom: 0px; + clear: both; + border: 0; + height: 1px; + background-image: -webkit-linear-gradient(left,rgba(0, 0, 0, 0),rgba(0, 0, 0, 0.15),rgba(0, 0, 0, 0)); + background-image: -moz-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0)); + background-image: -ms-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0)); + background-image: -o-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0)); +} +.panel-login input[type="text"],.panel-login input[type="email"],.panel-login input[type="password"] { + height: 45px; + border: 1px solid #ddd; + font-size: 16px; + -webkit-transition: all 0.1s linear; + -moz-transition: all 0.1s linear; + transition: all 0.1s linear; +} +.panel-login input:hover, +.panel-login input:focus { + outline:none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + border-color: #ccc; +} +.btn-login { + background-color: #59B2E0; + outline: none; + color: #fff; + font-size: 14px; + height: auto; + font-weight: normal; + padding: 14px 0; + text-transform: uppercase; + border-color: #59B2E6; +} +.btn-login:hover, +.btn-login:focus { + color: #fff; + background-color: #53A3CD; + border-color: #53A3CD; +} +.forgot-password { + text-decoration: underline; + color: #888; +} +.forgot-password:hover, +.forgot-password:focus { + text-decoration: underline; + color: #666; +} + +.btn-register { + background-color: #1CB94E; + outline: none; + color: #fff; + font-size: 14px; + height: auto; + font-weight: normal; + padding: 14px 0; + text-transform: uppercase; + border-color: #1CB94A; +} +.btn-register:hover, +.btn-register:focus { + color: #fff; + background-color: #1CA347; + border-color: #1CA347; +} diff --git a/webgoat-lessons/sql-injection/src/main/resources/html/SqlInjectionAdvanced.html b/webgoat-lessons/sql-injection/src/main/resources/html/SqlInjectionAdvanced.html index 3c4a1d6ec..a4b749dc6 100644 --- a/webgoat-lessons/sql-injection/src/main/resources/html/SqlInjectionAdvanced.html +++ b/webgoat-lessons/sql-injection/src/main/resources/html/SqlInjectionAdvanced.html @@ -52,34 +52,115 @@
- - -