mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-12 19:55:14 +02:00
[pitboss] phase 20: Track M.2 — MessageHandler end-to-end (Kafka / SQS / Pub-Sub / NATS / RabbitMQ)
This commit is contained in:
parent
fedc507e6a
commit
bd0135e423
45 changed files with 3227 additions and 25 deletions
|
|
@ -0,0 +1,9 @@
|
|||
// Phase 20 (Track M.2) — Kafka Java benign control.
|
||||
// `org.springframework.kafka` adapter marker preserved.
|
||||
public class Benign {
|
||||
public Benign() {}
|
||||
|
||||
public void onMessage(String body) throws Exception {
|
||||
new ProcessBuilder("echo", body).inheritIO().start().waitFor();
|
||||
}
|
||||
}
|
||||
15
tests/dynamic_fixtures/message_handler/kafka_java/Vuln.java
Normal file
15
tests/dynamic_fixtures/message_handler/kafka_java/Vuln.java
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// Phase 20 (Track M.2) — Kafka Java vuln fixture.
|
||||
//
|
||||
// Marker line so the kafka-java framework adapter binds:
|
||||
// `org.springframework.kafka` consumer entry point. Annotation is
|
||||
// elided so javac compiles without the Spring jar; the dynamic harness
|
||||
// invokes onMessage reflectively.
|
||||
|
||||
public class Vuln {
|
||||
public Vuln() {}
|
||||
|
||||
public void onMessage(String body) throws Exception {
|
||||
// SINK: tainted body concatenated into shell command
|
||||
new ProcessBuilder("sh", "-c", "echo " + body).inheritIO().start().waitFor();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
"""Phase 20 (Track M.2) — Kafka Python benign control."""
|
||||
import os
|
||||
import shlex
|
||||
|
||||
_NYX_ADAPTER_MARKER = "from kafka import KafkaConsumer"
|
||||
|
||||
|
||||
def handler(message):
|
||||
os.system("echo " + shlex.quote(str(message)))
|
||||
25
tests/dynamic_fixtures/message_handler/kafka_python/vuln.py
Normal file
25
tests/dynamic_fixtures/message_handler/kafka_python/vuln.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
"""Phase 20 (Track M.2) — Kafka Python vuln fixture.
|
||||
|
||||
`handler` is a Kafka consumer callback (modelled after
|
||||
`KafkaConsumer('orders').poll()` dispatch) that splices the raw
|
||||
message body into a shell command via `os.system`. A malicious
|
||||
producer can inject command-separator metacharacters into the body
|
||||
and the shell will execute them — the classic message-handler cmdi
|
||||
shape.
|
||||
|
||||
Adapter source-marker: `from kafka import KafkaConsumer` is kept as a
|
||||
docstring reference (not a top-level import) so the harness can run
|
||||
without the real `kafka-python` library installed on the host.
|
||||
"""
|
||||
import os
|
||||
|
||||
# Phase 20 framework adapter detects this fixture via the `from kafka`
|
||||
# / `import kafka` substring scan. Keeping the marker in source lets
|
||||
# the adapter bind without forcing the host to pin the kafka-python
|
||||
# pip dep just to load the fixture module.
|
||||
_NYX_ADAPTER_MARKER = "from kafka import KafkaConsumer"
|
||||
|
||||
|
||||
def handler(message):
|
||||
# SINK: tainted message body concatenated into shell command
|
||||
os.system("echo " + str(message))
|
||||
19
tests/dynamic_fixtures/message_handler/nats_go/benign.go
Normal file
19
tests/dynamic_fixtures/message_handler/nats_go/benign.go
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Phase 20 (Track M.2) — NATS Go benign control.
|
||||
package entry
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
const _adapterMarker = "github.com/nats-io/nats.go"
|
||||
|
||||
func OnMessage(payload string) {
|
||||
cmd := exec.Command("echo", payload)
|
||||
out, _ := cmd.Output()
|
||||
os.Stdout.Write(out)
|
||||
}
|
||||
|
||||
var NyxHandlers = map[string]interface{}{
|
||||
"OnMessage": OnMessage,
|
||||
}
|
||||
22
tests/dynamic_fixtures/message_handler/nats_go/vuln.go
Normal file
22
tests/dynamic_fixtures/message_handler/nats_go/vuln.go
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Phase 20 (Track M.2) — NATS Go vuln fixture.
|
||||
//
|
||||
// Adapter source-marker: github.com/nats-io/nats.go (string-literal only).
|
||||
package entry
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
const _adapterMarker = "github.com/nats-io/nats.go"
|
||||
|
||||
func OnMessage(payload string) {
|
||||
// SINK: tainted payload concatenated into shell command
|
||||
cmd := exec.Command("sh", "-c", "echo "+payload)
|
||||
out, _ := cmd.Output()
|
||||
os.Stdout.Write(out)
|
||||
}
|
||||
|
||||
var NyxHandlers = map[string]interface{}{
|
||||
"OnMessage": OnMessage,
|
||||
}
|
||||
19
tests/dynamic_fixtures/message_handler/pubsub_go/benign.go
Normal file
19
tests/dynamic_fixtures/message_handler/pubsub_go/benign.go
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Phase 20 (Track M.2) — Google Pub/Sub Go benign control.
|
||||
package entry
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
const _adapterMarker = "cloud.google.com/go/pubsub"
|
||||
|
||||
func OnMessage(payload string) {
|
||||
cmd := exec.Command("echo", payload)
|
||||
out, _ := cmd.Output()
|
||||
os.Stdout.Write(out)
|
||||
}
|
||||
|
||||
var NyxHandlers = map[string]interface{}{
|
||||
"OnMessage": OnMessage,
|
||||
}
|
||||
24
tests/dynamic_fixtures/message_handler/pubsub_go/vuln.go
Normal file
24
tests/dynamic_fixtures/message_handler/pubsub_go/vuln.go
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Phase 20 (Track M.2) — Google Pub/Sub Go vuln fixture.
|
||||
//
|
||||
// Adapter source-marker: cloud.google.com/go/pubsub (string-literal only).
|
||||
// The handler signature accepts a string so the Phase 20 harness
|
||||
// dispatch falls through to the NYX_PAYLOAD env var.
|
||||
package entry
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
const _adapterMarker = "cloud.google.com/go/pubsub"
|
||||
|
||||
func OnMessage(payload string) {
|
||||
// SINK: tainted payload concatenated into shell command
|
||||
cmd := exec.Command("sh", "-c", "echo "+payload)
|
||||
out, _ := cmd.Output()
|
||||
os.Stdout.Write(out)
|
||||
}
|
||||
|
||||
var NyxHandlers = map[string]interface{}{
|
||||
"OnMessage": OnMessage,
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
"""Phase 20 (Track M.2) — Google Pub/Sub Python benign control."""
|
||||
import os
|
||||
import shlex
|
||||
|
||||
_NYX_ADAPTER_MARKER = "from google.cloud import pubsub_v1"
|
||||
_NYX_TOPIC_MARKER = '.subscribe("projects/p/subscriptions/s"'
|
||||
|
||||
|
||||
def callback(message):
|
||||
body = getattr(message, 'data', None)
|
||||
if body is None and isinstance(message, dict):
|
||||
body = message.get('data')
|
||||
if isinstance(body, (bytes, bytearray)):
|
||||
body = body.decode('utf-8', 'replace')
|
||||
if body is None:
|
||||
body = str(message)
|
||||
os.system("echo " + shlex.quote(body))
|
||||
try:
|
||||
message.ack()
|
||||
except Exception:
|
||||
pass
|
||||
28
tests/dynamic_fixtures/message_handler/pubsub_python/vuln.py
Normal file
28
tests/dynamic_fixtures/message_handler/pubsub_python/vuln.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
"""Phase 20 (Track M.2) — Google Pub/Sub Python vuln fixture.
|
||||
|
||||
`callback` is a `pubsub_v1.SubscriberClient.subscribe` callback that
|
||||
takes `message.data` bytes straight into a shell command.
|
||||
|
||||
Adapter marker kept as a string literal so the google-cloud-pubsub dep
|
||||
is not required to load the module.
|
||||
"""
|
||||
import os
|
||||
|
||||
_NYX_ADAPTER_MARKER = "from google.cloud import pubsub_v1"
|
||||
_NYX_TOPIC_MARKER = '.subscribe("projects/p/subscriptions/s"'
|
||||
|
||||
|
||||
def callback(message):
|
||||
body = getattr(message, 'data', None)
|
||||
if body is None and isinstance(message, dict):
|
||||
body = message.get('data')
|
||||
if isinstance(body, (bytes, bytearray)):
|
||||
body = body.decode('utf-8', 'replace')
|
||||
if body is None:
|
||||
body = str(message)
|
||||
# SINK: tainted message body concatenated into shell command
|
||||
os.system("echo " + body)
|
||||
try:
|
||||
message.ack()
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// Phase 20 (Track M.2) — RabbitMQ Java benign control.
|
||||
// `org.springframework.amqp.rabbit` adapter marker preserved.
|
||||
|
||||
public class Benign {
|
||||
public Benign() {}
|
||||
|
||||
public void onMessage(String messageId, String body) throws Exception {
|
||||
new ProcessBuilder("echo", body).inheritIO().start().waitFor();
|
||||
}
|
||||
}
|
||||
12
tests/dynamic_fixtures/message_handler/rabbit_java/Vuln.java
Normal file
12
tests/dynamic_fixtures/message_handler/rabbit_java/Vuln.java
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Phase 20 (Track M.2) — RabbitMQ Java vuln fixture.
|
||||
// `org.springframework.amqp.rabbit` consumer marker preserved;
|
||||
// annotation elided so javac compiles without the Spring AMQP jar.
|
||||
|
||||
public class Vuln {
|
||||
public Vuln() {}
|
||||
|
||||
public void onMessage(String messageId, String body) throws Exception {
|
||||
// SINK: tainted body concatenated into shell command
|
||||
new ProcessBuilder("sh", "-c", "echo " + body).inheritIO().start().waitFor();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
"""Phase 20 (Track M.2) — RabbitMQ Python benign control."""
|
||||
import os
|
||||
import shlex
|
||||
|
||||
_NYX_ADAPTER_MARKER = "import pika"
|
||||
_NYX_QUEUE_MARKER = 'queue="work"'
|
||||
|
||||
|
||||
def on_message(ch, method, properties, body):
|
||||
if isinstance(body, (bytes, bytearray)):
|
||||
body = body.decode('utf-8', 'replace')
|
||||
os.system("echo " + shlex.quote(body))
|
||||
19
tests/dynamic_fixtures/message_handler/rabbit_python/vuln.py
Normal file
19
tests/dynamic_fixtures/message_handler/rabbit_python/vuln.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
"""Phase 20 (Track M.2) — RabbitMQ Python vuln fixture.
|
||||
|
||||
`on_message` is a `pika.BlockingConnection.channel.basic_consume`
|
||||
callback whose body argument flows into a shell command.
|
||||
|
||||
Adapter marker kept as a string literal so the pika dep is not
|
||||
required to load the module.
|
||||
"""
|
||||
import os
|
||||
|
||||
_NYX_ADAPTER_MARKER = "import pika"
|
||||
_NYX_QUEUE_MARKER = 'queue="work"'
|
||||
|
||||
|
||||
def on_message(ch, method, properties, body):
|
||||
if isinstance(body, (bytes, bytearray)):
|
||||
body = body.decode('utf-8', 'replace')
|
||||
# SINK: tainted body concatenated into shell command
|
||||
os.system("echo " + body)
|
||||
11
tests/dynamic_fixtures/message_handler/sqs_java/Benign.java
Normal file
11
tests/dynamic_fixtures/message_handler/sqs_java/Benign.java
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// Phase 20 (Track M.2) — SQS Java benign control.
|
||||
// `io.awspring.cloud.sqs` adapter marker preserved.
|
||||
|
||||
public class Benign {
|
||||
public Benign() {}
|
||||
|
||||
public void handleMessage(java.util.Map<String, String> env) throws Exception {
|
||||
String body = env != null ? env.getOrDefault("Body", "") : "";
|
||||
new ProcessBuilder("echo", body).inheritIO().start().waitFor();
|
||||
}
|
||||
}
|
||||
13
tests/dynamic_fixtures/message_handler/sqs_java/Vuln.java
Normal file
13
tests/dynamic_fixtures/message_handler/sqs_java/Vuln.java
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// Phase 20 (Track M.2) — SQS Java vuln fixture.
|
||||
// `io.awspring.cloud.sqs` consumer entry point — annotation elided so
|
||||
// javac compiles without the Spring Cloud AWS jar.
|
||||
|
||||
public class Vuln {
|
||||
public Vuln() {}
|
||||
|
||||
public void handleMessage(java.util.Map<String, String> env) throws Exception {
|
||||
String body = env != null ? env.getOrDefault("Body", "") : "";
|
||||
// SINK: tainted Body concatenated into shell command
|
||||
new ProcessBuilder("sh", "-c", "echo " + body).inheritIO().start().waitFor();
|
||||
}
|
||||
}
|
||||
16
tests/dynamic_fixtures/message_handler/sqs_node/benign.js
Normal file
16
tests/dynamic_fixtures/message_handler/sqs_node/benign.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Phase 20 (Track M.2) — SQS Node benign control.
|
||||
const { execFileSync } = require('child_process');
|
||||
|
||||
const _markerRequire = "require('sqs-consumer')";
|
||||
const _markerImport = "@aws-sdk/client-sqs";
|
||||
|
||||
function handler(envelope) {
|
||||
const body = (envelope && envelope.Body) ? envelope.Body : '';
|
||||
try {
|
||||
const out = execFileSync('echo', [body]).toString();
|
||||
process.stdout.write(out);
|
||||
} catch (_e) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { handler };
|
||||
22
tests/dynamic_fixtures/message_handler/sqs_node/vuln.js
Normal file
22
tests/dynamic_fixtures/message_handler/sqs_node/vuln.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Phase 20 (Track M.2) — SQS Node vuln fixture.
|
||||
// `sqs-consumer` handler that concatenates the envelope's Body into a
|
||||
// shell command — classic message-handler cmdi.
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
// Adapter source-marker: require('sqs-consumer') (string-literal only)
|
||||
const _markerRequire = "require('sqs-consumer')";
|
||||
const _markerImport = "@aws-sdk/client-sqs";
|
||||
|
||||
function handler(envelope) {
|
||||
const body = (envelope && envelope.Body) ? envelope.Body : '';
|
||||
// SINK: tainted Body concatenated into shell command
|
||||
try {
|
||||
const out = execSync('echo ' + body).toString();
|
||||
process.stdout.write(out);
|
||||
} catch (_e) {
|
||||
// surface stderr on the harness's stderr; the oracle reads
|
||||
// stdout
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { handler };
|
||||
10
tests/dynamic_fixtures/message_handler/sqs_python/benign.py
Normal file
10
tests/dynamic_fixtures/message_handler/sqs_python/benign.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
"""Phase 20 (Track M.2) — SQS Python benign control."""
|
||||
import os
|
||||
import shlex
|
||||
|
||||
_NYX_ADAPTER_MARKER = "boto3.client('sqs')"
|
||||
|
||||
|
||||
def handler(envelope):
|
||||
body = envelope.get('Body', '') if isinstance(envelope, dict) else str(envelope)
|
||||
os.system("echo " + shlex.quote(body))
|
||||
17
tests/dynamic_fixtures/message_handler/sqs_python/vuln.py
Normal file
17
tests/dynamic_fixtures/message_handler/sqs_python/vuln.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
"""Phase 20 (Track M.2) — SQS Python vuln fixture.
|
||||
|
||||
`handler` is a boto3 SQS poller callback that takes the raw envelope's
|
||||
`Body` field straight into a shell command.
|
||||
|
||||
Adapter marker kept as a string literal so the boto3 dep is not
|
||||
required to load the module.
|
||||
"""
|
||||
import os
|
||||
|
||||
_NYX_ADAPTER_MARKER = "boto3.client('sqs')"
|
||||
|
||||
|
||||
def handler(envelope):
|
||||
body = envelope.get('Body', '') if isinstance(envelope, dict) else str(envelope)
|
||||
# SINK: tainted Body concatenated into shell command
|
||||
os.system("echo " + body)
|
||||
Loading…
Add table
Add a link
Reference in a new issue