diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..1aff237 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +target/ +.git/ +.idea/ +*.iml +mise.toml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e0c7a68 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,51 @@ +# Stage 1: build the WAR using Java 8 + Maven +FROM maven:3.9-eclipse-temurin-8 AS build + +WORKDIR /build +COPY pom.xml . +COPY src ./src + +RUN mvn install -Dversion.webxml=30 -DskipTests -q + +# --------------------------------------------------------------------------- +# Stage 2: runtime — Tomcat 9 + JRE 8 +# --------------------------------------------------------------------------- +FROM tomcat:9-jre8-temurin AS runtime + +# Remove default webapps +RUN rm -rf "$CATALINA_HOME/webapps/ROOT" \ + "$CATALINA_HOME/webapps/docs" \ + "$CATALINA_HOME/webapps/examples" \ + "$CATALINA_HOME/webapps/host-manager" \ + "$CATALINA_HOME/webapps/manager" + +# Copy and pre-explode the WAR so the entrypoint can edit conf/ on disk +COPY --from=build /build/target/spiracle.war /tmp/spiracle.war +RUN apt-get update -qq && apt-get install -y --no-install-recommends unzip && rm -rf /var/lib/apt/lists/* \ + && mkdir -p "$CATALINA_HOME/webapps/spiracle" \ + && unzip -q /tmp/spiracle.war -d "$CATALINA_HOME/webapps/spiracle" \ + && rm /tmp/spiracle.war + +# ---- JDBC drivers (downloaded at image build time from Maven Central) ---- + +# MySQL Connector/J 5.1.49 — has com.mysql.jdbc.Driver (legacy classname) +RUN curl -fsSL \ + "https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.49/mysql-connector-java-5.1.49.jar" \ + -o "$CATALINA_HOME/lib/mysql-connector-java-5.1.49.jar" + +# MSSQL JDBC — jre8 classifier +RUN curl -fsSL \ + "https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/12.4.2.jre8/mssql-jdbc-12.4.2.jre8.jar" \ + -o "$CATALINA_HOME/lib/mssql-jdbc-12.4.2.jre8.jar" + +# Oracle ojdbc8 — Java 8 compatible +RUN curl -fsSL \ + "https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc8/21.13.0.0/ojdbc8-21.13.0.0.jar" \ + -o "$CATALINA_HOME/lib/ojdbc8-21.13.0.0.jar" + +# ---- entrypoint ---- +COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh + +EXPOSE 8080 +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] diff --git a/README.adoc b/README.adoc index 73ecd73..7fe5825 100644 --- a/README.adoc +++ b/README.adoc @@ -1,6 +1,6 @@ = Spiracle -Spiracle is an insecure web application used to test system security controls. +Spiracle is an insecure web application used to test system security controls. It can be used to read/write arbitrary files and open network connections. The application is also vulnerable to numerous other vulnerabilities such as: @@ -12,7 +12,7 @@ The application is also vulnerable to numerous other vulnerabilities such as: * Deserialization (CWE-502) * and many more... -CAUTION: Due to its insecure design, this application should NOT be deployed on an unsecured network or system. +CAUTION: Due to its insecure design, this application should NOT be deployed on an unsecured network or system. Run on localhost or throwaway networks only. This application has been tested on the following application servers: @@ -21,6 +21,35 @@ This application has been tested on the following application servers: Your mileage may vary with other application servers. +== Docker (quickstart) + +The fastest way to run Spiracle. No local Tomcat or database install needed. + +Pick a database and run its compose file from the repo root: + +---- +# MySQL (smallest image — recommended for first run) +$ docker compose -f docker-compose.mysql.yml up --build + +# Microsoft SQL Server (~1.5 GB image) +$ docker compose -f docker-compose.mssql.yml up --build + +# Oracle XE (~2–4 GB image; first pull takes several minutes) +$ docker compose -f docker-compose.oracle.yml up --build +---- + +Once healthy, browse to: http://localhost:8080/spiracle/ + +Tear down (removes volumes): + +---- +$ docker compose -f docker-compose.mysql.yml down -v +---- + +The multi-stage `Dockerfile` builds the WAR with JDK 8 / Maven and deploys it on Tomcat 9. MySQL, MSSQL, and Oracle JDBC drivers are bundled in the image; `docker/entrypoint.sh` rewrites `conf/Spiracle.properties` from environment variables at startup. + +Full Docker reference: link:docker/README.md[docker/README.md] + == Installation * Download pre-built `spiracle.war` file from the releases page: https://github.com/waratek/spiracle/releases @@ -54,22 +83,24 @@ $ jar xvf /path/to/downloaded/spiracle.war - - httpPort="9080" + httpPort="9080" httpsPort="9443"/> ---- + <1> Enable `Servlet-3.0` as a feature <2> Add a `webApplication` tag referencing Spiracle -<3> Change `httpSession` parameter length +<3> Change `httpSession` parameter length <4> Add a `host` attribute === Database setup If you would like to run the SQL injection tests, the database should be populated as follows. Data files are available in the web applications `spiracle/conf/` directory after the `spiracle.war` file has been deployed and exploded. +NOTE: When using Docker, database initialisation is handled automatically by the compose stack. Manual setup is only needed for bare-metal deployments. + ==== Oracle . Ensure that the link:http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-112010-090769.html[Oracle Database JDBC Driver] (ojdbc6.jar) is installed in the applications `WEB-INF/lib/` directory after the `spiracle.war` file is exploded on first run. @@ -124,23 +155,72 @@ Properties file can be overridden when submitting the request by appending the n &connectionType=c3p0.mysql ---- +== Testing + +Spiracle ships with a link:tests/hurl/README.md[Hurl] test harness under `tests/hurl/`. Tests are endpoint-based and run against any deployment (Docker or bare-metal). + +=== Suites + +[cols="1,1,3",options="header"] +|=== +|Suite |Agent required |What it covers + +|`smoke/` +|No +|App root responds 200; benign query returns data; unblocked SQLi widens result set (confirming injections succeed without agent) + +|`functional/` +|No +|SendRedirect, SQL queries, reflected XSS via `customTag.jsp`, path traversal, 404/empty-result/no-param negative cases + +|`rasp/` +|Yes (Waratek RASP) +|440-case SQL injection matrix (139 MySQL, 301 Oracle); asserts status `550`, which is only emitted when the Waratek agent intercepts the query +|=== + +=== Quick run (plain Docker stack) + +---- +# Bring up MySQL stack +$ docker compose -f docker-compose.mysql.yml up -d + +# Smoke +$ ./tests/hurl/run.sh smoke localhost 8080 + +# Functional +$ ./tests/hurl/run.sh functional localhost 8080 +---- + +The `rasp/` suite will fail on a plain deployment — expected. Run it only with the Waratek agent attached to Tomcat. + +Full harness reference: link:tests/hurl/README.md[tests/hurl/README.md] + == Building Prerequisites: -* Java >= 1.6 +* Java 5–8 (see toolchain note below) * Apache Maven * link:http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-112010-090769.html[Oracle Database JDBC Driver] (ojdbc6.jar) If you wish to use the database features, ensure that the Oracle database JDBC driver file `ojdbc6.jar` is available under `./src/main/webapp/WEB-INF/lib` -To build the Spiracle Test Application WAR file, run: +=== Build flags + +Two flags parameterise the build: - $ mvn install -Dversion.webxml=30 +`-Dversion.jdk=`:: Sets the Java source and target compiler level. Supported values on `master`: `1.5`, `1.6`, `1.7`, `1.8`. +`-Dversion.webxml=<25|30>`:: Selects the Servlet descriptor version (2.5 or 3.0). -or +Representative invocations: - $ mvn install -Dversion.webxml=25 +---- +# Java 8, Servlet 3.0 (recommended) +$ mvn install -Dversion.jdk=1.8 -Dversion.webxml=30 + +# Java 6, Servlet 2.5 +$ mvn install -Dversion.jdk=1.6 -Dversion.webxml=25 +---- To clean the build infrastructure, run: @@ -150,6 +230,28 @@ The WAR file will be output to: ./target/spiracle.war +=== Toolchain + +The repo carries a `mise.toml` pinning Temurin 8 and Maven 3.9. With link:https://mise.jdx.dev[mise] installed: + +---- +$ mise install # installs pinned JDK + Maven +$ mvn install -Dversion.jdk=1.8 -Dversion.webxml=30 +---- + +The Docker image pins its own JDK via its base image — no local JDK is needed when building through Docker. + +=== Branch model + +`master`:: Modern, parameterised source tree. Java 5–8 source level. Use `-Dversion.jdk` to select. +`java4`:: Java-1.4-source-compatible variant. Annotations replaced by `web.xml` registration; uses a legacy dependency set. Check out this branch if you need Java 4 compatibility. + +== Recent fixes + +* *#8* — `Content-Type: text/plain` is now set on the `SendRedirect` fallback response (no-parameter case). +* *#33* — `setupdb_mysql.sql` is idempotent; uses `IF [NOT] EXISTS` guards so re-running does not error. +* *#103* — Oracle connection NPE fixed in `CreateC3p0Connection`; was reading non-existent property keys from `Spiracle.properties`. + == License ---- @@ -167,4 +269,3 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ---- - diff --git a/docker-compose.mssql.yml b/docker-compose.mssql.yml new file mode 100644 index 0000000..a59bd62 --- /dev/null +++ b/docker-compose.mssql.yml @@ -0,0 +1,52 @@ +services: + db: + image: mcr.microsoft.com/mssql/server:2022-latest + environment: + ACCEPT_EULA: "Y" + SA_PASSWORD: "Spiracle_SA_2024!" + MSSQL_PID: Developer + healthcheck: + test: + - "CMD-SHELL" + - | + /opt/mssql-tools18/bin/sqlcmd -S localhost -U SA -P 'Spiracle_SA_2024!' \ + -No -Q 'SELECT 1' > /dev/null 2>&1 + interval: 10s + timeout: 5s + retries: 15 + start_period: 30s + + db-init: + image: mcr.microsoft.com/mssql/server:2022-latest + environment: + SA_PASSWORD: "Spiracle_SA_2024!" + volumes: + - ./src/main/webapp/conf/setupdb_mssql.sql:/init/setupdb_mssql.sql:ro + - ./docker/mssql-create-login.sql:/init/mssql-create-login.sql:ro + depends_on: + db: + condition: service_healthy + entrypoint: + - /bin/bash + - -c + - | + /opt/mssql-tools18/bin/sqlcmd -S db -U SA -P "$$SA_PASSWORD" -No \ + -i /init/setupdb_mssql.sql && \ + /opt/mssql-tools18/bin/sqlcmd -S db -U SA -P "$$SA_PASSWORD" -No \ + -d spiracle -i /init/mssql-create-login.sql + restart: "no" + + app: + build: + context: . + dockerfile: Dockerfile + ports: + - "8080:8080" + environment: + SPIRACLE_DEFAULT_CONNECTION: c3p0.mssql + SPIRACLE_DB_HOST: db + depends_on: + db: + condition: service_healthy + db-init: + condition: service_completed_successfully diff --git a/docker-compose.mysql.yml b/docker-compose.mysql.yml new file mode 100644 index 0000000..e3b259a --- /dev/null +++ b/docker-compose.mysql.yml @@ -0,0 +1,33 @@ +services: + db: + image: mysql:8.0 + command: --default-authentication-plugin=mysql_native_password + environment: + MYSQL_ROOT_PASSWORD: rootpassword + MYSQL_DATABASE: test + MYSQL_USER: test + MYSQL_PASSWORD: test + volumes: + # Seed SQL mounted outside initdb.d so the shell script controls execution + - ./src/main/webapp/conf/setupdb_mysql.sql:/init/setupdb_mysql.sql:ro + # Shell script in initdb.d runs seed with --force (bare DROPs on fresh DB) + - ./docker/mysql-seed.sh:/docker-entrypoint-initdb.d/01-seed.sh:ro + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "--password=rootpassword"] + interval: 10s + timeout: 5s + retries: 10 + start_period: 30s + + app: + build: + context: . + dockerfile: Dockerfile + ports: + - "8080:8080" + environment: + SPIRACLE_DEFAULT_CONNECTION: c3p0.mysql + SPIRACLE_DB_HOST: db + depends_on: + db: + condition: service_healthy diff --git a/docker-compose.oracle.yml b/docker-compose.oracle.yml new file mode 100644 index 0000000..a845e43 --- /dev/null +++ b/docker-compose.oracle.yml @@ -0,0 +1,29 @@ +services: + db: + image: gvenzl/oracle-xe:21-slim + environment: + ORACLE_PASSWORD: oraclepassword + APP_USER: test + APP_USER_PASSWORD: test + volumes: + - ./src/main/webapp/conf/setupdb_oracle.sql:/container-entrypoint-initdb.d/setupdb_oracle.sql:ro + healthcheck: + test: ["CMD", "healthcheck.sh"] + interval: 30s + timeout: 10s + retries: 20 + start_period: 120s + + app: + build: + context: . + dockerfile: Dockerfile + ports: + - "8080:8080" + environment: + SPIRACLE_DEFAULT_CONNECTION: c3p0.oracle + # gvenzl runs initdb scripts in the PDB (XEPDB1); use service-name URL form + SPIRACLE_DB_URL: "jdbc:oracle:thin:@//db:1521/XEPDB1" + depends_on: + db: + condition: service_healthy diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..02461aa --- /dev/null +++ b/docker/README.md @@ -0,0 +1,67 @@ +# Spiracle — Docker usage + +**WARNING: Spiracle is an intentionally-vulnerable application. Run on localhost / throwaway networks only. Never expose to the internet.** + +## Prerequisites + +- Docker Engine 24+ with the Compose v2 plugin (`docker compose`) +- No local Tomcat or database installation needed + +## Quick start + +Pick one database and run the corresponding compose file from the repo root. + +### MySQL (recommended for first run — smallest image) + +```sh +docker compose -f docker-compose.mysql.yml up --build +``` + +Browse to: http://localhost:8080/spiracle/ + +Tear down (removes volumes): +```sh +docker compose -f docker-compose.mysql.yml down -v +``` + +### Microsoft SQL Server + +```sh +docker compose -f docker-compose.mssql.yml up --build +``` + +SQL Server image (~1.5 GB). A one-shot `db-init` service seeds the database after SQL Server becomes healthy. + +Browse to: http://localhost:8080/spiracle/ + +```sh +docker compose -f docker-compose.mssql.yml down -v +``` + +### Oracle XE + +```sh +docker compose -f docker-compose.oracle.yml up --build +``` + +Oracle XE image (~2–4 GB). First pull takes several minutes. The container has a long startup; wait for the `db` service to show `healthy` before the app becomes ready. + +Browse to: http://localhost:8080/spiracle/ + +```sh +docker compose -f docker-compose.oracle.yml down -v +``` + +## How it works + +- A multi-stage Dockerfile builds the WAR with JDK 8 / Maven, then deploys it on Tomcat 9. +- MySQL (Connector/J 5.1.49), MSSQL (mssql-jdbc jre8) and Oracle (ojdbc8) JDBC drivers are bundled in the image. +- `docker/entrypoint.sh` rewrites `conf/Spiracle.properties` from environment variables before Tomcat starts. The committed `Spiracle.properties` is never modified. + +## Environment variables (app service) + +| Variable | Purpose | Example | +|---|---|---| +| `SPIRACLE_DEFAULT_CONNECTION` | Sets `default.connection` in properties | `c3p0.mysql` | +| `SPIRACLE_DB_HOST` | Replaces `localhost` in the chosen db URL | `db` | +| `SPIRACLE_DB_URL` | Overrides the entire URL line (Oracle service-name form) | `jdbc:oracle:thin:@//db:1521/XEPDB1` | diff --git a/docker/docker-grants-mysql.sql b/docker/docker-grants-mysql.sql new file mode 100644 index 0000000..4aef196 --- /dev/null +++ b/docker/docker-grants-mysql.sql @@ -0,0 +1,6 @@ +-- Docker-only: grant remote access for the 'test' user created by setupdb_mysql.sql. +-- setupdb_mysql.sql creates 'test'@'localhost'; that cannot connect from the app container. +-- This file runs AFTER setupdb_mysql.sql (lexicographic order ensures 0-prefix runs first). +CREATE USER IF NOT EXISTS 'test'@'%' IDENTIFIED BY 'test'; +GRANT ALL PRIVILEGES ON *.* TO 'test'@'%' WITH GRANT OPTION; +FLUSH PRIVILEGES; diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 0000000..e52039c --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,27 @@ +#!/bin/sh +# Rewrite Spiracle.properties from env vars before Tomcat starts. +# All changes are made to the exploded webapp copy only — source files untouched. + +PROPS="$CATALINA_HOME/webapps/spiracle/conf/Spiracle.properties" + +# SPIRACLE_DEFAULT_CONNECTION — e.g. "c3p0.mysql" +if [ -n "$SPIRACLE_DEFAULT_CONNECTION" ]; then + sed -i "s|^default\.connection=.*|default.connection=${SPIRACLE_DEFAULT_CONNECTION}|" "$PROPS" +fi + +# Derive the db key from the connection name (e.g. c3p0.mysql → mysql) +if [ -n "$SPIRACLE_DEFAULT_CONNECTION" ]; then + DB_KEY="${SPIRACLE_DEFAULT_CONNECTION#c3p0.}" +else + DB_KEY="" +fi + +# SPIRACLE_DB_URL — override the whole url line for this db (takes priority) +if [ -n "$SPIRACLE_DB_URL" ] && [ -n "$DB_KEY" ]; then + sed -i "s|^c3p0\.${DB_KEY}\.url=.*|c3p0.${DB_KEY}.url=${SPIRACLE_DB_URL}|" "$PROPS" +elif [ -n "$SPIRACLE_DB_HOST" ] && [ -n "$DB_KEY" ]; then + # Replace only 'localhost' in the specific db url line + sed -i "/^c3p0\.${DB_KEY}\.url=/ s|localhost|${SPIRACLE_DB_HOST}|g" "$PROPS" +fi + +exec "$CATALINA_HOME/bin/catalina.sh" run diff --git a/docker/mssql-create-login.sql b/docker/mssql-create-login.sql new file mode 100644 index 0000000..5c70204 --- /dev/null +++ b/docker/mssql-create-login.sql @@ -0,0 +1,17 @@ +-- Docker-only: create the 'test' login and user that Spiracle.properties expects. +-- setupdb_mssql.sql does not create this login; run this first. +IF NOT EXISTS (SELECT 1 FROM sys.server_principals WHERE name = 'test') +BEGIN + CREATE LOGIN [test] WITH PASSWORD = 'Mssql1234', CHECK_POLICY = OFF; +END +GO + +USE spiracle; +GO + +IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = 'test') +BEGIN + CREATE USER [test] FOR LOGIN [test]; + ALTER ROLE db_owner ADD MEMBER [test]; +END +GO diff --git a/docker/mysql-seed.sh b/docker/mysql-seed.sh new file mode 100644 index 0000000..45c36e8 --- /dev/null +++ b/docker/mysql-seed.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Docker-only init script for MySQL. +# The canonical setupdb_mysql.sql has bare DROP TABLE (no IF EXISTS) which +# errors on a fresh DB. Run it with --force to skip those errors. +set -e + +mysql --force -u root -p"${MYSQL_ROOT_PASSWORD}" < /init/setupdb_mysql.sql + +# Grant remote access for 'test'@'%' so the app container (different host) +# can connect. The canonical seed only creates 'test'@'localhost'. +mysql -u root -p"${MYSQL_ROOT_PASSWORD}" <<'SQL' +CREATE USER IF NOT EXISTS 'test'@'%' IDENTIFIED WITH mysql_native_password BY 'test'; +GRANT ALL PRIVILEGES ON *.* TO 'test'@'%' WITH GRANT OPTION; +FLUSH PRIVILEGES; +SQL diff --git a/src/main/java/com/waratek/spiracle/misc/SendRedirect.java b/src/main/java/com/waratek/spiracle/misc/SendRedirect.java index 2dce521..00d9d17 100644 --- a/src/main/java/com/waratek/spiracle/misc/SendRedirect.java +++ b/src/main/java/com/waratek/spiracle/misc/SendRedirect.java @@ -36,6 +36,7 @@ protected void executeRequest(HttpServletRequest request, HttpServletResponse re response.sendRedirect(redirectURI); } else { + response.setHeader("Content-Type", "text/plain;charset=UTF-8"); response.getWriter().println("Parameter '" + inputUriParam + "' not set in the URI."); response.getWriter().println("Please update URI to include '?" + inputUriParam + "=URI_TO_REDIRECT_TO'"); } diff --git a/src/main/java/com/waratek/spiracle/sql/c3p0/CreateC3p0Connection.java b/src/main/java/com/waratek/spiracle/sql/c3p0/CreateC3p0Connection.java index f8439b8..11bfe56 100644 --- a/src/main/java/com/waratek/spiracle/sql/c3p0/CreateC3p0Connection.java +++ b/src/main/java/com/waratek/spiracle/sql/c3p0/CreateC3p0Connection.java @@ -65,12 +65,16 @@ public void init() { // TODO Auto-generated catch block e.printStackTrace(); } - jdbcDriver = prop.getProperty("c3p0.classname"); - url = prop.getProperty("c3p0.url"); - username = prop.getProperty("c3p0.username"); - password = prop.getProperty("c3p0.password"); + String prefix = prop.getProperty("default.connection"); + if (prefix == null || prefix.trim().isEmpty()) { + prefix = "c3p0.oracle"; + } + jdbcDriver = prop.getProperty(prefix + ".classname"); + url = prop.getProperty(prefix + ".url"); + username = prop.getProperty(prefix + ".username"); + password = prop.getProperty(prefix + ".password"); try { - maxPoolSize = Integer.parseInt(prop.getProperty("c3p0.maxPoolSize")); + maxPoolSize = Integer.parseInt(prop.getProperty(prefix + ".maxPoolSize")); } catch (NumberFormatException e) { maxPoolSize = 25; } diff --git a/src/main/java/com/waratek/spiracle/xss/ReadHTML.java b/src/main/java/com/waratek/spiracle/xss/ReadHTML.java index f192635..ec3647a 100644 --- a/src/main/java/com/waratek/spiracle/xss/ReadHTML.java +++ b/src/main/java/com/waratek/spiracle/xss/ReadHTML.java @@ -14,7 +14,7 @@ static void readHTML(Object out, String taintedInput, ServletRequest req) throws IOException { String line = ""; String XSS = "XSS"; - String htmlFile = req.getServletContext().getRealPath("/") + "xss.html"; + String htmlFile = req.getRealPath("/") + "xss.html"; BufferedReader in = new BufferedReader(new FileReader(htmlFile)); while ((line = in.readLine()) != null) { diff --git a/src/main/webapp/conf/setupdb_mysql.sql b/src/main/webapp/conf/setupdb_mysql.sql index e97603a..ba771b8 100644 --- a/src/main/webapp/conf/setupdb_mysql.sql +++ b/src/main/webapp/conf/setupdb_mysql.sql @@ -1,13 +1,13 @@ -CREATE USER 'test'@'localhost' IDENTIFIED BY 'test'; +CREATE USER IF NOT EXISTS 'test'@'localhost' IDENTIFIED BY 'test'; GRANT ALL PRIVILEGES ON *.* TO 'test'@'localhost' WITH GRANT OPTION; CREATE DATABASE IF NOT EXISTS test; use test; -DROP TABLE users; -DROP TABLE address; -DROP TABLE TEXT_STORE; +DROP TABLE IF EXISTS users; +DROP TABLE IF EXISTS address; +DROP TABLE IF EXISTS TEXT_STORE; CREATE TABLE users ( id int, diff --git a/tests/hurl/README.md b/tests/hurl/README.md new file mode 100644 index 0000000..caa8ceb --- /dev/null +++ b/tests/hurl/README.md @@ -0,0 +1,171 @@ +# Spiracle Hurl Test Harness + +Language-agnostic HTTP tests using [Hurl](https://hurl.dev) (v5+). +Replaces the old `tests/spiracle_sqli_test.py` (Python 2, bespoke `` format). + +--- + +## The critical semantic: 550 requires the Waratek RASP agent + +The number `550` is **not** a standard HTTP status code. +`SelectUtil.verifySQLException` emits it **only** when the SQLException +message is exactly `"Attempted to execute a query with one or more bad +parameters."` — that string is produced by the **Waratek RASP agent** +intercepting the query before it reaches the database. + +**Without the Waratek agent** (e.g. plain Tomcat, CI Docker stack): + +| Payload type | Status code | +|--------------------------|-------------| +| Valid-SQL injection | **200** | +| Malformed/syntax error | **500** | +| Agent-blocked injection | **550** | + +You will **never** see 550 on a plain deployment. +The RASP suite will fail entirely without the agent — this is expected. + +--- + +## Suite layout + +``` +tests/hurl/ +├── generate.py # Generator: mysql.txt + oracle.txt → .hurl files +├── run.sh # Runner wrapper +├── functional/ # Endpoint-level functional suite (no agent required) +│ ├── local.env # Variables: host=localhost, port=8080 +│ ├── redirect.hurl # 2 tests: SendRedirect regression (#8 Content-Type fix) +│ ├── sql.hurl # 5 tests: benign queries + unprotected SQLi demo +│ ├── xss.hurl # 2 tests: reflected XSS via customTag.jsp +│ ├── traversal.hurl # 4 tests: benign file + path traversal demo +│ └── negative.hurl # 3 tests: 404, empty result set, no-param graceful +├── rasp/ # RASP-efficacy suite (needs Waratek agent) +│ ├── protected.env # Variables: host, port, block_status=550 +│ ├── mysql/ # MySQL servlet tests (139 cases, 5 files) +│ │ ├── get_int.hurl +│ │ ├── get_string.hurl +│ │ ├── get_union.hurl +│ │ ├── get_implicit_join.hurl +│ │ └── implicit_join_namespace.hurl +│ └── oracle/ # Oracle servlet tests (301 cases, 12 files) +│ ├── get_int.hurl +│ ├── get_string.hurl +│ └── ... +└── smoke/ # Smoke suite (no agent required) + ├── local.env # Variables: host=localhost, port=8080 + └── smoke.hurl # 3 tests: up-check, benign query, SQLi succeeds +``` + +Source of truth for the RASP payload matrices: +- `tests/mysql.txt` (139 cases) +- `tests/oracle.txt` (301 cases) + +--- + +## Running the functional suite (plain Docker / CI) + +The functional suite validates endpoint behaviour without any RASP agent: + +| File | Requests | What it covers | +|------------------|----------|----------------| +| `redirect.hurl` | 2 | SendRedirect: no-param→200+text/plain (#8 regression); param→302+Location | +| `sql.hurl` | 5 | MySql_Get_int, MySql_Get_string, MySql_Get_Implicit_Join (benign + SQLi), MySql_Get_Union | +| `xss.hurl` | 2 | customTag.jsp benign name; `` reflected unescaped | +| `traversal.hurl` | 4 | FileInputStreamServlet01 benign TestFile; `../TestFile` traversal succeeds | +| `negative.hurl` | 3 | 404 on unknown path; empty result set; no-param graceful 200 | + +```sh +# Start the Docker MySQL stack +docker compose -f docker-compose.mysql.yml up -d + +# Run functional tests +./tests/hurl/run.sh functional localhost 8080 + +# Or with hurl directly +hurl --test --variables-file tests/hurl/functional/local.env \ + tests/hurl/functional/*.hurl +``` + +**XSS note:** The ReadHTML-based servlets (`XSSWebAppHSRPW` etc.) do NOT reflect +the `taintedtext` param because `xss.html` contains no literal `"XSS"` token. +`customTag.jsp` is the GET-accessible reflected-XSS endpoint used here. + +--- + +## Running the smoke suite (plain Docker / CI) + +The smoke suite validates: +1. App root responds `200` +2. `GET /spiracle/MySql_Get_string?name=Patrick` → `200`, body contains `Moss` +3. SQLi payload widens the result set (body contains `Thomas`) → `200` + (documenting that injections are NOT blocked without the agent) + +```sh +# Start the Docker MySQL stack +docker compose -f docker-compose.mysql.yml up -d + +# Run smoke tests +./tests/hurl/run.sh smoke localhost 8080 + +# Or with hurl directly +hurl --test --variables-file tests/hurl/smoke/local.env \ + tests/hurl/smoke/smoke.hurl +``` + +--- + +## Running the RASP suite (Waratek agent required) + +```sh +# With agent attached to Tomcat: +./tests/hurl/run.sh rasp localhost 8080 + +# Override host/port: +./tests/hurl/run.sh rasp myserver.internal 9090 + +# Override expected block status (if agent uses a different code): +BLOCK_STATUS=403 ./tests/hurl/run.sh rasp localhost 8080 + +# Run a single servlet's cases: +hurl --test \ + --variables-file tests/hurl/rasp/protected.env \ + tests/hurl/rasp/mysql/get_int.hurl +``` + +Reports are written as JUnit XML to `/tmp/spiracle-{smoke,rasp}-report/junit.xml`. +Override with `REPORT_DIR=/path/to/dir ./tests/hurl/run.sh ...`. + +--- + +## Regenerating the .hurl files + +If `mysql.txt` or `oracle.txt` are updated, regenerate: + +```sh +python3 tests/hurl/generate.py +``` + +The generator: +- Reads `tests/mysql.txt` and `tests/oracle.txt` (one case per line, `` delimiter) +- Groups cases by servlet path +- Encodes URL-illegal characters (`space`, `|`, `"`, `<`, `>`) in query strings +- Emits `status == {{block_status}}` for 550-expected cases (variable-driven) +- Emits `status == 200` (literal) for the one benign probe case in mysql.txt +- Overwrites all files under `tests/hurl/rasp/` + +Commit the regenerated files — the suite must run without needing to regenerate. + +--- + +## Hurl assertion form used + +`HTTP {{var}}` in the status line is **not** valid in Hurl 5.x. +All files use the `[Asserts]` form: + +``` +HTTP * +[Asserts] +status == {{block_status}} +``` + +This was verified against Hurl 5.0.1 before committing. diff --git a/tests/hurl/functional/local.env b/tests/hurl/functional/local.env new file mode 100644 index 0000000..0182d07 --- /dev/null +++ b/tests/hurl/functional/local.env @@ -0,0 +1,2 @@ +host=localhost +port=8080 diff --git a/tests/hurl/functional/negative.hurl b/tests/hurl/functional/negative.hurl new file mode 100644 index 0000000..4fd3108 --- /dev/null +++ b/tests/hurl/functional/negative.hurl @@ -0,0 +1,29 @@ +# negative.hurl — boundary and error cases. +# +# These cases verify that the app responds deterministically to invalid +# or missing inputs, providing a stable baseline for regression. + +# ── 1. Non-existent servlet path → 404 ─────────────────────────────── +GET http://{{host}}:{{port}}/spiracle/NoSuchServletXYZ + +HTTP 404 + +# ── 2. MySql_Get_string with unknown name → 200, empty results ─────── +# No rows match name='NoSuchUser99'; the app still returns 200 with an +# empty result table (no error, no crash). +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=NoSuchUser99 + +HTTP 200 +[Asserts] +body contains "Results" +# App echoes param in SQL query preview but no rows should appear +body not contains "NoSuchUser99" + +# ── 3. MySql_Get_int with no param → 200, empty results ───────────── +# ParameterNullFix sanitises null to empty string; the SQL query +# WHERE id = '' returns zero rows — app handles gracefully. +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int + +HTTP 200 +[Asserts] +body contains "Results" diff --git a/tests/hurl/functional/redirect.hurl b/tests/hurl/functional/redirect.hurl new file mode 100644 index 0000000..57eede2 --- /dev/null +++ b/tests/hurl/functional/redirect.hurl @@ -0,0 +1,24 @@ +# redirect.hurl — regression tests for SendRedirect behaviour. +# +# Source: src/main/java/com/waratek/spiracle/misc/SendRedirect.java +# @WebServlet("/SendRedirect") +# +# Regression for #8: when redirectMeTo param is absent the servlet must +# respond 200 with Content-Type: text/plain and explain the missing param. +# If the fix is reverted the Content-Type header will be missing/wrong. + +# ── 1. No param → 200 plain text with usage hint ───────────────────── +GET http://{{host}}:{{port}}/spiracle/SendRedirect + +HTTP 200 +[Asserts] +header "Content-Type" contains "text/plain" +body contains "redirectMeTo" + +# ── 2. Valid param → 302 redirect to supplied URL ──────────────────── +# Hurl does NOT follow redirects by default; the 302 is directly observable. +GET http://{{host}}:{{port}}/spiracle/SendRedirect?redirectMeTo=https://example.com + +HTTP 302 +[Asserts] +header "Location" contains "example.com" diff --git a/tests/hurl/functional/sql.hurl b/tests/hurl/functional/sql.hurl new file mode 100644 index 0000000..d9a54bb --- /dev/null +++ b/tests/hurl/functional/sql.hurl @@ -0,0 +1,60 @@ +# sql.hurl — functional SQL tests against the unprotected MySQL stack. +# +# Sources: +# MySql_Get_int → @WebServlet("/MySql_Get_int") param: id +# MySql_Get_string → @WebServlet("/MySql_Get_string") param: name +# MySql_Get_Implicit_Join → @WebServlet("/MySql_Get_Implicit_Join") param: id +# MySql_Get_Union → @WebServlet("/MySql_Get_Union") param: id +# +# Seed data (setupdb_mysql.sql): +# id=1 → Patrick Moss +# id=2 → Margaret Thomas +# address id=1 → 2128 Vestibulum, St. / Dubuisson / San Marino + +# ── 1. MySql_Get_int benign: id=1 returns Patrick Moss ─────────────── +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=1 + +HTTP 200 +[Asserts] +body contains "Patrick" +body contains "Moss" + +# ── 2. MySql_Get_string benign: name=Patrick returns surname Moss ──── +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=Patrick + +HTTP 200 +[Asserts] +body contains "Moss" + +# ── 3. MySql_Get_Implicit_Join benign: id=1 returns row + address ──── +# Query: SELECT * FROM users, address WHERE users.id = 1 AND users.id = address.id +# Proves the join works for a known row. +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id=1 + +HTTP 200 +[Asserts] +body contains "Patrick" +body contains "Dubuisson" + +# ── 4. Unprotected SQL injection on MySql_Get_Implicit_Join ────────── +# Payload: id=1 OR 1=1 +# Query becomes: SELECT * FROM users, address WHERE users.id = 1 OR 1=1 AND users.id = address.id +# Without the Waratek RASP agent this executes and returns ALL users. +# id=1 only returns Patrick Moss; injection adds Margaret Thomas (id=2). +# Asserting both surnames proves injection executed and widened the result. +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id=1%20OR%201%3D1 + +HTTP 200 +[Asserts] +body contains "Moss" +body contains "Thomas" + +# ── 5. MySql_Get_Union benign: id=1 returns user + address rows ────── +# Query: SELECT name,surname,dob FROM users ... UNION SELECT address_1,address_2,address_3 FROM address ... +# Both result sets for id=1 are returned. +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Union?id=1 + +HTTP 200 +[Asserts] +body contains "Moss" +body contains "Dubuisson" diff --git a/tests/hurl/functional/traversal.hurl b/tests/hurl/functional/traversal.hurl new file mode 100644 index 0000000..a3e9fd8 --- /dev/null +++ b/tests/hurl/functional/traversal.hurl @@ -0,0 +1,39 @@ +# traversal.hurl — path traversal demonstration (unprotected). +# +# Source: src/main/java/com/waratek/spiracle/path_traversal/FileInputStreamServlet01.java +# @WebServlet("/FileInputStreamServlet01") param: FileInputStream01 +# +# The servlet constructs: +# absolutePathToTestFile = /pathTraversal/testFilesParent/testFilesChild/ +# + File.separator + FileInputStream01 +# No sanitisation is applied. A "../" sequence traverses up one directory. +# The servlet stores "File input stream opened for file: ''" in the +# session, then redirects to pathTraversal.jsp which renders it. +# Hurl follows the redirect automatically (session cookie carried). +# +# Known test files in the deployment: +# testFilesChild/TestFile (the intended target) +# testFilesParent/TestFile (one level up — requires traversal) + +# ── 1. Benign: access known file in testFilesChild ─────────────────── +GET http://{{host}}:{{port}}/spiracle/FileInputStreamServlet01?FileInputStream01=TestFile +[Options] +location: true + +HTTP 200 +[Asserts] +body contains "File input stream opened for file:" +body contains "testFilesChild" + +# ── 2. Path traversal: ../TestFile escapes testFilesChild ──────────── +# %2F = / so ../TestFile URL-encodes to ..%2FTestFile +# The constructed path resolves to testFilesParent/TestFile. +# Without a RASP agent the traversal is NOT blocked and the stream opens. +GET http://{{host}}:{{port}}/spiracle/FileInputStreamServlet01?FileInputStream01=..%2FTestFile +[Options] +location: true + +HTTP 200 +[Asserts] +body contains "File input stream opened for file:" +body contains "testFilesParent" diff --git a/tests/hurl/functional/xss.hurl b/tests/hurl/functional/xss.hurl new file mode 100644 index 0000000..2ad1e3c --- /dev/null +++ b/tests/hurl/functional/xss.hurl @@ -0,0 +1,28 @@ +# xss.hurl — reflected XSS demonstration (unprotected). +# +# Source: src/main/webapp/customTag.jsp +# The JSP reads request.getParameter("name") and passes it to HelloUserTag, +# which writes: Hello Spiracle user: NAME! +# No escaping is applied, so a script payload in "name" is reflected verbatim. +# +# Note: the ReadHTML-based XSS servlets (XSSWebAppHSRPW, XSSWebAppSRPW etc.) +# do NOT reflect the param because xss.html contains no literal "XSS" token +# to substitute — those are agent-trigger targets, not reflection endpoints. +# customTag.jsp is the cleanest GET-accessible reflected-XSS endpoint. + +# ── 1. Benign name: confirm normal reflection ──────────────────────── +GET http://{{host}}:{{port}}/spiracle/customTag.jsp?name=Alice + +HTTP 200 +[Asserts] +body contains "Hello Spiracle user" +body contains "Alice" + +# ── 2. XSS payload reflected unescaped ────────────────────────────── +# %3Cscript%3Ealert%281%29%3C%2Fscript%3E = +# Without sanitisation the raw tag appears in the HTML body. +GET http://{{host}}:{{port}}/spiracle/customTag.jsp?name=%3Cscript%3Ealert%281%29%3C%2Fscript%3E + +HTTP 200 +[Asserts] +body contains "" diff --git a/tests/hurl/generate.py b/tests/hurl/generate.py new file mode 100644 index 0000000..4c56310 --- /dev/null +++ b/tests/hurl/generate.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python3 +""" +Generate Hurl RASP test files from the -delimited payload matrices. + +Usage: + python3 tests/hurl/generate.py + +Reads: + tests/mysql.txt + tests/oracle.txt + +Writes: + tests/hurl/rasp/mysql/.hurl + tests/hurl/rasp/oracle/.hurl + +Each file contains one Hurl entry per test case for that servlet. +Status assertion uses: + HTTP * + [Asserts] + status == {{block_status}} + +so the expected status (550 for RASP-blocked, 200 for benign) is +injected at runtime via --variable block_status=550. + +NOTE: Raw spaces in URLs break Hurl's URL parser; the generator +percent-encodes bare spaces (0x20) only, preserving all other +characters (including already-encoded sequences like %25, %27, etc.) +exactly as they appear in the source files. +""" + +import os +import re +import sys +from collections import defaultdict + +TESTS_DIR = os.path.join(os.path.dirname(__file__), "..") +RASP_DIR = os.path.join(os.path.dirname(__file__), "rasp") + +SOURCES = { + "mysql": os.path.join(TESTS_DIR, "mysql.txt"), + "oracle": os.path.join(TESTS_DIR, "oracle.txt"), +} + +# Map servlet path segment → output filename (lowercase, underscores) +SERVLET_NAME_MAP = { + # MySQL servlets + "MySql_Get_int": "get_int", + "MySql_Get_string": "get_string", + "MySql_Get_Implicit_Join": "get_implicit_join", + "MySql_Implicit_Join_Namespace": "implicit_join_namespace", + "Get_Union": "get_union", # shared by both; mysql.txt uses it + # Oracle servlets + "Get_int": "get_int", + "Get_int_no_quote": "get_int_no_quote", + "Get_int_partialunion": "get_int_partialunion", + "Get_int_groupby": "get_int_groupby", + "Get_int_nooutput": "get_int_nooutput", + "Get_int_having": "get_int_having", + "Get_int_inline": "get_int_inline", + "Get_string": "get_string", + "Get_string_no_quote": "get_string_no_quote", + "Get_Implicit_Join": "get_implicit_join", + "Get_Full_Outer_Join": "get_full_outer_join", +} + + +def encode_url_illegal(s): + """ + Percent-encode characters that Hurl's URL parser rejects in GET lines. + + Hurl rejects: space, |, ", <, > + Everything else (including already-encoded %xx sequences, ', (, ), etc.) + is left intact so payload semantics are preserved exactly. + """ + replacements = [ + (" ", "%20"), + ("|", "%7C"), + ('"', "%22"), + ("<", "%3C"), + (">", "%3E"), + ] + for char, enc in replacements: + s = s.replace(char, enc) + return s + + +def servlet_from_path(path): + """Extract servlet name from /spiracle/.""" + return path.lstrip("/").split("/")[-1] + + +def output_filename(servlet): + return SERVLET_NAME_MAP.get(servlet, servlet.lower()) + ".hurl" + + +def parse_data_file(filepath): + """Return list of (path, querystring, expected_status) tuples.""" + cases = [] + with open(filepath, encoding="utf-8") as f: + for lineno, line in enumerate(f, 1): + line = line.rstrip("\n") + if not line: + continue + parts = line.split("") + if len(parts) != 3: + print( + f"WARNING: {filepath}:{lineno} — expected 3 parts, got {len(parts)}: {line!r}", + file=sys.stderr, + ) + continue + cases.append((parts[0], parts[1], parts[2])) + return cases + + +def generate_hurl_file(cases, base_url_template): + """ + Build Hurl file content for a list of (path, querystring, expected_status). + base_url_template: string with {path} and {querystring} slots. + """ + lines = [] + for path, qs, expected_status in cases: + # Encode URL-illegal chars in querystring only (not path) + safe_qs = encode_url_illegal(qs) + url = "http://{{{{host}}}}:{{{{port}}}}{path}{qs}".format( + path=path, qs=safe_qs + ) + lines.append(f"GET {url}") + lines.append("") + lines.append("HTTP *") + lines.append("[Asserts]") + # Use {{block_status}} variable for the standard blocked status (550). + # Cases with a different expected status (e.g. 200 for a benign probe) + # get the literal value so they remain correct regardless of variables. + if expected_status == "550": + lines.append(f"status == {{{{block_status}}}}") + else: + lines.append(f"status == {expected_status}") + lines.append("") + return "\n".join(lines) + + +def main(): + total = 0 + by_db = {} + + for db, filepath in SOURCES.items(): + cases = parse_data_file(filepath) + print(f"Read {len(cases)} cases from {filepath}") + total += len(cases) + by_db[db] = cases + + # Group by servlet + groups = defaultdict(list) + for path, qs, expected_status in cases: + servlet = servlet_from_path(path) + groups[servlet].append((path, qs, expected_status)) + + out_dir = os.path.join(RASP_DIR, db) + os.makedirs(out_dir, exist_ok=True) + + for servlet, servlet_cases in sorted(groups.items()): + fname = output_filename(servlet) + out_path = os.path.join(out_dir, fname) + content = generate_hurl_file(servlet_cases, "") + with open(out_path, "w", encoding="utf-8") as f: + f.write(content) + print(f" Wrote {len(servlet_cases):3d} cases → {out_path}") + + print(f"\nTotal: {total} cases converted.") + + +if __name__ == "__main__": + main() diff --git a/tests/hurl/rasp/mysql/get_implicit_join.hurl b/tests/hurl/rasp/mysql/get_implicit_join.hurl new file mode 100644 index 0000000..4e2428d --- /dev/null +++ b/tests/hurl/rasp/mysql/get_implicit_join.hurl @@ -0,0 +1,179 @@ +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='2'%20OR%20'name'%20LIKE%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='1'%20or%20'name'%20like%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='1'%20or%20users.id%20like%201 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='1'%20or%20'users.name'%20like'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='1'%20OR%20120=(SELECT%20COUNT(*)%20FROM%20users) + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='1'%20AND%20'users.cvv'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='1'%20AND%20'DOB'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='1'%20AND%20'cvv'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='1'%20OR%20'x'='x' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='1'%20or%201=1%20or%20'x'='y' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='1'%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id=''%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id=('hi')%20or%20('a'='a') + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='a'%20or%20'a'%20=%20'a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='joe'%20or%20'1'='1' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='hi'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='hi'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='a'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id=''%20or%20'x'='x'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id=''%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='a'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='Joe'%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id='Joe'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id=1%20or%20'a'='a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id=1%20or%20'1'='1' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id=1%20or%20'1'='1' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id=''%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id=''%20%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id=''%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_Implicit_Join?id=%27%27%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/mysql/get_int.hurl b/tests/hurl/rasp/mysql/get_int.hurl new file mode 100644 index 0000000..ce71aeb --- /dev/null +++ b/tests/hurl/rasp/mysql/get_int.hurl @@ -0,0 +1,179 @@ +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=2'%20OR%20name%20LIKE%20'%25'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=1'%20%7C%7C%20name%20like%20'%25'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=1'%20or%20users.name%20LIKE%20'%25'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=1'%20or%20id%20like%20'%25 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=1'%20OR%20100=(SELECT%20COUNT(*)%20FROM%20users)%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=1'%20OR%20users.cvv%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=1'%20AND%20DOB%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=1'%20OR%20cvv%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=1'%20OR%20'x'='x'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=1'%20or%201=1%20or%20'x'='y'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=1'%20UNION%20ALL%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=1'%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id='%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=(%22hi%22)'%20or%20('a'='a')-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=a'%20or%20'a'%20=%20'a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=joe'%20or%20'1'='1'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=1'%20UNION%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=hi'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=hi'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=a'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=%27%20or%20'x'='x'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id='%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=a'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=Joe'%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=Joe'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=1'%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id='%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id='%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id=%27%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_int?id='%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/mysql/get_string.hurl b/tests/hurl/rasp/mysql/get_string.hurl new file mode 100644 index 0000000..8ab638e --- /dev/null +++ b/tests/hurl/rasp/mysql/get_string.hurl @@ -0,0 +1,119 @@ +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=x'%20or%20name%20like%20'%25'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=%3C%3E%22%2527%25%3B)(%26%2B + +HTTP * +[Asserts] +status == 200 + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=x'%20AND%20100=(SELECT%20COUNT(*)%20FROM%20address)%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=x'%20OR%20cvv%20IS%20NULL-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=anything'%20OR%20'x'='x + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=x'%20or%201=1%20or%20'x'='y + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name='%20UNION%20ALL%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name='or%201=1%20or%20''=' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=a'%20or%20'a'%20=%20'a + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name='%20or%20'1'='1'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name='%20UNION%20SELECT%20*%20from%20users-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=a'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=%27%20or%20%27x%27=%27x + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name='or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=a'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name='%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name='%20or%201%20--' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name='%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=%27%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=x'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/mysql/get_union.hurl b/tests/hurl/rasp/mysql/get_union.hurl new file mode 100644 index 0000000..9b88ada --- /dev/null +++ b/tests/hurl/rasp/mysql/get_union.hurl @@ -0,0 +1,173 @@ +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='2'%20OR%20'name'%20LIKE%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20or%20'name'%20like%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20or%20id%20like%201 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20or%20'name'%20like'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20OR%20120=(SELECT%20COUNT(*)%20FROM%20users) + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20AND%20'users.cvv'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20AND%20'DOB'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20AND%20'cvv'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20OR%20'x'='x' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20or%201=1%20or%20'x'='y' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='(%22hi%22)'%20or%20('a'='a')-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='a'%20or%20'a'%20=%20'a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='joe'%20or%20'1'='1' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='hi'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='hi'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='a'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id=''%20or%20'x'='x'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id=''%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='a'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='Joe'%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='Joe'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id=1%20or%20'a'='a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id=1%20or%20'1'='1' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id=%27%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='%20%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/mysql/implicit_join_namespace.hurl b/tests/hurl/rasp/mysql/implicit_join_namespace.hurl new file mode 100644 index 0000000..db24b55 --- /dev/null +++ b/tests/hurl/rasp/mysql/implicit_join_namespace.hurl @@ -0,0 +1,179 @@ +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='2'%20OR%20'name'%20LIKE%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='1'%20or%20'name'%20like%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='1'%20or%20users.id%20like%201 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='1'%20or%20'users.name'%20like'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='1'%20OR%20120=(SELECT%20COUNT(*)%20FROM%20users) + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='1'%20AND%20'users.cvv'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='1'%20AND%20'DOB'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='1'%20AND%20'cvv'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='1'%20OR%20'x'='x' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='1'%20or%201=1%20or%20'x'='y' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='1'%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id=''%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id=('hi')%20or%20('a'='a') + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='a'%20or%20'a'%20=%20'a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='joe'%20or%20'1'='1' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='hi'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='hi'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='a'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id=''%20or%20'x'='x'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id=''%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='a'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='Joe'%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id='Joe'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id=1%20or%20'a'='a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id=1%20or%20'1'='1' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id=1%20or%20'1'='1' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id=''%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id=''%20%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id=''%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/MySql_Implicit_Join_Namespace?id=%27%27%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/oracle/get_full_outer_join.hurl b/tests/hurl/rasp/oracle/get_full_outer_join.hurl new file mode 100644 index 0000000..477e1fd --- /dev/null +++ b/tests/hurl/rasp/oracle/get_full_outer_join.hurl @@ -0,0 +1,173 @@ +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='2'%20OR%20'name'%20LIKE%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='1'%20or%20'name'%20like%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='1'%20or%20users.id%20like%201 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='1'%20or%20'users.name'%20like'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='1'%20OR%20120=(SELECT%20COUNT(*)%20FROM%20users) + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='1'%20AND%20'users.cvv'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='1'%20AND%20'DOB'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='1'%20AND%20'cvv'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='1'%20OR%20'x'='x' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='1'%20or%201=1%20or%20'x'='y' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='1'%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id=''%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id=('hi')%20or%20('a'='a') + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='a'%20or%20'a'%20=%20'a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='joe'%20or%20'1'='1' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='hi'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='hi'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='a'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id=''%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id=''%20or%20'x'='x'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='a'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='Joe'%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id='Joe'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id=1%20or%20'a'='a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id=1%20or%20'1'='1' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id=''%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id=''%20%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id=%27%27%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Full_Outer_Join?id=''%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/oracle/get_implicit_join.hurl b/tests/hurl/rasp/oracle/get_implicit_join.hurl new file mode 100644 index 0000000..6b2df79 --- /dev/null +++ b/tests/hurl/rasp/oracle/get_implicit_join.hurl @@ -0,0 +1,173 @@ +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='2'%20OR%20'name'%20LIKE%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='1'%20or%20'name'%20like%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='1'%20or%20users.id%20like%201 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='1'%20or%20'users.name'%20like'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='1'%20OR%20120=(SELECT%20COUNT(*)%20FROM%20users) + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='1'%20AND%20'users.cvv'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='1'%20AND%20'DOB'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='1'%20AND%20'cvv'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='1'%20OR%20'x'='x' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='1'%20or%201=1%20or%20'x'='y' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='1'%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id=''%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id=('hi')%20or%20('a'='a') + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='a'%20or%20'a'%20=%20'a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='joe'%20or%20'1'='1' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='hi'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='hi'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='a'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id=''%20or%20'x'='x'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id=''%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='a'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='Joe'%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id='Joe'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id=1%20or%20'a'='a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id=1%20or%20'1'='1' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id=''%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id=''%20%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id=''%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Implicit_Join?id=%27%27%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/oracle/get_int.hurl b/tests/hurl/rasp/oracle/get_int.hurl new file mode 100644 index 0000000..4664b88 --- /dev/null +++ b/tests/hurl/rasp/oracle/get_int.hurl @@ -0,0 +1,179 @@ +GET http://{{host}}:{{port}}/spiracle/Get_int?id=2'%20OR%20name%20LIKE%20'%25 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=1'%20or%20name%20like%20'%25 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=1'%20or%20id%20like%20'%25 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id='%20or%20name%20like%20'%25 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=1'%20OR%20120=(SELECT%20COUNT(*)%20FROM%20users)%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=1'%20AND%20users.cvv%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=1'%20AND%20DOB%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=1'%20AND%20cvv%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=1'%20OR%20'x'='x'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=1'%20or%201=1%20or%20'x'='y'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=1'%20UNION%20ALL%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=1'%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id='%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=(%22hi%22)'%20or%20('a'='a')-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=a'%20or%20'a'%20=%20'a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=joe'%20or%20'1'='1'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=1'%20UNION%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=hi'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=hi'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=a'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=%20or%20'x'='x'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id='%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=a'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=Joe'%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=Joe'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=1'%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id='%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id='%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id=%27%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int?id='%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/oracle/get_int_groupby.hurl b/tests/hurl/rasp/oracle/get_int_groupby.hurl new file mode 100644 index 0000000..9225de0 --- /dev/null +++ b/tests/hurl/rasp/oracle/get_int_groupby.hurl @@ -0,0 +1,11 @@ +GET http://{{host}}:{{port}}/spiracle/Get_int_groupby?id=name%20union%20all%20select%20null,%20to_char(dob)%20from%20users + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_groupby?id=name%20union%20select%20null,%20to_char(dob)%20from%20users + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/oracle/get_int_having.hurl b/tests/hurl/rasp/oracle/get_int_having.hurl new file mode 100644 index 0000000..253fb73 --- /dev/null +++ b/tests/hurl/rasp/oracle/get_int_having.hurl @@ -0,0 +1,11 @@ +GET http://{{host}}:{{port}}/spiracle/Get_int_having?id=1%20union%20select%20to_char(dob)%20from%20users + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_having?id=1%20union%20all%20select%20to_char(dob)%20from%20users + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/oracle/get_int_inline.hurl b/tests/hurl/rasp/oracle/get_int_inline.hurl new file mode 100644 index 0000000..9983372 --- /dev/null +++ b/tests/hurl/rasp/oracle/get_int_inline.hurl @@ -0,0 +1,191 @@ +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20=%20'x'%20OR%20name%20LIKE%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20=%20''%20or%20name%20like%20'' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20id%20=%20''%20or%20id%20like%20'' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20=%20''%20or%20name%20like%20'' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20='x'%20AND%20users.cvv%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20=%20'x'%20OR%20120=(SELECT%20COUNT(*)%20FROM%20users)%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20='Joe'%20AND%20DOB%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20='Joe'%20AND%20cvv%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20='anything'%20OR%20'x'='x' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20=%20'x'%20or%201=1%20or%20'x'='y' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20='Joe'%20UNION%20ALL%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20=%20''%20or%201=1%20or%20''='' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20=%20('hi')%20or%20('a'='a') + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20=%20'a'%20or%20'a'%20=%20'a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20=%20'joe'%20or%20'1'='1'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20='Joe'%20UNION%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name%20=%20(%27%27)%20or%20(%27x%27=%27x%27) + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name=('')%20or%20('a'='a') + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name='hi'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name='hi'%20or%20'a'='a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name='a'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name=''%20or%20'x'='x' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name=''%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name='a'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name='Joe'%20or%200=0%20# + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name='Joe'%20or%20'a'='a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name='Joe'%20or%20''='' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name='Joe'%20or%201=1 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name='Joe'%20or%20''='' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name='Joe'%20%20or%201=1 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name='Joe%20%27%20or%201=1 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_inline?id=select%20*%20from%20users%20where%20name='Joe'%20or%203=3 + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/oracle/get_int_no_quote.hurl b/tests/hurl/rasp/oracle/get_int_no_quote.hurl new file mode 100644 index 0000000..c4d8ab6 --- /dev/null +++ b/tests/hurl/rasp/oracle/get_int_no_quote.hurl @@ -0,0 +1,197 @@ +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=2%20OR%20name%20LIKE%20'%25' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=1%20or%20name%20like%20'%25' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=1%20or%20id%20like%20'%25' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=1%20or%20name%20like%20'%25' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=1%20OR%20120=(SELECT%20COUNT(*)%20FROM%20users)%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=1%20AND%20users.cvv%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=1%20AND%20DOB%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=1%20AND%20cvv%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=1%20OR%20'x'='x' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=1%20or%201=1%20or%20'x'='y' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=1%20UNION%20ALL%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=1%20or%201=1%20or%20''='' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=''%20or%201=1%20or%20''='' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=('hi')%20or%20('a'='a') + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id='a'%20or%20'a'%20=%20'a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=1%20UNION%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id='joe'%20or%20'1'='1'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=(%27%27)%20or%20(%27x%27=%27x%27) + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=('')%20or%20('a'='a') + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id='hi'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id='hi'%20or%20'a'='a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id='a'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=''%20or%20'x'='x' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=''%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id='a'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id='Joe'%20or%200=0%20# + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id='Joe'%20or%20'a'='a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=1%20or%20''='' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id=1%20or%20''='' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id='Joe'%20or%201=1 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id='Joe'%20%20or%201=1 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id='Joe%20%27%20or%201=1 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_no_quote?id='Joe'%20or%203=3 + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/oracle/get_int_nooutput.hurl b/tests/hurl/rasp/oracle/get_int_nooutput.hurl new file mode 100644 index 0000000..bb6e27e --- /dev/null +++ b/tests/hurl/rasp/oracle/get_int_nooutput.hurl @@ -0,0 +1,179 @@ +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=2'%20OR%20name%20LIKE%20'%25 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=1'%20or%20name%20like%20'%25 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=1'%20or%20id%20like%20'%25 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id='%20or%20name%20like%20'%25 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=1'%20OR%20120=(SELECT%20COUNT(*)%20FROM%20users)%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=1'%20AND%20users.cvv%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=1'%20AND%20DOB%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=1'%20AND%20cvv%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=1'%20OR%20'x'='x'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=1'%20or%201=1%20or%20'x'='y'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=1'%20UNION%20ALL%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=1'%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id='%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=(%22hi%22)'%20or%20('a'='a')-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=a'%20or%20'a'%20=%20'a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=joe'%20or%20'1'='1'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=1'%20UNION%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=hi'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=hi'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=a'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id='%20or%20'x'='x'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id='%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=a'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=Joe'%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=Joe'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=1'%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id='%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id=1%27%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id='%20%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_nooutput?id='%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/oracle/get_int_partialunion.hurl b/tests/hurl/rasp/oracle/get_int_partialunion.hurl new file mode 100644 index 0000000..a457a3b --- /dev/null +++ b/tests/hurl/rasp/oracle/get_int_partialunion.hurl @@ -0,0 +1,179 @@ +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=2'%20OR%20name%20LIKE%20'%25 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=1'%20or%20name%20like%20'%25 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=1'%20or%20id%20like%20'%25 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id='%20or%20name%20like%20'%25 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=1'%20OR%20120=(SELECT%20COUNT(*)%20FROM%20users)%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=1'%20AND%20users.cvv%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=1'%20AND%20DOB%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=1'%20AND%20cvv%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=1'%20OR%20'x'='x'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=1'%20or%201=1%20or%20'x'='y'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=1'%20UNION%20ALL%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=1'%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id='%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=(%22hi%22)'%20or%20('a'='a')-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=a'%20or%20'a'%20=%20'a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=joe'%20or%20'1'='1'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=1'%20UNION%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=hi'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=hi'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=a'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id='%20or%20'x'='x'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id='%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=a'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=Joe'%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=Joe'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=1'%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id='%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id='%20%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id=%27%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_int_partialunion?id='%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/oracle/get_string.hurl b/tests/hurl/rasp/oracle/get_string.hurl new file mode 100644 index 0000000..b7a8263 --- /dev/null +++ b/tests/hurl/rasp/oracle/get_string.hurl @@ -0,0 +1,125 @@ +GET http://{{host}}:{{port}}/spiracle/Get_string?name=x'%20or%20name%20like%20'%25'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name=t'exec%20master..xp_cmdshell%20'nslookup%20www%2egoogle%2ecom'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name='%3b%20exec%20master%2e%2exp_cmdshell%20'ping%20172%2e10%2e1%2e255'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name=x'%20AND%20100=(SELECT%20COUNT(*)%20FROM%20address)%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name=x'%20OR%20cvv%20IS%20NULL-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name=anything'%20OR%20'x'='x + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name=x'%20or%201=1%20or%20'x'='y + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name='%20UNION%20ALL%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name='or%201=1%20or%20''=' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name=a'%20or%20'a'%20=%20'a + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name='%20or%20'1'='1'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name='%20UNION%20SELECT%20*%20from%20users-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name=a'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name=%27%20or%20%27x%27=%27x + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name='or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name=a'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name='%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name='%20or%201%20--' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name='%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name=%27%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string?name=x'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/oracle/get_string_no_quote.hurl b/tests/hurl/rasp/oracle/get_string_no_quote.hurl new file mode 100644 index 0000000..a7ac1d7 --- /dev/null +++ b/tests/hurl/rasp/oracle/get_string_no_quote.hurl @@ -0,0 +1,203 @@ +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='2'%20OR%20name%20LIKE%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='Jon'%20or%20name%20like%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='1'%20or%20id%20like%20'2' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='1'%20or%20name%20like%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='Joe'%20OR%20120=(SELECT%20COUNT(*)%20FROM%20users)%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='1'%20or%20name%20like%20'Sammy' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='1'%20AND%20users.cvv%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='1'%20AND%20DOB%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='1'%20AND%20cvv%20IS%20NULL%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='1'%20OR%20'x'='x' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='1'%20or%201=1%20or%20'x'='y'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='1'%20UNION%20ALL%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name=''%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='1'%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name=(1)%20or%20('a'='a')-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name=1%20or%20'a'%20=%20'a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name=1%20or%20'1'='1'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='Joe'%20UNION%20SELECT%20*%20from%20users%20where%20id=1%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name=('')%20or%20('a'='a')-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name=('')%20or%20('x'='x')-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name=''%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name=''%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='a'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name=%27%27%20or%20%27x%27%3D%27x%27-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='a'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name=''%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='Joe'%20or%200=0%20# + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='Joe'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='Joe'%20or%20'a'='a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='1'%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='Joe'%20%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='Joe'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='Joe%20%27%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_string_no_quote?name='Joe'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/oracle/get_union.hurl b/tests/hurl/rasp/oracle/get_union.hurl new file mode 100644 index 0000000..9b88ada --- /dev/null +++ b/tests/hurl/rasp/oracle/get_union.hurl @@ -0,0 +1,173 @@ +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='2'%20OR%20'name'%20LIKE%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20or%20'name'%20like%20'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20or%20id%20like%201 + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20or%20'name'%20like'Joe' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20OR%20120=(SELECT%20COUNT(*)%20FROM%20users) + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20AND%20'users.cvv'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20AND%20'DOB'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20AND%20'cvv'%20IS%20NULL + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20OR%20'x'='x' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20or%201=1%20or%20'x'='y' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='1'%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='%20or%201=1%20or%20''=''-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='(%22hi%22)'%20or%20('a'='a')-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='a'%20or%20'a'%20=%20'a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='joe'%20or%20'1'='1' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='hi'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='hi'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='a'%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id=''%20or%20'x'='x'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id=''%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='a'%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='Joe'%20or%200=0%20-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='Joe'%20or%20'a'='a'-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id=1%20or%20'a'='a' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id=1%20or%20'1'='1' + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id=%27%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='%20%20or%201=1-- + +HTTP * +[Asserts] +status == {{block_status}} + +GET http://{{host}}:{{port}}/spiracle/Get_Union?id='%20or%203=3-- + +HTTP * +[Asserts] +status == {{block_status}} diff --git a/tests/hurl/rasp/protected.env b/tests/hurl/rasp/protected.env new file mode 100644 index 0000000..b6c1f83 --- /dev/null +++ b/tests/hurl/rasp/protected.env @@ -0,0 +1,3 @@ +host=localhost +port=8080 +block_status=550 diff --git a/tests/hurl/run.sh b/tests/hurl/run.sh new file mode 100755 index 0000000..19b8aab --- /dev/null +++ b/tests/hurl/run.sh @@ -0,0 +1,77 @@ +#!/bin/sh +# run.sh — Spiracle Hurl test runner +# +# Usage: +# ./tests/hurl/run.sh smoke [host] [port] +# ./tests/hurl/run.sh functional [host] [port] +# ./tests/hurl/run.sh rasp [host] [port] +# +# Arguments: +# suite — "smoke", "functional", or "rasp" +# host — hostname/IP of Spiracle (default: localhost) +# port — TCP port (default: 8080) +# +# Environment: +# BLOCK_STATUS — expected RASP block code (default: 550) +# only used by the "rasp" suite +# +# Requirements: +# hurl v5+ at ~/.local/bin/hurl or on PATH + +set -eu + +SUITE="${1:-smoke}" +HOST="${2:-localhost}" +PORT="${3:-8080}" +BLOCK_STATUS="${BLOCK_STATUS:-550}" + +# Resolve hurl binary +HURL="" +if command -v hurl >/dev/null 2>&1; then + HURL="hurl" +elif [ -x "$HOME/.local/bin/hurl" ]; then + HURL="$HOME/.local/bin/hurl" +else + echo "ERROR: hurl not found. Install from https://hurl.dev" >&2 + exit 1 +fi + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +case "$SUITE" in + smoke) + VARS_FILE="$SCRIPT_DIR/smoke/local.env" + FILES="$SCRIPT_DIR/smoke/smoke.hurl" + REPORT_DIR="${REPORT_DIR:-/tmp/spiracle-smoke-report}" + ;; + functional) + VARS_FILE="$SCRIPT_DIR/functional/local.env" + FILES="$SCRIPT_DIR/functional/redirect.hurl $SCRIPT_DIR/functional/sql.hurl $SCRIPT_DIR/functional/xss.hurl $SCRIPT_DIR/functional/traversal.hurl $SCRIPT_DIR/functional/negative.hurl" + REPORT_DIR="${REPORT_DIR:-/tmp/spiracle-functional-report}" + ;; + rasp) + VARS_FILE="$SCRIPT_DIR/rasp/protected.env" + FILES="$SCRIPT_DIR/rasp/mysql/*.hurl $SCRIPT_DIR/rasp/oracle/*.hurl" + REPORT_DIR="${REPORT_DIR:-/tmp/spiracle-rasp-report}" + ;; + *) + echo "ERROR: unknown suite '$SUITE'. Use 'smoke', 'functional', or 'rasp'." >&2 + exit 1 + ;; +esac + +mkdir -p "$REPORT_DIR" + +echo "Running Spiracle $SUITE suite against http://$HOST:$PORT" +echo "Report: $REPORT_DIR/junit.xml" +echo "" + +# shellcheck disable=SC2086 +$HURL \ + --test \ + --variables-file "$VARS_FILE" \ + --variable host="$HOST" \ + --variable port="$PORT" \ + --variable block_status="$BLOCK_STATUS" \ + --report-junit "$REPORT_DIR/junit.xml" \ + $FILES diff --git a/tests/hurl/smoke/local.env b/tests/hurl/smoke/local.env new file mode 100644 index 0000000..0182d07 --- /dev/null +++ b/tests/hurl/smoke/local.env @@ -0,0 +1,2 @@ +host=localhost +port=8080 diff --git a/tests/hurl/smoke/smoke.hurl b/tests/hurl/smoke/smoke.hurl new file mode 100644 index 0000000..c6fe4ac --- /dev/null +++ b/tests/hurl/smoke/smoke.hurl @@ -0,0 +1,32 @@ +# Spiracle smoke suite — runs against a PLAIN (no RASP agent) deployment. +# +# Purpose: prove the app is up, DB round-trips work, and that SQLi is +# NOT blocked without the Waratek agent. A 550 here would mean the +# agent is unexpectedly present; plain Tomcat returns 200 for valid +# SQL injections and 500 for malformed ones. + +# ── 1. App root is reachable ───────────────────────────────────────── +GET http://{{host}}:{{port}}/spiracle/ + +HTTP 200 + +# ── 2. Benign query returns the expected row ───────────────────────── +# Patrick Moss is id=1, name='Patrick' in the seed data. +# MySql_Get_string queries by name and returns the surname. +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=Patrick + +HTTP 200 +[Asserts] +body contains "Moss" + +# ── 3. SQL injection succeeds unprotected ─────────────────────────── +# Without the Waratek RASP agent the injection is NOT blocked. +# The payload ' OR '1'='1 widens the WHERE clause to match all rows. +# Margaret Thomas (id=2) is NOT in the result set for name='Patrick', +# but WILL appear when the injection succeeds. Asserting her surname +# proves more rows were returned than the benign query would give. +GET http://{{host}}:{{port}}/spiracle/MySql_Get_string?name=Patrick'%20OR%20'1'='1 + +HTTP 200 +[Asserts] +body contains "Thomas" diff --git a/tests/spiracle_sqli_test.py b/tests/spiracle_sqli_test.py deleted file mode 100755 index 3433c51..0000000 --- a/tests/spiracle_sqli_test.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/python - -from collections import defaultdict -import requests -import argparse - -parser = argparse.ArgumentParser(description="Run SQLI Tests") -parser.add_argument("-hn", "--hostname", help="Hostname", required=True) -parser.add_argument("-p", "--port", help="Port", required=True) -parser.add_argument("-f", "--file", help="Data file", required=True) -parser.add_argument("-d", "--debug", action="store_true") -args = parser.parse_args() - -input_file = open(args.file) -expected_dict = defaultdict(list) -actual_dict = defaultdict(list) -url = "http://{0}:{1}".format(args.hostname, args.port) - -for entry in input_file: - parts = entry.strip().split("") - if parts[0] in expected_dict: - expected_dict[parts[0]].append((parts[1], parts[2])) - else: - expected_dict[parts[0]] = [] - expected_dict[parts[0]].append((parts[1], parts[2])) - -for key in expected_dict.keys(): - actual_dict[key] = [] - -for key in expected_dict.keys(): - for entry in expected_dict[key]: - r = requests.get("{0}{1}{2}" - .format(url, key, entry[0])) - if args.debug: - print r.url, r.status_code - - actual_dict[key].append((entry[0], r.status_code)) - -successful_tests = 0 -log = open("results.csv", "a+") -for key in actual_dict.keys(): - counter = len(actual_dict[key]) - for x in range(0, counter): - if str(expected_dict[key][x][1]) == str(actual_dict[key][x][1]): - successful_tests += 1 - log.write("{0}{1},{2},{3}\n".format(url, key, expected_dict[key][x][1], - actual_dict[key][x][1])) - print("Servlet {0} had {1} tests. Pass: {2} Fail {3}" - .format(key, counter, successful_tests, counter - successful_tests)) - successful_tests = 0 -log.close()