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
|
Off-white blue: #b9e0ef
|
||||||
Dark brown: #35170c
|
Dark brown: #35170c
|
||||||
Light brown: #432115
|
Light brown: #432115
|
||||||
Tan: #e1c3b8
|
Tan: #e1caa5
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@import "../fonts/maven_pro.css";
|
@import "../fonts/maven_pro.css";
|
||||||
|
|
||||||
html {
|
html {
|
||||||
background: #35170c url(../brown-circles.jpg) repeat left bottom;
|
background: #35170c url(../images/brown-circles.jpg) repeat left bottom;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
font-family: "Maven Pro", Ubuntu, sans-serif;
|
font-family: "Maven Pro", Ubuntu, sans-serif;
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@ h1:first-child {
|
||||||
border-radius: 0.2em;
|
border-radius: 0.2em;
|
||||||
padding: 0 0.3em;
|
padding: 0 0.3em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
max-width: 66%;
|
||||||
|
margin: 0.5em auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.readme, pre {
|
.readme, pre {
|
||||||
|
@ -111,11 +113,11 @@ section, nav {
|
||||||
max-width: 35em;
|
max-width: 35em;
|
||||||
border-radius: 0.6em;
|
border-radius: 0.6em;
|
||||||
margin: 1em auto;
|
margin: 1em auto;
|
||||||
padding: 0.2em;
|
padding: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
section {
|
section {
|
||||||
background: #e1c3b8;
|
background: #e1caa5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** navigation bar ***/
|
/*** 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">
|
<link rel="stylesheet" href="css/style.css" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Tracer FIRE 6E</h1>
|
<h1>Tracer FIRE 6</h1>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
<h2>Getting Started</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Here is what you need to do:
|
Here is what you need to do:
|
||||||
</p>
|
</p>
|
||||||
|
@ -36,6 +38,25 @@
|
||||||
</ol>
|
</ol>
|
||||||
</section>
|
</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>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="register.html">Register</a></li>
|
<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 - $*) > $@
|
|