Skip to content

Commit 2eefb47

Browse files
committed
Allow {{url_for}} and {{lookup}} templates in Description
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.
1 parent 96df299 commit 2eefb47

File tree

2 files changed

+48
-11
lines changed

2 files changed

+48
-11
lines changed

cmgr/loader.go

+38-2
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,45 @@ func (m *Manager) validateMetadata(md *ChallengeMetadata) error {
141141
}
142142

143143
// Validate Description
144-
templates := templateRe.FindAllString(md.Description, -1)
144+
// picoCTF fork customization: allow template strings not involving connection information in the description section
145+
templates := httpBaseRe.FindAllString(md.Description, -1)
145146
if len(templates) > 0 {
146-
lastErr = fmt.Errorf("template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
147+
lastErr = fmt.Errorf("'http_base' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
148+
m.log.error(lastErr)
149+
}
150+
templates = shortHttpBaseRe.FindAllString(md.Description, -1)
151+
if len(templates) > 0 {
152+
lastErr = fmt.Errorf("'http_base' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
153+
m.log.error(lastErr)
154+
}
155+
templates = portRe.FindAllString(md.Description, -1)
156+
if len(templates) > 0 {
157+
lastErr = fmt.Errorf("'port' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
158+
m.log.error(lastErr)
159+
}
160+
templates = shortPortRe.FindAllString(md.Description, -1)
161+
if len(templates) > 0 {
162+
lastErr = fmt.Errorf("'port' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
163+
m.log.error(lastErr)
164+
}
165+
templates = serverRe.FindAllString(md.Description, -1)
166+
if len(templates) > 0 {
167+
lastErr = fmt.Errorf("'server' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
168+
m.log.error(lastErr)
169+
}
170+
templates = shortServerRe.FindAllString(md.Description, -1)
171+
if len(templates) > 0 {
172+
lastErr = fmt.Errorf("'server' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
173+
m.log.error(lastErr)
174+
}
175+
templates = linkRe.FindAllString(md.Description, -1)
176+
if len(templates) > 0 {
177+
lastErr = fmt.Errorf("'link' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
178+
m.log.error(lastErr)
179+
}
180+
templates = shortLinkRe.FindAllString(md.Description, -1)
181+
if len(templates) > 0 {
182+
lastErr = fmt.Errorf("'link' template strings not allowed in the 'description' field, but found: %s", strings.Join(templates, ", "))
147183
m.log.error(lastErr)
148184
}
149185

examples/markdown_challenges.md

+10-9
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,23 @@
99

1010
## Description
1111

12-
This is a static description of the challenge that is intended to be shown to
13-
the user and will be the same across all instances of the challenge.
12+
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:
13+
14+
- `{{url_for("file", "display text")}}` (link to an artifact file published in a build)
15+
- `{{lookup("key")}}` ("key" must have been published in `metadata.json` when creating a build)
1416

1517
## Details
1618

17-
This is templated information for the challenge that can use additional
18-
build-specific information to present information. In particular, the following
19-
templates are allowed (anything else is invalid):
20-
- `{{url_for("file", "display text")}}`
19+
This portion of the challenge description is displayed to users when an instance of a challenge is
20+
running. It may include any content permitted in the "Description" section, as well as the following
21+
instance-specific templates:
22+
2123
- `{{http_base("port_name")}}` (URL prefix for HTTP requests to the named port)
24+
- `{{server("port_name")}}` (hostname which hosts for connecting to the
25+
associated port for the challenge)
2226
- `{{port("port_name")}}` (The specific port number competitors will see which
2327
may not be the same number as exposed by Docker if the front-end is proxying
2428
connections.)
25-
- `{{server("port_name")}}` (hostname which hosts for connecting to the
26-
associated port for the challenge)
27-
- `{{lookup("key")}}` ("key" must have been published in `metadata.json` when creating a build)
2829
- `{{link("port_name", "/url/in/challenge")}}` (convenience wrapper for generating an HTML link)
2930
- `{{link_as("port_name", "/url/in/challenge", "display text")}}` (convenience
3031
wrapper for generating an HTML link with text different from the URL)

0 commit comments

Comments
 (0)