moth/kevin/kevin.py

148 lines
5.2 KiB
Python
Raw Normal View History

2009-10-01 18:35:12 -06:00
#! /usr/bin/env python3
import irc
import os
import optparse
import asynchat
import socket
import asyncore
from urllib.parse import quote_plus as quote
nobody = '\002[nobody]\002'
class Flagger(asynchat.async_chat):
"""Connection to flagd"""
def __init__(self, addr, auth):
asynchat.async_chat.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.connect((addr, 6668))
self.push(auth + b'\n')
self.flag = None
def handle_read(self):
msg = self.recv(4096)
raise ValueError("Flagger died: %r" % msg)
def handle_error(self):
# If we lose the connection to flagd, nobody can score any
# points. Terminate everything.
asyncore.close_all()
asynchat.async_chat.handle_error(self)
def set_flag(self, team):
if team:
eteam = team.encode('utf-8')
else:
eteam = b''
self.push(eteam + b'\n')
self.flag = team
class Kevin(irc.Bot):
def __init__(self, host, flagger, tokens, victims):
irc.Bot.__init__(self, host, ['kevin'], 'Kevin', ['#kevin'])
self.flagger = flagger
self.tokens = tokens
self.victims = victims
self.affiliation = {}
def cmd_join(self, sender, forum, addl):
if sender.name() in self.nicks:
self.tell_flag(forum)
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))
def cmd_privmsg(self, sender, forum, addl):
text = addl[0]
if text.startswith('!'):
parts = text[1:].lower().split(' ', 1)
cmd = parts[0]
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')
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()