It is recommended to create a version-controlled repository to manage the exploits during a competition.
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
ordewaste-1-v1
. - Don't:
Juice shop 1
,dewaste_v1
, orL$$t Shop V1
.
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.
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
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
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")
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.
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" |
TBD
TBD
- 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.