Installation script

This commit is contained in:
Neale Pickett 2015-04-09 17:40:03 -06:00
parent a86f5bfd8e
commit 23e750ed85
81 changed files with 256 additions and 2725 deletions

View File

@ -1,33 +0,0 @@
# Scratch directory for building extrenal sources
BUILD = build
# Root to install things before they're packaged
TARGET = target
# Downloaded source files go here
CACHE = cache
# The end result
BIN = bin
ifdef ARCH
export CC = ${ARCH}-cc
export STRIP = ${ARCH}-strip
endif
all: packages
dist: ctf-install.zip
ctf-install.zip: packages.zip bzImage rootfs.squashfs /usr/lib/syslinux/mbr.bin
zip --junk-paths $@ packages.zip bzImage rootfs.squashfs /usr/lib/syslinux/mbr.bin install.sh
packages.zip: packages
zip --junk-paths $@ bin/*.pkg
clean: packages-clean
rm -rf $(BUILD) $(TARGET) $(BIN)
scrub: clean
rm -rf $(CACHE)
-include */*.mk

View File

@ -1,25 +0,0 @@
IPv6 in Dirtbags CTF
====================
The contest network uses IPs in the unique local address space
fd84:b410:3441::/48. Each team gets a /64 internal subnet, with
their team number (generally the same digits as the switch port).
Each subnet's gateway is fd84:b410:3441:$teamno::1.
Team 15, in switch port 15, on VLAN 15, gets fd84:b410:3441:15::/64.
Server network is fd84:b410:3441::/64 (AKA fd84:b410:3441:0::/64). To
make things easier to type, use hosts in the /112. The MCP server lives
at fd84:b410:3441::2.
Vendors typically live on port 23. They usually want a static address.
Tell them this:
Pick any address in fd84:b410:3441:23::/64. Your default gateway
is fd84:b410:3441:23::1. You may want to assign yourself a subnet,
for example fd84:b410:3441:23:1234::
Kevin Nauer gets port 24. In 2012, we needed to route fd80:1::/48
through fd84:b410:3441:24::2, since he was using that subnet for
his systems.

View File

@ -1,68 +0,0 @@
CTF Packages
============
Packages are squashfs files.
A hypothetical package named pkgname.sfs will be mounted under
/opt/pkgname. The following top-level files and directories are
significant:
* /setup - Run after package is mounted
* /bin/ - Added to $PATH for login shells
* /puzzles/ - Appears as a puzzle category (see "Puzzles" below)
* /answers.txt - Puzzle answers for category pkgname (see "Puzzles" below)
setup script
------------
The setup script (if it exists and is executable) will be run from within
the mounted directory. This is mostly so you can copy things out of your
read-only package and into read/write areas.
Don't start your service here, instead, make a new directory in
/var/service and place a "run" script in it. More information can be found
at <http://smarden.org/runit/>.
Some common actions in setup:
cp -r service/* /var/service # Install startup services
# Set up a file with ownership
install -o ctf -m 0644 /var/lib/ctf/whatever.db
Puzzles
-------
To expose puzzles, place them in the /puzzles/ directory, like so:
/puzzles/10/index.html
/puzzles/20/index.html
/puzzles/20/script.cgi
/puzzles/30/index.html
/puzzles/30/something.jpg
/puzzles/40/index.html
where the second directory is the point value of the puzzle. This means
that no two puzzles in a category can have the same point value.
Files will be served up from the web server, and CGI scripts will be
executed.
Store answers to your puzzles in /answers.txt. Answers are one per
line, with the point value appearing first, followed by a space, then
the answer. Answers are case sensitive. You may have multiple answers
for each point value.
10 zip file
10 zip
10 ZIP
10 pkzip
10 PKZIP
20 varname
30 JFIF
40 0x8040fe67
40 8040FE67
40 8040fe67

Binary file not shown.

View File

@ -1,180 +0,0 @@
LANL CTF Token-Based Categories
===============================
LANL's CTF contest allows for easy addition of new modules which can use
"tokens". A token is a character string worth one point in the contest.
A point may only be claimed once per team, but multiple teams can claim
the same token and each will get a point. Tokens look like this:
example:xenon-donut-helix
where "example" is the category name, and "xenon-donut-helix" is a
bubblebabble hash of a 32-bit random number. The entire string must be
submitted as the token.
Tokens are issued by the token server using the tokencli program at the
end of this document. They can also be issued before the beginning of a
contest. If your category allows it, it will be much easier for you to
simply request a number of tokens before the contest begins, and
hard-code them into your category.
You will want to arrange that participants get a token after having
completed some sort of task. In existing categories, tokens are
frequently what lie beneath some trail of hacking. For instance, one
program provides a token when the proper printf formatting string is
provided. Another embeds five tokens into log messages using different
encodings.
Any machine that you connect to our network will get a wired connection
and should claim a static IP address on the 10.0.2.0/24 network. While
it's unlikely you'll conflict with anyone else, be prepared to
reconfigure it with a new IP on the morning of the event.
If you plan to request tokens, please do so at least 2 weeks before the
start of the event. I will need to know what you'd like your category
to be called, and how many tokens you'd like. It's not a problem if you
don't use all the tokens you request.
Remember that this is a security contest, and contestants will be far
more engaged with your category if they have to do real work to get the
tokens. For example, a vendor might be tempted to leave tokens lying
around in configuration boxes to reward people who explore its rich
configurability, but this would probably result in people clicking
through the UI as quickly as possible looking only for tokens. Far
better would be to have the tokens lying under the products
functionality somewhere, forcing contestants to interact with the
product like they would in their day to day work after having purchased
it. A Snort category, for instance, would do well to have tokens within
packet captures which triggered alarms.
I can't stress that last point enough: constestants have been known to
spend over 2 hours on a single problem. Don't be afraid to really
challenge them.
/* tokencli.c - LANL CTF token client
Author: Neale Pickett <neale@lanl.gov>
This program requires an arc4 implementation, email me if you can't find
one you like.
This also requires a shared 128-bit key. I need the key before you can
start requesting tokens from the server :)
This software has been authored by an employee or employees of Los
Alamos National Security, LLC, operator of the Los Alamos National
Laboratory (LANL) under Contract No. DE-AC52-06NA25396 with the
U.S. Department of Energy. The U.S. Government has rights to use,
reproduce, and distribute this software. The public may copy,
distribute, prepare derivative works and publicly display this software
without charge, provided that this Notice and any statement of
authorship are reproduced on all copies. Neither the Government nor
LANS makes any warranty, express or implied, or assumes any liability or
responsibility for the use of this software. If software is modified to
produce derivative works, such modified software should be clearly
marked, so as not to confuse it with the version available from LANL.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sysexits.h>
#include <stdio.h>
#include "arc4.h"
/* I don't feel compelled to put all the TCP client code in here
* when it's so simple to run this with netcat or ucspi. Plus, using
* stdin and stdout makes it simpler to test.
*/
int
read_key(char *filename, uint8_t *key, size_t *keylen)
{
int fd = open(filename, O_RDONLY);
int len;
if (-1 == fd) {
perror("open");
return EX_NOINPUT;
}
len = read(fd, key, *keylen);
if (-1 == len) {
perror("read");
return EX_NOINPUT;
}
*keylen = (size_t)len;
return 0;
}
int
main(int argc, char *argv[]) {
uint8_t skey[200];
size_t skeylen = sizeof(skey);
char token[200];
size_t tokenlen;
int ret;
if (argc != 3) {
fprintf(stderr, "Usage: %s SERVICE SERVICEKEY 3>TOKENFILE\n", argv[0]);
fprintf(stderr, "\n");
fprintf(stderr, "SERVICEKEY is a filename.\n");
fprintf(stderr, "Server chatter happens over stdin and stdout.\n");
fprintf(stderr, "Tokens are written to file descriptor 3.\n");
fprintf(stderr, "\n");
fprintf(stderr, "To run with netcat:\n");
fprintf(stderr, " nc 10.0.0.2 1 -e tokencli cat cat.key 3> tokenfile\n");
return EX_USAGE;
}
/* read in keys */
ret = read_key(argv[2], skey, &skeylen);
if (0 != ret) return ret;
/* write service name */
write(1, argv[1], strlen(argv[1]));
/* read nonce, send back encrypted version */
{
uint8_t nonce[80];
int noncelen;
noncelen = read(0, nonce, sizeof(nonce));
if (0 >= noncelen) {
perror("read");
return EX_IOERR;
}
arc4_crypt_buffer(skey, skeylen, nonce, (size_t)noncelen);
write(1, nonce, (size_t)noncelen);
}
/* read token */
{
int len;
len = read(0, token, sizeof(token));
if (0 >= len) {
perror("read");
return EX_IOERR;
}
tokenlen = (size_t)len;
}
/* decrypt it */
arc4_crypt_buffer(skey, skeylen, (uint8_t *)token, tokenlen);
/* write it to fd 3 */
write(3, token, tokenlen);
return 0;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

51
html/credits.html Normal file
View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<title>The Credits</title>
<link rel="stylesheet" href="css/style.css" type="text/css">
</head>
<body>
<h1>Credits</h1>
<section>
<p>Dirtbags King of the Hill was created by:</p>
<ul>
<li>Neale Pickett</li>
<li>Aaron McPhall</li>
<li>Russel Nolen</li>
<li>Patrick Avery</li>
<li>Kate Vajda</li>
<li>Alex Brugh</li>
<li>Paul Ferrell</li>
<li>Jeremy Scott</li>
<li>Danny Quist</li>
<li>Adam Glasgall</li>
<li>Curtis Hash</li>
<li>Erin Ochoa</li>
<li>William Phillips</li>
<li>Should your name be here? Please remind me!</li>
</ul>
<p>Parts of this contest were inspired by contests from:</p>
<ul>
<li>DC949</li>
<li>Tube Warriors</li>
<li>Sandia National Laboratories</li>
</ul>
<p>
Lastly, this contest would not exist were it not for hundreds of
thousands of lines of code from free software authors around the
world, including:
</p>
<ul>
<li>Busybox</li>
<li>Linux</li>
<li>dnsmasq</li>
<li>ngircd</li>
<li>lua</li>
</ul>
</section>
</body>
</html>

View File

@ -3,13 +3,13 @@ Light blue: #96d1e3
Off-white blue: #b9e0ef
Dark brown: #35170c
Light brown: #432115
Tan: #e1c3b8
Tan: #e1caa5
*/
@import "../fonts/maven_pro.css";
html {
background: #35170c url(../brown-circles.jpg) repeat left bottom;
background: #35170c url(../images/brown-circles.jpg) repeat left bottom;
min-height: 100%;
font-family: "Maven Pro", Ubuntu, sans-serif;
}
@ -28,6 +28,8 @@ h1:first-child {
border-radius: 0.2em;
padding: 0 0.3em;
text-align: center;
max-width: 66%;
margin: 0.5em auto;
}
.readme, pre {
@ -111,11 +113,11 @@ section, nav {
max-width: 35em;
border-radius: 0.6em;
margin: 1em auto;
padding: 0.2em;
padding: 0.5em;
}
section {
background: #e1c3b8;
background: #e1caa5;
}
/*** navigation bar ***/

View File

@ -1,207 +0,0 @@
/* Pallette: http://paletton.com/#uid=3360u0kkWtL00++bxKws6lGT03t */
/**** Color Scheme ****/
html {
background: #1C1000 url(smoke.jpg) no-repeat;
background-size: cover;
min-height: 100%;
}
body, h1:first-child:before {
color: #FFDAA3;
}
h1, h2, h3 {
color: #AD6F15;
}
a {
color: #379F7A;
}
a:hover {
color: #112;
background-color: #D84B6E;
}
input {
color: #F39CB2;
background-color: #190006;
border: solid #9E1336 2px;
border-radius: 2px;
}
.readme, pre {
background-color: #333;
}
/**** document ****/
body {
font-family: sans-serif;
padding: 10px;
max-width: 700px;
}
/**** heading ****/
h1:first-child {
text-transform: lowercase;
font-size: 1.6em;
padding: 3px;
margin: 0 0 1em 70px;
}
h1:first-child:before {
letter-spacing: -0.1em;
content: "FIRE: ";
}
/**** body ****/
a img {
border: 0px;
}
a {
text-decoration: underline;
}
h1, h2, h3 {
letter-spacing: -0.05em;
}
.readme {
margin: 1em;
}
pre {
border: solid #ddc 2px;
padding: 0.25em;
}
th {
vertical-align: top;
text-align: center;
}
td {
vertical-align: top;
text-align: left;
}
dt {
font-weight: bold;
}
p {
line-height: 1.4em;
margin-bottom: 20px;
}
hr {
border: 1px solid #ddc;
}
/*** navigation bar ***/
nav h2 {
display: none;
}
nav ul {
list-style: none;
text-align: center;
}
nav li {
display: inline;
}
nav li a {
text-transform: lowercase;
font-size: 0.9em;
}
nav li + li:before {
content: " | ";
}
/**** special cases ****/
.wide {
max-width: inherit;
}
.figure {
margin: 0.5em 1em;
float: right;
font-size: small;
text-align: center;
}
/* Scoreboard stuff */
.scoreboard, .scoreboard body {
height: 100%;
margin: 0;
padding: 0;
max-width: none;
}
#scoreboard {
height: 60%;
font-size: 75%;
}
#scoreboard td {
height: 100%;
}
#chart {
height: 30%;
width: 100%;
}
/* Tanks stuff */
#battlefield {
border: 2px solid green;
}
.solved {
text-decoration: line-through;
}
/* Names */
span[data-handle]:after {
content: ")";
}
span[data-handle="zephyr"]:before {
content: "Neale Pickett (";
}
span[data-handle="pflarr"]:before {
content: "Paul Ferrell (";
}
span[data-handle="chamuco"]:before {
content: "Danny Quist (";
}
span[data-handle="cashmoney"]:before {
content: "Jeremy Scott (";
}
span[data-handle="phorkus"]:before {
content: "Mark Carey (";
}
span[data-handle="cherish"]:before {
content: "Cherish Franco (";
}

