Merge branch 'master' of ssh://cfl.lanl.gov/var/projects/gctf

This commit is contained in:
Paul S. Ferrell 2009-10-13 16:08:31 -06:00
commit b658035581
68 changed files with 622 additions and 451 deletions

View File

@ -26,6 +26,10 @@ target: $(PYC)
$(INSTALL) -d $(PYCDIR)/ctf $(INSTALL) -d $(PYCDIR)/ctf
$(INSTALL) $(PYC) $(PYCDIR)/ctf $(INSTALL) $(PYC) $(PYCDIR)/ctf
$(INSTALL) -d $(DESTDIR)/usr/lib/python2.6/site-packages/ctf
$(INSTALL) ctf/__init__.py $(DESTDIR)/usr/lib/python2.6/site-packages/ctf
$(INSTALL) ctf/config.py $(DESTDIR)/usr/lib/python2.6/site-packages/ctf
$(INSTALL) -d $(DESTDIR)/usr/sbin $(INSTALL) -d $(DESTDIR)/usr/sbin
$(INSTALL) ctfd.py $(DESTDIR)/usr/sbin $(INSTALL) ctfd.py $(DESTDIR)/usr/sbin
$(INSTALL) new-contest $(DESTDIR)/usr/sbin $(INSTALL) new-contest $(DESTDIR)/usr/sbin

91
ctf.css
View File

@ -7,7 +7,7 @@ html {
body { body {
font-family: sans-serif; font-family: sans-serif;
color: #fff; color: #fff;
margin: 50px 0 0 100px; margin: 50px 0 0 110px;
padding: 10px; padding: 10px;
max-width: 700px; max-width: 700px;
} }
@ -30,6 +30,54 @@ h1:first-child:before {
content: "Capture The Flag: "; content: "Capture The Flag: ";
} }
/*** left side bar ***/
#navigation {
position: absolute;
background: #222;
opacity: 0.9;
top: 80px;
left: 0px;
padding: 0;
}
#navigation h3 {
font-size: 100%;
border-bottom: 2px solid #444;
}
#navigation ul {
list-style: none;
padding: 0;
margin: 0;
}
#navigation li a {
display: block;
height: 25px;
width: 90px;
padding: 5px;
margin: 5px;
background: inherit;
border-right: 4px solid #444;
color: #999;
text-transform: lowercase;
font-size: 0.9em;
}
#navigation li a:hover {
color: #f4f4f4;
background: #333;
border-right: 4px solid #2a2;
}
#navigation li .active {
color: #999;
background: #333;
border-right: 4px solid #444;
}
/**** body ****/ /**** body ****/
a img { a img {
@ -64,6 +112,39 @@ th, td {
vertical-align: top; vertical-align: top;
} }
p {
line-height: 1.4em;
margin-bottom: 20px;
color: #f4f4f4;
}
hr {
border: 1px solid #444;
}
dt {
white-space: pre;
background-color: #333;
padding: 5px;
border: 2px solid green;
border-bottom: none;
font-weight: bold;
}
dd {
border: 2px solid green;
margin: 0px;
padding: 5px;
background-color: #282828;
}
/**** special cases ****/
.wide {
max-width: inherit;
}
.scoreboard { .scoreboard {
background: #222; background: #222;
} }
@ -72,12 +153,6 @@ th, td {
height: 400px; height: 400px;
} }
p {
line-height: 1.4em;
margin-bottom: 20px;
color: #f4f4f4;
}
.solved { .solved {
text-decoration: line-through; text-decoration: line-through;
} }
@ -93,3 +168,5 @@ table.pollster td {
table.pollster thead { table.pollster thead {
font-weight: bold; font-weight: bold;
} }

View File

@ -28,8 +28,10 @@ if 'home' in os.environ.get('SCRIPT_FILENAME', ''):
} }
else: else:
# An actual installation # An actual installation
config = {'global': config = {
{'data_dir': '/var/lib/ctf', 'global':
{
'data_dir': '/var/lib/ctf',
'base_url': '/', 'base_url': '/',
'css_url': '/ctf.css', 'css_url': '/ctf.css',
'disabled_dir': '/var/lib/ctf/disabled', 'disabled_dir': '/var/lib/ctf/disabled',
@ -37,13 +39,17 @@ else:
'house_team': 'dirtbags', 'house_team': 'dirtbags',
'passwd': '/var/lib/ctf/passwd', 'passwd': '/var/lib/ctf/passwd',
'team_colors': team_colors, 'team_colors': team_colors,
},
'pollster':
{
'poll_interval': 60, 'poll_interval': 60,
'poll_timeout': 0.5, 'poll_timeout': 0.5,
'heartbeat_dir': '/var/lib/pollster', 'heartbeat_dir': '/var/lib/pollster',
'poll_dir': '/var/lib/www', 'results': '/var/lib/pollster/status.html',
}, },
'puzzler': 'puzzler':
{'dir': '/usr/lib/www/puzzler', {
'dir': '/usr/lib/www/puzzler',
'cgi_url': '/puzzler.cgi', 'cgi_url': '/puzzler.cgi',
'base_url': '/puzzler', 'base_url': '/puzzler',
'keys_file': '/usr/lib/ctf/puzzler.keys', 'keys_file': '/usr/lib/ctf/puzzler.keys',
@ -71,22 +77,45 @@ def datafile(filename):
def url(path): def url(path):
return base_url + path return base_url + path
def start_html(title): def start_html(title, hdr='', cls='', links=[], links_title=None):
ret = []
if os.environ.get('GATEWAY_INTERFACE'): if os.environ.get('GATEWAY_INTERFACE'):
print('Content-type: text/html') ret.append('Content-type: text/html')
print() ret.append('')
print('''<?xml version="1.0" encoding="UTF-8"?> ret.append('''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC <!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN" "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<title>%s</title> <title>%(title)s</title>
<link rel="stylesheet" href="%s" type="text/css" /> <link rel="stylesheet" href="%(css)s" type="text/css" />
%(hdr)s
</head> </head>
<body> <body class="%(class)s">
<h1>%s</h1> <h1>%(title)s</h1>
''' % (title, css, title)) <div id="navigation">
<ul>
<li><a href="%(base)sintro.html">Intro/Rules</a></li>
<li><a href="%(base)sservices.html">Svc flags</a></li>
<li><a href="%(base)stanks/results.cgi">Tanks</a></li>
<li><a href="%(base)spuzzler.cgi">Puzzles</a></li>
<li><a href="%(base)sscoreboard.cgi">Scoreboard</a></li>
</ul>
''' % {'title': title,
'css': css,
'hdr': hdr,
'base': base_url,
'class': cls})
if links:
if links_title:
ret.append('<h3>%s</h3>' % links_title)
else:
ret.append('<hr/>')
for url, name in links:
ret.append('<li><a href="%s">%s</a></li>' % (url, name))
ret.append(' </div>')
return '\n'.join(ret)
def end_html(): def end_html():
print('</body></html>') return '</body></html>'

View File

@ -59,12 +59,13 @@ set xtics nomirror
set ytics nomirror set ytics nomirror
set nokey set nokey
set terminal png transparent size 640,200 x000000 xffffff set terminal png transparent size 640,200 x000000 xffffff
set output "%(pngout)s" set output "%(pngout)s,tmp"
plot %(plot)s\n''' % {'plot': ','.join(plotparts), plot %(plot)s\n''' % {'plot': ','.join(plotparts),
'pngout': pngout}) 'pngout': pngout})
instructions.flush() instructions.flush()
gp = os.system('gnuplot %s 2>/dev/null </dev/null' % instructions.name) gp = os.system('gnuplot %s 2>/dev/null </dev/null' % instructions.name)
os.rename("%s,tmp" % pngout, pngout)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -66,9 +66,10 @@ def start_html(title):
if passwd: if passwd:
c['passwd'] = passwd c['passwd'] = passwd
print(c) print(c)
config.start_html(title) print(config.start_html(title))
end_html = config.end_html def end_html():
print(config.end_html())
def safe_join(*args): def safe_join(*args):
safe = list(args[:1]) safe = list(args[:1])
@ -156,7 +157,7 @@ def main():
# Show available puzzles in category # Show available puzzles in category
show_puzzles(cat, cat_dir) show_puzzles(cat, cat_dir)
else: else:
thekey = get_key(cat, points) thekeys = get_key(cat, points)
if not teams.chkpasswd(team, passwd): if not teams.chkpasswd(team, passwd):
start_html('Wrong password') start_html('Wrong password')
end_html() end_html()

View File

@ -7,26 +7,7 @@ import string
from . import teams from . import teams
from . import config from . import config
def head(title):
return '''<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Team Registration</title>
<link rel="stylesheet" href="%s" type="text/css" />
</head>
<body>
<h1>%s</h1>
''' % (config.css, title)
def foot():
return '''</body></html>'''
def main(): def main():
print('Content-type: text/html')
print()
f = cgi.FieldStorage() f = cgi.FieldStorage()
team = f.getfirst('team', '') team = f.getfirst('team', '')

View File

@ -15,20 +15,8 @@ def main():
categories = [(cat, s.cat_points(cat)) for cat in s.categories()] categories = [(cat, s.cat_points(cat)) for cat in s.categories()]
print('Content-type: text/html')
print('Refresh: 10') print('Refresh: 10')
print() print(config.start_html('Scoreboard', cls='wide'))
print('''<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Scoreboard</title>
<link rel="stylesheet" href="%sctf.css" type="text/css" />
</head>
<body style="max-width: inherit;">
<h1>Scoreboard</h1>
''' % config.base_url)
print('<table class="scoreboard">') print('<table class="scoreboard">')
print('<tr>') print('<tr>')
print('<th>Overall</th>') print('<th>Overall</th>')
@ -71,9 +59,8 @@ def main():
<p class="histogram"> <p class="histogram">
<img src="histogram.png" alt="scores over time" /> <img src="histogram.png" alt="scores over time" />
</p> </p>
''')
</body> print(config.end_html())
</html>''')
if __name__ == '__main__': if __name__ == '__main__':
main() main()

