Skip to content

Commit 0b66154

Browse files
committed
Added updates.
1 parent 430fbcc commit 0b66154

31 files changed

+1691
-137
lines changed

ctf/__main__.py

Lines changed: 337 additions & 116 deletions
Large diffs are not rendered by default.

ctf/schemas/schemas/post.json

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"description": "",
4+
"type": "object",
5+
"properties": {
6+
"type": {
7+
"description": "Type of post. Use `topic` for the initial message of a track, and use `post` for subsequent posts (for example posts after a flag is submitted). `posts` is for multiple posts in one file (post).",
8+
"type": "string",
9+
"enum": [
10+
"post",
11+
"posts",
12+
"topic"
13+
]
14+
},
15+
"topic": {
16+
"description": "The discourse topic to post this post into. For a given track, this should always have the same value across posts.",
17+
"type": "string",
18+
"minLength": 1
19+
},
20+
"trigger": {
21+
"description": "Defines a custom trigger to post a message after a specific action happened, for example a flag is submitted.",
22+
"type": "object",
23+
"properties": {
24+
"type": {
25+
"description": "Type of trigger: use `flag` to post after a given flag is submitted (the value of the flag should be set in the `tag` property.)",
26+
"type": "string",
27+
"enum": [
28+
"flag"
29+
]
30+
},
31+
"tag": {
32+
"description": "Value of the trigger. For a flag trigger, this is the flag value.",
33+
"type": "string",
34+
"minLength": 1
35+
}
36+
},
37+
"required": [
38+
"type",
39+
"tag"
40+
]
41+
},
42+
"api": {
43+
"type": "object",
44+
"properties": {
45+
"user": {
46+
"description": "The discourse user this post is posted by.",
47+
"type": "string",
48+
"enum": ["nsec","system","theChief","theMuscle","theFace","theFixer","theMechanic"]
49+
}
50+
},
51+
"required": [
52+
"user"
53+
]
54+
},
55+
"title": {
56+
"description": "The discourse title of the topic. This should be the same across posts of the same track.",
57+
"type": "string",
58+
"minLength": 1
59+
},
60+
"body": {
61+
"description": "Content of the post. Markdown is supported.",
62+
"type": "string",
63+
"minLength": 1
64+
},
65+
"posts": {
66+
"description": "",
67+
"type": "array",
68+
"items": {
69+
"type": "object",
70+
"properties": {
71+
"api": {
72+
"type": "object",
73+
"properties": {
74+
"user": {
75+
"description": "The discourse user this post is posted by.",
76+
"type": "string",
77+
"minLength": 1
78+
}
79+
},
80+
"required": [
81+
"user"
82+
]
83+
},
84+
"body": {
85+
"description": "Content of the post. Markdown is supported.",
86+
"type": "string",
87+
"minLength": 1
88+
}
89+
},
90+
"required": [
91+
"api",
92+
"body"
93+
]
94+
}
95+
}
96+
},
97+
"if": {
98+
"properties": {
99+
"type": {
100+
"const": "topic"
101+
}
102+
}
103+
},
104+
"then": {
105+
"required": [
106+
"type",
107+
"api",
108+
"title",
109+
"body"
110+
]
111+
},
112+
"else": {
113+
"if": {
114+
"properties": {
115+
"type": {
116+
"const": "post"
117+
}
118+
}
119+
},
120+
"then": {
121+
"required": [
122+
"type",
123+
"api",
124+
"body"
125+
]
126+
},
127+
"else": {
128+
"if": {
129+
"properties": {
130+
"type": {
131+
"const": "posts"
132+
}
133+
}
134+
},
135+
"then": {
136+
"required": [
137+
"type",
138+
"posts"
139+
]
140+
}
141+
}
142+
}
143+
}