View File

@ -1,208 +0,0 @@
/* Pallette: http://paletton.com/#uid=20+0a0kfKre1ZWZ8kDVnYiuzH8l */
/**** Color Scheme ****/
html {
background: #FFEABD url(smoke.jpg) no-repeat;
background-size: cover;
min-height: 100%;
}
body, h1:first-child:before {
color: #937025;
background-opacity: 0.9;
}
h1, h2, h3 {
color: #937025;
}
a {
color: #422D00;
}
a:hover {
color: #112;
background-color: #D84B6E;
}
input {
color: #213263;
background-color: #D9B76E;
border: solid #96A1C3 0.3em;
border-radius: 2px;
}
.readme, pre {
background-color: #333;
}
/**** document ****/
body {
font-family: sans-serif;
padding: 10px;
max-width: 700px;
}
/**** heading ****/
h1:first-child {
text-transform: lowercase;
font-size: 1.6em;
padding: 3px;
margin: 0 0 1em 70px;
}
h1:first-child:before {
letter-spacing: -0.1em;
content: "FIRE: ";
}
/**** body ****/
a img {
border: 0px;
}
a {
text-decoration: underline;
}
h1, h2, h3 {
letter-spacing: -0.05em;
}
.readme {
margin: 1em;
}
pre {
border: solid #ddc 2px;
padding: 0.25em;
}
th {
vertical-align: top;
text-align: center;
}
td {
vertical-align: top;
text-align: left;
}
dt {
font-weight: bold;
}
p {
line-height: 1.4em;
margin-bottom: 20px;
}
hr {
border: 1px solid #ddc;
}
/*** navigation bar ***/
nav h2 {
display: none;
}
nav ul {
list-style: none;
text-align: center;
}
nav li {
display: inline;
}
nav li a {
text-transform: lowercase;
font-size: 0.9em;
}
nav li + li:before {
content: " | ";
}
/**** special cases ****/
.wide {
max-width: inherit;
}
.figure {
margin: 0.5em 1em;
float: right;
font-size: small;
text-align: center;
}
/* Scoreboard stuff */
.scoreboard, .scoreboard body {
height: 100%;
margin: 0;
padding: 0;
max-width: none;
}
#scoreboard {
height: 60%;
font-size: 75%;
}
#scoreboard td {
height: 100%;
}
#chart {
height: 30%;
width: 100%;
}
/* Tanks stuff */
#battlefield {
border: 2px solid green;
}
.solved {
text-decoration: line-through;
}
/* Names */
span[data-handle]:after {
content: ")";
}
span[data-handle="zephyr"]:before {
content: "Neale Pickett (";
}
span[data-handle="pflarr"]:before {
content: "Paul Ferrell (";
}
span[data-handle="chamuco"]:before {
content: "Danny Quist (";
}
span[data-handle="cashmoney"]:before {
content: "Jeremy Scott (";
}
span[data-handle="phorkus"]:before {
content: "Mark Carey (";
}
span[data-handle="cherish"]:before {
content: "Cherish Franco (";
}

View File

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 107 KiB

View File

@ -6,9 +6,11 @@
<link rel="stylesheet" href="css/style.css" type="text/css">
</head>
<body>
<h1>Tracer FIRE 6E</h1>
<h1>Tracer FIRE 6</h1>
<section>
<h2>Getting Started</h2>
<p>
Here is what you need to do:
</p>
@ -35,6 +37,25 @@
</li>
</ol>
</section>
<section>
<h2>Reading Material</h2>
<p>
Stuck? Need a break? In the bathroom?
Here are some things to read.
</p>
<ul>
<li><a href="credits.html">Credits</a></li>
<li>
<a href="scoring.html">About Scoring</a>
explains how we calculate scores,
and why.
Reading this will help you formulate a strategy to win.
</li>
</ul>
</section>
<nav>
<ul>

109
html/scoring.html Normal file
View File