11
ctfd.py
View File

@ -20,13 +20,12 @@ def chart(s):
def reap(): def reap():
try: try:
while True: while True:
os.waitpid(0, os.WNOHANG) pid, ret = os.waitpid(0, os.WNOHANG)
if not pid:
break
except OSError: except OSError:
pass pass
def sigchld(signum, frame):
do_reap = True
def main(): def main():
p = optparse.OptionParser() p = optparse.OptionParser()
p.add_option('-p', '--genpass', dest='cat', default=None, p.add_option('-p', '--genpass', dest='cat', default=None,
@ -39,13 +38,11 @@ def main():
pointsrv = pointsd.start() pointsrv = pointsd.start()
flagsrv = flagd.start() flagsrv = flagd.start()
signal.signal(signal.SIGCHLD, sigchld)
s = pointsrv.store s = pointsrv.store
slen = 0 slen = 0
while True: while True:
if do_reap:
reap()
asyncore.loop(timeout=30, use_poll=True, count=1) asyncore.loop(timeout=30, use_poll=True, count=1)
reap()
if len(s) > slen: if len(s) > slen:
slen = len(s) slen = len(s)
chart(s) chart(s)

View File

@ -17,6 +17,37 @@ opts, args = p.parse_args()
keys = [] keys = []
js = '''
<script type="text/javascript">
function readCookie(key) {
var s = key + '=';
var toks = document.cookie.split(';');
for (var i = 0; i < toks.length; i++) {
var tok = toks[i];
while (tok.charAt(0) == ' ') {
tok = tok.substring(1, tok.length);
}
if (tok.indexOf(s) == 0) {
return tok.substring(s.length, tok.length);
}
}
return null;
}
function getTeamInfo() {
team = readCookie('team');
passwd = readCookie('passwd');
if (team != null) {
document.getElementById("form").t.value = team;
}
if (passwd != null) {
document.getElementById("form").w.value = passwd;
}
}
window.onload = getTeamInfo;
</script>
'''
for cat in os.listdir(opts.puzzles): for cat in os.listdir(opts.puzzles):
dirname = os.path.join(opts.puzzles, cat) dirname = os.path.join(opts.puzzles, cat)
for points in os.listdir(dirname): for points in os.listdir(dirname):
@ -46,47 +77,7 @@ for cat in os.listdir(opts.puzzles):
title = '%s for %s points' % (cat, points) title = '%s for %s points' % (cat, points)
f = open(os.path.join(outdir, 'index.html'), 'w', encoding='utf-8') f = open(os.path.join(outdir, 'index.html'), 'w', encoding='utf-8')
f.write('''<?xml version="1.0" encoding="UTF-8"?> f.write(config.start_html(title, js))
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>%(title)s</title>
<link rel="stylesheet" href="%(css)s" type="text/css" />
<script type="text/javascript">
function readCookie(key) {
var s = key + '=';
var toks = document.cookie.split(';');
for (var i = 0; i < toks.length; i++) {
var tok = toks[i];
while (tok.charAt(0) == ' ') {
tok = tok.substring(1, tok.length);
}
if (tok.indexOf(s) == 0) {
return tok.substring(s.length, tok.length);
}
}
return null;
}
function getTeamInfo() {
team = readCookie('team');
passwd = readCookie('passwd');
if (team != null) {
document.getElementById("form").t.value = team;
}
if (passwd != null) {
document.getElementById("form").w.value = passwd;
}
}
window.onload = getTeamInfo;
</script>
</head>
<body>
<h1>%(title)s</h1>
''' % {'title': title,
'css': config.css})
if readme: if readme:
f.write('<div class="readme">%s</div>\n' % readme) f.write('<div class="readme">%s</div>\n' % readme)
if files: if files:
@ -108,11 +99,10 @@ for cat in os.listdir(opts.puzzles):
<input type="submit" /> <input type="submit" />
</fieldset> </fieldset>
</form> </form>
</body>
</html>
''' % {'cgi': config.get('puzzler', 'cgi_url'), ''' % {'cgi': config.get('puzzler', 'cgi_url'),
'cat': cat, 'cat': cat,
'points': points}) 'points': points})
f.write(config.end_html())
f = open(opts.keyfile, 'w', encoding='utf-8') f = open(opts.keyfile, 'w', encoding='utf-8')
for key in keys: for key in keys:

View File

@ -13,6 +13,8 @@ rotate /var/lib/ctf/scores.dat
rotate /var/lib/ctf/passwd rotate /var/lib/ctf/passwd
rm -f /var/lib/ctf/flags/* || true rm -f /var/lib/ctf/flags/* || true
sv restart /var/service/ctf
echo "Things you may want to tweak:" echo "Things you may want to tweak:"
find /var/lib/ctf/disabled find /var/lib/ctf/disabled
find /var/lib/kevin/tokens find /var/lib/kevin/tokens

View File

@ -1,8 +1,9 @@
#! /bin/sh #! /bin/sh
case "$REMOTEADDR" in ip=$(echo $UDPREMOTEADDR | cut -d: -f1)
10.0.0.[2-254]) case "$ip" in
touch /var/lib/pollster/$REMOTEADDR 10.0.0.*)
touch /var/lib/pollster/$ip
;; ;;
esac esac
echo 'Hello.'

3
pollster/log.run.pollster Executable file
View File

@ -0,0 +1,3 @@
#! /bin/sh
exec logger -t pollster

View File

@ -2,41 +2,21 @@
import os import os
import re import re
import io
import sys import sys
import time import time
import socket import socket
import traceback import traceback
import threading
import queue
from ctf import config from ctf import config
from ctf import pointscli from ctf import pointscli
DEBUG = False DEBUG = False
POLL_INTERVAL = config.get('poll_interval') POLL_INTERVAL = config.get('pollster', 'poll_interval')
IP_DIR = config.get('heartbeat_dir') IP_DIR = config.get('pollster', 'heartbeat_dir')
REPORT_PATH = config.get('poll_dir') REPORT_PATH = config.get('pollster', 'results')
SOCK_TIMEOUT = config.get('poll_timeout') SOCK_TIMEOUT = config.get('pollster', 'poll_timeout')
class PointSubmitter(threading.Thread):
''' Pulls point allocations from the queue and submits them. '''
def __init__(self, point_queue):
threading.Thread.__init__(self)
self.point_queue = point_queue
self.sock = pointscli.makesock('localhost')
def run(self):
# loop forever
while(True):
cat, team, score = self.point_queue.get()
if None in [cat, team, score]:
continue
try:
pointscli.submit(cat, team, score, sock=self.sock)
except ValueError:
print('pollster: error submitting score (%s, %s, %d)' % (cat, team, score))
traceback.print_exc()
def socket_poll(ip, port, msg, prot, max_recv=1): def socket_poll(ip, port, msg, prot, max_recv=1):
''' Connect via socket to the specified <ip>:<port> using the ''' Connect via socket to the specified <ip>:<port> using the
@ -70,19 +50,16 @@ def socket_poll(ip, port, msg, prot, max_recv=1):
sock.send(msg) sock.send(msg)
# get a response # get a response
resp = '' resp = []
try: try:
# first read # read from the socket until <max_recv> responses or read,
# a timeout occurs, the socket closes, or some other exception
# is raised
for i in range(max_recv):
data = sock.recv(1024) data = sock.recv(1024)
resp += data.decode('utf-8') if len(data) == 0:
max_recv -= 1 break
resp.append(data)
# remaining reads as necessary until timeout or socket closes
while(len(data) > 0 and max_recv > 0):
data = sock.recv(1024)
resp += data.decode('utf-8')
max_recv -= 1
sock.close()
except socket.timeout as e: except socket.timeout as e:
print('pollster: timed out waiting for a response from %s:%d (%s)' % (ip, port, e)) print('pollster: timed out waiting for a response from %s:%d (%s)' % (ip, port, e))
@ -91,10 +68,12 @@ def socket_poll(ip, port, msg, prot, max_recv=1):
print('pollster: receive from %s:%d failed (%s)' % (ip, port, e)) print('pollster: receive from %s:%d failed (%s)' % (ip, port, e))
traceback.print_exc() traceback.print_exc()
sock.close()
if len(resp) == 0: if len(resp) == 0:
return None return None
return resp return b''.join(resp)
# PUT POLLS FUNCTIONS HERE # PUT POLLS FUNCTIONS HERE
# Each function should take an IP address and return a team name or None # Each function should take an IP address and return a team name or None
@ -105,14 +84,14 @@ def poll_fingerd(ip):
resp = socket_poll(ip, 79, b'flag\n', socket.SOCK_STREAM) resp = socket_poll(ip, 79, b'flag\n', socket.SOCK_STREAM)
if resp is None: if resp is None:
return None return None
return resp.strip('\r\n') return resp.strip(b'\r\n')
def poll_noted(ip): def poll_noted(ip):
''' Poll the noted service. Returns None or a team name. ''' ''' Poll the noted service. Returns None or a team name. '''
resp = socket_poll(ip, 4000, b'rflag\n', socket.SOCK_STREAM) resp = socket_poll(ip, 4000, b'rflag\n', socket.SOCK_STREAM)
if resp is None: if resp is None:
return None return None
return resp.strip('\r\n') return resp.strip(b'\r\n')
def poll_catcgi(ip): def poll_catcgi(ip):
''' Poll the cat.cgi web service. Returns None or a team name. ''' ''' Poll the cat.cgi web service. Returns None or a team name. '''
@ -121,11 +100,11 @@ def poll_catcgi(ip):
if resp is None: if resp is None:
return None return None
content = resp.split('\r\n\r\n') content = resp.split(b'\r\n\r\n')
if len(content) < 3: if len(content) < 3:
return None return None
content = content[1].split('\r\n') content = content[1].split(b'\r\n')
try: try:
content_len = int(content[0]) content_len = int(content[0])
@ -134,7 +113,7 @@ def poll_catcgi(ip):
if content_len <= 0: if content_len <= 0:
return None return None
return content[1].strip('\r\n') return content[1].strip(b'\r\n')
def poll_tftpd(ip): def poll_tftpd(ip):
''' Poll the tftp service. Returns None or a team name. ''' ''' Poll the tftp service. Returns None or a team name. '''
@ -145,8 +124,12 @@ def poll_tftpd(ip):
if len(resp) <= 5: if len(resp) <= 5:
return None return None
resp = resp.split('\n')[0] resp = resp.split(b'\n')[0]
return resp[4:].strip('\r\n')
# ack
_ = socket_poll(ip, 69, b'\x00\x04' + resp[2:4], socket.SOCK_DGRAM, 0)
return resp[4:].strip(b'\r\n')
# PUT POLL FUNCTIONS IN HERE OR THEY WONT BE POLLED # PUT POLL FUNCTIONS IN HERE OR THEY WONT BE POLLED
POLLS = { POLLS = {
@ -158,42 +141,17 @@ POLLS = {
ip_re = re.compile('(\d{1,3}\.){3}\d{1,3}') ip_re = re.compile('(\d{1,3}\.){3}\d{1,3}')
# start point submitter thread
point_queue = queue.Queue()
t = PointSubmitter(point_queue)
t.start()
# loop forever # loop forever
while True: while True:
t_start = time.time() t_start = time.time()
# gather the list of IPs to poll # gather the list of IPs to poll
try:
ips = os.listdir(IP_DIR) ips = os.listdir(IP_DIR)
except Exception as e:
print('pollster: could not list dir %s (%s)' % (IP_DIR, e))
traceback.print_exc()
try:
os.remove(REPORT_PATH)
except Exception as e:
pass
try:
out = open(REPORT_PATH, 'w')
except Exception as e:
out = None
pass
if out is not None:
out.write('<html>\n<head>\n')
out.write('<title>Pollster Results</title>\n')
out.write('<link rel="stylesheet" href="ctf.css" type="text/css" media="all" />\n')
out.write('</head><body>\n<h1>Polling Results</h1>\n')
out = io.StringIO()
out.write(config.start_html('Team Service Availability'))
for ip in ips: for ip in ips:
# check file name format is ip # check file name format is ip
if ip_re.match(ip) is None: if ip_re.match(ip) is None:
continue continue
@ -217,7 +175,7 @@ while True:
# perform polls # perform polls
for service,func in POLLS.items(): for service,func in POLLS.items():
team = func(ip) team = func(ip).decode('utf-8')
if team is None: if team is None:
team = 'dirtbags' team = 'dirtbags'
@ -227,7 +185,7 @@ while True:
if out is not None: if out is not None:
out.write('<tr><td>%s</td><td>%s</td>\n' % (service, team)) out.write('<tr><td>%s</td><td>%s</td>\n' % (service, team))
point_queue.put((service, team, 1)) pointscli.submit('svc.' + service, team, 1)
if out is not None: if out is not None:
out.write('</table>\n') out.write('</table>\n')
@ -240,9 +198,9 @@ while True:
sleep_time = POLL_INTERVAL - exec_time sleep_time = POLL_INTERVAL - exec_time
if out is not None: if out is not None:
out.write('<p><b>Next poll in: %ds</b></p>\n' % sleep_time) out.write(config.end_html())
out.write('</body>\n</html>\n')
out.close() open(REPORT_PATH, 'w').write(out.getvalue())
# sleep until its time to poll again # sleep until its time to poll again
time.sleep(sleep_time) time.sleep(sleep_time)

View File

@ -1,3 +1,3 @@
#! /bin/sh #! /bin/sh
exec udpsvd 0 9 /usr/sbin/in.heartbeatd exec udpsvd 0 9 envuidgid ctf /usr/sbin/in.heartbeatd

View File

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 184 KiB

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

Before

Width:  |  Height:  |  Size: 362 KiB

After

Width:  |  Height:  |  Size: 362 KiB

View File

@ -0,0 +1 @@

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

1
puzzles/hispaniola/5/key Normal file
View File

@ -0,0 +1 @@

View File

@ -0,0 +1,3 @@
Give the <b>entire sequence</b>. The symbols are here, in no particular order, for you to copy and paste.<br />
Make sure to include spaces between symbols (but no leading or trailing spaces).<br /><br />
&#9685; &#9873; &#9829; &#9698; &#9733;

View File

@ -0,0 +1 @@
The "hispaniola" category requires contenstants to treasure-hunt for tangible items to learn the keys to each puzzle.

View File

@ -1 +0,0 @@
You're well on your way :)

View File

@ -1 +0,0 @@
‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽

View File

@ -1 +0,0 @@
-462766

View File

@ -1 +0,0 @@
3acd767f2717b84076cdcd18e882f01d

View File

@ -1 +0,0 @@
&#9873; _ _ _ _ &#9698; _ _ _ _ &#9829; _ _ _ _ &#9733; _ _ _ _ &#9685; _ _ _ _

View File

@ -3,7 +3,7 @@ html,body {
min-height: 100%; min-height: 100%;
background-color: #000000; background-color: #000000;
background-image: url(",binary.png"); background-image: url(",binary.png");
background-repeat: repeat-x repeat-y; background-repeat: repeat;
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
@ -52,3 +52,11 @@ h1,h2,h3,h4 {
margin: 2em auto 2em auto; margin: 2em auto 2em auto;
border-bottom: 1px dotted #222; border-bottom: 1px dotted #222;
} }
.error {
padding: 1em;
background: #fff;
color: red;
border: 1px solid red;
font-weight: bold;
}

View File

@ -1 +1 @@
../1/,binary.png ../10/,binary.png

View File

@ -1 +1 @@
../1/,ctf.css ../10/,ctf.css

View File

@ -1 +1 @@
../1/,binary.png ../10/,binary.png

View File

@ -1 +1 @@
../1/,ctf.css ../10/,ctf.css

Binary file not shown.

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 17 B

View File

@ -0,0 +1 @@
../10/,binary.png

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 17 B

View File

@ -1,54 +0,0 @@
html,body {
height: 100%;
min-height: 100%;
background-color: #000000;
background-image: url(",binary.png");
background-repeat: repeat-x repeat-y;
margin: 0;
padding: 0;
}
#wrapper {
min-height: 100%;
height: 100%;
width: 800px;
margin: 0 auto;
border-left: 2px solid #009900;
border-right: 2px solid #009900;
font: .9em monospace;
color: #009900;
padding: 0;
background: #000;
}
#content {
padding: 2em 1.5em 2em 1.5em;
}
#footer {
padding: 0;
margin: 0;
height: 2em;
line-height: 2em;
width: 800px;
text-align: center;
}
input {
background-color: #222;
color: #fff;
border: 1px solid #009900;
padding: 1px 2px 1px 2px;
}
h1,h2,h3,h4 {
padding-bottom: 5px;
}
.vertsep {
width: 100%;
height: 1px;
padding: 0;
margin: 2em auto 2em auto;
border-bottom: 1px dotted #222;
}

1
puzzles/webapp/40/,ctf.css Symbolic link
View File

@ -0,0 +1 @@
../10/,ctf.css

View File

@ -0,0 +1 @@
../10/,binary.png

1
puzzles/webapp/50/,ctf.css Symbolic link
View File

@ -0,0 +1 @@
../10/,ctf.css

89
puzzles/webapp/50/5.cgi Executable file
View File

@ -0,0 +1,89 @@
#!/usr/bin/python
import os
import cgi
import cgitb
cgitb.enable(context=10)
if os.environ.has_key('QUERY_STRING'):
os.environ['QUERY_STRING'] = ''
fields = cgi.FieldStorage()
print 'Content-Type: text/html'
print ''
print '''
<html>
<head>
<title>5</title>
<link rel="stylesheet" type="text/css" href=",ctf.css" media="all" />
</head>
<body>
<div id="wrapper">
<div id="content">
<h1>Web Application Challenge 5</h1>
<p>Through some manipulation or interpretation of this CGI script
and the HTML page(s) that it generates, a 10 character key can be
found.</p>
<p><strong>Find the key!</strong></p>
<div class="vertsep"></div>
'''
PRODUCT_NAME = "Alex Brugh"
QUANT_LIMIT = 1
def purchase_success(quantity):
print '''
<p>Congratulations, your order for %d "%s" has been placed.</p>
''' % (quantity, PRODUCT_NAME)
class InvalidQuantityError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
quantity = None
if fields.has_key('quantity') and fields.has_key('product') and fields['product'].value == PRODUCT_NAME:
product = fields['product'].value
try:
quantity = int(fields['quantity'].value)
if quantity > QUANT_LIMIT:
# key = eVkIwHzOok
raise InvalidQuantityError("%d is not a valid quantity (limit %d)" % (quantity, QUANT_LIMIT))
except ValueError:
print '''
<p class="error">There was an error with your order request. Sorry.</p>
'''
quantity = None
if quantity is not None:
purchase_success(quantity)
else:
print '''
<h2>SALE: %s</h2>
<p>Use the order form below to place an order.</p>
<form method="post" action="5.cgi">
<em>Orders for "%s" are limited to 1 per customer.</em>
<br /><br />
<input type="submit" value="Order!" />
<input type="hidden" name="product" value="%s" />
<input type="hidden" name="quantity" value="1" />
</form>
''' % (PRODUCT_NAME, PRODUCT_NAME, PRODUCT_NAME)
print '''
</div>
<div id="footer">
<p>Copyright &copy; 2009 LANS, LLC.</p>
</div>
</div>
</body>
</html>
'''

1
puzzles/webapp/50/key Normal file
View File

@ -0,0 +1 @@
eVkIwHzOok

View File

@ -0,0 +1 @@
../10/,binary.png

1
puzzles/webapp/60/,ctf.css Symbolic link
View File

@ -0,0 +1 @@
../10/,ctf.css

72
puzzles/webapp/60/6.cgi Executable file
View File

@ -0,0 +1,72 @@
#!/usr/bin/python
import os
import cgi
import cgitb
cgitb.enable(context=10)
#if os.environ.has_key('QUERY_STRING'):
# os.environ['QUERY_STRING'] = ''
fields = cgi.FieldStorage()
import Cookie
c = Cookie.SimpleCookie()
c['key'] = 'QJebByJaKX'
c['content'] = '<p><em>Maybe I should have used sessions...</em></p>'
print 'Content-Type: text/html\n%s\n\n\n' % c
print ''
print '''
<html>
<head>
<title>6</title>
<link rel="stylesheet" type="text/css" href=",ctf.css" media="all" />
<script type="text/javascript">
function readCookie(key) {
var s = key + '=';
var toks = document.cookie.split(';');
for (var i = 0; i < toks.length; i++) {
var tok = toks[i];
while (tok.charAt(0) == ' ') {
tok = tok.substring(1, tok.length);
}
if (tok.indexOf(s) == 0) {
return tok.substring(s.length, tok.length);
}
}
return null;
}
function setContent() {
content = readCookie("content");
document.getElementById("stuff").innerHTML = content.substring(1, content.length-1);
}
window.onload = setContent;
</script>
</head>
<body>
<div id="wrapper">
<div id="content">
<h1>Web Application Challenge 6</h1>
<p>Through some manipulation or interpretation of this CGI script
and the HTML page(s) that it generates, a 10 character key can be
found.</p>
<p><strong>Find the key!</strong></p>
<div class="vertsep"></div>
<div id="stuff"></div>
'''
print '''
</div>
<div id="footer">
<p>Copyright &copy; 2009 LANS, LLC.</p>
</div>
</div>
</body>
</html>
'''

1
puzzles/webapp/60/key Normal file
View File

@ -0,0 +1 @@
QJebByJaKX

View File

@ -0,0 +1 @@
../10/,binary.png

1
puzzles/webapp/70/,ctf.css Symbolic link
View File

@ -0,0 +1 @@
../10/,ctf.css

86
puzzles/webapp/70/7.cgi Executable file
View File

@ -0,0 +1,86 @@
#!/usr/bin/python
import os
import cgi
import cgitb
cgitb.enable(context=10)
#if os.environ.has_key('QUERY_STRING'):
# os.environ['QUERY_STRING'] = ''
fields = cgi.FieldStorage()
import Cookie
c = Cookie.SimpleCookie(os.environ.get('HTTP_COOKIE', ''))
content = {
'joke1' : '<p>An infinite number of mathematicians walk into a bar. The first one orders a beer. The second orders half a beer. The third, a quarter of a beer. The bartender says <em>You are all idiots!</em> and pours two beers.<p>',
'joke2' : '<p>Two atoms are talking. One of them says <em>I think I lost an electron!</em> and the other says <em>Are you sure?</em> The first replies <em>Yeah, I am positive!</em></p>',
}
if c.has_key('content_name') and c.has_key('content'):
k = c['content_name'].value
try:
c['content'] = content[k]
except KeyError:
c['content'] = '<p><em>key = s4nNlaMScV</em></p>'
else:
c['content_name'] = 'joke1';
c['content'] = content['joke1']
print 'Content-Type: text/html\n%s\n\n\n' % c
print ''
print '''
<html>
<head>
<title>7</title>
<link rel="stylesheet" type="text/css" href=",ctf.css" media="all" />
<script type="text/javascript">
function readCookie(key) {
var s = key + '=';
var toks = document.cookie.split(';');
for (var i = 0; i < toks.length; i++) {
var tok = toks[i];
while (tok.charAt(0) == ' ') {
tok = tok.substring(1, tok.length);
}
if (tok.indexOf(s) == 0) {
return tok.substring(s.length, tok.length);
}
}
return null;
}
function getContent() {
content = readCookie("content");
document.getElementById("stuff").innerHTML = content.substring(1, content.length-1);
}
window.onload = getContent;
</script>
</head>
<body>
<div id="wrapper">
<div id="content">
<h1>Web Application Challenge 7</h1>
<p>Through some manipulation or interpretation of this CGI script
and the HTML page(s) that it generates, a 10 character key can be
found.</p>
<p><strong>Find the key!</strong></p>
<div class="vertsep"></div>
<div id="stuff"></div>
'''
print '''
</div>
<div id="footer">
<p>Copyright &copy; 2009 LANS, LLC.</p>
</div>
</div>
</body>
</html>
'''

1
puzzles/webapp/70/key Normal file
View File

@ -0,0 +1 @@
s4nNlaMScV

View File

@ -0,0 +1,14 @@
10: the key is in the generated source.
20: enter a non-integer into form field and submit. the key is in the resulting
traceback.
30: change the value in the GET request to a non-integer. the key is in the
resulting traceback.
40: change the value in the POST request to a non-integer. the key is in the
resulting traceback.
50: change the quantity value (hidden form field) to something greater than the
stated quantity limit. the key is in the resulting traceback. entering non-
integers is caught and handled, so that no longer works.
60: the key is in the cookie. note the javascript that reads a value from the
cookie, hopefully causing the player to take a look at the cookie.
70: modify the cookie's content_name field to something invalid, reload the page
and the key will be printed on the page.

View File

@ -7,7 +7,7 @@ skills at designing those wits to survive.
<H2>Programming Your Tank</H2> <H2>Programming Your Tank</H2>
Your tanks are programmed using the Super Useful Command and Kontrol language, Your tanks are programmed using the Super Useful Command and Kontrol language,
the very best in laser tank AI languages. It includes amazing feature such the very best in laser tank AI languages. It includes amazing features such
as comments (Started by a #, ended at EOL), logic, versatility, and as comments (Started by a #, ended at EOL), logic, versatility, and
semi-colons (all lines must end in one). As with all new military systems semi-colons (all lines must end in one). As with all new military systems
it utilizes only integers; we must never rest in our it utilizes only integers; we must never rest in our

View File

@ -4,9 +4,8 @@ def mkDocTable(objects):
objects.sort(lambda o1, o2: cmp(o1.__doc__, o2.__doc__)) objects.sort(lambda o1, o2: cmp(o1.__doc__, o2.__doc__))
for object in objects: for object in objects:
print '<table class="docs">'
if object.__doc__ is None: if object.__doc__ is None:
print '<tr><th>%s<tr><td colspan=2>Bad object' % \ print '<table><tr><th>%s<tr><td colspan=2>Bad object</table>' % \
xml.sax.saxutils.escape(str(object)) xml.sax.saxutils.escape(str(object))
continue continue
text = object.__doc__ text = object.__doc__
@ -23,5 +22,5 @@ def mkDocTable(objects):
body = '\n'.join(body) body = '\n'.join(body)
print '<DL><DT><DIV class="tab">%s</DIV></DT><DD>%s</DD></DL>' % (head, body) print '<DL><DT><DIV class="tab">%s</DIV></DT><DD>%s</DD></DL>' % (head, body)
#print '<tr><th>%s<th>Intentionally blank<th><tr><td colspan=3>%s' % (head, body) #print '<tr><th>%s<th>Intentionally blank<th><tr><td colspan=3>%s' % (head, body)
print '</table>'

View File

@ -14,6 +14,8 @@ MAX_HIST = 30
HIST_STEP = 100 HIST_STEP = 100
key = 'tanks:::2bac5e912ff2e1ad559b177eb5aeecca' key = 'tanks:::2bac5e912ff2e1ad559b177eb5aeecca'
running = True
class Flagger(asynchat.async_chat): class Flagger(asynchat.async_chat):
"""Use to connect to flagd and submit the current flag holder.""" """Use to connect to flagd and submit the current flag holder."""
@ -31,6 +33,7 @@ class Flagger(asynchat.async_chat):
def handle_error(self): def handle_error(self):
# If we lose the connection to flagd, nobody can score any # If we lose the connection to flagd, nobody can score any
# points. Terminate everything. # points. Terminate everything.
running = False
asyncore.close_all() asyncore.close_all()
asynchat.async_chat.handle_error(self) asynchat.async_chat.handle_error(self)
@ -84,6 +87,8 @@ def main():
lastrun = 0 lastrun = 0
while True: while True:
asyncore.loop(60, count=1) asyncore.loop(60, count=1)
if not running:
break
now = time.time() now = time.time()
if now - lastrun >= 60: if now - lastrun >= 60:
run_tanks(args, turns, flagger) run_tanks(args, turns, flagger)

View File

@ -1,104 +0,0 @@
/**** document ****/
html {
background: #222 url(grunge.png) repeat-x;
}
body {
font-family: sans-serif;
color: #eee;
margin: 50px 0 0 100px;
padding: 10px;
max-width: 700px;
}
/**** heading ****/
h1:first-child {
text-transform: lowercase;
font-size: 1.6em;
/* background-color: #222; */
/* opacity: 0.9; */
padding: 3px;
color: #2a2;
margin: 0 0 1em 70px;
}
h1:first-child:before {
color: #fff;
letter-spacing: -0.1em;
content: "Capture The Flag: ";
}
/**** body ****/
a img {
border: 0px;
}
a {
text-decoration: none;
color: #2a2;
font-weight: bold;
}
a:hover {
color: #fff;
background: #2a2;
font-weight: bold;
}
h1, h2, h3 {
color: #999;
letter-spacing: -0.05em;
}
code, pre, .readme, div.errors {
color: #fff;
background-color: #555;
margin: 1em;
}
th, td {
vertical-align: top;
}
.scoreboard td {
height: 400px;
}
p {
line-height: 1.4em;
margin-bottom: 20px;
color: #f4f4f4;
}
dt {
white-space: pre;
}
dt div.tab {
background-color: #333;
display: inline-block;
padding: 5px;
border: 3px solid green;
border-bottom: none;
font-weight: bold;
}
dd {
border: 3px solid green;
margin: 0px;
padding: 5px;
background-color: #282828;
}
fieldset * {
margin: 3px;
}
table.results td, th{
padding : 3px;
font-weight : bold;
}