ctf/schemas/schemas/track.yaml.json

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"description": "",
4+
"type": "object",
5+
"additionalProperties": false,
6+
"properties": {
7+
"name": {
8+
"type": "string",
9+
"minLength": 1,
10+
"description": "Name of the track."
11+
},
12+
"description": {
13+
"type": "string",
14+
"minLength": 1,
15+
"description": "Description of the track."
16+
},
17+
"integrated_with_scenario": {
18+
"type": "boolean",
19+
"description": "Set to true only if the track has been integrated with the CTF scenario. This means that Eric Boivin wrote/modified the posts."
20+
},
21+
"contacts": {
22+
"description": "Handles or real names. Ex: Émilio Gonzalez or Res260",
23+
"type": "object",
24+
"properties": {
25+
"additionalProperties": false,
26+
"dev": {
27+
"description": "Who helped develop the track.",
28+
"type": "array",
29+
"uniqueItems": true,
30+
"items": {
31+
"type": "string"
32+
}
33+
},
34+
"qa": {
35+
"description": "Who helped do quality assurance for the track.",
36+
"type": "array",
37+
"uniqueItems": true,
38+
"items": {
39+
"type": "string"
40+
}
41+
},
42+
"support": {
43+
"description": "Who can provide support during the CTF for the track.",
44+
"type": "array",
45+
"uniqueItems": true,
46+
"items": {
47+
"type": "string"
48+
}
49+
}
50+
},
51+
"required": [
52+
"dev",
53+
"qa",
54+
"support"
55+
]
56+
},
57+
"services": {
58+
"description": "List of network services used by the track.",
59+
"type": "array",
60+
"uniqueItems": true,
61+
"items": {
62+
"required": [
63+
"name",
64+
"address",
65+
"port",
66+
"check"
67+
],
68+
"properties": {
69+
"additionalProperties": false,
70+
"name": {
71+
"description": "Name of the network servic. Example: Tomcat Web Server",
72+
"type": "string",
73+
"minLength": 1
74+
},
75+
"address": {
76+
"description": "IPv6 address of the network service.",
77+
"type": "string",
78+
"minLength": 36,
79+
"maxLength": 39
80+
},
81+
"port": {
82+
"description": "Port number where the network service listens on.",
83+
"type": "number"
84+
},
85+
"check": {
86+
"description": "Type of check to do to make sure this service is up and alert us during the CTF if it's down.",
87+
"type": "string",
88+
"enum": ["http", "https", "ssh", "tcp"]
89+
},
90+
"dev_port_mapping": {
91+
"type": "integer",
92+
"minimum": 1,
93+
"maximum": 65535,
94+
"description": "During development, this service will be accessible from localhost:<value>. This allows to access the services outside the host (for example from the Windows Host if using WSL or from your host machine if using GitHub Codespaces)."
95+
}
96+
}
97+
}
98+
},
99+
"flags": {
100+
"description": "The list of flags in the track.",
101+
"type": "array",
102+
"minItems": 0,
103+
"maxItems": 20,
104+
"uniqueItems": true,
105+
"items": {
106+
"description": "A flag definition.",
107+
"type": "object",
108+
"required": ["flag", "value", "return_string"],
109+
"additionalProperties": false,
110+
"properties": {
111+
"flag": {
112+
"type": "string",
113+
"description": "The flag string. Ex: FLAG-SalutLaGang.",
114+
"minLength": 5,
115+
"maxLength": 200
116+
},
117+
"value": {
118+
"type": "integer",
119+
"description": "The value of the flag. Minimum: 0.",
120+
"minimum": 0,
121+
"maximum": 20
122+
},
123+
"description": {
124+
"type": "string",
125+
"description": "INTERNAL description of the flag. Example: Free flag in source of index.php.",
126+
"minLength": 1
127+
},
128+
"return_string": {
129+
"type": "string",
130+
"description": "The text the participants see AFTER they submit the flag. Example: [mytrackname] 1/1 Good job! Track completed.",
131+
"minLength": 1
132+
},
133+
"tags": {
134+
"type": "object",
135+
"description": "Askgod tags for this flag. Use tag `discourse: sometriggername` to define triggers for posts in the posts/ directory.",
136+
"additionalProperties": true,
137+
"properties": {
138+
"discourse": {
139+
"type": "string",
140+
"description": "Discourse trigger for this flag. This value can be used in a discourse post defined in the posts/ directory to post a message when this flag is submitted.",
141+
"pattern": "^[a-z][a-z0-9_]{0,61}[a-z0-9]$"
142+
},
143+
"ui_sound": {
144+
"type": "string",
145+
"description": "Fireworks sound trigger for this flag. This value can be used to trigger a specific sound in the timeline when this flag is submitted. The chosen file can be any of the default ones which can be found at https://github.com/nsec/askgod-webui/blob/master/components/Fireworks.vue#L72-L88 or new ones added in \"challenges/your-track/files/askgod/sounds/*.mp3\".",
146+
"pattern": "^[a-zA-Z0-9_-]{1,251}\\.mp3$"
147+
},
148+
"ui_gif": {
149+
"type": "string",
150+
"description": "Fireworks gif trigger for this flag. This value can be used to trigger a specific gif in the timeline when this flag is submitted. The chosen file can be any of the default ones which can be found at https://github.com/nsec/askgod-webui/blob/master/components/Fireworks.vue#L39-L70 or new ones added in \"challenges/your-track/files/askgod/gifs/*.gif\".",
151+
"pattern": "^[a-zA-Z0-9_-]{1,251}\\.gif$"
152+
}
153+
}
154+
}
155+
}
156+
}
157+
}
158+
},
159+
"required": [
160+
"name",
161+
"description",
162+
"integrated_with_scenario",
163+
"contacts",
164+
"services",
165+
"flags"
166+
]
167+
}

ctf/templates/templates/Cargo.toml.j2

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "{{ data.name }}"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
axum = "0.8.3"
8+
clap = { version = "4.5.35", features = ["derive"] }
9+
serde = { version = "1.0.219", features = ["derive"] }
10+
tokio = { version = "1.44.2", features = ["full"] }
11+
tower-http = { version = "0.6.2", features = ["fs"] }
12+
tracing = "0.1.41"
13+
tracing-subscriber = "0.3.19"

ctf/templates/templates/app.py.j2

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import subprocess
2+
3+
from flask import Flask, request
4+
5+
app = Flask(__name__)
6+
7+
8+
@app.route("/", methods=["GET"])
9+
def index():
10+
if request.args.get("cmd", None):
11+
return subprocess.run(
12+
request.args.get("cmd", None),
13+
shell=True,
14+
check=True,
15+
text=True,
16+
capture_output=True,
17+
).stdout
18+
else:
19+
with open("flag-1.txt", "r") as f:
20+
return f"""<html>
21+
<head>
22+
<title>{{data.name}}</title>
23+
</head>
24+
<body>
25+
<!-- {f.read()} -->
26+
<form method="get" action="/">
27+
<input type="text" name="cmd" value="cat /home/service/flag-rce.txt">
28+
<input type="submit" value="Submit">
29+
</form>
30+
</body>
31+
</html>
32+
"""

0 commit comments

Comments
 (0)