mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-21 20:18:06 +02:00
Dynamic (#77)
This commit is contained in:
parent
55247b7fcd
commit
991c84a1eb
1464 changed files with 225448 additions and 1985 deletions
16
tests/dynamic_fixtures/class_method/c/benign.c
Normal file
16
tests/dynamic_fixtures/class_method/c/benign.c
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/* Phase 19 (Track M.1) — class-method benign control for C. */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void UserService_run(const char *input, size_t len) {
|
||||
(void)len;
|
||||
/* Uses execve via fork; the shell never sees or echoes `input`. */
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
char *argv[] = { (char*)"/usr/bin/true", (char*)(input ? input : ""), NULL };
|
||||
execv("/usr/bin/true", argv);
|
||||
_exit(127);
|
||||
}
|
||||
}
|
||||
16
tests/dynamic_fixtures/class_method/c/vuln.c
Normal file
16
tests/dynamic_fixtures/class_method/c/vuln.c
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/* Phase 19 (Track M.1) — class-method vuln fixture for C.
|
||||
*
|
||||
* C has no class system; the harness calls a free function whose name
|
||||
* follows the `<Class>_<method>` convention (`UserService_run`). The
|
||||
* function piping `input` straight into `system(3)` is the SINK. */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
void UserService_run(const char *input, size_t len) {
|
||||
(void)len;
|
||||
char buf[512];
|
||||
snprintf(buf, sizeof(buf), "true %s", input ? input : "");
|
||||
/* SINK: tainted input → system(3) */
|
||||
system(buf);
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/* Benign control for the recursive C receiver fixture. */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct ShellRunner {
|
||||
int enabled;
|
||||
} ShellRunner;
|
||||
|
||||
typedef struct CommandRunner {
|
||||
ShellRunner *shell;
|
||||
} CommandRunner;
|
||||
|
||||
typedef struct UserService {
|
||||
CommandRunner *runner;
|
||||
} UserService;
|
||||
|
||||
void UserService_run(UserService *self, const char *input, size_t len) {
|
||||
(void)input;
|
||||
(void)len;
|
||||
if (!self || !self->runner || !self->runner->shell) {
|
||||
return;
|
||||
}
|
||||
system("true");
|
||||
}
|
||||
26
tests/dynamic_fixtures/class_method/c_recursive_deps/vuln.c
Normal file
26
tests/dynamic_fixtures/class_method/c_recursive_deps/vuln.c
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* ClassMethod C fixture with a receiver pointer and recursive struct deps. */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct ShellRunner {
|
||||
int enabled;
|
||||
} ShellRunner;
|
||||
|
||||
typedef struct CommandRunner {
|
||||
ShellRunner *shell;
|
||||
} CommandRunner;
|
||||
|
||||
typedef struct UserService {
|
||||
CommandRunner *runner;
|
||||
} UserService;
|
||||
|
||||
void UserService_run(UserService *self, const char *input, size_t len) {
|
||||
(void)len;
|
||||
if (!self || !self->runner || !self->runner->shell) {
|
||||
return;
|
||||
}
|
||||
char buf[512];
|
||||
snprintf(buf, sizeof(buf), "true %s", input ? input : "");
|
||||
system(buf);
|
||||
}
|
||||
19
tests/dynamic_fixtures/class_method/cpp/benign.cpp
Normal file
19
tests/dynamic_fixtures/class_method/cpp/benign.cpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Phase 19 (Track M.1) — class-method benign control for C++.
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <string>
|
||||
|
||||
class UserService {
|
||||
public:
|
||||
UserService() = default;
|
||||
void run(const std::string& input) {
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
const char* argv[] = { "/usr/bin/true", input.c_str(), nullptr };
|
||||
execv("/usr/bin/true", const_cast<char* const*>(argv));
|
||||
_exit(127);
|
||||
}
|
||||
int status = 0;
|
||||
waitpid(pid, &status, 0);
|
||||
}
|
||||
};
|
||||
17
tests/dynamic_fixtures/class_method/cpp/vuln.cpp
Normal file
17
tests/dynamic_fixtures/class_method/cpp/vuln.cpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Phase 19 (Track M.1) — class-method vuln fixture for C++.
|
||||
//
|
||||
// UserService::run pipes user input into `system(3)`. Default
|
||||
// constructor exists; the harness can build the receiver with
|
||||
// `UserService instance;`.
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
class UserService {
|
||||
public:
|
||||
UserService() = default;
|
||||
void run(const std::string& input) {
|
||||
std::string cmd = std::string("true ") + input;
|
||||
// SINK: tainted input → system(3)
|
||||
std::system(cmd.c_str());
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Benign control for recursive C++ class-method receiver construction.
|
||||
#include <string>
|
||||
|
||||
class ShellRunner {
|
||||
public:
|
||||
void exec(const std::string& _cmd) {}
|
||||
};
|
||||
|
||||
class CommandRunner {
|
||||
ShellRunner shell;
|
||||
|
||||
public:
|
||||
explicit CommandRunner(ShellRunner shell) : shell(shell) {}
|
||||
|
||||
void run(const std::string& input) {
|
||||
shell.exec(input);
|
||||
}
|
||||
};
|
||||
|
||||
class UserService {
|
||||
CommandRunner runner;
|
||||
|
||||
public:
|
||||
explicit UserService(CommandRunner runner) : runner(runner) {}
|
||||
|
||||
void run(const std::string& input) {
|
||||
runner.run(input);
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// C++ class-method fixture whose receiver has same-file constructor
|
||||
// dependencies but no default constructor.
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
class ShellRunner {
|
||||
public:
|
||||
void exec(const std::string& cmd) {
|
||||
std::system(cmd.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
class CommandRunner {
|
||||
ShellRunner shell;
|
||||
|
||||
public:
|
||||
explicit CommandRunner(ShellRunner shell) : shell(shell) {}
|
||||
|
||||
void run(const std::string& input) {
|
||||
shell.exec(std::string("true ") + input);
|
||||
}
|
||||
};
|
||||
|
||||
class UserService {
|
||||
CommandRunner runner;
|
||||
|
||||
public:
|
||||
explicit UserService(CommandRunner runner) : runner(runner) {}
|
||||
|
||||
void run(const std::string& input) {
|
||||
runner.run(input);
|
||||
}
|
||||
};
|
||||
11
tests/dynamic_fixtures/class_method/go/benign.go
Normal file
11
tests/dynamic_fixtures/class_method/go/benign.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// Phase 19 (Track M.1) — class-method benign control for Go.
|
||||
package entry
|
||||
|
||||
import "os/exec"
|
||||
|
||||
type UserService struct{}
|
||||
|
||||
func (UserService) Run(input string) string {
|
||||
out, _ := exec.Command("true", input).Output()
|
||||
return string(out)
|
||||
}
|
||||
17
tests/dynamic_fixtures/class_method/go/vuln.go
Normal file
17
tests/dynamic_fixtures/class_method/go/vuln.go
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Phase 19 (Track M.1) — class-method vuln fixture for Go.
|
||||
//
|
||||
// UserService.Run accepts user input and passes it to `sh -c` so the
|
||||
// shell interprets it. The harness compiles in a generated
|
||||
// `nyx_auto_registry.go` that publishes `UserService{}` so reflection
|
||||
// works without a hand-rolled registry in the fixture.
|
||||
package entry
|
||||
|
||||
import "os/exec"
|
||||
|
||||
type UserService struct{}
|
||||
|
||||
func (UserService) Run(input string) string {
|
||||
// SINK: tainted input → shell -c
|
||||
out, _ := exec.Command("sh", "-c", "true "+input).Output()
|
||||
return string(out)
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// Benign control for recursively populated Go struct dependencies.
|
||||
package entry
|
||||
|
||||
import "strings"
|
||||
|
||||
type ShellRunner struct{}
|
||||
|
||||
func (ShellRunner) Run(command string) string {
|
||||
return strings.ReplaceAll(command, "NYX_PWN", "")
|
||||
}
|
||||
|
||||
type UserRepository struct {
|
||||
Runner *ShellRunner
|
||||
}
|
||||
|
||||
func (r UserRepository) Find(input string) string {
|
||||
if r.Runner == nil {
|
||||
return ""
|
||||
}
|
||||
return r.Runner.Run(input)
|
||||
}
|
||||
|
||||
type UserService struct {
|
||||
Repository *UserRepository
|
||||
}
|
||||
|
||||
func (s UserService) Run(input string) string {
|
||||
if s.Repository == nil {
|
||||
return ""
|
||||
}
|
||||
return s.Repository.Find(input)
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// Class-method fixture with recursively populated Go struct dependencies.
|
||||
package entry
|
||||
|
||||
import "os/exec"
|
||||
|
||||
type ShellRunner struct{}
|
||||
|
||||
func (ShellRunner) Run(command string) string {
|
||||
out, _ := exec.Command("sh", "-c", "true "+command).Output()
|
||||
return string(out)
|
||||
}
|
||||
|
||||
type UserRepository struct {
|
||||
Runner *ShellRunner
|
||||
}
|
||||
|
||||
func (r UserRepository) Find(input string) string {
|
||||
if r.Runner == nil {
|
||||
return ""
|
||||
}
|
||||
return r.Runner.Run(input)
|
||||
}
|
||||
|
||||
type UserService struct {
|
||||
Repository *UserRepository
|
||||
}
|
||||
|
||||
func (s UserService) Run(input string) string {
|
||||
if s.Repository == nil {
|
||||
return ""
|
||||
}
|
||||
return s.Repository.Find(input)
|
||||
}
|
||||
16
tests/dynamic_fixtures/class_method/java/Benign.java
Normal file
16
tests/dynamic_fixtures/class_method/java/Benign.java
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Phase 19 (Track M.1) — class-method benign control for Java.
|
||||
//
|
||||
// The payload is passed as an argv element to true(1), so no shell parses or
|
||||
// echoes marker bytes.
|
||||
public class Benign {
|
||||
public static class UserRepository {
|
||||
public UserRepository() {}
|
||||
|
||||
public void findByName(String name) throws Exception {
|
||||
Process p = new ProcessBuilder("/usr/bin/true", name)
|
||||
.redirectErrorStream(true)
|
||||
.start();
|
||||
p.waitFor();
|
||||
}
|
||||
}
|
||||
}
|
||||
22
tests/dynamic_fixtures/class_method/java/Vuln.java
Normal file
22
tests/dynamic_fixtures/class_method/java/Vuln.java
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Phase 19 (Track M.1) — class-method vuln fixture for Java.
|
||||
//
|
||||
// UserRepository.findByName concatenates user input into a shell command.
|
||||
// The nested class has a default constructor so the ClassMethod harness can
|
||||
// build the receiver reflectively.
|
||||
import java.io.InputStream;
|
||||
|
||||
public class Vuln {
|
||||
public static class UserRepository {
|
||||
public UserRepository() {}
|
||||
|
||||
public void findByName(String name) throws Exception {
|
||||
Process p = new ProcessBuilder("sh", "-c", "true " + name)
|
||||
.redirectErrorStream(true)
|
||||
.start();
|
||||
try (InputStream in = p.getInputStream()) {
|
||||
in.transferTo(System.out);
|
||||
}
|
||||
p.waitFor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// Benign control for recursively constructed Java dependencies.
|
||||
public class Benign {
|
||||
public static class ShellRunner {
|
||||
public String run(String command) {
|
||||
return command.replace("NYX_PWN", "");
|
||||
}
|
||||
}
|
||||
|
||||
public static class UserRepository {
|
||||
private final ShellRunner shellRunner;
|
||||
|
||||
public UserRepository(ShellRunner shellRunner) {
|
||||
this.shellRunner = shellRunner;
|
||||
}
|
||||
|
||||
public String find(String input) {
|
||||
return shellRunner.run(input);
|
||||
}
|
||||
}
|
||||
|
||||
public static class UserService {
|
||||
private final UserRepository userRepository;
|
||||
|
||||
public UserService(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
public String run(String input) {
|
||||
return userRepository.find(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// Class-method fixture with recursively constructed Java dependencies.
|
||||
import java.io.InputStream;
|
||||
|
||||
public class Vuln {
|
||||
public static class ShellRunner {
|
||||
public String run(String command) throws Exception {
|
||||
Process p = new ProcessBuilder("sh", "-c", "true " + command)
|
||||
.redirectErrorStream(true)
|
||||
.start();
|
||||
try (InputStream in = p.getInputStream()) {
|
||||
return new String(in.readAllBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class UserRepository {
|
||||
private final ShellRunner shellRunner;
|
||||
|
||||
public UserRepository(ShellRunner shellRunner) {
|
||||
this.shellRunner = shellRunner;
|
||||
}
|
||||
|
||||
public String find(String input) throws Exception {
|
||||
return shellRunner.run(input);
|
||||
}
|
||||
}
|
||||
|
||||
public static class UserService {
|
||||
private final UserRepository userRepository;
|
||||
|
||||
public UserService(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
public String run(String input) throws Exception {
|
||||
return userRepository.find(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
tests/dynamic_fixtures/class_method/javascript/benign.js
Normal file
15
tests/dynamic_fixtures/class_method/javascript/benign.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// Phase 19 (Track M.1) — class-method benign control for JavaScript.
|
||||
//
|
||||
// UserService.run routes the input through execFileSync with argv form so
|
||||
// the shell never interprets the string or echoes marker bytes.
|
||||
'use strict';
|
||||
const { execFileSync } = require('child_process');
|
||||
|
||||
class UserService {
|
||||
constructor() {}
|
||||
run(input) {
|
||||
return execFileSync('true', [input]).toString();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { UserService };
|
||||
16
tests/dynamic_fixtures/class_method/javascript/vuln.js
Normal file
16
tests/dynamic_fixtures/class_method/javascript/vuln.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Phase 19 (Track M.1) — class-method vuln fixture for JavaScript.
|
||||
//
|
||||
// UserService.run forwards a tainted string straight into child_process.exec,
|
||||
// classic OS command injection. Default ctor — no stubbed deps needed.
|
||||
'use strict';
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
class UserService {
|
||||
constructor() {}
|
||||
run(input) {
|
||||
// SINK: untrusted input → shell
|
||||
return execSync('true ' + input).toString();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { UserService };
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
'use strict';
|
||||
|
||||
class ShellRunner {
|
||||
run(_command) {
|
||||
return 'safe';
|
||||
}
|
||||
}
|
||||
|
||||
class UserRepository {
|
||||
constructor(shellRunner) {
|
||||
this.shellRunner = shellRunner;
|
||||
}
|
||||
|
||||
find(input) {
|
||||
return this.shellRunner.run(input);
|
||||
}
|
||||
}
|
||||
|
||||
class UserService {
|
||||
constructor(userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
run(input) {
|
||||
return this.userRepository.find(input);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { UserService, UserRepository, ShellRunner };
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
'use strict';
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
class ShellRunner {
|
||||
run(command) {
|
||||
return execSync('true ' + command).toString();
|
||||
}
|
||||
}
|
||||
|
||||
class UserRepository {
|
||||
constructor(shellRunner) {
|
||||
this.shellRunner = shellRunner;
|
||||
}
|
||||
|
||||
find(input) {
|
||||
return this.shellRunner.run(input);
|
||||
}
|
||||
}
|
||||
|
||||
class UserService {
|
||||
constructor(userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
run(input) {
|
||||
return this.userRepository.find(input);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { UserService, UserRepository, ShellRunner };
|
||||
10
tests/dynamic_fixtures/class_method/php/benign.php
Normal file
10
tests/dynamic_fixtures/class_method/php/benign.php
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
// Phase 19 (Track M.1) — class-method benign control for PHP.
|
||||
|
||||
class UserService {
|
||||
public function __construct() {}
|
||||
|
||||
public function run($input) {
|
||||
return shell_exec('true ' . escapeshellarg($input));
|
||||
}
|
||||
}
|
||||
14
tests/dynamic_fixtures/class_method/php/vuln.php
Normal file
14
tests/dynamic_fixtures/class_method/php/vuln.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
// Phase 19 (Track M.1) — class-method vuln fixture for PHP.
|
||||
//
|
||||
// UserService::run concatenates user input into a shell command;
|
||||
// default ctor, no stubbed deps needed.
|
||||
|
||||
class UserService {
|
||||
public function __construct() {}
|
||||
|
||||
public function run($input) {
|
||||
// SINK: tainted input → shell.
|
||||
return shell_exec('true ' . $input);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
// Benign control for recursive typed ClassMethod dependencies.
|
||||
|
||||
class Repository {
|
||||
private $dbConnection;
|
||||
|
||||
public function __construct($dbConnection) {
|
||||
$this->dbConnection = $dbConnection;
|
||||
}
|
||||
|
||||
public function run($payload) {
|
||||
return 'ok';
|
||||
}
|
||||
}
|
||||
|
||||
class Service {
|
||||
private Repository $repository;
|
||||
|
||||
public function __construct(Repository $repository) {
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function run($payload) {
|
||||
return $this->repository->run($payload);
|
||||
}
|
||||
}
|
||||
|
||||
class UserController {
|
||||
private Service $service;
|
||||
|
||||
public function __construct(Service $service) {
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
public function run($payload) {
|
||||
return $this->service->run($payload);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
// Class-method fixture with recursively constructed typed dependencies.
|
||||
|
||||
class Repository {
|
||||
private $dbConnection;
|
||||
|
||||
public function __construct($dbConnection) {
|
||||
$this->dbConnection = $dbConnection;
|
||||
}
|
||||
|
||||
public function run($payload) {
|
||||
return shell_exec('true ' . $payload);
|
||||
}
|
||||
}
|
||||
|
||||
class Service {
|
||||
private Repository $repository;
|
||||
|
||||
public function __construct(Repository $repository) {
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function run($payload) {
|
||||
return $this->repository->run($payload);
|
||||
}
|
||||
}
|
||||
|
||||
class UserController {
|
||||
private Service $service;
|
||||
|
||||
public function __construct(Service $service) {
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
public function run($payload) {
|
||||
return $this->service->run($payload);
|
||||
}
|
||||
}
|
||||
20
tests/dynamic_fixtures/class_method/python/benign.py
Normal file
20
tests/dynamic_fixtures/class_method/python/benign.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
"""Phase 19 (Track M.1) — class-method benign control for Python.
|
||||
|
||||
Same surface as `vuln.py` but uses parameterised SQL so user input
|
||||
never concatenates into the query string.
|
||||
"""
|
||||
import sqlite3
|
||||
|
||||
|
||||
class UserRepository:
|
||||
def __init__(self):
|
||||
self._db = sqlite3.connect(":memory:")
|
||||
self._db.executescript(
|
||||
"CREATE TABLE users (id INTEGER, name TEXT); "
|
||||
"INSERT INTO users VALUES (1, 'alice');"
|
||||
)
|
||||
|
||||
def find_by_name(self, name):
|
||||
cur = self._db.cursor()
|
||||
cur.execute("SELECT id FROM users WHERE name = ?", (name,))
|
||||
return cur.fetchall()
|
||||
24
tests/dynamic_fixtures/class_method/python/vuln.py
Normal file
24
tests/dynamic_fixtures/class_method/python/vuln.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
"""Phase 19 (Track M.1) — class-method vuln fixture for Python.
|
||||
|
||||
`UserRepository.find_by_name` accepts user input and builds a raw SQL
|
||||
query, classic concatenation-driven SQL injection. The class has a
|
||||
zero-arg constructor so the harness builds the receiver without
|
||||
needing a stubbed dependency.
|
||||
"""
|
||||
import sqlite3
|
||||
|
||||
|
||||
class UserRepository:
|
||||
def __init__(self):
|
||||
self._db = sqlite3.connect(":memory:")
|
||||
self._db.executescript(
|
||||
"CREATE TABLE users (id INTEGER, name TEXT); "
|
||||
"INSERT INTO users VALUES (1, 'alice');"
|
||||
)
|
||||
|
||||
def find_by_name(self, name):
|
||||
cur = self._db.cursor()
|
||||
# SINK: user input concatenated into the query
|
||||
sql = "SELECT id FROM users WHERE name = '" + name + "'"
|
||||
cur.execute(sql)
|
||||
return cur.fetchall()
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
"""Benign control for the recursive ClassMethod dependency fixture."""
|
||||
|
||||
|
||||
class Repository:
|
||||
def __init__(self, db_connection):
|
||||
self._db = db_connection
|
||||
|
||||
def run(self, payload):
|
||||
return "ok"
|
||||
|
||||
|
||||
class Service:
|
||||
def __init__(self, repository: Repository):
|
||||
self._repository = repository
|
||||
|
||||
def run(self, payload):
|
||||
return self._repository.run(payload)
|
||||
|
||||
|
||||
class UserController:
|
||||
def __init__(self, service: Service):
|
||||
self._service = service
|
||||
|
||||
def run(self, payload):
|
||||
return self._service.run(payload)
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
"""Class-method fixture with recursively constructed dependencies."""
|
||||
|
||||
import os
|
||||
|
||||
|
||||
class Repository:
|
||||
def __init__(self, db_connection):
|
||||
self._db = db_connection
|
||||
|
||||
def run(self, payload):
|
||||
os.system(payload)
|
||||
|
||||
|
||||
class Service:
|
||||
def __init__(self, repository: Repository):
|
||||
self._repository = repository
|
||||
|
||||
def run(self, payload):
|
||||
self._repository.run(payload)
|
||||
|
||||
|
||||
class UserController:
|
||||
def __init__(self, service: Service):
|
||||
self._service = service
|
||||
|
||||
def run(self, payload):
|
||||
self._service.run(payload)
|
||||
29
tests/dynamic_fixtures/class_method/python_with_deps/vuln.py
Normal file
29
tests/dynamic_fixtures/class_method/python_with_deps/vuln.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
"""Phase 19 (Track M.1) — class-method vuln with constructor deps.
|
||||
|
||||
`UserController.__init__` takes an HTTP client + a database connection
|
||||
(controller → service → repository shape). The Phase 19 harness's
|
||||
`_nyx_build_receiver` walks the ctor formals, stubs each with the
|
||||
matching `Mock*` test double from `src/dynamic/stubs/mocks.rs`, and
|
||||
invokes the sink method.
|
||||
"""
|
||||
import sqlite3
|
||||
|
||||
|
||||
class UserController:
|
||||
def __init__(self, http_client, db_connection):
|
||||
# Phase 19 harness wires MockHttpClient + MockDatabaseConnection
|
||||
# through these two formals so the ctor returns without I/O.
|
||||
self._http = http_client
|
||||
self._db = db_connection or sqlite3.connect(":memory:")
|
||||
|
||||
def search(self, query):
|
||||
cur = self._db.cursor() if hasattr(self._db, "cursor") else None
|
||||
if cur is None:
|
||||
return None
|
||||
# SINK: concatenated SQL
|
||||
sql = "SELECT 1 FROM dual WHERE x = '" + query + "'"
|
||||
try:
|
||||
cur.execute(sql)
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
11
tests/dynamic_fixtures/class_method/ruby/benign.rb
Normal file
11
tests/dynamic_fixtures/class_method/ruby/benign.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Phase 19 (Track M.1) — class-method benign control for Ruby.
|
||||
require 'shellwords'
|
||||
|
||||
class UserService
|
||||
def initialize
|
||||
end
|
||||
|
||||
def run(input)
|
||||
`true #{Shellwords.escape(input)}`
|
||||
end
|
||||
end
|
||||
13
tests/dynamic_fixtures/class_method/ruby/vuln.rb
Normal file
13
tests/dynamic_fixtures/class_method/ruby/vuln.rb
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# Phase 19 (Track M.1) — class-method vuln fixture for Ruby.
|
||||
#
|
||||
# UserService#run pipes user input into a shell, classic OS command
|
||||
# injection. Default `.new` ctor — no mock deps needed.
|
||||
class UserService
|
||||
def initialize
|
||||
end
|
||||
|
||||
def run(input)
|
||||
# SINK: tainted input → shell
|
||||
`true #{input}`
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# Benign control for recursively constructed Ruby dependencies.
|
||||
class ShellRunner
|
||||
def run(command)
|
||||
command.gsub('NYX_PWN', '')
|
||||
end
|
||||
end
|
||||
|
||||
class UserRepository
|
||||
def initialize(shell_runner)
|
||||
@shell_runner = shell_runner
|
||||
end
|
||||
|
||||
def find(input)
|
||||
@shell_runner.run(input)
|
||||
end
|
||||
end
|
||||
|
||||
class UserService
|
||||
def initialize(user_repository)
|
||||
@user_repository = user_repository
|
||||
end
|
||||
|
||||
def run(input)
|
||||
@user_repository.find(input)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# Class-method fixture with recursively constructed Ruby dependencies.
|
||||
class ShellRunner
|
||||
def run(command)
|
||||
`true #{command}`
|
||||
end
|
||||
end
|
||||
|
||||
class UserRepository
|
||||
def initialize(shell_runner)
|
||||
@shell_runner = shell_runner
|
||||
end
|
||||
|
||||
def find(input)
|
||||
@shell_runner.run(input)
|
||||
end
|
||||
end
|
||||
|
||||
class UserService
|
||||
def initialize(user_repository)
|
||||
@user_repository = user_repository
|
||||
end
|
||||
|
||||
def run(input)
|
||||
@user_repository.find(input)
|
||||
end
|
||||
end
|
||||
14
tests/dynamic_fixtures/class_method/rust/benign.rs
Normal file
14
tests/dynamic_fixtures/class_method/rust/benign.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// Phase 19 (Track M.1) — class-method benign control for Rust.
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct UserService;
|
||||
|
||||
impl UserService {
|
||||
pub fn run(&self, input: &str) -> String {
|
||||
let out = std::process::Command::new("true")
|
||||
.arg(input)
|
||||
.output()
|
||||
.expect("exec");
|
||||
String::from_utf8_lossy(&out.stdout).into_owned()
|
||||
}
|
||||
}
|
||||
21
tests/dynamic_fixtures/class_method/rust/vuln.rs
Normal file
21
tests/dynamic_fixtures/class_method/rust/vuln.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Phase 19 (Track M.1) — class-method vuln fixture for Rust.
|
||||
//
|
||||
// `UserService::run` shells out with a concatenated `sh -c <input>`,
|
||||
// classic OS command injection. Derives Default so the harness can
|
||||
// build the receiver without manual stubbing.
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct UserService;
|
||||
|
||||
impl UserService {
|
||||
pub fn run(&self, input: &str) -> String {
|
||||
// SINK: tainted input → shell -c
|
||||
let cmd = format!("true {}", input);
|
||||
let out = std::process::Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(&cmd)
|
||||
.output()
|
||||
.expect("exec");
|
||||
String::from_utf8_lossy(&out.stdout).into_owned()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// Benign control for recursive Rust class-method receiver construction.
|
||||
|
||||
pub struct CommandRunner;
|
||||
|
||||
impl CommandRunner {
|
||||
pub fn run(&self, input: &str) -> String {
|
||||
let out = std::process::Command::new("true")
|
||||
.arg(input)
|
||||
.output()
|
||||
.expect("exec");
|
||||
String::from_utf8_lossy(&out.stdout).into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UserService {
|
||||
pub runner: CommandRunner,
|
||||
}
|
||||
|
||||
impl UserService {
|
||||
pub fn run(&self, input: &str) -> String {
|
||||
self.runner.run(input)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// Rust class-method fixture whose receiver has same-file dependencies
|
||||
// but no Default or new() constructor.
|
||||
|
||||
pub struct CommandRunner;
|
||||
|
||||
impl CommandRunner {
|
||||
pub fn run(&self, input: &str) -> String {
|
||||
let cmd = format!("true {}", input);
|
||||
let out = std::process::Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(&cmd)
|
||||
.output()
|
||||
.expect("exec");
|
||||
String::from_utf8_lossy(&out.stdout).into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UserService {
|
||||
pub runner: CommandRunner,
|
||||
}
|
||||
|
||||
impl UserService {
|
||||
pub fn run(&self, input: &str) -> String {
|
||||
self.runner.run(input)
|
||||
}
|
||||
}
|
||||
12
tests/dynamic_fixtures/class_method/typescript/benign.ts
Normal file
12
tests/dynamic_fixtures/class_method/typescript/benign.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Phase 19 (Track M.1) — class-method benign control for TypeScript.
|
||||
'use strict';
|
||||
const { execFileSync } = require('child_process');
|
||||
|
||||
class UserService {
|
||||
constructor() {}
|
||||
run(input) {
|
||||
return execFileSync('true', [input]).toString();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { UserService };
|
||||
17
tests/dynamic_fixtures/class_method/typescript/vuln.ts
Normal file
17
tests/dynamic_fixtures/class_method/typescript/vuln.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Phase 19 (Track M.1) — class-method vuln fixture for TypeScript.
|
||||
//
|
||||
// UserService.run forwards user input directly to a shell. The source
|
||||
// stays CommonJS-compatible because the harness stages TS fixtures as
|
||||
// entry.js for stock Node.
|
||||
'use strict';
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
class UserService {
|
||||
constructor() {}
|
||||
run(input) {
|
||||
// SINK: untrusted input flows into the shell
|
||||
return execSync('true ' + input).toString();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { UserService };
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
'use strict';
|
||||
|
||||
class ShellRunner {
|
||||
run(_command) {
|
||||
return 'safe';
|
||||
}
|
||||
}
|
||||
|
||||
class UserRepository {
|
||||
constructor(shellRunner) {
|
||||
this.shellRunner = shellRunner;
|
||||
}
|
||||
|
||||
find(input) {
|
||||
return this.shellRunner.run(input);
|
||||
}
|
||||
}
|
||||
|
||||
class UserService {
|
||||
constructor(userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
run(input) {
|
||||
return this.userRepository.find(input);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { UserService, UserRepository, ShellRunner };
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
'use strict';
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
class ShellRunner {
|
||||
run(command) {
|
||||
return execSync('true ' + command).toString();
|
||||
}
|
||||
}
|
||||
|
||||
class UserRepository {
|
||||
constructor(shellRunner) {
|
||||
this.shellRunner = shellRunner;
|
||||
}
|
||||
|
||||
find(input) {
|
||||
return this.shellRunner.run(input);
|
||||
}
|
||||
}
|
||||
|
||||
class UserService {
|
||||
constructor(userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
run(input) {
|
||||
return this.userRepository.find(input);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { UserService, UserRepository, ShellRunner };
|
||||
Loading…
Add table
Add a link
Reference in a new issue