View File

@ -1,10 +1,9 @@
#!/usr/bin/python #!/usr/bin/python
print """Content-Type: text/html\n\n"""
print """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n\n"""
import cgitb; cgitb.enable() import cgitb; cgitb.enable()
import os import os
import sys import sys
from ctf import config
try: try:
from tanks import Program, setup, conditions, actions, docs from tanks import Program, setup, conditions, actions, docs
@ -15,10 +14,13 @@ except:
sys.path.append(os.path.join('/', *path)) sys.path.append(os.path.join('/', *path))
import Program, setup, conditions, actions, docs import Program, setup, conditions, actions, docs
print open('head.html').read() % "Documentation" print(config.start_html('Tanks Documentation',
print '<BODY>' links_title='Tanks',
print '<H1>Pflanzarr Documentation</H1>' links=[('docs.cgi', 'Docs'),
print open('links.html').read() ('results.cgi', 'Results'),
('submit.html', 'Submit'),
('errors.cgi', 'My Errors')]))
print Program.__doc__ print Program.__doc__
print '<H3>Setup Actions:</H3>' print '<H3>Setup Actions:</H3>'
@ -34,4 +36,4 @@ print '<H3>Actions:</H3>'
print 'These actions are not for cowards. Remember, if actions contradict, your tank will simply do the last thing it was told in a turn. If ordered to hop on a plane to hell it will gladly do so. If order to make tea shortly afterwards, it will serve it politely and with cookies instead.<P>' print 'These actions are not for cowards. Remember, if actions contradict, your tank will simply do the last thing it was told in a turn. If ordered to hop on a plane to hell it will gladly do so. If order to make tea shortly afterwards, it will serve it politely and with cookies instead.<P>'
docs.mkDocTable(actions.actions.values()) docs.mkDocTable(actions.actions.values())
print '</body></html>' print(config.end_html())

