Merge branch 'master' of ssh://cfl.lanl.gov/var/projects/gctf
4
Makefile
|
@ -26,6 +26,10 @@ target: $(PYC)
|
|||
$(INSTALL) -d $(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) ctfd.py $(DESTDIR)/usr/sbin
|
||||
$(INSTALL) new-contest $(DESTDIR)/usr/sbin
|
||||
|
|
97
ctf.css
|
@ -7,7 +7,7 @@ html {
|
|||
body {
|
||||
font-family: sans-serif;
|
||||
color: #fff;
|
||||
margin: 50px 0 0 100px;
|
||||
margin: 50px 0 0 110px;
|
||||
padding: 10px;
|
||||
max-width: 700px;
|
||||
}
|
||||
|
@ -30,6 +30,54 @@ h1:first-child:before {
|
|||
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 ****/
|
||||
|
||||
a img {
|
||||
|
@ -64,6 +112,39 @@ th, td {
|
|||
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 {
|
||||
background: #222;
|
||||
}
|
||||
|
@ -72,24 +153,20 @@ th, td {
|
|||
height: 400px;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.4em;
|
||||
margin-bottom: 20px;
|
||||
color: #f4f4f4;
|
||||
}
|
||||
|
||||
.solved {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
table.pollster {
|
||||
margin-left: 5em;
|
||||
margin-left: 5em;
|
||||
}
|
||||
|
||||
table.pollster td {
|
||||
padding: 2px 1em 2px 5px;
|
||||
padding: 2px 1em 2px 5px;
|
||||
}
|
||||
|
||||
table.pollster thead {
|
||||
font-weight: bold;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,27 +28,33 @@ if 'home' in os.environ.get('SCRIPT_FILENAME', ''):
|
|||
}
|
||||
else:
|
||||
# An actual installation
|
||||
config = {'global':
|
||||
{'data_dir': '/var/lib/ctf',
|
||||
'base_url': '/',
|
||||
'css_url': '/ctf.css',
|
||||
'disabled_dir': '/var/lib/ctf/disabled',
|
||||
'flags_dir': '/var/lib/ctf/flags',
|
||||
'house_team': 'dirtbags',
|
||||
'passwd': '/var/lib/ctf/passwd',
|
||||
'team_colors': team_colors,
|
||||
'poll_interval': 60,
|
||||
'poll_timeout': 0.5,
|
||||
'heartbeat_dir': '/var/lib/pollster',
|
||||
'poll_dir': '/var/lib/www',
|
||||
},
|
||||
'puzzler':
|
||||
{'dir': '/usr/lib/www/puzzler',
|
||||
'cgi_url': '/puzzler.cgi',
|
||||
'base_url': '/puzzler',
|
||||
'keys_file': '/usr/lib/ctf/puzzler.keys',
|
||||
},
|
||||
}
|
||||
config = {
|
||||
'global':
|
||||
{
|
||||
'data_dir': '/var/lib/ctf',
|
||||
'base_url': '/',
|
||||
'css_url': '/ctf.css',
|
||||
'disabled_dir': '/var/lib/ctf/disabled',
|
||||
'flags_dir': '/var/lib/ctf/flags',
|
||||
'house_team': 'dirtbags',
|
||||
'passwd': '/var/lib/ctf/passwd',
|
||||
'team_colors': team_colors,
|
||||
},
|
||||
'pollster':
|
||||
{
|
||||
'poll_interval': 60,
|
||||
'poll_timeout': 0.5,
|
||||
'heartbeat_dir': '/var/lib/pollster',
|
||||
'results': '/var/lib/pollster/status.html',
|
||||
},
|
||||
'puzzler':
|
||||
{
|
||||
'dir': '/usr/lib/www/puzzler',
|
||||
'cgi_url': '/puzzler.cgi',
|
||||
'base_url': '/puzzler',
|
||||
'keys_file': '/usr/lib/ctf/puzzler.keys',
|
||||
},
|
||||
}
|
||||
|
||||
def get(section, key):
|
||||
return config[section][key]
|
||||
|
@ -71,22 +77,45 @@ def datafile(filename):
|
|||
def 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'):
|
||||
print('Content-type: text/html')
|
||||
print()
|
||||
print('''<?xml version="1.0" encoding="UTF-8"?>
|
||||
ret.append('Content-type: text/html')
|
||||
ret.append('')
|
||||
ret.append('''<?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">
|
||||
<head>
|
||||
<title>%s</title>
|
||||
<link rel="stylesheet" href="%s" type="text/css" />
|
||||
<title>%(title)s</title>
|
||||
<link rel="stylesheet" href="%(css)s" type="text/css" />
|
||||
%(hdr)s
|
||||
</head>
|
||||
<body>
|
||||
<h1>%s</h1>
|
||||
''' % (title, css, title))
|
||||
<body class="%(class)s">
|
||||
<h1>%(title)s</h1>
|
||||
<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():
|
||||
print('</body></html>')
|
||||
return '</body></html>'
|
||||
|
|
|
@ -59,12 +59,13 @@ set xtics nomirror
|
|||
set ytics nomirror
|
||||
set nokey
|
||||
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),
|
||||
'pngout': pngout})
|
||||
instructions.flush()
|
||||
|
||||
gp = os.system('gnuplot %s 2>/dev/null </dev/null' % instructions.name)
|
||||
os.rename("%s,tmp" % pngout, pngout)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -66,9 +66,10 @@ def start_html(title):
|
|||
if passwd:
|
||||
c['passwd'] = passwd
|
||||
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):
|
||||
safe = list(args[:1])
|
||||
|
@ -156,7 +157,7 @@ def main():
|
|||
# Show available puzzles in category
|
||||
show_puzzles(cat, cat_dir)
|
||||
else:
|
||||
thekey = get_key(cat, points)
|
||||
thekeys = get_key(cat, points)
|
||||
if not teams.chkpasswd(team, passwd):
|
||||
start_html('Wrong password')
|
||||
end_html()
|
||||
|
|
|
@ -7,26 +7,7 @@ import string
|
|||
from . import teams
|
||||
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():
|
||||
print('Content-type: text/html')
|
||||
print()
|
||||
|
||||
f = cgi.FieldStorage()
|
||||
|
||||
team = f.getfirst('team', '')
|
||||
|
|
|
@ -15,20 +15,8 @@ def main():
|
|||
|
||||
categories = [(cat, s.cat_points(cat)) for cat in s.categories()]
|
||||
|
||||
print('Content-type: text/html')
|
||||
print('Refresh: 10')
|
||||
print()
|
||||
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(config.start_html('Scoreboard', cls='wide'))
|
||||
print('<table class="scoreboard">')
|
||||
print('<tr>')
|
||||
print('<th>Overall</th>')
|
||||
|
@ -71,9 +59,8 @@ def main():
|
|||
<p class="histogram">
|
||||
<img src="histogram.png" alt="scores over time" />
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>''')
|
||||
''')
|
||||
print(config.end_html())
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
11
ctfd.py
|
@ -20,13 +20,12 @@ def chart(s):
|
|||
def reap():
|
||||
try:
|
||||
while True:
|
||||
os.waitpid(0, os.WNOHANG)
|
||||
pid, ret = os.waitpid(0, os.WNOHANG)
|
||||
if not pid:
|
||||
break
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def sigchld(signum, frame):
|
||||
do_reap = True
|
||||
|
||||
def main():
|
||||
p = optparse.OptionParser()
|
||||
p.add_option('-p', '--genpass', dest='cat', default=None,
|
||||
|
@ -39,13 +38,11 @@ def main():
|
|||
pointsrv = pointsd.start()
|
||||
flagsrv = flagd.start()
|
||||
|
||||
signal.signal(signal.SIGCHLD, sigchld)
|
||||
s = pointsrv.store
|
||||
slen = 0
|
||||
while True:
|
||||
if do_reap:
|
||||
reap()
|
||||
asyncore.loop(timeout=30, use_poll=True, count=1)
|
||||
reap()
|
||||
if len(s) > slen:
|
||||
slen = len(s)
|
||||
chart(s)
|
||||
|
|
76
mkpuzzles.py
|
@ -17,6 +17,37 @@ opts, args = p.parse_args()
|
|||
|
||||
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):
|
||||
dirname = os.path.join(opts.puzzles, cat)
|
||||
for points in os.listdir(dirname):
|
||||
|
@ -46,47 +77,7 @@ for cat in os.listdir(opts.puzzles):
|
|||
|
||||
title = '%s for %s points' % (cat, points)
|
||||
f = open(os.path.join(outdir, 'index.html'), 'w', encoding='utf-8')
|
||||
f.write('''<?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">
|
||||
<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})
|
||||
f.write(config.start_html(title, js))
|
||||
if readme:
|
||||
f.write('<div class="readme">%s</div>\n' % readme)
|
||||
if files:
|
||||
|
@ -108,11 +99,10 @@ for cat in os.listdir(opts.puzzles):
|
|||
<input type="submit" />
|
||||
</fieldset>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
''' % {'cgi': config.get('puzzler', 'cgi_url'),
|
||||
'cat': cat,
|
||||
'points': points})
|
||||
f.write(config.end_html())
|
||||
|
||||
f = open(opts.keyfile, 'w', encoding='utf-8')
|
||||
for key in keys:
|
||||
|
|
|
@ -13,6 +13,8 @@ rotate /var/lib/ctf/scores.dat
|
|||
rotate /var/lib/ctf/passwd
|
||||
rm -f /var/lib/ctf/flags/* || true
|
||||
|
||||
sv restart /var/service/ctf
|
||||
|
||||
echo "Things you may want to tweak:"
|
||||
find /var/lib/ctf/disabled
|
||||
find /var/lib/kevin/tokens
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#! /bin/sh
|
||||
|
||||
case "$REMOTEADDR" in
|
||||
10.0.0.[2-254])
|
||||
touch /var/lib/pollster/$REMOTEADDR
|
||||
ip=$(echo $UDPREMOTEADDR | cut -d: -f1)
|
||||
case "$ip" in
|
||||
10.0.0.*)
|
||||
touch /var/lib/pollster/$ip
|
||||
;;
|
||||
esac
|
||||
|
||||
echo 'Hello.'
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
#! /bin/sh
|
||||
|
||||
exec logger -t pollster
|
|
@ -2,45 +2,25 @@
|
|||
|
||||
import os
|
||||
import re
|
||||
import io
|
||||
import sys
|
||||
import time
|
||||
import socket
|
||||
import traceback
|
||||
import threading
|
||||
import queue
|
||||
|
||||
from ctf import config
|
||||
from ctf import pointscli
|
||||
|
||||
DEBUG = False
|
||||
POLL_INTERVAL = config.get('poll_interval')
|
||||
IP_DIR = config.get('heartbeat_dir')
|
||||
REPORT_PATH = config.get('poll_dir')
|
||||
SOCK_TIMEOUT = config.get('poll_timeout')
|
||||
DEBUG = False
|
||||
POLL_INTERVAL = config.get('pollster', 'poll_interval')
|
||||
IP_DIR = config.get('pollster', 'heartbeat_dir')
|
||||
REPORT_PATH = config.get('pollster', 'results')
|
||||
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):
|
||||
''' Connect via socket to the specified <ip>:<port> using the
|
||||
specified <prot>, send the specified <msg> and return the
|
||||
specified <prot>, send the specified <msg> and return the
|
||||
response or None if something went wrong. <max_recvs> specifies
|
||||
how many times to read from the socket (default to once). '''
|
||||
|
||||
|
@ -51,7 +31,7 @@ def socket_poll(ip, port, msg, prot, max_recv=1):
|
|||
print('pollster: create socket failed (%s)' % e)
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
|
||||
sock.settimeout(SOCK_TIMEOUT)
|
||||
|
||||
# connect
|
||||
|
@ -70,19 +50,16 @@ def socket_poll(ip, port, msg, prot, max_recv=1):
|
|||
sock.send(msg)
|
||||
|
||||
# get a response
|
||||
resp = ''
|
||||
resp = []
|
||||
try:
|
||||
# first read
|
||||
data = sock.recv(1024)
|
||||
resp += data.decode('utf-8')
|
||||
max_recv -= 1
|
||||
|
||||
# remaining reads as necessary until timeout or socket closes
|
||||
while(len(data) > 0 and max_recv > 0):
|
||||
# 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)
|
||||
resp += data.decode('utf-8')
|
||||
max_recv -= 1
|
||||
sock.close()
|
||||
if len(data) == 0:
|
||||
break
|
||||
resp.append(data)
|
||||
|
||||
except socket.timeout as e:
|
||||
print('pollster: timed out waiting for a response from %s:%d (%s)' % (ip, port, e))
|
||||
|
@ -90,11 +67,13 @@ def socket_poll(ip, port, msg, prot, max_recv=1):
|
|||
except Exception as e:
|
||||
print('pollster: receive from %s:%d failed (%s)' % (ip, port, e))
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
sock.close()
|
||||
|
||||
if len(resp) == 0:
|
||||
return None
|
||||
|
||||
return resp
|
||||
return b''.join(resp)
|
||||
|
||||
# PUT POLLS FUNCTIONS HERE
|
||||
# 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)
|
||||
if resp is None:
|
||||
return None
|
||||
return resp.strip('\r\n')
|
||||
return resp.strip(b'\r\n')
|
||||
|
||||
def poll_noted(ip):
|
||||
''' Poll the noted service. Returns None or a team name. '''
|
||||
resp = socket_poll(ip, 4000, b'rflag\n', socket.SOCK_STREAM)
|
||||
if resp is None:
|
||||
return None
|
||||
return resp.strip('\r\n')
|
||||
return resp.strip(b'\r\n')
|
||||
|
||||
def poll_catcgi(ip):
|
||||
''' Poll the cat.cgi web service. Returns None or a team name. '''
|
||||
|
@ -121,79 +100,58 @@ def poll_catcgi(ip):
|
|||
if resp is None:
|
||||
return None
|
||||
|
||||
content = resp.split('\r\n\r\n')
|
||||
content = resp.split(b'\r\n\r\n')
|
||||
if len(content) < 3:
|
||||
return None
|
||||
|
||||
content = content[1].split('\r\n')
|
||||
content = content[1].split(b'\r\n')
|
||||
|
||||
try:
|
||||
content_len = int(content[0])
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
|
||||
if content_len <= 0:
|
||||
return None
|
||||
return content[1].strip('\r\n')
|
||||
return content[1].strip(b'\r\n')
|
||||
|
||||
def poll_tftpd(ip):
|
||||
''' Poll the tftp service. Returns None or a team name. '''
|
||||
resp = socket_poll(ip, 69, b'\x00\x01' + b'flag' + b'\x00' + b'octet' + b'\x00', socket.SOCK_DGRAM)
|
||||
if resp is None:
|
||||
return None
|
||||
|
||||
|
||||
if len(resp) <= 5:
|
||||
return None
|
||||
|
||||
resp = resp.split('\n')[0]
|
||||
return resp[4:].strip('\r\n')
|
||||
|
||||
|
||||
resp = resp.split(b'\n')[0]
|
||||
|
||||
# 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
|
||||
POLLS = {
|
||||
'fingerd' : poll_fingerd,
|
||||
'noted' : poll_noted,
|
||||
'noted' : poll_noted,
|
||||
'catcgi' : poll_catcgi,
|
||||
'tftpd' : poll_tftpd,
|
||||
'tftpd' : poll_tftpd,
|
||||
}
|
||||
|
||||
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
|
||||
while True:
|
||||
|
||||
t_start = time.time()
|
||||
|
||||
# gather the list of IPs to poll
|
||||
try:
|
||||
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')
|
||||
ips = os.listdir(IP_DIR)
|
||||
|
||||
out = io.StringIO()
|
||||
out.write(config.start_html('Team Service Availability'))
|
||||
for ip in ips:
|
||||
|
||||
# check file name format is ip
|
||||
if ip_re.match(ip) is None:
|
||||
continue
|
||||
|
@ -217,7 +175,7 @@ while True:
|
|||
|
||||
# perform polls
|
||||
for service,func in POLLS.items():
|
||||
team = func(ip)
|
||||
team = func(ip).decode('utf-8')
|
||||
if team is None:
|
||||
team = 'dirtbags'
|
||||
|
||||
|
@ -227,11 +185,11 @@ while True:
|
|||
if out is not None:
|
||||
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:
|
||||
out.write('</table>\n')
|
||||
|
||||
|
||||
if DEBUG is True:
|
||||
print('+-----------------------------------------+')
|
||||
|
||||
|
@ -240,9 +198,9 @@ while True:
|
|||
sleep_time = POLL_INTERVAL - exec_time
|
||||
|
||||
if out is not None:
|
||||
out.write('<p><b>Next poll in: %ds</b></p>\n' % sleep_time)
|
||||
out.write('</body>\n</html>\n')
|
||||
out.close()
|
||||
out.write(config.end_html())
|
||||
|
||||
open(REPORT_PATH, 'w').write(out.getvalue())
|
||||
|
||||
# sleep until its time to poll again
|
||||
time.sleep(sleep_time)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#! /bin/sh
|
||||
|
||||
exec udpsvd 0 9 /usr/sbin/in.heartbeatd
|
||||
exec udpsvd 0 9 envuidgid ctf /usr/sbin/in.heartbeatd
|
||||
|
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 184 KiB |
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1 @@
|
|||
‽
|
Before Width: | Height: | Size: 362 KiB After Width: | Height: | Size: 362 KiB |
|
@ -0,0 +1 @@
|
|||
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
|
@ -0,0 +1 @@
|
|||
|
|
@ -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 />
|
||||
◕ ⚑ ♥ ◢ ★
|
|
@ -0,0 +1 @@
|
|||
The "hispaniola" category requires contenstants to treasure-hunt for tangible items to learn the keys to each puzzle.
|
|
@ -1 +0,0 @@
|
|||
You're well on your way :)
|
|
@ -1 +0,0 @@
|
|||
‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽‽
|
|
@ -1 +0,0 @@
|
|||
-462766
|
|
@ -1 +0,0 @@
|
|||
3acd767f2717b84076cdcd18e882f01d
|
|
@ -1 +0,0 @@
|
|||
⚑ _ _ _ _ ◢ _ _ _ _ ♥ _ _ _ _ ★ _ _ _ _ ◕ _ _ _ _
|
|
@ -3,7 +3,7 @@ html,body {
|
|||
min-height: 100%;
|
||||
background-color: #000000;
|
||||
background-image: url(",binary.png");
|
||||
background-repeat: repeat-x repeat-y;
|
||||
background-repeat: repeat;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
@ -52,3 +52,11 @@ h1,h2,h3,h4 {
|
|||
margin: 2em auto 2em auto;
|
||||
border-bottom: 1px dotted #222;
|
||||
}
|
||||
|
||||
.error {
|
||||
padding: 1em;
|
||||
background: #fff;
|
||||
color: red;
|
||||
border: 1px solid red;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
../1/,binary.png
|
||||
../10/,binary.png
|
|
@ -1 +1 @@
|
|||
../1/,ctf.css
|
||||
../10/,ctf.css
|
|
@ -1 +1 @@
|
|||
../1/,binary.png
|
||||
../10/,binary.png
|
|
@ -1 +1 @@
|
|||
../1/,ctf.css
|
||||
../10/,ctf.css
|
Before Width: | Height: | Size: 626 B After Width: | Height: | Size: 17 B |
|
@ -0,0 +1 @@
|
|||
../10/,binary.png
|
Before Width: | Height: | Size: 626 B After Width: | Height: | Size: 17 B |
|
@ -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;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
../10/,ctf.css
|
|
@ -0,0 +1 @@
|
|||
../10/,binary.png
|
|
@ -0,0 +1 @@
|
|||
../10/,ctf.css
|
|
@ -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 © 2009 LANS, LLC.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
'''
|
||||
|
|
@ -0,0 +1 @@
|
|||
eVkIwHzOok
|
|
@ -0,0 +1 @@
|
|||
../10/,binary.png
|
|
@ -0,0 +1 @@
|
|||
../10/,ctf.css
|
|
@ -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 © 2009 LANS, LLC.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
'''
|
||||
|
|
@ -0,0 +1 @@
|
|||
QJebByJaKX
|
|
@ -0,0 +1 @@
|
|||
../10/,binary.png
|
|
@ -0,0 +1 @@
|
|||
../10/,ctf.css
|
|
@ -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 © 2009 LANS, LLC.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
'''
|
||||
|
|
@ -0,0 +1 @@
|
|||
s4nNlaMScV
|
|
@ -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.
|
|
@ -7,7 +7,7 @@ skills at designing those wits to survive.
|
|||
|
||||
<H2>Programming Your Tank</H2>
|
||||
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
|
||||
semi-colons (all lines must end in one). As with all new military systems
|
||||
it utilizes only integers; we must never rest in our
|
||||
|
|
|
@ -4,9 +4,8 @@ def mkDocTable(objects):
|
|||
objects.sort(lambda o1, o2: cmp(o1.__doc__, o2.__doc__))
|
||||
|
||||
for object in objects:
|
||||
print '<table class="docs">'
|
||||
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))
|
||||
continue
|
||||
text = object.__doc__
|
||||
|
@ -23,5 +22,5 @@ def mkDocTable(objects):
|
|||
body = '\n'.join(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 '</table>'
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ MAX_HIST = 30
|
|||
HIST_STEP = 100
|
||||
key = 'tanks:::2bac5e912ff2e1ad559b177eb5aeecca'
|
||||
|
||||
running = True
|
||||
|
||||
class Flagger(asynchat.async_chat):
|
||||
"""Use to connect to flagd and submit the current flag holder."""
|
||||
|
||||
|
@ -31,6 +33,7 @@ class Flagger(asynchat.async_chat):
|
|||
def handle_error(self):
|
||||
# If we lose the connection to flagd, nobody can score any
|
||||
# points. Terminate everything.
|
||||
running = False
|
||||
asyncore.close_all()
|
||||
asynchat.async_chat.handle_error(self)
|
||||
|
||||
|
@ -84,6 +87,8 @@ def main():
|
|||
lastrun = 0
|
||||
while True:
|
||||
asyncore.loop(60, count=1)
|
||||
if not running:
|
||||
break
|
||||
now = time.time()
|
||||
if now - lastrun >= 60:
|
||||
run_tanks(args, turns, flagger)
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -1,10 +1,9 @@
|
|||
#!/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 os
|
||||
import sys
|
||||
from ctf import config
|
||||
|
||||
try:
|
||||
from tanks import Program, setup, conditions, actions, docs
|
||||
|
@ -15,10 +14,13 @@ except:
|
|||
sys.path.append(os.path.join('/', *path))
|
||||
import Program, setup, conditions, actions, docs
|
||||
|
||||
print open('head.html').read() % "Documentation"
|
||||
print '<BODY>'
|
||||
print '<H1>Pflanzarr Documentation</H1>'
|
||||
print open('links.html').read()
|
||||
print(config.start_html('Tanks Documentation',
|
||||
links_title='Tanks',
|
||||
links=[('docs.cgi', 'Docs'),
|
||||
('results.cgi', 'Results'),
|
||||
('submit.html', 'Submit'),
|
||||
('errors.cgi', 'My Errors')]))
|
||||
|
||||
print Program.__doc__
|
||||
|
||||
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>'
|
||||
docs.mkDocTable(actions.actions.values())
|
||||
|
||||
print '</body></html>'
|
||||
print(config.end_html())
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#!/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 cgitb; cgitb.enable()
|
||||
import sys
|
||||
|
@ -20,15 +18,18 @@ except:
|
|||
path = '/home/pflarr/repos/gctf/'
|
||||
sys.path.append(path)
|
||||
from ctf import teams
|
||||
from ctf import config
|
||||
teams.build_teams()
|
||||
|
||||
head = open('head.html').read() % "Error Report"
|
||||
print(head)
|
||||
print('<H1>Your Errors</H1>')
|
||||
print(open('links.html').read())
|
||||
print(config.start_html('Tanks Errors',
|
||||
links_title='Tanks',
|
||||
links=[('docs.cgi', 'Docs'),
|
||||
('results.cgi', 'Results'),
|
||||
('submit.html', 'Submit'),
|
||||
('errors.cgi', 'My Errors')]))
|
||||
|
||||
def done():
|
||||
print('</body></html>')
|
||||
print(config.end_html())
|
||||
sys.exit(0)
|
||||
|
||||
fields = cgi.FieldStorage()
|
||||
|
|
Before Width: | Height: | Size: 5.8 KiB |
|
@ -1,5 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<link href="ctf.css" rel="stylesheet" type="text/css">
|
||||
<title>%s</title>
|
||||
</head>
|
|
@ -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>
|
|
@ -2,16 +2,16 @@
|
|||
|
||||
import cgitb; cgitb.enable()
|
||||
import os
|
||||
from ctf import config
|
||||
|
||||
import Config
|
||||
|
||||
print """Content-Type: text/html\n\n"""
|
||||
print """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n\n"""
|
||||
head = open('head.html').read() % "Pflanzarr Results"
|
||||
print head
|
||||
print "<H1>Results</H1>"
|
||||
print open('links.html').read()
|
||||
|
||||
print(config.start_html('Tanks Results',
|
||||
links_title='Tanks',
|
||||
links=[('docs.cgi', 'Docs'),
|
||||
('results.cgi', 'Results'),
|
||||
('submit.html', 'Submit'),
|
||||
('errors.cgi', 'My Errors')]))
|
||||
try:
|
||||
winner = open(os.path.join(Config.DATA_PATH, 'winner')).read()
|
||||
except:
|
||||
|
@ -52,4 +52,4 @@ for num in gameNums:
|
|||
print '<a href="results/%d/game.avi">v</a>' % num,
|
||||
print '<a href="results/%d/results.html">r</a>' % num
|
||||
|
||||
print '</body></html>'
|
||||
print(config.end_html())
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#!/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 cgitb; cgitb.enable()
|
||||
import os
|
||||
|
@ -20,15 +18,18 @@ except:
|
|||
path = '/home/pflarr/repos/gctf/'
|
||||
sys.path.append(path)
|
||||
from ctf import teams
|
||||
from ctf import config
|
||||
teams.build_teams()
|
||||
|
||||
head = open('head.html').read() % "Submission Results"
|
||||
print(head)
|
||||
print("<H1>Results</H1>")
|
||||
print(open('links.html').read())
|
||||
print(config.start_html('Tanks Submission',
|
||||
links_title='Tanks',
|
||||
links=[('docs.cgi', 'Docs'),
|
||||
('results.cgi', 'Results'),
|
||||
('submit.html', 'Submit'),
|
||||
('errors.cgi', 'My Errors')]))
|
||||
|
||||
def done():
|
||||
print('</body></html>')
|
||||
print(config.end_html())
|
||||
sys.exit(0)
|
||||
|
||||
fields = cgi.FieldStorage()
|
||||
|
@ -36,23 +37,23 @@ team = fields.getfirst('team', '').strip()
|
|||
passwd = fields.getfirst('passwd', '').strip()
|
||||
code = fields.getfirst('code', '')
|
||||
if not team:
|
||||
print('<p>No team specified'); done()
|
||||
print('<p>No team specified</p>'); done()
|
||||
elif not passwd:
|
||||
print('<p>No password given'); done()
|
||||
print('<p>No password given</p>'); done()
|
||||
elif not code:
|
||||
print('<p>No program given.'); done()
|
||||
print('<p>No program given.</p>'); done()
|
||||
|
||||
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]:
|
||||
print('<p>Invalid password.'); done()
|
||||
print('<p>Invalid password.</p>'); done()
|
||||
|
||||
path = os.path.join(Config.DATA_PATH, 'ai/players', quote(team) )
|
||||
file = open(path, 'w')
|
||||
file.write(code)
|
||||
file.close()
|
||||
|
||||
print("<P>Submission Successful")
|
||||
print("<p>Submission successful.</p>")
|
||||
|
||||
done()
|
||||
|
|
|
@ -1,16 +1,33 @@
|
|||
<html>
|
||||
<head>
|
||||
<link href="ctf.css" rel="stylesheet" type="text/css">'
|
||||
<title>Program Submission</title>"
|
||||
</head>
|
||||
<?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">
|
||||
<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">
|
||||
<fieldset>
|
||||
<legend>Your program:</legend>
|
||||
|
|