mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-15 20:05:13 +02:00
refactor(dynamic): add recursive dependency resolution for Java, Go, and Ruby receivers, expand corresponding tests
This commit is contained in:
parent
0e8c900078
commit
acec041676
10 changed files with 366 additions and 10 deletions
|
|
@ -182,14 +182,26 @@ fn class_method_java_emits_reflective_dispatch() {
|
|||
let h = lang::emit(&spec).expect("emit ok");
|
||||
assert!(h.source.contains("Class.forName"));
|
||||
assert!(h.source.contains("nyxBuildReceiver"));
|
||||
assert!(h.source.contains("nyxValueForType(params[i], depth - 1"));
|
||||
assert!(h.source.contains("Object result = match.invoke"));
|
||||
assert!(h.source.contains("UserRepository"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn class_method_ruby_dispatch_builds_recursive_receiver() {
|
||||
let spec = make_spec(Lang::Ruby);
|
||||
let h = lang::emit(&spec).expect("emit ok");
|
||||
assert!(h.source.contains("_nyx_build_receiver(cls, depth = 3"));
|
||||
assert!(h.source.contains("_nyx_const_for_param"));
|
||||
assert!(h.source.contains("depth - 1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn class_method_go_uses_reflect_receivers_registry() {
|
||||
let spec = make_spec(Lang::Go);
|
||||
let h = lang::emit(&spec).expect("emit ok");
|
||||
assert!(h.source.contains("entry.NyxAutoReceivers"));
|
||||
assert!(h.source.contains("nyxPopulateReceiver"));
|
||||
assert!(h.source.contains("MethodByName"));
|
||||
let registry = h
|
||||
.extra_files
|
||||
|
|
@ -284,6 +296,17 @@ mod e2e_phase_19 {
|
|||
cap: Cap::CODE_EXEC,
|
||||
bins: &["ruby"],
|
||||
},
|
||||
Case {
|
||||
lang: Lang::Ruby,
|
||||
fixture_dir: "ruby_recursive_deps",
|
||||
vuln_file: "vuln.rb",
|
||||
benign_file: "benign.rb",
|
||||
vuln_class: "UserService",
|
||||
benign_class: "UserService",
|
||||
method: "run",
|
||||
cap: Cap::CODE_EXEC,
|
||||
bins: &["ruby"],
|
||||
},
|
||||
Case {
|
||||
lang: Lang::JavaScript,
|
||||
fixture_dir: "javascript",
|
||||
|
|
@ -361,6 +384,17 @@ mod e2e_phase_19 {
|
|||
cap: Cap::CODE_EXEC,
|
||||
bins: &["java", "javac"],
|
||||
},
|
||||
Case {
|
||||
lang: Lang::Java,
|
||||
fixture_dir: "java_recursive_deps",
|
||||
vuln_file: "Vuln.java",
|
||||
benign_file: "Benign.java",
|
||||
vuln_class: "Vuln$UserService",
|
||||
benign_class: "Benign$UserService",
|
||||
method: "run",
|
||||
cap: Cap::CODE_EXEC,
|
||||
bins: &["java", "javac"],
|
||||
},
|
||||
Case {
|
||||
lang: Lang::Go,
|
||||
fixture_dir: "go",
|
||||
|
|
@ -372,6 +406,17 @@ mod e2e_phase_19 {
|
|||
cap: Cap::CODE_EXEC,
|
||||
bins: &["go"],
|
||||
},
|
||||
Case {
|
||||
lang: Lang::Go,
|
||||
fixture_dir: "go_recursive_deps",
|
||||
vuln_file: "vuln.go",
|
||||
benign_file: "benign.go",
|
||||
vuln_class: "UserService",
|
||||
benign_class: "UserService",
|
||||
method: "Run",
|
||||
cap: Cap::CODE_EXEC,
|
||||
bins: &["go"],
|
||||
},
|
||||
Case {
|
||||
lang: Lang::Rust,
|
||||
fixture_dir: "rust",
|
||||
|
|
|
|||
|
|
@ -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_CMDI", "")
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
@ -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_CMDI", "");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# Benign control for recursively constructed Ruby dependencies.
|
||||
class ShellRunner
|
||||
def run(command)
|
||||
command.gsub('NYX_PWN_CMDI', '')
|
||||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue