Skip to content

Commit

Permalink
Allow {{url_for}} and {{lookup}} templates in Description
Browse files Browse the repository at this point in the history
The values of these templates can be determined as soon as a build of a
challenge has been created, and differ from connection-related templates
like {{port}} which require a running instance to have meaningful
values.

The advantage of allowing these tags in the Description section is that
for on-demand challenges containing both artifacts and a server
component (for example, binary exploitation challenges that provide both
a source file and a remote server containing the flag), players no
longer need to start an instances just to gain access to the artifact
downloads and begin working on the challenge. This way, they do not need
to start an instance of the challenge until they have developed an
exploit locally and are ready to test it against the remote server.

This is both more convenient for players, who historically have been
confused as to why they need to start an instance just to download
artifacts, and also reduces load on the Docker server.

This change does mean that the Description field loses the initially
intended property of being truly static across all challenge instances.
In theory, it might be cleaner to instead separate descriptions into
three sections: static, build-level templatable, and instance-level
templatable. However, this is a much less intrusive change.

Note that technically {{server}} could also be resolved by clients while
only having build-level information available. However, I can't think of
any situation where it is useful on its own without {{port}}, and it
would be confusing to split the permitted connection-related templates
between the two sections.
  • Loading branch information
dmartin committed Jan 26, 2024
1 parent 96df299 commit 2eefb47
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 11 deletions.
40 changes: 38 additions & 2 deletions cmgr/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,45 @@ func (m *Manager) validateMetadata(md *ChallengeMetadata) error {
}

// Validate Description
templates := templateRe.FindAllString(md.Description, -1)
// picoCTF fork customization: allow template strings not involving connection information in the description section
templates := httpBaseRe.FindAllString(md.Description, -1)
if len(templates) > 0 {
lastErr = fmt.Errorf("template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
lastErr = fmt.Errorf("'http_base' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
m.log.error(lastErr)
}
templates = shortHttpBaseRe.FindAllString(md.Description, -1)
if len(templates) > 0 {
lastErr = fmt.Errorf("'http_base' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
m.log.error(lastErr)
}
templates = portRe.FindAllString(md.Description, -1)
if len(templates) > 0 {
lastErr = fmt.Errorf("'port' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
m.log.error(lastErr)
}
templates = shortPortRe.FindAllString(md.Description, -1)
if len(templates) > 0 {
lastErr = fmt.Errorf("'port' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
m.log.error(lastErr)
}
templates = serverRe.FindAllString(md.Description, -1)
if len(templates) > 0 {
lastErr = fmt.Errorf("'server' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
m.log.error(lastErr)
}
templates = shortServerRe.FindAllString(md.Description, -1)
if len(templates) > 0 {
lastErr = fmt.Errorf("'server' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
m.log.error(lastErr)
}
templates = linkRe.FindAllString(md.Description, -1)
if len(templates) > 0 {
lastErr = fmt.Errorf("'link' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
m.log.error(lastErr)
}
templates = shortLinkRe.FindAllString(md.Description, -1)
if len(templates) > 0 {
lastErr = fmt.Errorf("'link' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
m.log.error(lastErr)
}

Expand Down
19 changes: 10 additions & 9 deletions examples/markdown_challenges.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,23 @@

## Description

This is a static description of the challenge that is intended to be shown to
the user and will be the same across all instances of the challenge.
This portion of the challenge description is displayed to users regardless of whether an instance of the challenge is currently running. It may include static text, as well as the following templates:

- `{{url_for("file", "display text")}}` (link to an artifact file published in a build)
- `{{lookup("key")}}` ("key" must have been published in `metadata.json` when creating a build)

## Details

This is templated information for the challenge that can use additional
build-specific information to present information. In particular, the following
templates are allowed (anything else is invalid):
- `{{url_for("file", "display text")}}`
This portion of the challenge description is displayed to users when an instance of a challenge is
running. It may include any content permitted in the "Description" section, as well as the following
instance-specific templates:

- `{{http_base("port_name")}}` (URL prefix for HTTP requests to the named port)
- `{{server("port_name")}}` (hostname which hosts for connecting to the
associated port for the challenge)
- `{{port("port_name")}}` (The specific port number competitors will see which
may not be the same number as exposed by Docker if the front-end is proxying
connections.)
- `{{server("port_name")}}` (hostname which hosts for connecting to the
associated port for the challenge)
- `{{lookup("key")}}` ("key" must have been published in `metadata.json` when creating a build)
- `{{link("port_name", "/url/in/challenge")}}` (convenience wrapper for generating an HTML link)
- `{{link_as("port_name", "/url/in/challenge", "display text")}}` (convenience
wrapper for generating an HTML link with text different from the URL)
Expand Down

0 comments on commit 2eefb47

Please sign in to comment.