mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-12 19:55:14 +02:00
457 lines
16 KiB
Rust
457 lines
16 KiB
Rust
//! Minimal `org.owasp.benchmark.helpers`, `org.owasp.esapi`, and Spring
|
|
//! shim stubs for Java harnesses against OWASP Benchmark v1.2 fixtures.
|
|
//!
|
|
//! OWASP Benchmark testcases lean on a handful of helper classes that
|
|
//! ship with the upstream Maven project but are not on the harness
|
|
//! workdir classpath. Without them `javac` reports
|
|
//! `error: package org.owasp.benchmark.helpers does not exist` (and
|
|
//! the matching `esapi` / `springframework` variants) and the verifier
|
|
//! flips to `BuildFailed` before any sink probe runs.
|
|
//!
|
|
//! The bundle here covers the surface OWASP Benchmark v1.2 fixtures
|
|
//! actually reference (verified by walking
|
|
//! `~/.cache/nyx/eval_corpus/owasp_benchmark_v1.2/`):
|
|
//!
|
|
//! * `org.owasp.benchmark.helpers.Utils` — `testfileDir` field plus
|
|
//! the encode / OS-command helpers.
|
|
//! * `org.owasp.benchmark.helpers.DatabaseHelper` — `JDBCtemplate`
|
|
//! field of stub `BenchmarkJdbcTemplate` type, plus the
|
|
//! `getSqlConnection` / `getSqlStatement` / `printResults` family.
|
|
//! * `org.owasp.benchmark.helpers.LDAPManager` — directory-context
|
|
//! handle pair.
|
|
//! * `org.owasp.benchmark.helpers.SeparateClassRequest` — wraps a
|
|
//! `javax.servlet.http.HttpServletRequest` and exposes
|
|
//! `getTheParameter` / `getTheValue`.
|
|
//! * `org.owasp.benchmark.helpers.ThingFactory` / `ThingInterface` —
|
|
//! reflection-style indirection used by reflection-shape fixtures.
|
|
//! * `org.owasp.esapi.ESAPI` / `org.owasp.esapi.Encoder` — the
|
|
//! `ESAPI.encoder().encodeForHTML(...)` / `encodeForBase64(...)`
|
|
//! pair.
|
|
//! * `org.springframework.dao.DataAccessException` —
|
|
//! `RowMapper.mapRow` throws it.
|
|
//! * `org.springframework.jdbc.core.RowMapper` — anonymous-impl
|
|
//! target.
|
|
//! * `org.springframework.jdbc.support.rowset.SqlRowSet` — return
|
|
//! type of `JDBCtemplate.queryForRowSet`.
|
|
//! * `org.springframework.web.util.HtmlUtils` — `htmlEscape` static.
|
|
//!
|
|
//! Methods return null / empty defaults; runtime correctness past the
|
|
//! `javac` link step is the job of the spec-derivation fallback
|
|
//! paths, not the build-time stubs.
|
|
//!
|
|
//! Detection gate ([`entry_needs_owasp_stubs`]) checks the entry
|
|
//! source for substring hits on `org.owasp.benchmark` /
|
|
//! `org.owasp.esapi` / `org.springframework`. Non-OWASP harnesses
|
|
//! pay zero workdir cost.
|
|
|
|
/// Returns `(workdir_relative_path, file_content)` pairs ready to
|
|
/// drop into [`crate::dynamic::lang::HarnessSource::extra_files`].
|
|
/// Always returns the full bundle; callers gate on
|
|
/// [`entry_needs_owasp_stubs`] when scoping is desired.
|
|
pub fn owasp_stub_files() -> Vec<(String, String)> {
|
|
vec![
|
|
(
|
|
"org/owasp/benchmark/helpers/Utils.java".to_owned(),
|
|
utils_stub(),
|
|
),
|
|
(
|
|
"org/owasp/benchmark/helpers/DatabaseHelper.java".to_owned(),
|
|
database_helper_stub(),
|
|
),
|
|
(
|
|
"org/owasp/benchmark/helpers/BenchmarkJdbcTemplate.java".to_owned(),
|
|
benchmark_jdbc_template_stub(),
|
|
),
|
|
(
|
|
"org/owasp/benchmark/helpers/LDAPManager.java".to_owned(),
|
|
ldap_manager_stub(),
|
|
),
|
|
(
|
|
"org/owasp/benchmark/helpers/SeparateClassRequest.java".to_owned(),
|
|
separate_class_request_stub(),
|
|
),
|
|
(
|
|
"org/owasp/benchmark/helpers/ThingFactory.java".to_owned(),
|
|
thing_factory_stub(),
|
|
),
|
|
(
|
|
"org/owasp/benchmark/helpers/ThingInterface.java".to_owned(),
|
|
thing_interface_stub(),
|
|
),
|
|
("org/owasp/esapi/ESAPI.java".to_owned(), esapi_stub()),
|
|
("org/owasp/esapi/Encoder.java".to_owned(), encoder_stub()),
|
|
(
|
|
"org/springframework/dao/DataAccessException.java".to_owned(),
|
|
data_access_exception_stub(),
|
|
),
|
|
(
|
|
"org/springframework/jdbc/core/RowMapper.java".to_owned(),
|
|
row_mapper_stub(),
|
|
),
|
|
(
|
|
"org/springframework/jdbc/support/rowset/SqlRowSet.java".to_owned(),
|
|
sql_row_set_stub(),
|
|
),
|
|
(
|
|
"org/springframework/web/util/HtmlUtils.java".to_owned(),
|
|
html_utils_stub(),
|
|
),
|
|
]
|
|
}
|
|
|
|
/// Substring probe to decide whether an entry source pulls in the
|
|
/// OWASP Benchmark helper set. Matches `org.owasp.benchmark` /
|
|
/// `org.owasp.esapi` / `org.springframework` references, including
|
|
/// import statements and inline FQNs. Conservative on false
|
|
/// positives: a fixture that only mentions one of these in a comment
|
|
/// will still get the stubs staged, which is harmless javac work.
|
|
pub fn entry_needs_owasp_stubs(source: &str) -> bool {
|
|
source.contains("org.owasp.benchmark")
|
|
|| source.contains("org.owasp.esapi")
|
|
|| source.contains("org.springframework")
|
|
}
|
|
|
|
fn utils_stub() -> String {
|
|
r#"package org.owasp.benchmark.helpers;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
public class Utils {
|
|
public static String testfileDir = "/tmp/testfiles/";
|
|
public static String encodeForHTML(String s) { return s == null ? "" : s; }
|
|
public static String escapeHtml(String s) { return s == null ? "" : s; }
|
|
public static String htmlEscape(String s) { return s == null ? "" : s; }
|
|
public static String getFileFromClasspath(String name, ClassLoader cl) { return name; }
|
|
public static String getInsecureOSCommandString(ClassLoader cl) { return "/bin/sh"; }
|
|
public static String getOSCommandString(String cmd) { return cmd == null ? "/bin/sh" : cmd; }
|
|
public static void printOSCommandResults(Process p, Object response) {
|
|
try {
|
|
InputStream is = p.getInputStream();
|
|
if (is != null) { is.close(); }
|
|
} catch (IOException ignore) {}
|
|
}
|
|
}
|
|
"#
|
|
.to_owned()
|
|
}
|
|
|
|
fn database_helper_stub() -> String {
|
|
r#"package org.owasp.benchmark.helpers;
|
|
import java.sql.Connection;
|
|
import java.sql.ResultSet;
|
|
import java.sql.SQLException;
|
|
import java.sql.Statement;
|
|
public class DatabaseHelper {
|
|
public static boolean hideSQLErrors = false;
|
|
public static BenchmarkJdbcTemplate JDBCtemplate = new BenchmarkJdbcTemplate();
|
|
public static Connection getSqlConnection() throws SQLException { return null; }
|
|
public static Statement getSqlStatement() throws SQLException { return null; }
|
|
public static void printResults(ResultSet rs, String sql, Object response) throws SQLException {}
|
|
public static void printResults(Statement statement, String sql, Object response) throws SQLException {}
|
|
public static void outputUpdateComplete(String sql, Object response) {}
|
|
}
|
|
"#
|
|
.to_owned()
|
|
}
|
|
|
|
fn benchmark_jdbc_template_stub() -> String {
|
|
// Names the small JdbcTemplate-shaped surface OWASP fixtures call
|
|
// off `DatabaseHelper.JDBCtemplate`. Real Spring JdbcTemplate
|
|
// ships in spring-jdbc; this stub keeps the link step succeeding
|
|
// without dragging that jar in.
|
|
r#"package org.owasp.benchmark.helpers;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import org.springframework.jdbc.core.RowMapper;
|
|
import org.springframework.jdbc.support.rowset.SqlRowSet;
|
|
public class BenchmarkJdbcTemplate {
|
|
public int queryForInt(String sql) { return 0; }
|
|
public Long queryForLong(String sql) { return 0L; }
|
|
public List<?> queryForList(String sql) { return Collections.emptyList(); }
|
|
public Map<String, Object> queryForMap(String sql) { return Collections.emptyMap(); }
|
|
public <T> T queryForObject(String sql, Object[] args, Class<T> requiredType) { return null; }
|
|
public SqlRowSet queryForRowSet(String sql) { return null; }
|
|
public <T> List<T> query(String sql, RowMapper<T> mapper) { return Collections.emptyList(); }
|
|
public int[] batchUpdate(String sql) { return new int[0]; }
|
|
public void execute(String sql) {}
|
|
}
|
|
"#
|
|
.to_owned()
|
|
}
|
|
|
|
fn ldap_manager_stub() -> String {
|
|
r#"package org.owasp.benchmark.helpers;
|
|
import javax.naming.NamingException;
|
|
import javax.naming.directory.DirContext;
|
|
public class LDAPManager {
|
|
public LDAPManager() {}
|
|
public DirContext getDirContext() throws NamingException { return null; }
|
|
public void closeDirContext() {}
|
|
}
|
|
"#
|
|
.to_owned()
|
|
}
|
|
|
|
fn separate_class_request_stub() -> String {
|
|
// Real SeparateClassRequest wraps a servlet request and delegates
|
|
// getTheParameter / getTheValue through to it; the stub keeps the
|
|
// public surface but discards the request reference.
|
|
r#"package org.owasp.benchmark.helpers;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
public class SeparateClassRequest {
|
|
public SeparateClassRequest(HttpServletRequest request) {}
|
|
public String getTheParameter(String name) { return null; }
|
|
public String getTheValue(String name) { return null; }
|
|
}
|
|
"#
|
|
.to_owned()
|
|
}
|
|
|
|
fn thing_factory_stub() -> String {
|
|
r#"package org.owasp.benchmark.helpers;
|
|
public class ThingFactory {
|
|
public static ThingInterface createThing() {
|
|
return new ThingInterface() {
|
|
@Override public String doSomething(String input) { return input; }
|
|
};
|
|
}
|
|
}
|
|
"#
|
|
.to_owned()
|
|
}
|
|
|
|
fn thing_interface_stub() -> String {
|
|
r#"package org.owasp.benchmark.helpers;
|
|
public interface ThingInterface {
|
|
String doSomething(String input);
|
|
}
|
|
"#
|
|
.to_owned()
|
|
}
|
|
|
|
fn esapi_stub() -> String {
|
|
r#"package org.owasp.esapi;
|
|
public class ESAPI {
|
|
private static final Encoder ENCODER = new Encoder() {
|
|
@Override public String encodeForHTML(String s) { return s == null ? "" : s; }
|
|
@Override public String encodeForBase64(byte[] b, boolean wrap) {
|
|
return b == null ? "" : java.util.Base64.getEncoder().encodeToString(b);
|
|
}
|
|
};
|
|
public static Encoder encoder() { return ENCODER; }
|
|
}
|
|
"#
|
|
.to_owned()
|
|
}
|
|
|
|
fn encoder_stub() -> String {
|
|
r#"package org.owasp.esapi;
|
|
public interface Encoder {
|
|
String encodeForHTML(String s);
|
|
String encodeForBase64(byte[] b, boolean wrap);
|
|
}
|
|
"#
|
|
.to_owned()
|
|
}
|
|
|
|
fn data_access_exception_stub() -> String {
|
|
r#"package org.springframework.dao;
|
|
public class DataAccessException extends RuntimeException {
|
|
public DataAccessException(String msg) { super(msg); }
|
|
public DataAccessException(String msg, Throwable cause) { super(msg, cause); }
|
|
}
|
|
"#
|
|
.to_owned()
|
|
}
|
|
|
|
fn row_mapper_stub() -> String {
|
|
r#"package org.springframework.jdbc.core;
|
|
import java.sql.ResultSet;
|
|
import java.sql.SQLException;
|
|
import org.springframework.dao.DataAccessException;
|
|
public interface RowMapper<T> {
|
|
T mapRow(ResultSet rs, int rowNum) throws SQLException, DataAccessException;
|
|
}
|
|
"#
|
|
.to_owned()
|
|
}
|
|
|
|
fn sql_row_set_stub() -> String {
|
|
r#"package org.springframework.jdbc.support.rowset;
|
|
public interface SqlRowSet {
|
|
boolean next();
|
|
String getString(int columnIndex);
|
|
String getString(String columnLabel);
|
|
int getInt(int columnIndex);
|
|
int getInt(String columnLabel);
|
|
Object getObject(int columnIndex);
|
|
Object getObject(String columnLabel);
|
|
}
|
|
"#
|
|
.to_owned()
|
|
}
|
|
|
|
fn html_utils_stub() -> String {
|
|
r#"package org.springframework.web.util;
|
|
public class HtmlUtils {
|
|
public static String htmlEscape(String s) { return s == null ? "" : s; }
|
|
public static String htmlUnescape(String s) { return s == null ? "" : s; }
|
|
}
|
|
"#
|
|
.to_owned()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn entry_needs_owasp_stubs_detects_helper_imports() {
|
|
let src = "package x;\nimport org.owasp.benchmark.helpers.Utils;\npublic class V {}\n";
|
|
assert!(entry_needs_owasp_stubs(src));
|
|
}
|
|
|
|
#[test]
|
|
fn entry_needs_owasp_stubs_detects_esapi_imports() {
|
|
let src = "import org.owasp.esapi.ESAPI;\npublic class V {}\n";
|
|
assert!(entry_needs_owasp_stubs(src));
|
|
}
|
|
|
|
#[test]
|
|
fn entry_needs_owasp_stubs_detects_spring_imports() {
|
|
let src = "import org.springframework.web.util.HtmlUtils;\n";
|
|
assert!(entry_needs_owasp_stubs(src));
|
|
}
|
|
|
|
#[test]
|
|
fn entry_needs_owasp_stubs_detects_inline_fqn() {
|
|
// OWASP fixtures often use inline FQNs without an import line.
|
|
let src = "public class V { void f() { org.owasp.esapi.ESAPI.encoder(); } }";
|
|
assert!(entry_needs_owasp_stubs(src));
|
|
}
|
|
|
|
#[test]
|
|
fn entry_needs_owasp_stubs_rejects_non_owasp_source() {
|
|
let src = "public class V { void f() { System.out.println(\"hi\"); } }";
|
|
assert!(!entry_needs_owasp_stubs(src));
|
|
}
|
|
|
|
#[test]
|
|
fn bundle_includes_owasp_helpers() {
|
|
let paths: Vec<String> = owasp_stub_files().into_iter().map(|(p, _)| p).collect();
|
|
for required in &[
|
|
"org/owasp/benchmark/helpers/Utils.java",
|
|
"org/owasp/benchmark/helpers/DatabaseHelper.java",
|
|
"org/owasp/benchmark/helpers/BenchmarkJdbcTemplate.java",
|
|
"org/owasp/benchmark/helpers/LDAPManager.java",
|
|
"org/owasp/benchmark/helpers/SeparateClassRequest.java",
|
|
"org/owasp/benchmark/helpers/ThingFactory.java",
|
|
"org/owasp/benchmark/helpers/ThingInterface.java",
|
|
"org/owasp/esapi/ESAPI.java",
|
|
"org/owasp/esapi/Encoder.java",
|
|
"org/springframework/dao/DataAccessException.java",
|
|
"org/springframework/jdbc/core/RowMapper.java",
|
|
"org/springframework/jdbc/support/rowset/SqlRowSet.java",
|
|
"org/springframework/web/util/HtmlUtils.java",
|
|
] {
|
|
assert!(
|
|
paths.iter().any(|p| p == required),
|
|
"owasp stub bundle missing {required}; got {paths:?}",
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn utils_stub_carries_owasp_method_surface() {
|
|
let src = utils_stub();
|
|
for method in &[
|
|
"testfileDir",
|
|
"encodeForHTML",
|
|
"escapeHtml",
|
|
"htmlEscape",
|
|
"getFileFromClasspath",
|
|
"getInsecureOSCommandString",
|
|
"getOSCommandString",
|
|
"printOSCommandResults",
|
|
] {
|
|
assert!(
|
|
src.contains(method),
|
|
"Utils stub missing OWASP surface member `{method}`",
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn database_helper_stub_carries_owasp_method_surface() {
|
|
let src = database_helper_stub();
|
|
for method in &[
|
|
"hideSQLErrors",
|
|
"JDBCtemplate",
|
|
"getSqlConnection",
|
|
"getSqlStatement",
|
|
"printResults",
|
|
"outputUpdateComplete",
|
|
] {
|
|
assert!(
|
|
src.contains(method),
|
|
"DatabaseHelper stub missing OWASP surface member `{method}`",
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn benchmark_jdbc_template_carries_call_surface() {
|
|
let src = benchmark_jdbc_template_stub();
|
|
for method in &[
|
|
"queryForInt",
|
|
"queryForLong",
|
|
"queryForList",
|
|
"queryForMap",
|
|
"queryForObject",
|
|
"queryForRowSet",
|
|
"query",
|
|
"batchUpdate",
|
|
"execute",
|
|
] {
|
|
assert!(
|
|
src.contains(method),
|
|
"BenchmarkJdbcTemplate stub missing OWASP surface member `{method}`",
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn encoder_stub_declares_two_encode_methods() {
|
|
let src = encoder_stub();
|
|
assert!(src.contains("encodeForHTML"));
|
|
assert!(src.contains("encodeForBase64"));
|
|
}
|
|
|
|
#[test]
|
|
fn esapi_stub_returns_anonymous_encoder() {
|
|
let src = esapi_stub();
|
|
assert!(src.contains("public static Encoder encoder()"));
|
|
assert!(src.contains("new Encoder()"));
|
|
}
|
|
|
|
#[test]
|
|
fn separate_class_request_takes_servlet_request() {
|
|
let src = separate_class_request_stub();
|
|
assert!(src.contains("javax.servlet.http.HttpServletRequest"));
|
|
assert!(src.contains("getTheParameter"));
|
|
assert!(src.contains("getTheValue"));
|
|
}
|
|
|
|
#[test]
|
|
fn bundle_has_thirteen_files() {
|
|
// Tripwire: 9 OWASP-namespace + 4 spring-namespace stubs. A
|
|
// count drift here usually means a stub was added without
|
|
// updating the assertion or a stub got accidentally dropped.
|
|
let files = owasp_stub_files();
|
|
assert_eq!(
|
|
files.len(),
|
|
13,
|
|
"expected 9 owasp + 4 springframework stubs"
|
|
);
|
|
}
|
|
}
|