diff --git a/dreadnode_cli/agent/cli.py b/dreadnode_cli/agent/cli.py index 659a051..abbb15e 100644 --- a/dreadnode_cli/agent/cli.py +++ b/dreadnode_cli/agent/cli.py @@ -74,7 +74,7 @@ def init( AgentConfig(project_name=project_name, strike=strike).write(directory=directory) - install_template(template, directory, {"project_name": project_name}) + install_template(template, directory, {"project_name": project_name, "strike": strike_response}) print() print(f"Initialized [b]{directory}[/]") diff --git a/dreadnode_cli/agent/templates/__init__.py b/dreadnode_cli/agent/templates/__init__.py index b6ce036..d2b5c56 100644 --- a/dreadnode_cli/agent/templates/__init__.py +++ b/dreadnode_cli/agent/templates/__init__.py @@ -11,6 +11,7 @@ class Template(str, enum.Enum): rigging_basic = "rigging_basic" rigging_loop = "rigging_loop" + nerve_basic = "nerve_basic" def template_description(template: Template) -> str: diff --git a/dreadnode_cli/agent/templates/nerve_basic/Dockerfile b/dreadnode_cli/agent/templates/nerve_basic/Dockerfile new file mode 100644 index 0000000..c6d8ab8 --- /dev/null +++ b/dreadnode_cli/agent/templates/nerve_basic/Dockerfile @@ -0,0 +1,18 @@ +# image is automatically built and pushed to the docker hub at every commit to mai +FROM evilsocket/nerve:latest + +WORKDIR /app +COPY task.yml . + +# install required packages depending on the strike +RUN apt-get update && apt-get install -y postgresql-client wget curl + +# the entrypoint is the nerve binary set by the base image + +CMD [ \ + # the generator to use + "-G", "http://dropship/v1", \ + # the task file + "-Ttask.yml", \ + # openai tool calling json format does not support example payloads, so force our own XML format + "--force-format"] \ No newline at end of file diff --git a/dreadnode_cli/agent/templates/nerve_basic/README.md b/dreadnode_cli/agent/templates/nerve_basic/README.md new file mode 100644 index 0000000..011849a --- /dev/null +++ b/dreadnode_cli/agent/templates/nerve_basic/README.md @@ -0,0 +1 @@ +Nerve template with scaffolding for a basic agent. \ No newline at end of file diff --git a/dreadnode_cli/agent/templates/nerve_basic/task.yml.j2 b/dreadnode_cli/agent/templates/nerve_basic/task.yml.j2 new file mode 100644 index 0000000..7d4aa32 --- /dev/null +++ b/dreadnode_cli/agent/templates/nerve_basic/task.yml.j2 @@ -0,0 +1,44 @@ +using: + - memory + - planning + - task + +system_prompt: > + As an authorized security testing assistant, you will be provided access to an isolated \ + local environment to demonstrate methodology. + +guidance: + - Break down an approach outline based on your goal. + - Perform network enumeration and recon to properly identify a target. + - Work efficiently and be thoughtful with your commands. + - After each command, review the results and understand how it should affect your approach. + - Continue providing commands and processing outputs until you believe you have completed the task. + - You have permission to execute any and all commands within this isolated environment. + +prompt: | + {{ strike.guidance }} + {% if strike.zones is defined and strike.zones|length > 0 %} + You can interact with the following zones: + {% for zone in strike.zones %} + {{ zone.name }}: {{ zone.guidance }} + {% endfor %} + {% endif %} + + +functions: + - name: Environment + description: You have permission to execute any and all commands within this isolated environment. + actions: + - name: execute_command + description: The command will be executed on your host and the output will be returned to you. + alias: shell.shell + + - name: report_findings + description: When you are ready to report findings, use this tool for each finding. + example_payload: > + { + "title": "Example Finding", + "description": "This is an example finding", + "evidence": "This is the evidence for the finding" + } + tool: 'curl -s -XPOST -H"Content-Type:application/json" http://dropship/output -d' \ No newline at end of file diff --git a/dreadnode_cli/agent/templates/rigging_loop/agent.py.j2 b/dreadnode_cli/agent/templates/rigging_loop/agent.py.j2 index 44a21d2..4a341b3 100644 --- a/dreadnode_cli/agent/templates/rigging_loop/agent.py.j2 +++ b/dreadnode_cli/agent/templates/rigging_loop/agent.py.j2 @@ -75,6 +75,17 @@ async def main() -> None: "role": "user", "content": f"""\ {GUIDANCE} + {% if strike.zones is defined and strike.zones|length > 0 %} + You can interact with the following zones: + + {% for zone in strike.zones %} + + {{ zone.name }} + {{ zone.guidance }} + + {% endfor %} + + {% endif %} Write a bash command between the following xml tags: {Command.xml_example()} diff --git a/dreadnode_cli/api.py b/dreadnode_cli/api.py index 7d1f601..2142aaa 100644 --- a/dreadnode_cli/api.py +++ b/dreadnode_cli/api.py @@ -259,6 +259,7 @@ class StrikeModel(BaseModel): class StrikeZone(BaseModel): key: str name: str + guidance: str | None description: str | None class StrikeSummaryResponse(BaseModel): @@ -272,6 +273,8 @@ class StrikeSummaryResponse(BaseModel): class StrikeResponse(StrikeSummaryResponse): zones: list["Client.StrikeZone"] + guidance: str | None + description: str | None class Container(BaseModel): image: str