Installation script
33
Makefile
|
@ -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
|
25
doc/ipv6.txt
|
@ -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.
|
|
@ -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
|
BIN
doc/smoke.xcf
|
@ -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;
|
||||
}
|
||||
|
BIN
html/burn.jpg
Before Width: | Height: | Size: 1.8 MiB |
|
@ -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>
|
|
@ -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 ***/
|
||||
|
|
207
html/ctf1.css
|
@ -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 (";
|
||||
}
|
||||
|
208
html/ctf2.css
|
@ -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 (";
|
||||
}
|
||||
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 107 KiB |
|
@ -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>
|
||||
|
@ -36,6 +38,25 @@
|
|||
</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>
|
||||
<li><a href="register.html">Register</a></li>
|
||||
|
|
|
@ -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>
|
BIN
html/smoke.jpg
Before Width: | Height: | Size: 121 KiB |
BIN
html/stripes.jpg
Before Width: | Height: | Size: 576 KiB |
BIN
html/trident.jpg
Before Width: | Height: | Size: 1.5 MiB |
|
@ -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
|
|
@ -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.
|
|
@ -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
|
|
@ -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 $<
|
||||
|
Before Width: | Height: | Size: 247 B |
|
@ -1,3 +0,0 @@
|
|||
#! /bin/sh
|
||||
|
||||
exec svlogd -tt $PWD
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
#! /bin/sh
|
||||
|
||||
exec svlogd -tt $PWD
|
|
@ -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
|
|
@ -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
|
|
@ -1,58 +0,0 @@
|
|||
#! /bin/sh -e
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "Usage: $0 TEAM" 1>&2
|
||||
exit 64
|
||||
fi
|
||||
|
||||
|
||||
|
||||
escape () {
|
||||
sed 's/&/\&/g;s/</\</g;s/>/\>/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"
|
|
@ -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
|
|
@ -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
|
|
@ -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("&", "&", s)
|
||||
gsub("<", "<", s)
|
||||
gsub(">", ">", 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()
|
||||
}
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
#! /bin/sh
|
||||
|
||||
dbip -d
|
|
@ -1 +0,0 @@
|
|||
2
|
|
@ -1,3 +0,0 @@
|
|||
#! /bin/sh
|
||||
|
||||
exec svlogd -tt $PWD
|
|
@ -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.
|
|
@ -1,5 +0,0 @@
|
|||
#! /bin/sh
|
||||
|
||||
while sleep 5; do
|
||||
echo -n . 1>&2
|
||||
done
|
|
@ -1,3 +0,0 @@
|
|||
#! /bin/sh
|
||||
|
||||
exec ./logclean
|
|
@ -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!"
|
|
@ -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>
|
|
@ -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 (";
|
||||
}
|
||||
|
|
@ -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>
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
Before Width: | Height: | Size: 85 KiB |
|
@ -1,6 +0,0 @@
|
|||
#! /bin/sh
|
||||
|
||||
echo 'Content-type: application/octet-stream'
|
||||
echo
|
||||
|
||||
tar czf - /var/lib/ctf | KEY=crashmaster arc4
|
|
@ -1,6 +0,0 @@
|
|||
#! /bin/sh
|
||||
|
||||
grep -v "'" /usr/share/dict/words | shuf -n 2 | while read word; do
|
||||
echo -n "$word "
|
||||
done
|
||||
echo
|
|
@ -1,4 +0,0 @@
|
|||
#! /bin/sh
|
||||
|
||||
dd bs=1 count=16 if=/dev/urandom | hd
|
||||
|
|
@ -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 [1m$hash[0m. 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, [1m%s[0m.\n' "$name"
|
||||
|
||||
while true; do
|
||||
printf "[7mp2>[0m "
|
||||
read -r answer
|
||||
|
||||
case "$answer" in
|
||||
\?|help)
|
||||
cat <<EOD
|
||||
[1m Help
|
||||
----------------------------------------------------------[0m
|
||||
|
||||
Type [1mquit[0m to leave the p2 shell.
|
||||
Type [1mlog[0m 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
|
||||
[1mPuzzles Answered By $name
|
||||
---------------------------------------[0m
|
||||
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 [1m$points[0m more points in the [1m$cat[0m category."
|
||||
matches=$(expr $matches + 1)
|
||||
else
|
||||
echo "[1mError recording points. Tell the officials![0m"
|
||||
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
|
||||
|
|
@ -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("&", "&", s)
|
||||
gsub("<", "<", s)
|
||||
gsub(">", ">", 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()
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#! /bin/sh
|
||||
|
||||
exec svlogd -tt $PWD
|
|
@ -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.
|
|
@ -1,3 +0,0 @@
|
|||
#! /bin/sh
|
||||
|
||||
dbip -d
|
|
@ -1 +0,0 @@
|
|||
10.0.1.2/24
|
|
@ -1,3 +0,0 @@
|
|||
#! /bin/sh
|
||||
|
||||
exec svlogd -tt $PWD
|
|
@ -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
|
|
@ -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
|
|
@ -1,4 +0,0 @@
|
|||
all: modem
|
||||
|
||||
clean:
|
||||
rm -f modem
|
|
@ -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;
|
||||
}
|
Before Width: | Height: | Size: 247 B |
|
@ -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;
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
Before Width: | Height: | Size: 39 KiB |
|
@ -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>
|
|
@ -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 - $*) > $@
|