View File

@ -1,7 +1,5 @@
#!/usr/bin/python3 #!/usr/bin/python3
print("""Content-Type: text/html\n\n""")
print("""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">\n\n""")
import cgi import cgi
import cgitb; cgitb.enable() import cgitb; cgitb.enable()
import sys import sys
@ -20,15 +18,18 @@ except:
path = '/home/pflarr/repos/gctf/' path = '/home/pflarr/repos/gctf/'
sys.path.append(path) sys.path.append(path)
from ctf import teams from ctf import teams
from ctf import config
teams.build_teams() teams.build_teams()
head = open('head.html').read() % "Error Report" print(config.start_html('Tanks Errors',
print(head) links_title='Tanks',
print('<H1>Your Errors</H1>') links=[('docs.cgi', 'Docs'),
print(open('links.html').read()) ('results.cgi', 'Results'),
('submit.html', 'Submit'),
('errors.cgi', 'My Errors')]))
def done(): def done():
print('</body></html>') print(config.end_html())
sys.exit(0) sys.exit(0)
fields = cgi.FieldStorage() fields = cgi.FieldStorage()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -1,5 +0,0 @@
<html>
<head>
<link href="ctf.css" rel="stylesheet" type="text/css">
<title>%s</title>
</head>

View File

@ -1,4 +0,0 @@
<a href="docs.cgi">Documentation</a> |
<a href="results.cgi">Results</a> |
<a href="submit.html">Submit</a> |
<a href="errors.cgi">My Errors</a>

View File

@ -2,16 +2,16 @@
import cgitb; cgitb.enable() import cgitb; cgitb.enable()
import os import os
from ctf import config
import Config import Config
print """Content-Type: text/html\n\n""" print(config.start_html('Tanks Results',
print """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n\n""" links_title='Tanks',
head = open('head.html').read() % "Pflanzarr Results" links=[('docs.cgi', 'Docs'),
print head ('results.cgi', 'Results'),
print "<H1>Results</H1>" ('submit.html', 'Submit'),
print open('links.html').read() ('errors.cgi', 'My Errors')]))
try: try:
winner = open(os.path.join(Config.DATA_PATH, 'winner')).read() winner = open(os.path.join(Config.DATA_PATH, 'winner')).read()
except: except:
@ -52,4 +52,4 @@ for num in gameNums:
print '<a href="results/%d/game.avi">v</a>' % num, print '<a href="results/%d/game.avi">v</a>' % num,
print '<a href="results/%d/results.html">r</a>' % num print '<a href="results/%d/results.html">r</a>' % num
print '</body></html>' print(config.end_html())

View File

@ -1,7 +1,5 @@
#!/usr/bin/python3 #!/usr/bin/python3
print("Content-Type: text/html\n\n")
print("""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">\n\n""")
import cgi import cgi
import cgitb; cgitb.enable() import cgitb; cgitb.enable()
import os import os
@ -20,15 +18,18 @@ except:
path = '/home/pflarr/repos/gctf/' path = '/home/pflarr/repos/gctf/'
sys.path.append(path) sys.path.append(path)
from ctf import teams from ctf import teams
from ctf import config
teams.build_teams() teams.build_teams()
head = open('head.html').read() % "Submission Results" print(config.start_html('Tanks Submission',
print(head) links_title='Tanks',
print("<H1>Results</H1>") links=[('docs.cgi', 'Docs'),
print(open('links.html').read()) ('results.cgi', 'Results'),
('submit.html', 'Submit'),
('errors.cgi', 'My Errors')]))
def done(): def done():
print('</body></html>') print(config.end_html())
sys.exit(0) sys.exit(0)
fields = cgi.FieldStorage() fields = cgi.FieldStorage()
@ -36,23 +37,23 @@ team = fields.getfirst('team', '').strip()
passwd = fields.getfirst('passwd', '').strip() passwd = fields.getfirst('passwd', '').strip()
code = fields.getfirst('code', '') code = fields.getfirst('code', '')
if not team: if not team:
print('<p>No team specified'); done() print('<p>No team specified</p>'); done()
elif not passwd: elif not passwd:
print('<p>No password given'); done() print('<p>No password given</p>'); done()
elif not code: elif not code:
print('<p>No program given.'); done() print('<p>No program given.</p>'); done()
if team not in teams.teams: if team not in teams.teams:
print('<p>Team is not registered.'); done() print('<p>Team is not registered.</p>'); done()
if passwd != teams.teams[team][0]: if passwd != teams.teams[team][0]:
print('<p>Invalid password.'); done() print('<p>Invalid password.</p>'); done()
path = os.path.join(Config.DATA_PATH, 'ai/players', quote(team) ) path = os.path.join(Config.DATA_PATH, 'ai/players', quote(team) )
file = open(path, 'w') file = open(path, 'w')
file.write(code) file.write(code)
file.close() file.close()
print("<P>Submission Successful") print("<p>Submission successful.</p>")
done() done()

