2009-10-01 18:35:12 -06:00
|
|
|
#! /usr/bin/env python3
|
|
|
|
|
|
|
|
import os
|
|
|
|
import optparse
|
|
|
|
import asynchat
|
|
|
|
import socket
|
|
|
|
import asyncore
|
|
|
|
from urllib.parse import quote_plus as quote
|
2009-10-05 15:30:37 -06:00
|
|
|
|
|
|
|
from ctf import irc
|
|
|
|
from ctf.flagd import Flagger
|
2009-10-01 18:35:12 -06:00
|
|
|
|
|
|
|
nobody = '\002[nobody]\002'
|
|
|
|
|
|
|
|
class Kevin(irc.Bot):
|
|
|
|
def __init__(self, host, flagger, tokens, victims):
|
2009-10-02 16:38:25 -06:00
|
|
|
irc.Bot.__init__(self, host,
|
|
|
|
['kevin', 'kev', 'kevin_', 'kev_', 'kevinm', 'kevinm_'],
|
|
|
|
'Kevin',
|
|
|
|
['+kevin'])
|
2009-10-01 18:35:12 -06:00
|
|
|
self.flagger = flagger
|
|
|
|
self.tokens = tokens
|
|
|
|
self.victims = victims
|
|
|
|
self.affiliation = {}
|
|
|
|
|
2009-10-02 16:38:25 -06:00
|
|
|
def cmd_001(self, sender, forum, addl):
|
|
|
|
self.write(['OPER', 'bot', 'BottyMcBotpants'])
|
|
|
|
irc.Bot.cmd_001(self, sender, forum, addl)
|
|
|
|
|
|
|
|
def cmd_JOIN(self, sender, forum, addl):
|
|
|
|
if sender.name == self.nick:
|
2009-10-01 18:35:12 -06:00
|
|
|
self.tell_flag(forum)
|
|
|
|
|
2009-10-02 16:38:25 -06:00
|
|
|
def cmd_381(self, sender, forum, addl):
|
|
|
|
# You are now an IRC Operator
|
|
|
|
if self.nick != 'kevin':
|
|
|
|
self.write(['KILL', 'kevin'], 'You are not kevin. I am kevin.')
|
|
|
|
self.write(['NICK', 'kevin'])
|
|
|
|
|
2009-10-01 18:35:12 -06:00
|
|
|
def err(self, exception):
|
|
|
|
"""Save the traceback for later inspection"""
|
|
|
|
irc.Bot.err(self, exception)
|
|
|
|
t,v,tb = exception
|
|
|
|
info = []
|
|
|
|
while 1:
|
|
|
|
info.append('%s:%d(%s)' % (os.path.basename(tb.tb_frame.f_code.co_filename),
|
|
|
|
tb.tb_lineno,
|
|
|
|
tb.tb_frame.f_code.co_name))
|
|
|
|
tb = tb.tb_next
|
|
|
|
if not tb:
|
|
|
|
break
|
|
|
|
del tb # just to be safe
|
|
|
|
infostr = '[' + '] ['.join(info) + ']'
|
|
|
|
self.last_tb = '%s %s %s' % (t, v, infostr)
|
|
|
|
print(self.last_tb)
|
|
|
|
|
|
|
|
def tell_flag(self, forum):
|
|
|
|
forum.msg('%s has the flag.' % (self.flagger.flag or nobody))
|
|
|
|
|
2009-10-02 16:38:25 -06:00
|
|
|
def cmd_PRIVMSG(self, sender, forum, addl):
|
2009-10-01 18:35:12 -06:00
|
|
|
text = addl[0]
|
|
|
|
if text.startswith('!'):
|
2009-10-07 08:19:06 -06:00
|
|
|
parts = text[1:].split(' ', 1)
|
|
|
|
cmd = parts[0].lower()
|
2009-10-01 18:35:12 -06:00
|
|
|
if len(parts) > 1:
|
|
|
|
args = parts[1]
|
|
|
|
else:
|
|
|
|
args = None
|
|
|
|
if cmd.startswith('r'):
|
|
|
|
# Register
|
|
|
|
who = sender.name()
|
|
|
|
if args:
|
|
|
|
self.affiliation[who] = args
|
|
|
|
team = self.affiliation.get(who, nobody)
|
|
|
|
forum.msg('%s is playing for %s' % (who, team))
|
|
|
|
elif cmd.startswith('e'):
|
|
|
|
# Embrace
|
|
|
|
forum.ctcp('ACTION', 'hugs %s' % sender.name())
|
|
|
|
elif cmd.startswith('f'):
|
|
|
|
# Flag
|
|
|
|
self.tell_flag(forum)
|
|
|
|
elif cmd.startswith('h'):
|
|
|
|
# Help
|
|
|
|
forum.msg('Goal: Obtain a token with social engineering.')
|
|
|
|
forum.msg('Commands: !help, !flag, !register [TEAM], !claim TOKEN, !victims, !embrace')
|
|
|
|
elif cmd.startswith('c') and args:
|
|
|
|
# Claim
|
|
|
|
sn = sender.name()
|
|
|
|
team = self.affiliation.get(sn)
|
|
|
|
token = quote(args, safe='')
|
|
|
|
fn = os.path.join(self.tokens, token)
|
|
|
|
if not team:
|
|
|
|
forum.msg('%s: register first (!register TEAM).' % sn)
|
|
|
|
elif self.flagger.flag == team:
|
|
|
|
forum.msg('%s: Greedy, greedy.' % sn)
|
|
|
|
elif not os.path.exists(fn):
|
|
|
|
forum.msg('%s: Token does not exist (possibly already claimed).' % sn)
|
|
|
|
else:
|
|
|
|
os.unlink(fn)
|
|
|
|
self.flagger.set_flag(team)
|
|
|
|
self.tell_flag(forum)
|
|
|
|
elif cmd.startswith('v'):
|
|
|
|
# Victims
|
|
|
|
# Open the file each time, so it can change
|
|
|
|
try:
|
|
|
|
for line in open(self.victims):
|
|
|
|
forum.msg(line.strip())
|
|
|
|
except IOError:
|
|
|
|
forum.msg('There are no victims!')
|
|
|
|
elif cmd == 'traceback':
|
|
|
|
forum.msg(self.last_tb or 'No traceback')
|
|
|
|
|
|
|
|
def main():
|
|
|
|
p = optparse.OptionParser()
|
|
|
|
p.add_option('-t', '--tokens', dest='tokens', default='./tokens',
|
|
|
|
help='Directory containing tokens')
|
|
|
|
p.add_option('-v', '--victims', dest='victims', default='victims.txt',
|
|
|
|
help='File containing victims information')
|
|
|
|
p.add_option('-i', '--ircd', dest='ircd', default='localhost',
|
|
|
|
help='IRC server to connect to')
|
|
|
|
p.add_option('-f', '--flagd', dest='flagd', default='localhost',
|
|
|
|
help='Flag server to connect to')
|
|
|
|
p.add_option('-p', '--password', dest='password',
|
|
|
|
default='kevin:::7db3e44d53d4a466f8facd7b7e9aa2b7',
|
|
|
|
help='Flag server password')
|
2009-10-05 15:30:37 -06:00
|
|
|
p.add_option('-c', '--channel', dest='channel',
|
|
|
|
help='Channel to join')
|
2009-10-01 18:35:12 -06:00
|
|
|
opts, args = p.parse_args()
|
|
|
|
|
|
|
|
f = Flagger(opts.flagd, opts.password.encode('utf-8'))
|
|
|
|
k = Kevin((opts.ircd, 6667), f, opts.tokens, opts.victims)
|
|
|
|
irc.run_forever()
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|