Skip to content

Commit f577173

Browse files
authored
Have a working example of mounting gcsfuse for web tasks (#273)
* Update README.md * refactor web task * add mounts * update readme
1 parent 5ba1161 commit f577173

File tree

12 files changed

+171
-52
lines changed

12 files changed

+171
-52
lines changed

dist/challenge-templates/web/README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ The basic steps when preparing a challenge are:
1010
* To access the challenge, create a port forward with `kctf chal debug port-forward` and connect to it via `nc localhost PORT` using the printed port.
1111
* Check out `kctf chal <tab>` for more commands.
1212

13+
## Sandboxing
14+
15+
In order to make it possible to have RCE-style web challenges, kCTF provides two ways to sandbox a web server:
16+
1. **CGI-sandbox**: You can configure PHP (or any other CGI) to be sandboxed.
17+
2. **Proxy sandbox**: You can configure an HTTP server that sandboxes every HTTP request.
18+
19+
A Proxy sandbox is a bit expensive, it starts an HTTP server on every TCP connection, hence it is a bit slow. A CGI sandbox is cheaper, and it just calls the normal CGI endpoint but with nsjail.
20+
21+
The template challenge has an example of both (NodeJS running as a proxy, and PHP running as CGI). It is recommended that static resources are served with only Apache, as to save CPU and RAM.
22+
1323
## Directory layout
1424

1525
The following files/directories are available:
@@ -24,6 +34,7 @@ For documentation on the available fields, you can run `kubectl explain challeng
2434

2535
If you would like to have a shared directory (for sessions, or uploads), you can mount it using:
2636

37+
2738
```yaml
2839
spec:
2940
persistentVolumeClaims:
@@ -35,16 +46,18 @@ spec:
3546
volumeMounts:
3647
- name: gcsfuse
3748
subPath: sessions # this this a folder inside volume
38-
mountPath: /where-to-mount/sessions
49+
mountPath: /mnt/disks/sessions
3950
- name: gcsfuse
4051
subPath: uploads
41-
mountPath: /where-to-mount/uploads
52+
mountPath: /mnt/disks/uploads
4253
volumes:
4354
- name: gcsfuse
4455
persistentVolumeClaim:
4556
claimName: $PUT_THE_NAME_OF_THE_CHALLENGE_HERE
4657
```
4758
59+
This will mount a file across all challenges in that directory. You can test this setup on a remote cluster using the PHP/CGI sandbox.
60+
4861
### /challenge
4962
5063
The `challenge` directory contains a Dockerfile that describes the challenge and

dist/challenge-templates/web/challenge/Dockerfile

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ RUN /usr/sbin/useradd -u 1000 user
1717

1818
RUN apt-get update \
1919
&& apt-get install -yq --no-install-recommends \
20-
curl ca-certificates socat gnupg lsb-release software-properties-common \
20+
curl ca-certificates socat gnupg lsb-release software-properties-common php-cgi \
2121
&& rm -rf /var/lib/apt/lists/*
2222

2323
RUN curl -sSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - \
@@ -29,35 +29,44 @@ RUN curl -sSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add
2929
&& apt-get install -yq --no-install-recommends nodejs socat \
3030
&& rm -rf /var/lib/apt/lists/*
3131

32-
RUN mkdir -p /home/user/chroot
32+
VOLUME /mnt/disks/sessions
33+
VOLUME /mnt/disks/uploads
3334

34-
FROM gcr.io/kctf-docker/challenge@sha256:e550af5df266cb89a26ace1ba5dcc685981f01d1cb61e45a898cce0c9753de7a
35-
36-
COPY --from=chroot / /chroot
35+
COPY web-apps /web-apps
36+
COPY web-servers /web-servers
3737

38-
RUN touch /chroot/dev/null
38+
COPY flag /
3939

40-
COPY flag /chroot/
40+
FROM gcr.io/kctf-docker/challenge@sha256:e550af5df266cb89a26ace1ba5dcc685981f01d1cb61e45a898cce0c9753de7a
4141

4242
RUN apt-get update \
43-
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends tzdata \
43+
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends tzdata apache2 \
4444
&& ln -fs /usr/share/zoneinfo/Europe/Berlin /etc/localtime \
4545
&& dpkg-reconfigure --frontend noninteractive tzdata \
4646
&& rm -rf /var/lib/apt/lists/*
4747

48-
RUN apt-get update && apt-get install -yq --no-install-recommends apache2 && rm -rf /var/lib/apt/lists/*
49-
5048
RUN service apache2 start
5149

50+
COPY --from=chroot / /chroot
51+
52+
# For Proxy
5253
RUN ln -s /etc/apache2/mods-available/proxy.load /etc/apache2/mods-enabled/
5354
RUN ln -s /etc/apache2/mods-available/proxy_http.load /etc/apache2/mods-enabled/
54-
COPY apache2-nsjail-others.conf /etc/apache2/conf-enabled/
5555

56-
COPY chroot /home/user/chroot
57-
COPY node /home/user/node
58-
COPY nsjail.cfg /home/user/nsjail.cfg
56+
# For CGI sandboxing
57+
RUN ln -s /etc/apache2/mods-available/cgi.load /etc/apache2/mods-enabled/cgi.load
58+
RUN ln -s /etc/apache2/mods-available/actions.load /etc/apache2/mods-enabled/actions.load
59+
RUN ln -s /chroot/web-apps /web-apps
60+
COPY cgi-bin /usr/lib/cgi-bin
61+
62+
COPY apache2-kctf-nsjail.conf /etc/apache2/conf-enabled/
63+
64+
COPY web-servers.nsjail.cfg /home/user/web-servers.nsjail.cfg
65+
COPY cgi-bin.nsjail.cfg /home/user/cgi-bin.nsjail.cfg
66+
67+
VOLUME /var/log/apache2
68+
VOLUME /var/run/apache2
5969

6070
CMD kctf_setup \
61-
&& /home/user/node/start.sh \
62-
&& mount -t tmpfs none /var/run/apache2 \
71+
&& (kctf_drop_privs nsjail --config /home/user/web-servers.nsjail.cfg --port 8081 -- /web-servers/nodejs.sh &) \
6372
&& bash -c 'source /etc/apache2/envvars && APACHE_RUN_USER=user APACHE_RUN_GROUP=user /usr/sbin/apache2 -D FOREGROUND'
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
ServerName kctf-nsjail
2+
Listen 1337
3+
User user
4+
5+
# This is only necessary for CGI sandboxing
6+
<Directory "/web-apps/php">
7+
Options +ExecCGI
8+
Options +FollowSymLinks
9+
Action application/x-nsjail-httpd-php /cgi-bin/nsjail-php-cgi
10+
AddHandler application/x-nsjail-httpd-php php
11+
Require all granted
12+
</Directory>
13+
14+
<VirtualHost *:1337>
15+
# For proxy sandboxing use the two lines below
16+
ProxyPreserveHost On
17+
ProxyPass "/nodejs" "http://localhost:8081/"
18+
# For CGI sandboxing use the line below
19+
DocumentRoot "/web-apps/php"
20+
</VirtualHost>

dist/challenge-templates/web/challenge/apache2-nsjail-others.conf

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Copyright 2020 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# See options available at https://github.com/google/nsjail/blob/master/config.proto
16+
17+
name: "apache2-proxy-nsjail"
18+
description: "Example nsjail configuration for containing a web server."
19+
20+
mode: ONCE
21+
uidmap {inside_id: "1000"}
22+
gidmap {inside_id: "1000"}
23+
mount_proc: true
24+
keep_env: true
25+
rlimit_as_type: HARD
26+
rlimit_cpu_type: HARD
27+
rlimit_nofile_type: HARD
28+
rlimit_nproc_type: HARD
29+
30+
mount: [
31+
{
32+
src: "/chroot"
33+
dst: "/"
34+
is_bind: true
35+
},
36+
{
37+
src: "/dev"
38+
dst: "/dev"
39+
is_bind: true
40+
},
41+
{
42+
src: "/dev/null"
43+
dst: "/dev/null"
44+
is_bind: true
45+
},
46+
{
47+
src: "/etc/resolv.conf"
48+
dst: "/etc/resolv.conf"
49+
is_bind: true
50+
},
51+
{
52+
src: "/mnt/disks/sessions"
53+
dst: "/mnt/disks/sessions"
54+
is_bind: true
55+
rw: true
56+
},
57+
{
58+
src: "/mnt/disks/uploads"
59+
dst: "/mnt/disks/uploads"
60+
is_bind: true
61+
rw: true
62+
},
63+
{
64+
dst: "/tmp"
65+
fstype: "tmpfs"
66+
rw: true
67+
}
68+
]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/bash
2+
3+
/usr/bin/nsjail --config /home/user/cgi-bin.nsjail.cfg -- /usr/lib/cgi-bin/php $@

dist/challenge-templates/web/challenge/chroot/node/run.sh

Lines changed: 0 additions & 13 deletions
This file was deleted.

dist/challenge-templates/web/challenge/node/start.sh

Lines changed: 0 additions & 6 deletions
This file was deleted.

dist/challenge-templates/web/challenge/chroot/node/app.js renamed to dist/challenge-templates/web/challenge/web-apps/nodejs/app.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,5 @@ const server = http.createServer((req, res) => {
1010
});
1111

1212
server.listen(port, hostname, () => {
13-
// Send something to STDOUT to signal we are ready to accept connections
1413
console.log(`Server running at http://${hostname}:${port}/`);
1514
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
session_start();
3+
4+
if (isset($_REQUEST['session_data'])) {
5+
$_SESSION['session_data'] = $_REQUEST['session_data'];
6+
}
7+
?>
8+
<pre>
9+
<?php
10+
if (isset($_FILES['file'])) {
11+
print_r($_FILES['file']);
12+
$filename = uniqid('file_', true);
13+
echo $filename;
14+
move_uploaded_file($_FILES['file']['tmp_name'], '/mnt/disks/uploads/'. $filename);
15+
}
16+
?>
17+
</pre>
18+
<hr/>
19+
<form method=post enctype=multipart/form-data>
20+
<input name=session_data value="<?=$_SESSION['session_data'];?>">
21+
<input name=file type=file>
22+
<input type=submit>
23+
</form>
24+
<hr/>
25+
<?php
26+
phpinfo();
27+
?>

dist/challenge-templates/web/challenge/nsjail.cfg renamed to dist/challenge-templates/web/challenge/web-servers.nsjail.cfg

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,22 @@ mount: [
3232
dst: "/"
3333
is_bind: true
3434
},
35+
{
36+
src: "/dev"
37+
dst: "/dev"
38+
is_bind: true
39+
},
3540
{
3641
src: "/dev/null"
3742
dst: "/dev/null"
3843
is_bind: true
44+
rw: true
3945
},
4046
{
4147
src: "/etc/resolv.conf"
4248
dst: "/etc/resolv.conf"
4349
is_bind: true
4450
},
45-
{
46-
src: "/home/user/chroot"
47-
dst: "/home/user/chroot"
48-
is_bind: true
49-
},
5051
{
5152
dst: "/tmp"
5253
fstype: "tmpfs"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash
2+
3+
# Start node web server
4+
(&>/dev/null node /web-apps/nodejs/app.js)&
5+
6+
# Proxy stdin/stdout to web server
7+
socat - TCP:127.0.0.1:8080,forever

0 commit comments

Comments
 (0)