Skip to content

Commit

Permalink
Merge branch 'main' of github.com:JosephTLucas/vger
Browse files Browse the repository at this point in the history
  • Loading branch information
JosephTLucas committed Feb 12, 2024
2 parents de8068a + 2374d50 commit ebee367
Show file tree
Hide file tree
Showing 9 changed files with 725 additions and 551 deletions.
18 changes: 13 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,27 @@

![](static/vger.jpg)

V'ger is an interactive command-line application for interacting with authenticated Jupyter instances.
V'ger is an interactive command-line application for post-exploitation of authenticated Jupyter instances with a focus on AI/ML security operations.

## User Stories

- As a **Red Teamer**, you've found Jupyter credentials, but don't know what you can do with them. V'ger is organized in a format that should be intuitive for most offensive security professionals to help them understand the functionality of the target Jupyter server.
- As a **Red Teamer**, you know that some browser-based actions will be visibile to the legitimate Jupyter users. For example, modifying tabs will appear in their workspace and commands entered in cells will be recorded to the history. V'ger decreases the likelihood of detection.
- As an **AI Red Teamer**, you understand academic algorthmic attacks, but need a more practical execution vector. For instance, you may need to modify a large, foundational internet-scale dataset as part of a model poisoning operation. Modifying that dataset at its source may be impossible or generate undesirable auditable artifacts. with V'ger you can achieve the same objectives in-memory, a significant improvement in tradecraft.
- As a **Blue Teamer**, you want to understand logging and visibility into a live Jupyter deployment. V'ger can help you generate repeatable artifacts for testing instrumentation and performing incident response exercises.

## Usage

![](static/usage.gif)

## Initial Setup

`pip install vger`
1. `pip install vger`
2. `vger --help`

Currently, `vger interactive` has maximum functionality, maintaining state for discovered artifacts and recurring jobs. However, most functionality is also available by-name in non-interactive format with `vger <module>`. List available modules with `vger --help`.

Upon opening the application, users will be prompted for connection information.
1. Provide the full target host including the port and trailing slash (such as `http://172.0.0.1:8888/`).
2. Provide the token or password.
![](static/cli-help.png)

## Commands

Expand Down
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "vger"
version = "0.1.6"
version = "0.1.7"
description = "An execution framework for Jupyter environments."
authors = ["Joseph Lucas <joe@joetl.com>"]
license = "GPL-3.0-only"
Expand All @@ -11,7 +11,7 @@ packages = [
]

[tool.poetry.scripts]
vger = 'vger.menu:cli'
vger = 'vger.application:app'

[tool.poetry.dependencies]
python = "^3.11"
Expand All @@ -20,6 +20,7 @@ rich = "^13.7"
urllib3 = "^2.1"
websockets = "^12.0"
requests = "^2.30"
typer = {extras = ["all"], version = "^0.9.0"}



Expand Down
121 changes: 121 additions & 0 deletions vger/application.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
from vger.menu import Menu
from vger.enumerate import Enumerate
from vger.exploit import Exploit
from vger.persist import Persist
import typer

app = typer.Typer(rich_markup_mode="rich")


@app.command()
def interactive(rich_help_panel="Execution Mode"):
"""
Interactive execution for [bold red]maximum functionality[/bold red]
"""
return Menu().main()


@app.command(rich_help_panel="Server-Level Interactions")
def terminal(host: str, secret: str, code: str):
"""
Run a [bold red]shell command[/bold red] on the server
"""
return Enumerate(host, secret).run_in_shell(interactive=False, code=code)


@app.command(rich_help_panel="Notebook-Level Interactions")
def nb_list(host: str, secret: str):
"""
List [bold red]running notebooks[/bold red] on the server
"""
return Enumerate(host, secret).list_notebooks()


@app.command(rich_help_panel="Server-Level Interactions")
def file_list(host: str, secret: str, dir_path: str = "/"):
"""
List [bold red]directories[/bold red] or [bold red]file contents[/bold red]
"""
return Enumerate(host, secret).list_dir(interactive=False, dir=dir_path)


@app.command(rich_help_panel="Server-Level Interactions")
def find_models(host: str, secret: str, dir_path: str = "/"):
"""
[bold red]Find models[/bold red] based on common file extensions
"""
return Enumerate(host, secret).find_files_runner(
file_type="model", interactive=False, path=dir_path
)


@app.command(rich_help_panel="Server-Level Interactions")
def find_datasets(host: str, secret: str, dir_path: str = "/"):
"""
[bold red]Find datasets[/bold red] based on common file extensions
"""
return Enumerate(host, secret).find_files_runner(
file_type="data", interactive=False, path=dir_path
)


@app.command(rich_help_panel="Server-Level Interactions")
def file_upload(host: str, secret: str, local_path: str, remote_path: str):
"""
[bold red]Upload a file[/bold red] to the server
"""
return Exploit(host, secret).upload(
interactive=False, in_path=local_path, out_path=remote_path
)


@app.command(rich_help_panel="Server-Level Interactions")
def file_delete(host: str, secret: str, file_path: str):
"""
[bold red]Delete a file[/bold red] on the server
"""
return Exploit(host, secret).delete(interactive=False, path=file_path)


@app.command(rich_help_panel="Server-Level Interactions")
def backdoor_jupyter(host: str, secret: str, port: int = 7777, new_secret: str = ""):
"""
Launch your own Jupyter server [green](it is a code execution service, after all)[/green]
"""
return Persist(host, secret).jupyter_backdoor(
interactive=False, port=port, secret=new_secret
)


@app.command(rich_help_panel="Notebook-Level Interactions")
def nb_inject(host: str, secret: str, notebook: str, code_path: str):
"""
[bold red]Invisibly inject[/bold red] code into a notebook
"""
return Exploit(host, secret, notebook).inject(
interactive=False, payload_path=code_path
)


@app.command(rich_help_panel="Notebook-Level Interactions")
def nb_history(host: str, secret: str, notebook: str):
"""
Dump the history of a notebook to see [bold red]previously executed code[/bold red]
"""
return Exploit(host, secret, notebook).dump_history()


@app.command(rich_help_panel="Notebook-Level Interactions")
def nb_snoop(host: str, secret: str, notebook: str, seconds: int = 60):
"""
Snoop on a notebook for a specified duration to see [bold red]code as it is executed[/bold red]
"""
return Exploit(host, secret, notebook).snoop_for(interactive=False, timeout=seconds)


@app.command(rich_help_panel="Notebook-Level Interactions")
def nb_modules(host: str, secret: str, notebook: str):
"""
List [bold red]all available modules[/bold red] in a given notebook context
"""
return Exploit(host, secret, notebook).list_modules()
Loading

0 comments on commit ebee367

Please sign in to comment.