mirror of
https://github.com/maxDcb/C2TeamServer
synced 2026-06-06 16:14:27 +00:00
158 lines
5.8 KiB
Python
158 lines
5.8 KiB
Python
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from C2Client.assistant_agent.tools.command_builder import build_command_line
|
|
from C2Client.assistant_agent.tools.command_specs import command_spec_to_tool_spec
|
|
|
|
from helpers import arg, command_spec
|
|
|
|
|
|
def tool_spec(command):
|
|
return command_spec_to_tool_spec(command)
|
|
|
|
|
|
def test_build_command_line_quotes_paths_with_spaces():
|
|
cat = tool_spec(command_spec("cat", "cat {path:q}", [arg("path", arg_type="path", required=True)]))
|
|
ls = tool_spec(command_spec("ls", "ls {path:q?}", [arg("path", arg_type="path")]))
|
|
|
|
assert build_command_line(cat, {"beacon_hash": "b", "listener_hash": "l", "path": "C:\\Users\\Public\\notes.txt"}) == "cat C:\\Users\\Public\\notes.txt"
|
|
assert build_command_line(ls, {"beacon_hash": "b", "listener_hash": "l", "path": "C:\\Program Files"}) == "ls 'C:\\Program Files'"
|
|
|
|
|
|
def test_build_command_line_supports_raw_command_tail():
|
|
run = tool_spec(command_spec("run", "run {command:raw}", [arg("command", required=True, variadic=True)]))
|
|
|
|
assert build_command_line(
|
|
run,
|
|
{"beacon_hash": "b", "listener_hash": "l", "command": "whoami /all"},
|
|
) == "run whoami /all"
|
|
|
|
|
|
def test_build_command_line_omits_empty_optional_argument():
|
|
enumerate_shares = tool_spec(command_spec("enumerateShares", "enumerateShares {host:q?}", [arg("host")]))
|
|
ls = tool_spec(command_spec("ls", "ls {path:q?}", [arg("path", arg_type="path")]))
|
|
|
|
assert build_command_line(
|
|
enumerate_shares,
|
|
{"beacon_hash": "b", "listener_hash": "l", "host": ""},
|
|
) == "enumerateShares"
|
|
assert build_command_line(
|
|
ls,
|
|
{"beacon_hash": "b", "listener_hash": "l"},
|
|
) == "ls"
|
|
|
|
|
|
def test_build_command_line_supports_optional_flag_segments():
|
|
dcom_exec = tool_spec(
|
|
command_spec(
|
|
"dcomExec",
|
|
"dcomExec -h {h:q} -c {c:q} [-a {a:q}] [-n {n:flag}]",
|
|
[
|
|
arg("-h", required=True),
|
|
arg("-c", required=True),
|
|
arg("-a"),
|
|
arg("-n"),
|
|
],
|
|
)
|
|
)
|
|
|
|
assert build_command_line(
|
|
dcom_exec,
|
|
{
|
|
"beacon_hash": "b",
|
|
"listener_hash": "l",
|
|
"h": "host1",
|
|
"c": "cmd.exe",
|
|
"a": "/c whoami",
|
|
"n": True,
|
|
},
|
|
) == "dcomExec -h host1 -c cmd.exe -a '/c whoami' -n"
|
|
|
|
|
|
def test_build_command_line_rejects_missing_required_argument():
|
|
cat = tool_spec(command_spec("cat", "cat {path:q}", [arg("path", arg_type="path", required=True)]))
|
|
|
|
with pytest.raises(KeyError):
|
|
build_command_line(cat, {"beacon_hash": "b", "listener_hash": "l"})
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("command", "arguments", "expected"),
|
|
[
|
|
(
|
|
command_spec(
|
|
"assemblyExec",
|
|
"assemblyExec [--mode {mode}] [--donut-exe {donut_exe:q}] [--method {method:q}] [-- {arguments:raw}]",
|
|
[
|
|
arg("--mode", values=["thread", "process"]),
|
|
arg("--donut-exe", artifact=True),
|
|
arg("--method"),
|
|
arg("arguments", variadic=True),
|
|
],
|
|
),
|
|
{"mode": "process", "donut_exe": "Rubeus.exe", "arguments": "triage"},
|
|
"assemblyExec --mode process --donut-exe Rubeus.exe -- triage",
|
|
),
|
|
(
|
|
command_spec(
|
|
"inject",
|
|
"inject --pid {pid} [--donut-exe {donut_exe:q}] [-- {arguments:raw}]",
|
|
[
|
|
arg("--pid", arg_type="number", required=True),
|
|
arg("--donut-exe", artifact=True),
|
|
arg("arguments", variadic=True),
|
|
],
|
|
),
|
|
{"pid": -1, "donut_exe": "BeaconHttp.exe", "arguments": "arg1 arg2"},
|
|
"inject --pid -1 --donut-exe BeaconHttp.exe -- arg1 arg2",
|
|
),
|
|
(
|
|
command_spec(
|
|
"registry",
|
|
"registry {operation} -h {h:q} -k {k:q} [-n {n:q}]",
|
|
[
|
|
arg("operation", values=["query", "set"], required=True),
|
|
arg("-h", required=True),
|
|
arg("-k", required=True),
|
|
arg("-n"),
|
|
],
|
|
),
|
|
{"operation": "query", "h": "HKCU", "k": "Software\\C2", "n": "Smoke"},
|
|
"registry query -h HKCU -k Software\\C2 -n Smoke",
|
|
),
|
|
(
|
|
command_spec(
|
|
"spawnAs",
|
|
"spawnAs [--no-profile {no_profile:flag}] {username:q} {password:q} -- {command:raw}",
|
|
[
|
|
arg("--no-profile"),
|
|
arg("username", required=True),
|
|
arg("password", required=True),
|
|
arg("command", required=True, variadic=True),
|
|
],
|
|
),
|
|
{"no_profile": True, "username": ".\\c2test", "password": "pw", "command": "cmd.exe /c whoami"},
|
|
"spawnAs --no-profile .\\c2test pw -- cmd.exe /c whoami",
|
|
),
|
|
(
|
|
command_spec(
|
|
"sshExec",
|
|
"sshExec -h {h:q} [-P {P}] -u {u:q} -p {p:q} -- {command:raw}",
|
|
[
|
|
arg("-h", required=True),
|
|
arg("-P", arg_type="number"),
|
|
arg("-u", required=True),
|
|
arg("-p", required=True),
|
|
arg("command", required=True, variadic=True),
|
|
],
|
|
),
|
|
{"h": "server", "P": 2222, "u": "admin", "p": "pw", "command": "/bin/id"},
|
|
"sshExec -h server -P 2222 -u admin -p pw -- /bin/id",
|
|
),
|
|
],
|
|
)
|
|
def test_build_command_lines_from_command_spec_templates(command, arguments, expected):
|
|
arguments = {"beacon_hash": "b", "listener_hash": "l", **arguments}
|
|
assert build_command_line(tool_spec(command), arguments) == expected
|