mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-09 19:45:13 +02:00
[pitboss/grind] deferred session-0001 (20260520T233019Z-6958)
This commit is contained in:
parent
f9bd51c024
commit
3b49b4d4b5
5 changed files with 88 additions and 7 deletions
|
|
@ -44,7 +44,9 @@
|
|||
use criterion::{Criterion, criterion_group, criterion_main};
|
||||
|
||||
#[cfg(feature = "dynamic")]
|
||||
use nyx_scanner::dynamic::spec::{EntryKind, HarnessSpec, PayloadSlot, SpecDerivationStrategy};
|
||||
use nyx_scanner::dynamic::spec::{
|
||||
EntryKind, HarnessSpec, JavaToolchain, PayloadSlot, SpecDerivationStrategy,
|
||||
};
|
||||
#[cfg(feature = "dynamic")]
|
||||
use nyx_scanner::labels::Cap;
|
||||
#[cfg(feature = "dynamic")]
|
||||
|
|
@ -68,6 +70,7 @@ fn make_rust_sqli_spec() -> HarnessSpec {
|
|||
derivation: SpecDerivationStrategy::FromFlowSteps,
|
||||
stubs_required: vec![],
|
||||
framework: None,
|
||||
java_toolchain: JavaToolchain::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,6 +92,7 @@ fn make_sqli_spec() -> HarnessSpec {
|
|||
derivation: SpecDerivationStrategy::FromFlowSteps,
|
||||
stubs_required: vec![],
|
||||
framework: None,
|
||||
java_toolchain: JavaToolchain::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -288,6 +292,7 @@ fn make_js_sqli_spec() -> HarnessSpec {
|
|||
derivation: SpecDerivationStrategy::FromFlowSteps,
|
||||
stubs_required: vec![],
|
||||
framework: None,
|
||||
java_toolchain: JavaToolchain::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -309,6 +314,7 @@ fn make_go_sqli_spec() -> HarnessSpec {
|
|||
derivation: SpecDerivationStrategy::FromFlowSteps,
|
||||
stubs_required: vec![],
|
||||
framework: None,
|
||||
java_toolchain: JavaToolchain::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -330,6 +336,7 @@ fn make_java_sqli_spec() -> HarnessSpec {
|
|||
derivation: SpecDerivationStrategy::FromFlowSteps,
|
||||
stubs_required: vec![],
|
||||
framework: None,
|
||||
java_toolchain: JavaToolchain::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -351,6 +358,7 @@ fn make_php_sqli_spec() -> HarnessSpec {
|
|||
derivation: SpecDerivationStrategy::FromFlowSteps,
|
||||
stubs_required: vec![],
|
||||
framework: None,
|
||||
java_toolchain: JavaToolchain::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -723,6 +723,8 @@ fn emit_middleware_harness(handler: &str, name: &str) -> HarnessSource {
|
|||
r#"{preamble}
|
||||
puts "__NYX_MIDDLEWARE__: " + {name:?}
|
||||
|
||||
require 'stringio'
|
||||
|
||||
# Rack-shape middleware: class with #call(env).
|
||||
env = {{
|
||||
'REQUEST_METHOD' => 'POST',
|
||||
|
|
@ -731,7 +733,6 @@ env = {{
|
|||
'rack.input' => StringIO.new($nyx_payload),
|
||||
'nyx.payload' => $nyx_payload,
|
||||
}}
|
||||
require 'stringio'
|
||||
|
||||
if Object.const_defined?({handler:?})
|
||||
cls = Object.const_get({handler:?})
|
||||
|
|
@ -1233,7 +1234,8 @@ fn invoke_for_shape(spec: &HarnessSpec, shape: RubyShape, entry_fn: &str) -> Str
|
|||
RubyShape::RackMiddleware => {
|
||||
let cls = entry_class_from_spec(spec);
|
||||
format!(
|
||||
r#" cls = Object.const_defined?({cls:?}) ? Object.const_get({cls:?}) : nil
|
||||
r#" require 'stringio'
|
||||
cls = Object.const_defined?({cls:?}) ? Object.const_get({cls:?}) : nil
|
||||
if cls
|
||||
inner = cls.respond_to?(:new) ? (cls.method(:new).arity == 0 ? cls.new : cls.new(nil)) : nil
|
||||
env = {{
|
||||
|
|
@ -1243,7 +1245,6 @@ fn invoke_for_shape(spec: &HarnessSpec, shape: RubyShape, entry_fn: &str) -> Str
|
|||
'rack.input' => StringIO.new(($nyx_request[:body] rescue '')),
|
||||
'nyx.payload' => $nyx_payload,
|
||||
}}
|
||||
require 'stringio'
|
||||
status, headers, body = inner.call(env)
|
||||
Array(body).each {{ |chunk| print(chunk.to_s) }}
|
||||
end"#,
|
||||
|
|
|
|||
|
|
@ -775,7 +775,20 @@ pub fn run(
|
|||
}
|
||||
}
|
||||
SandboxBackend::Auto => {
|
||||
if docker_available() && harness_is_interpreted(&harness.command) {
|
||||
// Docker containers run the interpreter image's bare runtime
|
||||
// (python:3-slim, node:20-slim, ruby:3-slim, ...) with no
|
||||
// network access under NetworkPolicy::None. Harness shapes
|
||||
// that depend on packages declared via requirements.txt /
|
||||
// package.json / Gemfile / composer.json can be served from
|
||||
// the host build cache by prepare_*, but the container has
|
||||
// no way to fetch them at exec time. Route to the process
|
||||
// backend in that case so the harness picks up the host
|
||||
// venv / node_modules / vendor dir already prepared.
|
||||
let needs_host_deps = harness_needs_host_deps(harness);
|
||||
if docker_available()
|
||||
&& harness_is_interpreted(&harness.command)
|
||||
&& !needs_host_deps
|
||||
{
|
||||
run_docker(harness, payload_bytes, opts)
|
||||
} else if docker_available() && harness_is_native_binary(&harness.command) {
|
||||
run_native_binary_docker(harness, payload_bytes, opts)
|
||||
|
|
@ -788,6 +801,33 @@ pub fn run(
|
|||
}
|
||||
}
|
||||
|
||||
/// True when the harness workdir carries a dependency manifest that the
|
||||
/// docker backend has no mechanism to materialise inside the container.
|
||||
///
|
||||
/// `prepare_python` / `prepare_node` / `prepare_php` / etc. resolve these
|
||||
/// against the host build cache before the run, so the process backend
|
||||
/// already has a fully-populated venv / node_modules / vendor dir to
|
||||
/// invoke. The docker backend, on the other hand, mounts the workdir
|
||||
/// into a bare interpreter image (python:3-slim, node:20-slim, ...) and
|
||||
/// runs under `--network=none`, leaving no path for an in-container
|
||||
/// `pip install` / `npm install` / `composer install` to fetch the deps.
|
||||
/// Routing those shapes to the process backend keeps the verifier honest
|
||||
/// on dev hosts where docker is available but the bare image lacks the
|
||||
/// third-party libs the entry source imports.
|
||||
fn harness_needs_host_deps(harness: &BuiltHarness) -> bool {
|
||||
const MANIFESTS: &[&str] = &[
|
||||
"requirements.txt",
|
||||
"Pipfile.lock",
|
||||
"pyproject.toml",
|
||||
"package.json",
|
||||
"Gemfile",
|
||||
"composer.json",
|
||||
];
|
||||
MANIFESTS
|
||||
.iter()
|
||||
.any(|name| harness.workdir.join(name).exists())
|
||||
}
|
||||
|
||||
/// Phase 20 (Track E.4): dispatch the Firecracker backend.
|
||||
///
|
||||
/// When `--features firecracker` is off, the call returns
|
||||
|
|
|
|||
|
|
@ -424,7 +424,8 @@ mod e2e_phase_07 {
|
|||
Lang::Java => "java",
|
||||
Lang::Python => "python3",
|
||||
Lang::Php => "php",
|
||||
_ => unreachable!("e2e_phase_07 covers Java/Python/PHP"),
|
||||
Lang::JavaScript => "node",
|
||||
_ => unreachable!("e2e_phase_07 covers Java/Python/PHP/JS"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -433,6 +434,7 @@ mod e2e_phase_07 {
|
|||
Lang::Java => "java",
|
||||
Lang::Python => "python",
|
||||
Lang::Php => "php",
|
||||
Lang::JavaScript => "js",
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
@ -549,4 +551,18 @@ mod e2e_phase_07 {
|
|||
.expect("Confirmed run must carry a DifferentialOutcome");
|
||||
assert_eq!(diff.verdict, DifferentialVerdict::Confirmed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn javascript_vuln_confirms_via_run_spec() {
|
||||
let Some(outcome) = run(Lang::JavaScript, "vuln.js", "run") else { return };
|
||||
assert!(
|
||||
outcome.triggered_by.is_some(),
|
||||
"JavaScript XPath vuln must Confirm via run_spec; got {outcome:?}",
|
||||
);
|
||||
let diff = outcome
|
||||
.differential
|
||||
.as_ref()
|
||||
.expect("Confirmed run must carry a DifferentialOutcome");
|
||||
assert_eq!(diff.verdict, DifferentialVerdict::Confirmed);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -354,7 +354,8 @@ mod e2e_phase_05 {
|
|||
Lang::Python => "python3",
|
||||
Lang::Php => "php",
|
||||
Lang::Ruby => "ruby",
|
||||
_ => unreachable!("e2e_phase_05 covers Java/Python/PHP/Ruby"),
|
||||
Lang::Go => "go",
|
||||
_ => unreachable!("e2e_phase_05 covers Java/Python/PHP/Ruby/Go"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -364,6 +365,7 @@ mod e2e_phase_05 {
|
|||
Lang::Python => "python",
|
||||
Lang::Php => "php",
|
||||
Lang::Ruby => "ruby",
|
||||
Lang::Go => "go",
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
@ -494,4 +496,18 @@ mod e2e_phase_05 {
|
|||
.expect("Confirmed run must carry a DifferentialOutcome");
|
||||
assert_eq!(diff.verdict, DifferentialVerdict::Confirmed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn go_vuln_confirms_via_run_spec() {
|
||||
let Some(outcome) = run(Lang::Go, "vuln.go", "run") else { return };
|
||||
assert!(
|
||||
outcome.triggered_by.is_some(),
|
||||
"Go XXE vuln must Confirm via run_spec; got {outcome:?}",
|
||||
);
|
||||
let diff = outcome
|
||||
.differential
|
||||
.as_ref()
|
||||
.expect("Confirmed run must carry a DifferentialOutcome");
|
||||
assert_eq!(diff.verdict, DifferentialVerdict::Confirmed);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue