Skip to content

Latest commit

 

History

History
150 lines (102 loc) · 4.64 KB

exploits.md

File metadata and controls

150 lines (102 loc) · 4.64 KB

Exploits

Writing Exploits

Create a development environment

It is recommended to create a version-controlled repository to manage the exploits during a competition.

Create the exploit

First, create the exploit using the CLI:

kriger create

Then, answer the interactive prompts accordingly.

Note

The exploit name should match the following pattern: [a-z1-9]+(-[a-z1-9]+)*.

  • Do:juiceshop-1 or dewaste-1-v1.
  • Don't:Juice shop 1, dewaste_v1, or L$$t Shop V1.

Writing the exploit

Navigate to the newly created exploit directory:

cd exploit-name

Then, open it in any preferred editor/IDE:

nvim . # neovim
hx . # helix
code . # (VS)Code

The template itself should be self-explanatory. The entire flag hint object will be automatically provided to the exploit program as an object.

Testing the exploit

After developing a functional exploit, the exploit can be tested using the CLI. By default, this will run test the exploit against the NOP team.

kriger exploit dev

Or, by manually testing it:

# For Python exploits:
IP=10.60.0.1 HINT='flag id' python exploit.py

Note

When manually testing an exploit, the HINT environment variable is expected to be a JSON value.

Valid (shell-escape required):

  • HINT="flag id"
  • HINT={"key": "value"}

Invalid:

  • HINT=flag id

Deploying the exploit

Important

Before deploying the exploit, ensure that the resource constraints defined in exploit.toml is sensible for the exploit. Allocating too much resource will negatively impact other exploits running on the farm.

Run the following command to deploy the exploit:

kriger deploy

Writing Exploits Manually

Warning

This method of writing exploits is discouraged. If the language/framework/tool being used is supported by a template, use it instead.

The simplest way to write an exploit manually would be to use the simple exploit execution mode.

The following Python code is provided for reference:

import json
import os

ip = os.getenv("IP")
hint = json.loads(os.getenv("HINT"))

# ... Logic here

print("FLAG_ABCDEF123456")

Anatomy of an Exploit

In short, each exploit is expected to be run as a command. Each exploit can be a self-contained binary, a script written in an interpreted language, an automated playbook, etc.

Exploits are packaged as a container image along with the runner binary. Base images and templates will be provided for common languages and platforms. Many of the details mentioned here will be abstracted away in the template for the ease of development.

Exploits exiting with a non-zero exit code will be automatically retried.

Execution Modes

Simple Exploits

In simple exploits, each runner will execute each execution as separate processes. The exploit will receive its parameters and hints via environment variables. The exploit MUST print flags to the stdout, terminated by a newline (\n) character.

The following environment variables are passed to exploits:

Name Description
EXPLOIT The name fo the exploit.
IP The IP address of the target.
HINT Optional. JSON-serialized hint for the exploit to use, often referred to as "flag IDs"

Warmup-optimized Exploits

TBD

Shared-runtime Exploits

TBD

Architectural Decisions

  • Containers are used to package exploits in a portable manner. Runtime dependencies, packages, custom binaries, etc. can be taken care of by the exploit author. This allows the exploits to be developed and deployed in the exact same way without kriger having to be responsible for package management, environment management, etc.
  • Base images are used to cache common packages, tools, and image layers. This will reduce the image building time, making it even faster to write and deploy exploits.
  • Running each execution separately reduces the risks of side effects causing instability or indeterministic executions. However, this approach is significantly slower than sharing a single runtime for multiple execution.