@ -0,0 +1,109 @@
<!DOCTYPE html>
<html>
<head>
<title>About scoring</title>
<link rel="stylesheet" href="css/style.css" type="text/css">
<meta charset="utf-8">
</head>
<body>
<h1>About scoring</h1>
<section>
<h2>How we compute scores</h2>
<p>
The contest is made up of multiple categories.
Each category is worth one point toward the total score;
your team's score in a category is the fraction of the total points unlocked so far in that category.
</p>
<p>
The team that has 30% of the points
in each of five categories has 1.5 points, whereas the team that
has 80% of the points in only one category has 0.8 points. It is
typically better to have a few points in many categories, than
many points in a few categories.
</p>
<p>
When points are unlocked in a category,
every other team's score in that category goes down until they too score that point.
Unlike previous years, however,
unlocking points is the only way to reduce another team's score.
</p>
<p>
There are two main ways to make points: <em>puzzles</em>
and <em>tokens</em>. Your contest may have other ways to make
points: these will either be automatic, or explained elsewhere.
</p>
</section>
<section>
<h2>Puzzles</h2>
<p>
Many of the categories are in the form of
multiple <em>puzzles</em>: for each puzzle presented, a
case-sensitive answer must be found to receive the amount of
points that puzzle is worth. Any team may answer any puzzle
question at any time. A new puzzle is revealed when a team
correctly answers the highest-valued puzzle in that category.
</p>
</section>
<section>
<h2 id="tokens">Tokens</h2>
<p>
Tokens are strings redeemable once for points. They take on
two forms: a single or multipoint token. A single point
token for the "example" category might look like this:
</p>
<pre>example:xylep-radar-nanox</pre>
<p>
A 42 point
token for the "example" category might look like this:
</p>
<pre>example:42:xihyp-ropar-nanix</pre>
<p>
Tokens are typically associated with "live" categories, such as a
network-based service or a treasure hunt. Tokens can be submitted
with the form on the <a href="index.html">welcome page</a>, or you
can write your own script to automate token submission.
</p>
<p>
Some tokens change periodically, typically once a minute. If you
find a token, it's worth looking in the same place again later to
see if the token changes.
</p>
</section>
<section>
<h2>About time</h2>
<p>
Many Capture The Flag contests attempt to reward teams who answer
quickly, by adding a "quick answer" bonus or by decaying point
values over time. Our contest doesn't work this way.
</p>
<p>
We want to focus on rewarding technical proficiency, allowing
skilled contestants to prove their worth independent of their
ability to hit F5 quickly. It is our hope that by providing
enough things to work on, quick-moving teams will emerge with more
points by solving lots of puzzles, while novice teams get a solid
benchmark against which to judge their technical skill level: you
don't have to make allowances for reaction time in comparing
scores. In addition, when the game infrastructure goes down—which
seems to happen a lot in anybody's CTF—there's no losing points
while the organizers struggle to get things back up.
</p>
</section>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 576 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

68
install Executable file
View File

@ -0,0 +1,68 @@
#! /bin/sh
DESTDIR=${1:-/opt/koth}
cd $(dirname $0)
older () {
[ -z "$1" ] && return 1
target=$1; shift
[ -f $target ] || return 0
for i in "$@"; do
[ $i -nt $target ] && return 0
done
return 1
}
html () {
target=$DESTDIR/${1%mdwn}html
if older $target $1 tmpl/*; then
echo "HTML $1"
mkdir -p $(dirname $target)
./tmpl/mdwntohtml < $1 > $target
fi
}
copy () {
target=$DESTDIR/$1
if older $target $1; then
echo "COPY $1"
mkdir -p $(dirname $target)
cp $1 $target
fi
}
cc () {
target=$DESTDIR/bin/$(basename $1 .c)
if older $target $@; then
src=$1; shift
echo "CC $src"
gcc -Wall -Werror -o $target $@ $src
fi
}
git ls-files | while read fn; do
case "$fn" in
install|.*)
;;
doc/*)
;;
html/*)
copy $fn
;;
bin/*)
copy $fn
;;
src/*.cgi.c|src/pointscli.c)
cc src/common.c $fn
;;
src/*.c)
cc $fn
;;
src/*.h)
;;
*)
echo "??? $fn"
;;
esac
done

View File

@ -1,5 +0,0 @@
This directory is for things that multiple packages need.
For example, eris httpd is used by mcp, p2, and inferno.
This directory does not create its own package, though.

View File

@ -1,21 +0,0 @@
TEA_BIN = packages/00common/src/tea
POINTSCLI_BIN = packages/00common/src/pointscli
PUZZLES_BIN = packages/00common/src/puzzles.cgi
.PHONY: ctfbase
ctfbase: $(TEA_BIN) $(POINTSCLI_BIN) $(PUZZLES_BIN)
$(TEA_BIN) $(POINTSCLI_BIN) $(PUZZLES_BIN):
$(MAKE) -C $(@D)
packages-clean: ctfbase-clean
ctfbase-clean:
$(MAKE) -C packages/00common/src clean
define CTFBASE_INSTALL
$(call COPYTREE, packages/00common/service, $1/service)
mkdir -p $(1)/bin
cp $(TEA_BIN) $(1)/bin
cp $(POINTSCLI_BIN) $(1)/bin
cp $(PUZZLES_BIN) $(1)/bin
endef

View File

@ -1,22 +0,0 @@
##
## This is a non-package, for building eris httpd, which
## several packages use. Just depend on $(ERIS_BIN), and
## copy it wherever you want in your install rule.
##
ERIS_CACHE = $(CACHE)/eris.git
ERIS_BUILDDIR = $(BUILD)/eris
ERIS_URL = http://woozle.org/~neale/projects/eris
ERIS_BIN := $(ERIS_BUILDDIR)/eris
$(ERIS_CACHE):
git clone --bare $(ERIS_URL) $@
$(ERIS_BUILDDIR): $(ERIS_CACHE)
git clone $< $@
eris: $(ERIS_BIN)
$(ERIS_BIN): $(ERIS_BUILDDIR)
make -C $<

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 B

View File

@ -1,3 +0,0 @@
#! /bin/sh
exec svlogd -tt $PWD

View File

@ -1,22 +0,0 @@
#! /bin/sh
# Use first installed binary
for bin in $CTF_BASE/packages/*/bin/$1; do
if [ -x $bin ]; then
exec $bin
fi
done
cat <<EOD
<!DOCTYPE html>
<html>
<head>
<title>$1</title>
</head>
<body>
<h1>$1</h1>
<p>No $1 binary installed!</p>
</body>
</html>
EOD
exit 1

View File

@ -1,43 +0,0 @@
#! /bin/sh -e
fn=$2/$3
PACKAGES=$CTF_BASE/packages
STATE=$CTF_BASE/state
WWW=$CTF_BASE/www
POINTS=$STATE/points.log
BACKUP=$WWW/backup.png
SCOREBOARD=$WWW/scoreboard.html
PUZZLES=$WWW/puzzles.html
# Only do this if this score hasn't yet been recorded
if [ -n "$(sort -k2 $POINTS $fn | uniq -f1 -d)" ]; then
exit
fi
# Append point. pointsd is called serially from inotify,
# so we don't need to lock it.
cat $fn >> $POINTS
rm $fn
# Generate new backup if we can find a password file
for pwfile in $PACKAGES/*/password; do
if [ -f $pwfile ]; then
(
cat bkup.png
tar cf - $STATE | gzip -c | $PACKAGES/*/bin/tea -e 3< $pwfile
) > $BACKUP.new
mv $BACKUP.new $BACKUP
break
fi
done
# Render scoreboard
./mkpage scoreboard < $POINTS > $SCOREBOARD.new
mv $SCOREBOARD.new $SCOREBOARD
# Render puzzles list
./mkpage puzzles.cgi > $PUZZLES.new
mv $PUZZLES.new $PUZZLES

View File

@ -1,45 +0,0 @@
#! /bin/sh -e
exec 2>&1
STATE=$CTF_BASE/state
WWW=$CTF_BASE/www
# Create CTF and nobody users
touch /etc/group /etc/passwd
addgroup -g 65534 nogroup || true
adduser -DH -G nogroup -u 65534 nobody || true
adduser -DHS ctf || true
# Set up base directories
NEWDIR=$STATE/points.new
TMPDIR=$STATE/points.tmp
install -o ctf -m 0755 -d $NEWDIR
install -o ctf -m 0755 -d $TMPDIR
# Create some files
touch $STATE/points.log
# Generate preliminary scoreboard
if [ ! -f $WWW/scoreboard.html ]; then
./mkpage scoreboard < /dev/null > $WWW/scoreboard.html
fi
# Generate preliminary puzzles list
if [ ! -f $WWW/puzzles.html ]; then
./mkpage puzzles.cgi > $WWW/puzzles.html
fi
# Run pointsd every time a new points file is dropped
if [ -x /sbin/inotifyd ]; then
exec /sbin/inotifyd ./pointsd $NEWDIR:y
fi
# Simulate inotifyd by polling
while true; do
find $NEWDIR -type f | while read fn; do
./pointsd m $NEWDIR ${fn##*/}
done
sleep 7
done

View File

@ -1,3 +0,0 @@
#! /bin/sh
exec svlogd -tt $PWD

View File

@ -1,16 +0,0 @@
#! /bin/sh
exec 2>&1
password='grape guts'
for fn in $CTF_BASE/packages/*/password; do
read password < $fn && break
done
printf 'root:%s' "$password" | chpasswd --md5
# Bring up the NIC; this will get us at least a link-local address, and
# hopefully a global address with stateless autoconfiguration.
ip link set eth0 up
exec dropbear -r ./rsa.key -E -F

View File

@ -1,16 +0,0 @@
CFLAGS = -Wall -Werror
TARGETS = claim.cgi puzzler.cgi puzzles.cgi pointscli
TARGETS += tea bubblebabble
all: build
build: $(TARGETS)
pointscli: common.o
puzzles.cgi: puzzles.cgi.o common.o
claim.cgi: claim.cgi.o common.o
puzzler.cgi: puzzler.cgi.o common.o
clean:
rm -f $(TARGETS) *.o

View File

@ -1,58 +0,0 @@
#! /bin/sh -e
if [ $# -ne 1 ]; then
echo "Usage: $0 TEAM" 1>&2
exit 64
fi
escape () {
sed 's/&/\&amp;/g;s/</\&lt;/g;s/>/\&gt;/g'
}
# Don't overwrite files
set -C
STATE=$CTF_BASE/state
WWW=$CTF_BASE/www
mkdir -p $STATE/teams/names
mkdir -p $STATE/teams/colors
if ! [ -f $STATE/teams/salt ]; then
dd if=/dev/urandom count=1 2>/dev/null | md5sum | cut -b 1-8 > $STATE/teams/salt
fi
salt=$(cat $STATE/teams/salt)
# Assign a color. I spent weeks selecting a color pallette that
# wouldn't be hell on people with protanopia. Please don't change these
# colors.
nteams=$(ls $STATE/teams/names/ | wc -l)
case $(expr $nteams % 10) in
0) color=a6cee3;;
1) color=1f78b4;;
2) color=b2df8a;;
3) color=33a02c;;
4) color=fb9a99;;
5) color=e31a1c;;
6) color=fdbf6f;;
7) color=ff7f00;;
8) color=cab2d6;;
9) color=6a3d9a;;
*)
echo 'ERROR ERROR' 1>&2
echo 'DOES NOT COMPUTE' 1>&2
exit 69
;;
esac
# Compute hash of team name; they'll use this for everything in the
# contest instead of their team name, which makes stuff much easier on
# me since all team hashes are in the set /[0-9a-f]{8}/.
hash=$(printf "%s:%s" $salt "$1" | md5sum | cut -b 1-8)
echo "$1" > $STATE/teams/names/$hash
echo "$color" > $STATE/teams/colors/$hash
echo "Registered with hash: $hash"

View File

@ -1,29 +0,0 @@
#! /bin/sh
if [ "$1" != "-f" ]; then
echo "Usage: $0 -f"
echo
echo "Wipes out the current contest. This operation is not"
echo "reversable, which is why you have to specify -f to signify"
echo "that you know what you're getting into."
exit
fi
sv d tokend
sv d pointsd
sv d puzzled
sv d tanksd
rm -f $CTF_BASE/state/tokens.db
rm -f $CTF_BASE/state/points.log
rm -f $CTF_BASE/www/scoreboard.html
rm -f $CTF_BASE/state/puzzles.db
rm -rf $CTF_BASE/state/points.new
rm -rf $CTF_BASE/state/points.tmp
rm -rf $CTF_BASE/state/tanks
rm -rf $CTF_BASE/state/teams
sv u tokend
sv u pointsd
sv u puzzled
sv u tanksd

View File

@ -1,40 +0,0 @@
#! /bin/sh
# First argument is seconds between running everything
period=${1:-60}
packages=$CTF_BASE/packages
state=$CTF_BASE/state
www=$CTF_BASE/www
BIN=$packages/mcp/bin
NEWPOINTS=$state/points.new
POINTS=$state/points.log
SCOREBOARD=$www/scoreboard.html
if ! [ -f $SCOREBOARD ]; then
$BIN/scoreboard < $POINTS > $SCOREBOARD
fi
while true; do
start=$(date +%s)
next=$(expr $start + $period)
# Collect any new points
for fn in $NEWPOINTS/*; do
[ -f $fn ] || continue
cat $fn >> $POINTS || break
rm $fn
done
# Render scoreboard
if [ $POINTS -nt $SCOREBOARD ]; then
$BIN/scoreboard < $POINTS > $SCOREBOARD.new && mv $SCOREBOARD.new $SCOREBOARD
fi
now=$(date +%s)
if [ $now -lt $next ]; then
sleep $(expr $next - $now)
fi
done

View File

@ -1,157 +0,0 @@
#! /usr/bin/awk -f
##
##
## I'm not super happy with how this code looks. Rest assured, though,
## the C version would look far, far worse.
##
##
function qsort(A, left, right, i, last) {
if (left >= right)
return
swap(A, left, left+int((right-left+1)*rand()))
last = left
for (i = left+1; i <= right; i++)
if (A[i] < A[left])
swap(A, ++last, i)
swap(A, left, last)
qsort(A, left, last-1)
qsort(A, last+1, right)
}
function swap(A, i, j, t) {
t = A[i]; A[i] = A[j]; A[j] = t
}
function escape(s) {
gsub("&", "&amp;", s)
gsub("<", "&lt;", s)
gsub(">", "&gt;", s)
return s
}
function head() {
print "<!DOCTYPE html>"
print "<html><head><title>Project 2 Scoreboard</title>"
print "<meta http-equiv=\"refresh\" content=\"60\">"
print "<link rel=\"stylesheet\" href=\"ctf.css\" type=\"text/css\">"
print "<style>"
print "body {opacity: 0.9; margin: 0; padding: 0; max-width: inherit;}"
print "p {margin: 0; padding:0; line-height: inherit;}"
print "span {display: inline-block; margin: 0; border: 0; padding: 0;}"
print ".cat0 {background-color: #a6cee3; color: black;}"
print ".cat1 {background-color: #1f78b4;}"
print ".cat2 {background-color: #b2df8a; color: black;}"
print ".cat3 {background-color: #33a02c;}"
print ".cat4 {background-color: #fb9a99;}"
print ".cat5 {background-color: #e31a1c;}"
print ".cat6 {background-color: #fdbf6f;}"
print ".cat7 {background-color: #ff7f00;}"
print ".cat8 {background-color: #cab2d6; color: black;}"
print ".name {position: absolute; right: 10px;}"
print "#scores p {margin: 0; padding: 0; border: thin solid #222; opacity: 0.92;}"
print "#scores p:hover {border: thin solid yellow;}"
print "</style>"
print "</head><body>"
print "<div id=\"scores\">"
}
function foot() {
print " </div>"
print " </body>"
print "</body></html>"
}
BEGIN {
base = ENVIRON["CTF_BASE"]
if (! base) {
base = "/var/lib/ctf"
}
head()
}
# MAINLOOP
{
time = $1
hash = $2
cat = $3
points = int($4)
# Build a list of team names
if (! (hash in team_names)) {
fn = sprintf("%s/state/teams/names/%s", base, hash)
getline team_names[hash] < fn
close(fn)
}
# Enumerate categories
if (! (cat in seen_cats)) {
seen_cats[cat] = 1
categories[ncats++] = cat
}
# Points this team has in this category
cat_points[hash, cat] += points
# Token-based categories can make cat_pointval irrelevant
if (cat_points[hash, cat] > cat_total[cat]) {
cat_total[cat] = cat_points[hash, cat]
}
}
END {
# Adjust per-category points to a per-category percentage complete
for (hash in team_names) {
for (cat in cat_total) {
cat_score[hash, cat] = cat_points[hash, cat] / cat_total[cat]
total_score[hash] += cat_score[hash, cat]
}
scores[nteams++] = total_score[hash]
if (total_score[hash] > max_score) {
max_score = total_score[hash]
}
}
# Sort scores
qsort(scores, 0, nteams-1)
print "<p>"
for (ncat = 0; ncat < ncats; ncat += 1) {
printf("<span class=\"cat%d\">%s</span>\n", ncat, categories[ncat]);
}
print "</p>"
for (i = nteams-1; i >= 0; i -= 1) {
score = scores[i];
if (score == scores[i-1]) continue; # Skip duplicates
for (hash in team_names) {
if (total_score[hash] != score) {
continue;
}
name = escape(team_names[hash])
print "<p>"
printf("<span class=\"name\">%s</span>\n", name)
for (ncat = 0; ncat < ncats; ncat += 1) {
cat = categories[ncat];
points = cat_points[hash, cat];
if (cat_points[hash, cat] > 0) {
width = cat_score[hash, cat] / max_score * 90
printf("<!-- %s %s %s -->", cat, points, name)
printf("<span class=\"cat%d\" style=\"width: %.2f%%;\">%d</span>",
ncat, width, cat_points[hash, cat])
}
}
print "</p>"
}
}
foot()
}

View File

@ -1,21 +0,0 @@
MCP_PKGDIR = $(TARGET)/mcp
mcp-install: eris ctfbase
mkdir -p $(MCP_PKGDIR)
$(call CTFBASE_INSTALL, $(MCP_PKGDIR))
$(call COPYTREE, packages/mcp/bin, $(MCP_PKGDIR)/bin)
cp $(ERIS_BIN) $(MCP_PKGDIR)/bin/
$(call COPYTREE, packages/mcp/service, $(MCP_PKGDIR)/service)
$(call COPYTREE, packages/mcp/www, $(MCP_PKGDIR)/www)
cp packages/00common/src/puzzler.cgi $(MCP_PKGDIR)/www/
cp packages/00common/src/claim.cgi $(MCP_PKGDIR)/www/
mcp-test: mcp-build
packages/mcp/test.sh
PACKAGES += mcp

View File

@ -1,3 +0,0 @@
#! /bin/sh
dbip -d

View File

@ -1 +0,0 @@
2

View File

@ -1,3 +0,0 @@
#! /bin/sh
exec svlogd -tt $PWD

View File

@ -1,21 +0,0 @@
#! /bin/sh -e
exec 2>&1
IP=$(dbip -a)
hostname mcp
# Link in puzzles and web pages
for d in /packages/*; do
w=$CTF_BASE/www/$(basename $d)
if [ -d $d/puzzles ] && ! [ -d $w ]; then
ln -sf $d/puzzles $w
fi
if [ -d $d/www ]; then
ln -sf $d/www/* $CTF_BASE/www/
fi
done
cd $CTF_BASE/www
exec tcpsvd -u ctf ${IP%/*} 80 $CTF_BASE/packages/mcp/bin/eris -c.

View File

@ -1,5 +0,0 @@
#! /bin/sh
while sleep 5; do
echo -n . 1>&2
done

View File

@ -1,3 +0,0 @@
#! /bin/sh
exec ./logclean

View File

@ -1,119 +0,0 @@
#! /bin/sh -e
die () {
echo "ERROR ERROR: $*"
exit 1
}
CTF_BASE=/tmp/ctf-test.$$ export CTF_BASE
trap "rm -rf $CTF_BASE" 0
mkdir $CTF_BASE
# Some skeletal structure
mkdir -p $CTF_BASE/points.new
mkdir -p $CTF_BASE/points.tmp
# Set up some packages
for cat in cat1 cat2 cat3; do
mkdir -p $CTF_BASE/$cat
cat >$CTF_BASE/$cat/answers.txt <<EOF
10 ${cat}answer10
20 ${cat}answer20
30 ${cat}answer30
EOF
for i in 10 20 30; do
mkdir -p $CTF_BASE/$cat/puzzles/$i
done
done
# Set up some teams
mkdir -p $CTF_BASE/teams/names
mkdir -p $CTF_BASE/teams/colors
for team in team1 team2 team3; do
hash=$(bin/addteam $team | awk '{print $NF;}')
done
##
## Puzzler tests
##
if src/puzzles.cgi | grep 20; then
die "20 points puzzles shouldn't show up here"
fi
if src/puzzler.cgi t=$hash c=cat1 p=10 a=cat1answer20 | grep -q 'awarded'; then
die "Awarded points with wrong answer"
fi
if src/puzzler.cgi t=$hash c=cat2 p=10 a=cat1answer10 | grep -q 'awarded'; then
die "Awarded points with wrong category"
fi
if src/puzzler.cgi t=$hash c=cat1 p=20 a=cat1answer10 | grep -q 'awarded'; then
die "Awarded points with wrong point value"
fi
if src/puzzler.cgi t=merfmerfmerfmerf c=cat2 p=10 a=cat1answer10 | grep -q 'awarded'; then
die "Awarded points with bad team"
fi
if ! src/puzzler.cgi t=$hash c=cat1 p=10 a=cat1answer10 | grep -q 'awarded 10'; then
die "Didn't award points for correct answer"
fi
if ! src/puzzles.cgi | grep -q 20; then
die "20 point answer didn't show up"
fi
if src/puzzler.cgi t=$hash c=cat1 p=10 a=cat1answer10 | grep -q 'awarded 10'; then
die "Awarded same points twice"
fi
##
## Scoreboard tests
##
if ! cat $CTF_BASE/points.new/* | bin/scoreboard | grep -q 'total.*team3: 1'; then
die "Scoreboard total incorrect"
fi
if ! cat $CTF_BASE/points.new/* | bin/scoreboard | grep -q 'cat1.*team3: 10'; then
die "Scoreboard cat1 points incorrect"
fi
##
## Token tests
##
mkdir -p $CTF_BASE/mcp/tokend.keys
echo -n '0123456789abcdef' > $CTF_BASE/mcp/tokend.keys/tokencat
mkfifo $CTF_BASE/nancy
src/tokencli tokencat $CTF_BASE/mcp/tokend.keys/tokencat < $CTF_BASE/nancy 3>$CTF_BASE/t | src/in.tokend > $CTF_BASE/nancy
if ! grep -q 'tokencat:x....-....x' $CTF_BASE/tokens.db; then
die "in.tokend didn't write to database"
fi
if src/claim.cgi t=lalalala k=$(cat $CTF_BASE/tokens.db) | grep -q success; then
die "claim.cgi gave points to a bogus team"
fi
if src/claim.cgi t=$hash k=tokencat:xanax-xanax | grep -q success; then
die "claim.cgi gave points for a bogus token"
fi
if ! src/claim.cgi t=$hash k=$(cat $CTF_BASE/t) | grep -q success; then
die "claim.cgi didn't give me any points"
fi
if src/claim.cgi t=$hash k=$(cat $CTF_BASE/t) | grep -q success; then
die "claim.cgi gave me points twice for the same token"
fi
if ! [ -f $CTF_BASE/points.new/*.$hash.tokencat.1 ]; then
die "claim.cgi didn't actually record any points"
fi
echo "All tests passed! You're the best programmer ever!"

View File

@ -1,54 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>The Credits</title>
<link rel="stylesheet" href="ctf.css" type="text/css">
</head>
<body>
<h1>Credits</h1>
<p>Dirtbags King of the Hill was created by:</p>
<ul>
<li>Neale Pickett</li>
<li>Aaron McPhall</li>
<li>Russel Nolen</li>
<li>Patrick Avery</li>
<li>Kate Vajda</li>
<li>Alex Brugh</li>
<li>Paul Ferrell</li>
<li>Jeremy Scott</li>
<li>Danny Quist</li>
<li>Adam Glasgall</li>
<li>Curtis Hash</li>
<li>Erin Ochoa</li>
<li>William Phillips</li>
<li>Should your name be here? Please remind me!</li>
</ul>
<p>Parts of this contest were inspired by contests from:</p>
<ul>
<li>DC949</li>
<li>Tube Warriors</li>
<li>Sandia National Laboratories</li>
</ul>
<p>Lastly, this contest would not exist were it not for hundreds of
thousands of lines of code from free software authors around the
world, including:</p>
<ul>
<li>Busybox and Buildroot</li>
<li>the Linux kernel</li>
<li>dnsmasq</li>
<li>fnord httpd</li>
<li>ngircd</li>
<li>lua</li>
</ul>
<p>
Special thanks to <a href="http://linode.com/">Linode</a>,
for running the public version of the contest.
You guys are awesome!
</p>
</body>
</html>

View File

@ -1,199 +0,0 @@
/* green phosphor: #2a4 */
/**** Color Scheme ****/
html {
background: #112 url(smoke.jpg) no-repeat;
background-size: contain;
}
body, h1:first-child:before {
color: #ddc;
}
h1, h2, h3 {
color: #1dd;
}
a {
color: #f80;
}
a:hover {
color: #112;
background-color: #f80;
}
.readme, pre {
background-color: #333;
}
/**** document ****/
body {
font-family: sans-serif;
padding: 10px;
max-width: 700px;
}
/**** heading ****/
h1:first-child {
text-transform: lowercase;
font-size: 1.6em;
padding: 3px;
margin: 0 0 1em 70px;
}
h1:first-child:before {
letter-spacing: -0.1em;
content: "FIRE: ";
}
/**** body ****/
a img {
border: 0px;
}
a {
text-decoration: underline;
}
h1, h2, h3 {
letter-spacing: -0.05em;
}
.readme {
margin: 1em;
}
pre {
border: solid #ddc 2px;
padding: 0.25em;
}
th {
vertical-align: top;
text-align: center;
}
td {
vertical-align: top;
text-align: left;
}
dt {
font-weight: bold;
}
p {
line-height: 1.4em;
margin-bottom: 20px;
}
hr {
border: 1px solid #ddc;
}
/*** navigation bar ***/
nav h2 {
display: none;
}
nav ul {
list-style: none;
text-align: center;
}
nav li {
display: inline;
}
nav li a {
text-transform: lowercase;
font-size: 0.9em;
}
nav li + li:before {
content: " | ";
}
/**** special cases ****/
.wide {
max-width: inherit;
}
.figure {
margin: 0.5em 1em;
float: right;
font-size: small;
text-align: center;
}
/* Scoreboard stuff */
.scoreboard, .scoreboard body {
height: 100%;
margin: 0;
padding: 0;
max-width: none;
}
#scoreboard {
height: 60%;
font-size: 75%;
}
#scoreboard td {
height: 100%;
}
#chart {
height: 30%;
width: 100%;
}
/* Tanks stuff */
#battlefield {
border: 2px solid green;
}
.solved {
text-decoration: line-through;
}
/* Names */
span[data-handle]:after {
content: ")";
}
span[data-handle="zephyr"]:before {
content: "Neale Pickett (";
}
span[data-handle="pflarr"]:before {
content: "Paul Ferrell (";
}
span[data-handle="chamuco"]:before {
content: "Danny Quist (";
}
span[data-handle="cashmoney"]:before {
content: "Jeremy Scott (";
}
span[data-handle="phorkus"]:before {
content: "Mark Carey (";
}
span[data-handle="cherish"]:before {
content: "Cherish Franco (";
}

