Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
target/
.git/
.idea/
*.iml
mise.toml
51 changes: 51 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -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"]
123 changes: 112 additions & 11 deletions README.adoc
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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:

Expand All @@ -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
Expand Down Expand Up @@ -54,22 +83,24 @@ $ jar xvf /path/to/downloaded/spiracle.war
<webApplication contextRoot="spiracle" location="spiracle"/> <!--2-->
<httpSession idLength="28" /> <!--3-->

<httpEndpoint id="defaultHttpEndpoint"
<httpEndpoint id="defaultHttpEndpoint"
host="*" <!--4-->
httpPort="9080"
httpPort="9080"
httpsPort="9443"/>
</server>
----
+
<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.
Expand Down Expand Up @@ -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=<level>`:: 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:

Expand All @@ -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

----
Expand All @@ -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.
----

52 changes: 52 additions & 0 deletions docker-compose.mssql.yml
Original file line number Diff line number Diff line change
@@ -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
33 changes: 33 additions & 0 deletions docker-compose.mysql.yml
Original file line number Diff line number Diff line change
@@ -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
29 changes: 29 additions & 0 deletions docker-compose.oracle.yml
Original file line number Diff line number Diff line change
@@ -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
Loading