mirror of https://github.com/dirtbags/moth.git
Add new "kevin" category
This commit is contained in:
parent
36a430e9a1
commit
4b2ebe9418
|
@ -0,0 +1,26 @@
|
|||
FAKE = fakeroot -s fake -i fake
|
||||
INSTALL = $(FAKE) install
|
||||
|
||||
all: kevin.tce
|
||||
|
||||
kevin.tce: target
|
||||
$(FAKE) sh -c 'cd target && tar -czf - --exclude=placeholder --exclude=*~ .' > $@
|
||||
|
||||
|
||||
target: kevin.py irc.pyc run log.run
|
||||
$(INSTALL) -d target/usr/lib/ctf
|
||||
$(INSTALL) kevin.py irc.py target/usr/lib/ctf
|
||||
|
||||
$(INSTALL) --owner=100 -d target/var/lib/ctf/kevin/tokens
|
||||
|
||||
$(INSTALL) -d target/var/service/kevin
|
||||
$(INSTALL) run target/var/service/kevin/run
|
||||
|
||||
$(INSTALL) -d target/var/service/kevin/log
|
||||
$(INSTALL) log.run target/var/service/kevin/log/run
|
||||
|
||||
clean:
|
||||
rm -rf target kevin.tce fake
|
||||
|
||||
%.pyc: %.py
|
||||
python3 -c 'import $*'
|
|
@ -0,0 +1,528 @@
|
|||
#! /usr/bin/env python3
|
||||
|
||||
import asynchat
|
||||
import asyncore
|
||||
import socket
|
||||
import sys
|
||||
import traceback
|
||||
import time
|
||||
|
||||
class IRCHandler(asynchat.async_chat):
|
||||
"""IRC Server connection.
|
||||
|
||||
This is the one you want to derive your connection classes from.
|
||||
|
||||
"""
|
||||
|
||||
debug = False
|
||||
heartbeat_interval = 1 # seconds per heartbeat
|
||||
|
||||
def __init__(self, host=None, nick=None, gecos=None):
|
||||
asynchat.async_chat.__init__(self)
|
||||
self.line = b''
|
||||
self.timers = []
|
||||
self.last_heartbeat = 0
|
||||
self.set_terminator(b'\r\n')
|
||||
if host:
|
||||
self.open_connection(host, nick, gecos)
|
||||
|
||||
def dbg(self, msg):
|
||||
if self.debug:
|
||||
print(msg)
|
||||
|
||||
def open_connection(self, host, nick, gecos):
|
||||
self.nick = nick
|
||||
self.gecos = gecos
|
||||
self.host = host
|
||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.connect(host)
|
||||
|
||||
def handle_connect(self):
|
||||
self.write(['NICK', self.nick])
|
||||
self.write(['USER', self.nick, '+iw', self.nick], self.gecos)
|
||||
|
||||
def connect(self, host):
|
||||
self.waiting = False
|
||||
asynchat.async_chat.connect(self, host)
|
||||
|
||||
def heartbeat(self):
|
||||
"""Invoke all timers."""
|
||||
|
||||
if not self.timers:
|
||||
return
|
||||
timers, self.timers = self.timers, []
|
||||
now = time.time()
|
||||
for t, cb in timers:
|
||||
if t > now:
|
||||
self.timers.append((t, cb))
|
||||
else:
|
||||
cb()
|
||||
|
||||
def add_timer(self, secs, callback):
|
||||
"""After secs seconds, call callback"""
|
||||
self.timers.append((time.time() + secs, callback))
|
||||
|
||||
def readable(self):
|
||||
"""Called by asynchat to see if we're readable.
|
||||
|
||||
We hook our heartbeat in here.
|
||||
"""
|
||||
|
||||
now = time.time()
|
||||
if now > self.last_heartbeat + self.heartbeat_interval:
|
||||
self.heartbeat()
|
||||
self.last_heartbeat = now
|
||||
|
||||
if self.connected:
|
||||
return asynchat.async_chat.readable(self)
|
||||
else:
|
||||
return False
|
||||
|
||||
def collect_incoming_data(self, data):
|
||||
"""Called by asynchat when data arrives"""
|
||||
self.line += data
|
||||
|
||||
def found_terminator(self):
|
||||
"""Called by asynchat when it finds the terminating character.
|
||||
"""
|
||||
line = self.line.decode('utf-8')
|
||||
self.line = b''
|
||||
self.parse_line(line)
|
||||
|
||||
def write(self, args, text=None):
|
||||
"""Send out an IRC command
|
||||
|
||||
This function helps to prevent you from shooting yourself in the
|
||||
foot, by forcing you to send commands that are in a valid format
|
||||
(although it doesn't check the validity of the actual commands).
|
||||
|
||||
As we all know, IRC commands take the form
|
||||
|
||||
:COMMAND ARG1 ARG2 ARG3 ... :text string
|
||||
|
||||
where 'text string' is optional. Well, that's exactly how this
|
||||
function works. Args is a list of length at least one, and text
|
||||
string is a string.
|
||||
|
||||
write(['PRIVMSG', nick], 'Hello 12')
|
||||
|
||||
will send
|
||||
|
||||
PRIVMSG nick :Hello 12
|
||||
|
||||
"""
|
||||
|
||||
cmdstr = ' '.join(args)
|
||||
if text:
|
||||
cmdstr = '%s :%s' % (cmdstr, text)
|
||||
self.dbg('-> %s' % cmdstr)
|
||||
try:
|
||||
line = '%s\n' % cmdstr
|
||||
self.send(line.encode('utf-8'))
|
||||
except socket.error:
|
||||
pass
|
||||
|
||||
|
||||
def parse_line(self, line):
|
||||
"""Parse a server-provided line
|
||||
|
||||
This does all the magic of parsing those ill-formatted IRC
|
||||
messages. It will also decide if a PRIVMSG or NOTICE is using
|
||||
CTCP (the client-to-client protocol, which by convention is any
|
||||
of the above messages with ^A on both ends of the text.
|
||||
|
||||
This function goes on to invoke self.eval_triggers on the parsed
|
||||
data like this:
|
||||
|
||||
self.eval_triggers(operation, arguments, text)
|
||||
|
||||
where operation and text are strings, and arguments is a list.
|
||||
|
||||
It returns the same tuple (op, args, text).
|
||||
|
||||
"""
|
||||
|
||||
if (line[0] == ':'):
|
||||
with_uname = 1
|
||||
line = line [1:]
|
||||
else:
|
||||
with_uname = 0
|
||||
try:
|
||||
[args, text] = line.split(' :', 1)
|
||||
args = args.split()
|
||||
except ValueError:
|
||||
args = line.split()
|
||||
text = ''
|
||||
if (with_uname != 1):
|
||||
op = args[0]
|
||||
elif ((args[1] in ["PRIVMSG", "NOTICE"]) and
|
||||
(text and (text[0] == '\001') and (text[-1] == '\001'))):
|
||||
op = "C" + args[1]
|
||||
text = text[1:-1]
|
||||
else:
|
||||
op = args[1]
|
||||
self.dbg("<- %s %s %s" % (op, args, text))
|
||||
self.handle(op, args, text)
|
||||
return (op, args, text)
|
||||
|
||||
|
||||
def handle(self, op, args, text):
|
||||
"""Take action on a server message
|
||||
|
||||
Right now, just invokes
|
||||
|
||||
self.do_[op](args, text)
|
||||
|
||||
where [op] is the operation passed in.
|
||||
|
||||
This is a good method to overload if you want a really advanced
|
||||
client supporting bindings.
|
||||
|
||||
"""
|
||||
try:
|
||||
method = getattr(self, "do_" + lower(op))
|
||||
except AttributeError:
|
||||
self.dbg("Unhandled: %s" % (op, args, text))
|
||||
return
|
||||
method(args, text)
|
||||
|
||||
|
||||
class Recipient:
|
||||
"""Abstract recipient object"""
|
||||
|
||||
def __init__(self, interface, name):
|
||||
self._interface = interface
|
||||
self._name = name
|
||||
|
||||
def __repr__(self):
|
||||
return 'Recipient(%s)' % self.name()
|
||||
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
def is_channel(self):
|
||||
return False
|
||||
|
||||
def write(self, cmd, addl):
|
||||
"""Write a raw IRC command to our interface"""
|
||||
|
||||
self._interface.write(cmd, addl)
|
||||
|
||||
def cmd(self, cmd, text):
|
||||
"""Send a command to ourself"""
|
||||
|
||||
self.write([cmd, self._name], text)
|
||||
|
||||
def msg(self, text):
|
||||
"""Tell the recipient something"""
|
||||
|
||||
self.cmd("PRIVMSG", text)
|
||||
|
||||
def notice(self, text):
|
||||
"""Send a notice to the recipient"""
|
||||
|
||||
self.cmd("NOTICE", text)
|
||||
|
||||
def ctcp(self, command, text):
|
||||
"""Send a CTCP command to the recipient"""
|
||||
|
||||
return self.msg("\001%s %s\001" % (command.upper(), text))
|
||||
|
||||
def act(self, text):
|
||||
"""Send an action to the recipient"""
|
||||
|
||||
return self.ctcp("ACTION", text)
|
||||
|
||||
def cnotice(self, command, text):
|
||||
"""Send a CTCP notice to the recipient"""
|
||||
|
||||
return self.notice("\001%s %s\001" % (command.upper(), text))
|
||||
|
||||
class Channel(Recipient):
|
||||
def __repr__(self):
|
||||
return 'Channel(%s)' % self.name()
|
||||
|
||||
def is_channel(self):
|
||||
return True
|
||||
|
||||
class User(Recipient):
|
||||
def __init__(self, interface, name, user, host, op=False):
|
||||
Recipient.__init__(self, interface, name)
|
||||
self.user = user
|
||||
self.host = host
|
||||
self.op = op
|
||||
|
||||
def __repr__(self):
|
||||
return 'User(%s, %s, %s)' % (self.name(), self.user, self.host)
|
||||
|
||||
def recipient(interface, name):
|
||||
if name[0] in ["&", "#"]:
|
||||
return Channel(interface, name)
|
||||
else:
|
||||
return User(interface, name, None, None)
|
||||
|
||||
class SmartIRCHandler(IRCHandler):
|
||||
"""This is like the IRCHandler, except it creates Recipient objects
|
||||
for IRC messages. The intent is to make it easier to write stuff
|
||||
without knowledge of the IRC protocol.
|
||||
|
||||
"""
|
||||
|
||||
def recipient(self, name):
|
||||
return recipient(self, name)
|
||||
|
||||
def err(self, exception):
|
||||
if self.debug:
|
||||
traceback.print_exception(*exception)
|
||||
|
||||
def handle(self, op, args, text):
|
||||
"""Parse more, creating objects and stuff
|
||||
|
||||
makes a call to self.handle_op(sender, forum, addl)
|
||||
|
||||
sender is always a Recipient object; if you want to reply
|
||||
privately, you can send your reply to sender.
|
||||
|
||||
forum is a Recipient object corresponding with the forum over
|
||||
which the message was carried. For user-to-user PRIVMSG and
|
||||
NOTICE commands, this is the same as sender. For those same
|
||||
commands sent to a channel, it is the channel. Thus, you can
|
||||
always send a reply to forum, and it will be sent back in an
|
||||
appropriate manner (ie. the way you expect).
|
||||
|
||||
addl is a tuple, containing additional information which might
|
||||
be relelvant. Here's what it will contain, based on the server
|
||||
operation:
|
||||
|
||||
op | addl
|
||||
---------+----------------
|
||||
PRIVMSG | text of the message
|
||||
NOTICE | text of the notice
|
||||
CPRIVMSG | CTCP command, text of the command
|
||||
CNOTICE | CTCP response, text of the response
|
||||
KICK * | victim of kick, kick text
|
||||
MODE * | all mode args
|
||||
JOIN * | empty
|
||||
PART * | empty
|
||||
QUIT | quit message
|
||||
PING | ping text
|
||||
NICK ! | old nickname
|
||||
others | all arguments; text is last element
|
||||
|
||||
* The forum in these items is the channel to which the action
|
||||
pertains.
|
||||
! The sender for the NICK command is the *new* nickname. This
|
||||
is so you can send messages to the sender object and they'll
|
||||
go to the right place.
|
||||
"""
|
||||
|
||||
try:
|
||||
sender = User(self, *unpack_nuhost(args))
|
||||
except ValueError:
|
||||
sender = None
|
||||
forum = None
|
||||
addl = ()
|
||||
|
||||
if op in ("PRIVMSG", "NOTICE"):
|
||||
# PRIVMSG ['neale!~user@127.0.0.1', 'PRIVMSG', '#hydra'] firebot, foo
|
||||
# PRIVMSG ['neale!~user@127.0.0.1', 'PRIVMSG', 'firebot'] firebot, foo
|
||||
try:
|
||||
if args[2][0] in '#&':
|
||||
forum = self.recipient(args[2])
|
||||
else:
|
||||
forum = sender
|
||||
addl = (text,)
|
||||
except IndexError:
|
||||
addl = (text, args[1])
|
||||
elif op in ("CPRIVMSG", "CNOTICE"):
|
||||
forum = self.recipient(args[2])
|
||||
splits = text.split(" ")
|
||||
if splits[0] == "DCC":
|
||||
op = "DC" + op
|
||||
addl = (splits[1],) + tuple(splits[2:])
|
||||
else:
|
||||
addl = (splits[0],) + tuple(splits[1:])
|
||||
elif op in ("KICK",):
|
||||
forum = self.recipient(args[2])
|
||||
addl = (self.recipient(args[3]), text)
|
||||
elif op in ("MODE",):
|
||||
forum = self.recipient(args[2])
|
||||
addl = args[3:]
|
||||
elif op in ("JOIN", "PART"):
|
||||
try:
|
||||
forum = self.recipient(args[2])
|
||||
except IndexError:
|
||||
forum = self.recipient(text)
|
||||
elif op in ("QUIT",):
|
||||
addl = (text,)
|
||||
elif op in ("PING", "PONG"):
|
||||
# PING ['PING'] us.boogernet.org.
|
||||
# PONG ['irc.foonet.com', 'PONG', 'irc.foonet.com'] 1114199424
|
||||
addl = (text,)
|
||||
elif op in ("NICK",):
|
||||
# NICK ['brad!~brad@10.168.2.33', 'NICK'] bradaway
|
||||
#
|
||||
# The sender is the new nickname here, in case you want to
|
||||
# send something to the sender.
|
||||
|
||||
# Apparently there are two different standards for this
|
||||
# command.
|
||||
if text:
|
||||
sender = self.recipient(text)
|
||||
else:
|
||||
sender = self.recipient(args[2])
|
||||
addl = (unpack_nuhost(args)[0],)
|
||||
elif op in ("INVITE",):
|
||||
# INVITE [u'pflarr!~pflarr@www.clanspum.net', u'INVITE', u'gallium', u'#mysterious']
|
||||
# INVITE [u'pflarr!~pflarr@www.clanspum.net', u'INVITE', u'gallium'] #mysterious
|
||||
if len(args) > 3:
|
||||
forum = self.recipient(args[3])
|
||||
else:
|
||||
forum = self.recipient(text)
|
||||
else:
|
||||
try:
|
||||
int(op)
|
||||
except ValueError:
|
||||
self.dbg("WARNING: unknown server code: %s" % op)
|
||||
addl = tuple(args[3:]) + (text,)
|
||||
|
||||
try:
|
||||
self.handle_cooked(op, sender, forum, addl)
|
||||
except SystemExit:
|
||||
raise
|
||||
except:
|
||||
self.err(sys.exc_info())
|
||||
|
||||
def handle_cooked(self, op, sender, forum, addl):
|
||||
try:
|
||||
func = getattr(self, 'cmd_' + op.lower())
|
||||
except AttributeError:
|
||||
self.unhandled(op, sender, forum, addl)
|
||||
return
|
||||
func(sender, forum, addl)
|
||||
|
||||
def cmd_ping(self, sender, forum, addl):
|
||||
self.write(['PONG'], addl[0])
|
||||
|
||||
def unhandled(self, op, sender, forum, addl):
|
||||
"""Handle all the stuff that had no handler.
|
||||
|
||||
This is a special handler in that it also gets the server code
|
||||
as the first argument.
|
||||
|
||||
"""
|
||||
|
||||
self.dbg("unhandled: %s" % ((op, sender, forum, addl),))
|
||||
|
||||
|
||||
class Bot(SmartIRCHandler):
|
||||
"""A simple bot.
|
||||
|
||||
This automatically joins the channels you pass to the constructor,
|
||||
tries to use one of the nicks provided, and reconnects if it gets
|
||||
booted. You can use this as a base for more sophisticated bots.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, host, nicks, gecos, channels):
|
||||
self.nicks = nicks
|
||||
self.channels = channels
|
||||
self.waiting = True
|
||||
self._spool = []
|
||||
SmartIRCHandler.__init__(self, host, nicks[0], gecos)
|
||||
|
||||
def despool(self, target, lines):
|
||||
"""Slowly despool a bunch of lines to a target
|
||||
|
||||
Since the IRC server will block all output if we send it too
|
||||
fast, use this to send large multi-line responses.
|
||||
|
||||
"""
|
||||
|
||||
self._spool.append((target, list(lines)))
|
||||
|
||||
def heartbeat(self):
|
||||
SmartIRCHandler.heartbeat(self)
|
||||
|
||||
# Despool data
|
||||
if self._spool:
|
||||
# Take the first one on the queue, and put it on the end
|
||||
which = self._spool[0]
|
||||
del self._spool[0]
|
||||
self._spool.append(which)
|
||||
|
||||
# Despool a line
|
||||
target, lines = which
|
||||
if lines:
|
||||
line = lines[0]
|
||||
target.msg(line)
|
||||
del lines[0]
|
||||
else:
|
||||
self._spool.remove(which)
|
||||
|
||||
def announce(self, text):
|
||||
for c in self.channels:
|
||||
self.write(['PRIVMSG', c], text)
|
||||
|
||||
def err(self, exception):
|
||||
SmartIRCHandler.err(self, exception)
|
||||
self.announce('*bzert*')
|
||||
|
||||
def cmd_001(self, sender, forum, addl):
|
||||
for c in self.channels:
|
||||
self.write(['JOIN'], c)
|
||||
|
||||
def writable(self):
|
||||
if not self.waiting:
|
||||
return asynchat.async_chat.writable(self)
|
||||
else:
|
||||
return False
|
||||
|
||||
def write(self, *args):
|
||||
SmartIRCHandler.write(self, *args)
|
||||
|
||||
def close(self, final=False):
|
||||
SmartIRCHandler.close(self)
|
||||
if not final:
|
||||
self.dbg("Connection closed, reconnecting...")
|
||||
self.waiting = True
|
||||
self.connected = 0
|
||||
# Wait a bit and reconnect
|
||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.add_timer(23, lambda : self.connect(self.host))
|
||||
|
||||
def handle_close(self):
|
||||
self.close()
|
||||
|
||||
|
||||
##
|
||||
## Miscellaneous IRC functions
|
||||
##
|
||||
|
||||
def unpack_nuhost(nuhost):
|
||||
"""Unpack nick!user@host
|
||||
|
||||
Frequently, the first argument in a server message is in
|
||||
nick!user@host format. You can just pass your whole argument list
|
||||
to this function and get back a tuple containing:
|
||||
|
||||
(nick, user, host)
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
[nick, uhost] = nuhost[0].split('!', 1)
|
||||
[user, host] = uhost.split('@', 1)
|
||||
except ValueError:
|
||||
raise ValueError("not in nick!user@host format")
|
||||
return (nick, user, host)
|
||||
|
||||
def run_forever(timeout=2.0):
|
||||
"""Run your clients forever.
|
||||
|
||||
Just a handy front-end to asyncore.loop, so you don't have to import
|
||||
asyncore yourself.
|
||||
|
||||
"""
|
||||
|
||||
asyncore.loop(timeout)
|
|
@ -0,0 +1,147 @@
|
|||
#! /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()
|
|
@ -0,0 +1,3 @@
|
|||
#! /bin/sh
|
||||
|
||||
exec logger -t kevin
|
|
@ -0,0 +1,5 @@
|
|||
#! /bin/sh
|
||||
|
||||
[ -f /var/lib/ctf/disabled/kevin ] && exit 0
|
||||
|
||||
exec envuidgid ctf /usr/lib/ctf/kevin.py --victims=/var/lib/ctf/kevin/victims.txt --tokens=/var/lib/ctf/kevin/tokens
|
|
@ -0,0 +1,4 @@
|
|||
Michael Smith (505)555-1212 SMS OK
|
||||
Janet Berger (505)555-7382
|
||||
Dimwit Flathead dimwit on irc.efnet.net
|
||||
Jacob Schmidt jacob@dirtbags.net
|
Loading…
Reference in New Issue