View File

@ -1,75 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Welcome</title>
<link rel="stylesheet" href="ctf.css" type="text/css">
</head>
<body>
<h1>Welcome</h1>
<h2>Important Links</h2>
<ul>
<li>
<a href="scoreboard.html">Scoreboard</a>
</li>
<li>
<a href="puzzles.html">Puzzles</a>
</li>
<li>
<a href="news.html">News</a>
</li>
<li>
<a href="scoring.html">About scoring</a>
</li>
<li>
<a href="irc://[fd84:b410:3441::6]/ctf"
title="IRC on fd84:b410:3441::6, channel #ctf">Contest chat</a>
(<a href="irc://10.0.0.6/ctf" title="IRC on 10.0.0.6, channel #ctf">IPv4</a>)
carries important announcements, and sometimes clues and
puzzles.
</li>
</ul>
<h2>Claim Token</h2>
<p>
If you find a <a href="scoring.html#tokens">token</a>
(like <samp>example:xylep-radar-nanox</samp>), submit it here for
a point.
</p>
<form action="claim.cgi" method="post">
<fieldset>
team hash:<input name="t" size="8">
token:<input name="k" size="30">
<input type="submit" value="claim">
</fieldset>
</form>
<h2>Rules</h2>
<ul>
<li>
No DoS attacks. No link layer (ARP, NDP) attacks.
</li>
<li>
Contest servers lie within <samp>fd84:b410:3441::/112</samp>
(or <samp>10.0.0.0/24</samp> for IPv4 contests).
Do not attack machines outside <samp>fd84:b410:3441::/48</samp>
(<samp>10.0.0.0/16</samp>).
Low ports (under 1024) do not run contest categories, don't
waste your time.
</li>
<li>
Consider the contest network hostile. It is up to you to
safeguard, encrypt, or delete sensitive data on your computer.
</li>
<li>
We reserve the right to kick you out of the contest for any
reason, so play nice.
</li>
</ul>
<p>
This event would not be possible without the help of many people.
<a href="credits.html">Thank you, people</a>.
</p>
</body>
</html>

View File

@ -1,18 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>News</title>
<link rel="stylesheet" href="ctf.css" type="text/css">
</head>
<body>
<h1>News</h1>
<ul>
<li>Contest is open</li>
</ul>
<p>
This page will be updated with any new announcements.
</p>
</body>
</html>

View File

@ -1,120 +0,0 @@
function dbg(o) {
e = document.getElementById("debug");
e.innerHTML = o;
}
function torgba(color, alpha) {
if (color.substring(0, 1) == "#") {
var r = parseInt(color.substring(1,3), 16);
var g = parseInt(color.substring(3,5), 16);
var b = parseInt(color.substring(5,7), 16);
return "rgba(" + r + "," + g + "," + b + "," + alpha + ")";
} else {
return color;
}
}
function Chart(id, width, height, lines) {
var canvas = document.getElementById(id);
var ctx = canvas.getContext('2d');
// We'll let the canvas do all the tricksy math
var xscale = canvas.width/width;
var yscale = canvas.height/height;
var nlines = lines.length;
function moveTo(x, y) {
ctx.moveTo(Math.round(x * xscale), Math.round((height - y) * yscale));
}
function lineTo(x, y) {
ctx.lineTo(Math.round(x * xscale), Math.round((height - y) * yscale));
}
function draw(color, values) {
var lasty = 0;
ctx.strokeStyle = color;
ctx.lineWidth = 4;
ctx.beginPath();
moveTo(values[0][0], 0);
for (i in values) {
var x = values[i][0];
var y = values[i][1];
lineTo(x, lasty);
lineTo(x, y);
lasty = y;
}
lineTo(width, lasty);
ctx.stroke();
}
this.highlight = function(id, color) {
var line = lines[id];
if (! color) color = line[0];
draw(color, line[1]);
}
for (id in lines) {
var line = lines[id];
draw(line[0], line[1]);
}
}
var thechart;
function plot(id, width, height, lines) {
thechart = new Chart(id, width, height, lines);
}
function getElementsByClass( searchClass, domNode, tagName) {
if (domNode == null) domNode = document;
if (tagName == null) tagName = '*';
var el = new Array();
var tags = domNode.getElementsByTagName(tagName);
var tcl = " "+searchClass+" ";
for(i=0,j=0; i<tags.length; i++) {
var test = " " + tags[i].className + " ";
if (test.indexOf(tcl) != -1)
el[j++] = tags[i];
}
return el;
}
function highlight(cls, color) {
if (! color) color = "#ffffff";
elements = getElementsByClass("t" + cls);
for (i in elements) {
e = elements[i];
e.style.borderColor = e.style.backgroundColor;
e.style.backgroundColor = color;
}
thechart.highlight(cls, color);
}
function restore(cls) {
elements = getElementsByClass("t" + cls);
for (i in elements) {
e = elements[i];
e.style.backgroundColor = e.style.borderColor;
}
thechart.highlight(cls);
}
var state = 0;
function cycle() {
if (state == 0) {
v = document.getElementById("scoreboard");
i = document.getElementById("chart");
} else {
v = document.getElementById("chart");
i = document.getElementById("scoreboard");
}
v.style.display = "block";
i.style.display = "none";
state = (state + 1) % 2;
}

View File

@ -1,98 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>About scoring</title>
<link rel="stylesheet" href="ctf.css" type="text/css">
<meta charset="utf-8">
</head>
<body>
<h1>About scoring</h1>
<p>
The contest is made up of multiple categories.
Each category is worth one point toward the total score;
your team's score in a category is the fraction of the total points unlocked so far in that category.
</p>
<p>
The team that has 30% of the points
in each of five categories has 1.5 points, whereas the team that
has 80% of the points in only one category has 0.8 points. It is
typically better to have a few points in many categories, than
many points in a few categories.
</p>
<p>
When points are unlocked in a category,
every other team's score in that category goes down until they too score that point.
Unlike previous years, however,
unlocking points is the only way to reduce another team's score.
</p>
<p>
There are two main ways to make points: <em>puzzles</em>
and <em>tokens</em>. Your contest may have other ways to make
points: these will either be automatic, or explained elsewhere.
</p>
<h2>Puzzles</h2>
<p>
Many of the categories are in the form of
multiple <em>puzzles</em>: for each puzzle presented, a
case-sensitive answer must be found to receive the amount of
points that puzzle is worth. Any team may answer any puzzle
question at any time. A new puzzle is revealed when a team
correctly answers the highest-valued puzzle in that category.
</p>
<h2 id="tokens">Tokens</h2>
<p>
Tokens are strings redeemable once for points. They take on
two forms: a single or multipoint token. A single point
token for the "example" category might look like this:
</p>
<pre>example:xylep-radar-nanox</pre>
<p>
A 42 point
token for the "example" category might look like this:
</p>
<pre>example:42:xihyp-ropar-nanix</pre>
<p>
Tokens are typically associated with "live" categories, such as a
network-based service or a treasure hunt. Tokens can be submitted
with the form on the <a href="index.html">welcome page</a>, or you
can write your own script to automate token submission.
</p>
<p>
Some tokens change periodically, typically once a minute. If you
find a token, it's worth looking in the same place again later to
see if the token changes.
</p>
<h2>About time</h2>
<p>
Many Capture The Flag contests attempt to reward teams who answer
quickly, by adding a "quick answer" bonus or by decaying point
values over time. Our contest doesn't work this way.
</p>
<p>
We want to focus on rewarding technical proficiency, allowing
skilled contestants to prove their worth independent of their
ability to hit F5 quickly. It is our hope that by providing
enough things to work on, quick-moving teams will emerge with more
points by solving lots of puzzles, while novice teams get a solid
benchmark against which to judge their technical skill level: you
don't have to make allowances for reaction time in comparing
scores. In addition, when the game infrastructure goes down—which
seems to happen a lot in anybody's CTF—there's no losing points
while the organizers struggle to get things back up.
</p>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

View File

@ -1,6 +0,0 @@
#! /bin/sh
echo 'Content-type: application/octet-stream'
echo
tar czf - /var/lib/ctf | KEY=crashmaster arc4

View File

@ -1,6 +0,0 @@
#! /bin/sh
grep -v "'" /usr/share/dict/words | shuf -n 2 | while read word; do
echo -n "$word "
done
echo

