Skip to content

Commit

Permalink
Tests for union based sql injection (#444)
Browse files Browse the repository at this point in the history
* Add first version of unit tests for union based sql injection vulnerability

* Added tests for the UnionBasedSQLInjction

Co-authored-by: Paul Weber <[email protected]>
  • Loading branch information
000panther and Paul Weber authored Sep 15, 2023
1 parent ecfe0a0 commit 571108b
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.sasanlabs.service.vulnerability.sqlInjection;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import org.sasanlabs.internal.utility.LevelConstants;
import org.sasanlabs.internal.utility.Variant;
Expand All @@ -25,10 +27,10 @@
value = "UnionBasedSQLInjectionVulnerability")
public class UnionBasedSQLInjectionVulnerability {

private JdbcTemplate applicationJdbcTemplate;
private final JdbcTemplate applicationJdbcTemplate;

public UnionBasedSQLInjectionVulnerability(
@Qualifier("applicationJdbcTemplate") JdbcTemplate applicationJdbcTemplate) {
@Qualifier("applicationJdbcTemplate") final JdbcTemplate applicationJdbcTemplate) {
this.applicationJdbcTemplate = applicationJdbcTemplate;
}

Expand All @@ -40,19 +42,10 @@ public UnionBasedSQLInjectionVulnerability(
value = LevelConstants.LEVEL_1,
htmlTemplate = "LEVEL_1/SQLInjection_Level1")
public ResponseEntity<CarInformation> getCarInformationLevel1(
@RequestParam Map<String, String> queryParams) {
String id = queryParams.get("id");
@RequestParam final Map<String, String> queryParams) {
final String id = queryParams.get("id");
return applicationJdbcTemplate.query(
"select * from cars where id=" + id,
(rs) -> {
CarInformation carInformation = new CarInformation();
if (rs.next()) {
carInformation.setId(rs.getInt(1));
carInformation.setName(rs.getString(2));
carInformation.setImagePath(rs.getString(3));
}
return new ResponseEntity<CarInformation>(carInformation, HttpStatus.OK);
});
"select * from cars where id=" + id, this::resultSetToResponse);
}

@AttackVector(
Expand All @@ -64,19 +57,10 @@ public ResponseEntity<CarInformation> getCarInformationLevel1(
value = LevelConstants.LEVEL_2,
htmlTemplate = "LEVEL_1/SQLInjection_Level1")
public ResponseEntity<CarInformation> getCarInformationLevel2(
@RequestParam Map<String, String> queryParams) {
String id = queryParams.get("id");
CarInformation carInformation = new CarInformation();
@RequestParam final Map<String, String> queryParams) {
final String id = queryParams.get("id");
return applicationJdbcTemplate.query(
"select * from cars where id='" + id + "'",
(rs) -> {
if (rs.next()) {
carInformation.setId(rs.getInt(1));
carInformation.setName(rs.getString(2));
carInformation.setImagePath(rs.getString(3));
}
return new ResponseEntity<CarInformation>(carInformation, HttpStatus.OK);
});
"select * from cars where id='" + id + "'", this::resultSetToResponse);
}

@AttackVector(
Expand All @@ -88,42 +72,34 @@ public ResponseEntity<CarInformation> getCarInformationLevel2(
variant = Variant.SECURE,
htmlTemplate = "LEVEL_1/SQLInjection_Level1")
public ResponseEntity<CarInformation> getCarInformationLevel3(
@RequestParam Map<String, String> queryParams) {
String id = queryParams.get("id").replaceAll("'", "");
@RequestParam final Map<String, String> queryParams) {
final String id = queryParams.get("id").replaceAll("'", "");
return applicationJdbcTemplate.query(
"select * from cars where id='" + id + "'",
(rs) -> {
CarInformation carInformation = new CarInformation();
if (rs.next()) {
carInformation.setId(rs.getInt(1));
carInformation.setName(rs.getString(2));
carInformation.setImagePath(rs.getString(3));
}
return new ResponseEntity<CarInformation>(carInformation, HttpStatus.OK);
});
"select * from cars where id='" + id + "'", this::resultSetToResponse);
}