View File

@ -1,16 +1,33 @@
<html> <?xml version="1.0" encoding="UTF-8"?>
<head> <!DOCTYPE html PUBLIC
<link href="ctf.css" rel="stylesheet" type="text/css">' "-//W3C//DTD XHTML 1.0 Strict//EN"
<title>Program Submission</title>" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
</head> <html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Tanks Submission</title>
<link rel="stylesheet" href="/ctf.css" type="text/css" />
</head>
<body class="">
<h1>Tanks Submission</h1>
<div id="navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/intro.html">Intro/Rules</a></li>
<li><a href="/services.html">Svc flags</a></li>
<li><a href="/puzzler.cgi">Puzzles</a></li>
<li><a href="/scoreboard.cgi">Scoreboard</a></li>
</ul>
<h3>Tanks</h3>
<li><a href="docs.cgi">Docs</a></li>
<li><a href="results.cgi">Results</a></li>
<li><a href="submit.html">Submit</a></li>
<li><a href="errors.cgi">My Errors</a></li>
</div>
<body>
<H1>Program Submission</H1>
<p>
<a href="docs.cgi">Documentation</a> |
<a href="results.cgi">Results</a> |
<a href="submit.html">Submit</a> |
<a href="errors.cgi">My Errors</a>
<form action="submit.cgi" method="post"> <form action="submit.cgi" method="post">
<fieldset> <fieldset>
<legend>Your program:</legend> <legend>Your program:</legend>