View File

@ -1,4 +0,0 @@
#! /bin/sh
dd bs=1 count=16 if=/dev/urandom | hd

View File

@ -1,132 +0,0 @@
#! /bin/sh
BASE=$CTF_BASE/state/teams
esc () {
printf '%s' "$*" | sed 's/[^-0-9A-Za-z ]/_/g; s/ /+/g'
}
newteam () {
echo '== Team Creation =='
echo
echo -n 'What would you like your team to be called (3-12 chars)? '
read -r name
echo
namelen=$(printf "%s" "$name" | wc -c)
if [ $namelen -lt 3 ] || [ $namelen -gt 12 ]; then
echo 'Invalid name length'
return
fi
hash=$(printf '%s %s' "$salt" "$name" | md5sum | cut -b 1-8)
if [ -f $BASE/names/$hash ]; then
echo "That name is already in use. Try another one."
return
fi
printf '%s' "$name" > $BASE/names/$hash
cat <<EOD
Your team hash is $hash. Write that down somewhere and don't lose it.
If you forget your hash, you'll have to start over from the beginning
with a new team and everybody will laugh at you.
EOD
}
fini () {
echo
echo "Press [Enter] to clear the screen."
read
exit 0
}
log () {
awk -v H=$1 '($2 == H) { print($3, $4); }' $CTF_BASE/points.log
}
clear
read salt < $BASE/salt
printf '\017Team hash ("new" to create a new team): '
read -r hash
echo
if [ -z "$hash" ]; then
exit 0
elif [ "$hash" = "new" ]; then
newteam
fini
elif [ "$hash" = 58 ]; then
name='Thumper Bumper'
elif ! [ -f $BASE/names/$hash ]; then
echo "No such team, fool."
echo "Is this when everybody laughs at you for forgetting your hash?"
fini
else
read -r name < $BASE/names/$hash
fi
clear
printf 'Welcome back, %s.\n' "$name"
while true; do
printf "p2> "
read -r answer
case "$answer" in
\?|help)
cat <<EOD
 Help
----------------------------------------------------------
Type quit to leave the p2 shell.
Type log to show answered puzzles.
Any other string is checked as an answer. If the answer
is correct, you are awarded points and the scoreboard will
update within 10 seconds. Check the puzzles overview to
see if your answer unlocked a new puzzle.
EOD
continue
;;
log)
cat <<EOD
Puzzles Answered By $name
---------------------------------------
EOD
log $hash
continue
;;
quit)
break
;;
esac
clear
matches=0
for fn in /opt/*/answers.txt; do
cat=$(basename ${fn%/answers.txt})
while read points ans; do
if [ "$ans" = "$answer" ]; then
if log $hash | grep -wq "$cat $points"; then
echo "You've already received points for this answer."
elif /opt/p2/bin/pointscli $hash $cat $points p2console; then
echo "You get $points more points in the $cat category."
matches=$(expr $matches + 1)
else
echo "Error recording points. Tell the officials!"
fi
fi
done < $fn
done
if [ "$matches" -eq 0 ]; then
echo 'That is not a correct answer. Type "help" for help.'
fi
if [ "$matches" -gt 1 ]; then
echo "Holy shit! Double word score!"
fi
done

View File

@ -1,167 +0,0 @@
#! /usr/bin/awk -f
##
##
## I'm not super happy with how this code looks. Rest assured, though,
## the C version would look far, far worse.
##
##
function qsort(A, left, right, i, last) {
if (left >= right)
return
swap(A, left, left+int((right-left+1)*rand()))
last = left
for (i = left+1; i <= right; i++)
if (A[i] < A[left])
swap(A, ++last, i)
swap(A, left, last)
qsort(A, left, last-1)
qsort(A, last+1, right)
}
function swap(A, i, j, t) {
t = A[i]; A[i] = A[j]; A[j] = t
}
function escape(s) {
gsub("&", "&amp;", s)
gsub("<", "&lt;", s)
gsub(">", "&gt;", s)
return s
}
function head() {
print "<!DOCTYPE html>"
print "<html><head><title>Project 2 Scoreboard</title>"
print "<meta http-equiv=\"refresh\" content=\"60\">"
print "<style>"
print "html {background: black url(\"p2inv.png\") no-repeat top center; background-size: contain; min-height: 100%; color: white;}"
print "body {background: black; opacity: 0.92; margin: 0;}"
print "p {margin: 0;}"
print "span {display: inline-block; margin: 0; border: 0;}"
print ".cat0 {background-color: #a6cee3; color: black;}"
print ".cat1 {background-color: #1f78b4;}"
print ".cat2 {background-color: #b2df8a; color: black;}"
print ".cat3 {background-color: #33a02c;}"
print ".cat4 {background-color: #fb9a99;}"
print ".cat5 {background-color: #e31a1c;}"
print ".cat6 {background-color: #fdbf6f;}"
print ".cat7 {background-color: #ff7f00;}"
print ".cat8 {background-color: #cab2d6;}"
print ".name {position: absolute; right: 10px;}"
print "#scores p {margin: 0; padding: 0; border: thin solid #222; opacity: 0.92;}"
print "#scores p:hover {border: thin solid yellow;}"
print "</style>"
print "</head><body>"
print "<div id=\"scores\">"
}
function foot() {
print " </div>"
print " <pre style=\"position: fixed; bottom: 0; left: 20%; font-size: 250%;"
print " opacity: 0.8; background-color: black\">"
print "Project 2<br>"
print "<p>A CTF for people with limited time/patience/self-confidence.</p>"
print "<p>Plug in ethernet at this table, download puzzles, go think.</p>"
print "<p>http://10.0.0.2/</p>"
print "<p>Use the terminal to claim points when you've figured something out.</p>"
print " </pre>"
print " </body>"
print "</body></html>"
}
BEGIN {
base = ENVIRON["CTF_BASE"]
if (! base) {
base = "/var/lib/ctf"
}
head()
}
# MAINLOOP
{
time = $1
hash = $2
cat = $3
points = int($4)
# Build a list of team names
if (! (hash in team_names)) {
fn = sprintf("%s/teams/names/%s", base, hash)
getline team_names[hash] < fn
close(fn)
}
# Total points possible so far in this category
if (! ((cat, points) in cat_pointval)) {
cat_total[cat] += points
cat_pointval[cat, points] = 1
}
# Enumerate categories
if (! (cat in seen_cats)) {
seen_cats[cat] = 1
categories[ncats++] = cat
}
# Points this team has in this category
cat_points[hash, cat] += points
}
END {
# Adjust per-category points to a per-category percentage complete
for (hash in team_names) {
for (cat in cat_total) {
cat_score[hash, cat] = cat_points[hash, cat] / cat_total[cat]
total_score[hash] += cat_score[hash, cat]
}
scores[nteams++] = total_score[hash]
if (total_score[hash] > max_score) {
max_score = total_score[hash]
}
}
# Sort scores
qsort(scores, 0, nteams-1)
print "<p>"
for (ncat = 0; ncat < ncats; ncat += 1) {
printf("<span class=\"cat%d\">%s</span>\n", ncat, categories[ncat]);
}
print "</p>"
for (i = nteams-1; i >= 0; i -= 1) {
score = scores[i];
if (score == scores[i-1]) continue; # Skip duplicates
for (hash in team_names) {
if (total_score[hash] != score) {
continue;
}
name = escape(team_names[hash])
print "<p>"
printf("<span class=\"name\">%s</span>\n", name)
for (ncat = 0; ncat < ncats; ncat += 1) {
cat = categories[ncat];
points = cat_points[hash, cat];
if (cat_points[hash, cat] > 0) {
width = cat_score[hash, cat] / max_score * 90
printf("<!-- %s %s %s -->", cat, points, name)
printf("<span class=\"cat%d\" style=\"width: %.2f%%;\">%d</span>",
ncat, width, cat_points[hash, cat])
}
}
print "</p>"
}
}
foot()
}

View File

@ -1,25 +0,0 @@
P2_PKGDIR = $(TARGET)/p2
p2-build: packages/p2/src/modem
packages/p2/src/modem:
$(MAKE) -C packages/p2/src
p2-install: packages/p2/src/modem eris ctfbase
mkdir -p $(P2_PKGDIR)
$(call CTFBASE_INSTALL, $(P2_PKGDIR))
$(call COPYTREE, packages/p2/bin, $(P2_PKGDIR)/bin)
cp $(ERIS_BIN) $(P2_PKGDIR)/bin/
cp packages/p2/src/modem $(P2_PKGDIR)/bin/
$(call COPYTREE, packages/p2/service, $(P2_PKGDIR)/service)
$(call COPYTREE, packages/p2/www, $(P2_PKGDIR)/www)
p2-clean:
$(MAKE) -C packages/p2/src clean
PACKAGES += p2

View File

@ -1,3 +0,0 @@
#! /bin/sh
exec svlogd -tt $PWD

View File

@ -1,31 +0,0 @@
#! /bin/sh -e
exec 2>&1
IP=$(dbip -p ../p2console/ip.txt)
ip route add default via 10.0.0.1
if [ -z "$CTF_BASE" ] && ! grep -q " /www " /proc/mounts; then
mount -t tmpfs www /www
fi
# Link in puzzles and web pages
for d in $CTF_BASE/packages/*; do
w=$CTF_BASE/www/$(basename $d)
if [ -d $d/puzzles ] && ! [ -d $w ]; then
ln -sf $d/puzzles $w
fi
if [ -d $d/www ]; then
ln -sf $d/www/* $CTF_BASE/www/
fi
done
# news.html is persistent
if ! [ -f $CTF_BASE/state/news.html ]; then
cat $CTF_BASE/packages/p2/www/news.html > $CTF_BASE/state/news.html
fi
ln -sf $CTF_BASE/state/news.html $CTF_BASE/www
cd $CTF_BASE/www
exec tcpsvd -u nobody ${IP%/*} 80 $CTF_BASE/packages/p2/bin/eris -c.

View File

@ -1,3 +0,0 @@
#! /bin/sh
dbip -d

View File

@ -1 +0,0 @@
10.0.1.2/24

View File

@ -1,3 +0,0 @@
#! /bin/sh
exec svlogd -tt $PWD

View File

@ -1,9 +0,0 @@
#! /bin/sh
while true; do
TIME=$(date +%s)
/opt/p2/bin/p2console
if [ $TIME = $(date +%s) ]; then
exit
fi
done | /opt/p2/bin/modem

View File

@ -1,15 +0,0 @@
#! /bin/sh -e
exec 2>&1
hostname p2
IP=$(dbip -a)
install -d /var/lib/ctf/teams
install -o ctf -m 0755 -d /var/lib/ctf/teams/names
if ! [ -f /var/lib/ctf/teams/salt ]; then
dd if=/dev/urandom count=1 | md5sum - > /var/lib/ctf/teams/salt
fi
exec setuidgid ctf tcpsvd 0 5555 ./p2console

View File

@ -1,4 +0,0 @@
all: modem
clean:
rm -f modem

View File

@ -1,60 +0,0 @@
#include <unistd.h>
#include <stdlib.h>
#define NOISE_PROB 2000
#define NOISE_BITS 16
int badbits = 0;
char
line_noise(char c)
{
int i = 7;
while (badbits && (i >= 0)) {
c = c ^ ((rand() % 2) << i);
badbits -= 1;
i -= 1;
}
if (rand() % NOISE_PROB == 0) {
badbits = rand() % NOISE_BITS;
}
return c;
}
int
main(int argc, char *argv[])
{
char c;
ssize_t ret;
int baud = 0;
useconds_t usec;
if (argv[1]) {
baud = atoi(argv[1]);
}
if (! baud) {
baud = 1200;
}
srandom(getpid());
/*
N81 uses 1 stop bit, and 1 parity bit. That works out to
exactly 10 bits per byte.
*/
usec = 10000000 / baud;
while (1) {
ret = read(0, &c, 1);
if (ret != 1) {
break;
}
c = line_noise(c);
write(1, &c, 1);
usleep(usec);
}
return 0;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 B