@VulnerableAppRequestMapping(
value = LevelConstants.LEVEL_4,
variant = Variant.SECURE,
htmlTemplate = "LEVEL_1/SQLInjection_Level1")
public ResponseEntity<CarInformation> getCarInformationLevel4(
@RequestParam Map<String, String> queryParams) {
String id = queryParams.get("id");
@RequestParam final Map<String, String> queryParams) {
final String id = queryParams.get("id");

return applicationJdbcTemplate.query(
"select * from cars where id=?",
(prepareStatement) -> {
prepareStatement.setString(1, id);
},
(rs) -> {
CarInformation carInformation = new CarInformation();
if (rs.next()) {
carInformation.setId(rs.getInt(1));
carInformation.setName(rs.getString(2));
carInformation.setImagePath(rs.getString(3));
}
return new ResponseEntity<CarInformation>(carInformation, HttpStatus.OK);
});
prepareStatement -> prepareStatement.setString(1, id),
this::resultSetToResponse);
}

private ResponseEntity<CarInformation> resultSetToResponse(final ResultSet rs)
throws SQLException {
final CarInformation carInformation = new CarInformation();
if (rs.next()) {
carInformation.setId(rs.getInt(1));
carInformation.setName(rs.getString(2));
carInformation.setImagePath(rs.getString(3));
}
return new ResponseEntity<>(carInformation, HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package org.sasanlabs.service.vulnerability.sqlInjection;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;

import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.jdbc.core.ResultSetExtractor;

class UnionBasedSQLInjectionVulnerabilityTest {

private UnionBasedSQLInjectionVulnerability unionBasedSQLInjectionVulnerability;
private JdbcTemplate template;

@BeforeEach
void setUp() throws IOException {
template = Mockito.mock(JdbcTemplate.class);

// mock database
doReturn(null)
.when(template)
.query(anyString(), (ResultSetExtractor<? extends Object>) any());
doReturn(null)
.when(template)
.query(
anyString(),
(PreparedStatementSetter) any(),
(ResultSetExtractor<? extends Object>) any());

unionBasedSQLInjectionVulnerability = new UnionBasedSQLInjectionVulnerability(template);
}

@Test
void getCarInformationLevel1_ExpectParamInjected() throws IOException {
// Act
final Map<String, String> params =
Collections.singletonMap("id", "1 UNION SELECT * FROM cars;");
unionBasedSQLInjectionVulnerability.getCarInformationLevel1(params);

// Assert
verify(template)
.query(
eq("select * from cars where id=1 UNION SELECT * FROM cars;"),
(ResultSetExtractor<? extends Object>) any());
}

@Test
void getCarInformationLevel2_ExpectParamInjected() throws IOException {
// Act
final Map<String, String> params =
Collections.singletonMap("id", "1' UNION SELECT * FROM cars; --");
unionBasedSQLInjectionVulnerability.getCarInformationLevel2(params);

// Assert
verify(template)
.query(
eq("select * from cars where id='1' UNION SELECT * FROM cars; --'"),
(ResultSetExtractor<? extends Object>) any());
}

@Test
void getCarInformationLevel3_ExpectParamEscaped() throws IOException {
// Act
final Map<String, String> params =
Collections.singletonMap("id", "1' UNION SELECT * FROM cars; --");
unionBasedSQLInjectionVulnerability.getCarInformationLevel3(params);

// Assert
verify(template)
.query(
eq("select * from cars where id='1 UNION SELECT * FROM cars; --'"),
(ResultSetExtractor<? extends Object>) any());
}

@Test
void getCarInformationLevel4_ExpecParamEscaped() throws IOException {
// Act
final Map<String, String> params =
Collections.singletonMap("id", "1' UNION SELECT * FROM cars; --");
unionBasedSQLInjectionVulnerability.getCarInformationLevel4(params);

// Assert
verify(template)
.query(
eq("select * from cars where id=?"),
(PreparedStatementSetter) any(),
(ResultSetExtractor<? extends Object>) any());
}
}

0 comments on commit 571108b

Please sign in to comment.