View File

@ -1,174 +0,0 @@
/* green phosphor: #2a4 */
/**** Color Scheme ****/
html {
background: #112 url(p2inv.jpg) no-repeat;
background-size: contain;
}
body, h1:first-child:before {
color: #ddc;
}
h1, h2, h3 {
color: #1dd;
}
a {
color: #f80;
}
a:hover {
color: #112;
background-color: #f80;
}
.readme, pre {
background-color: #333;
}
/**** document ****/
body {
font-family: sans-serif;
padding: 10px;
max-width: 700px;
}
/**** heading ****/
h1:first-child {
text-transform: lowercase;
font-size: 1.6em;
padding: 3px;
margin: 0 0 1em 70px;
}
h1:first-child:before {
letter-spacing: -0.1em;
content: "P2: ";
}
/**** body ****/
a img {
border: 0px;
}
a {
text-decoration: underline;
}
h1, h2, h3 {
letter-spacing: -0.05em;
}
.readme {
margin: 1em;
}
pre {
border: solid #ddc 2px;
padding: 0.25em;
}
th {
vertical-align: top;
text-align: center;
}
td {
vertical-align: top;
text-align: left;
}
dt {
font-weight: bold;
}
p {
line-height: 1.4em;
margin-bottom: 20px;
}
hr {
border: 1px solid #ddc;
}
/*** navigation bar ***/
nav h2 {
display: none;
}
nav ul {
list-style: none;
text-align: center;
}
nav li {
display: inline;
}
nav li a {
text-transform: lowercase;
font-size: 0.9em;
}
nav li + li:before {
content: " | ";
}
/**** special cases ****/
.wide {
max-width: inherit;
}
.figure {
margin: 0.5em 1em;
float: right;
font-size: small;
text-align: center;
}
/* P2 stuff */
#puzzler {
/* The puzzler form is not used in Project 2 */
display: none;
}
/* Scoreboard stuff */
.scoreboard, .scoreboard body {
height: 100%;
margin: 0;
padding: 0;
max-width: none;
}
#scoreboard {
height: 60%;
font-size: 75%;
}
#scoreboard td {
height: 100%;
}
#chart {
height: 30%;
width: 100%;
}
/* Tanks stuff */
#battlefield {
border: 2px solid green;
}
.solved {
text-decoration: line-through;
}

View File

@ -1,44 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Welcome</title>
<link rel="stylesheet" href="ctf.css" type="text/css">
</head>
<body>
<h1>Welcome</h1>
<h2>Important Links</h2>
<ul>
<li>
<a href="scoreboard.html">Scoreboard</a>
</li>
<li>
<a href="puzzles.html">Puzzles</a>
</li>
<li>
<a href="nyan.ogg">Some Music</a> to help you concentrate.
Tune to 101.1 FM for more great hits!
</li>
<li>
<a href="news.html">News</a> -- updated when things go wrong.
</li>
<li>
<a href="scoring.html">About scoring</a>
</li>
</ul>
<p>
We can't make any guarantees about the behavior of others on this network.
We advise you to disconnect as soon as you've retrieved the puzzles
you want to work on.
</p>
<p>
Project 2 is a puzzle-based game for individuals or teams.
Get started by creating a new team at the console, then start
working on the <a href="puzzles.html">puzzles</a>.
When you have solved a puzzle, enter the answer at the console
to change your ranking on the <a href="scoreboard.html">scoreboard</a>.
</p>
</body>
</html>

View File

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>News</title>
<link rel="stylesheet" href="ctf.css" type="text/css">
</head>
<body>
<h1>News</h1>
<p>Usually updated when something goes wrong.</p>
<ul>
<!-- Add new items at the top -->
<li>Event begins</li>
</ul>
</body>
</html>

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

View File

@ -1,46 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>About scoring</title>
<link rel="stylesheet" href="ctf.css" type="text/css">
<meta charset="utf-8">
</head>
<body>
<h1>About scoring</h1>
<p>
The contest is made up of multiple categories. Each category is
worth one point toward the total score; the percentage of the
total points held by your team is the percentage of one point your
team has for that category.
</p>
<p>
Categories are in the form of
multiple <em>puzzles</em>: for each puzzle presented, a
case-sensitive answer must be found to receive the amount of
points that puzzle is worth. Any team may answer any puzzle
question at any time. A new puzzle is revealed when a team
correctly answers the highest-valued puzzle in that category.
</p>
<h2>About time</h2>
<p>
Many Capture The Flag contests attempt to reward teams who answer
quickly, by adding a "quick answer" bonus or by decaying point
values over time. Our contest doesn't work this way.
</p>
<p>
We want to focus on rewarding technical proficiency, allowing
skilled contestants to prove their worth independent of their
ability to hit F5 quickly. It is our hope that by providing
enough things to work on, quick-moving teams will emerge with more
points by solving lots of puzzles, while novice teams get a solid
benchmark against which to judge their technical skill level: you
don't have to make allowances for reaction time in comparing
scores. In addition, when the game infrastructure goes down—which
seems to happen a lot in anybody's CTF—there's no losing points
while the organizers struggle to get things back up.
</p>
</body>
</html>

View File

@ -1,29 +0,0 @@
PACKAGES =
define COPYTREE
mkdir -p $(2)
(cd $(1) && find . -not -name "*~" | cpio -o) | (cd $(2) && cpio -i)
endef
include packages/*/*.mk
# Things configure likes to see
CONFIG_XCOMPILE_FLAGS = --host=i386-linux --program-transform-name=
# Make foo depend on foo.pkg
$(foreach p, $(PACKAGES), $(eval $p: $(BIN)/$p.pkg))
packages: $(patsubst %, $(BIN)/%.pkg, $(PACKAGES))
packages-install: $(addsuffix -install, $(PACKAGES))
packages-clean: $(addsuffix -clean, $(PACKAGES))
rm -rf $(TARGET) $(BIN)
$(foreach p, $(PACKAGES), $(eval $p-clean: $p-pkgclean))
%-pkgclean:
rm -f $(BIN)/$*.pkg
$(BIN)/%.pkg: %-install
@ mkdir -p $(@D)
(cd $(TARGET); tar czf - $*) > $@