class Puppyscript(db.Model): """ Puppyscript model contains the following parameters: name = name of javascript file. code = code that will be executed when a sleepy puppy payload is executed notes = notes Puppyscript is many to many with payload. """ __tablename__ = 'puppyscript' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(500), nullable=False) code = db.Column(db.Text(), nullable=False) notes = db.Column(db.String(500)) payloads = db.relationship("Payload", backref='puppyscript', secondary=taxonomy) def show_puppyscript_ids(self): """ Print puppyscripts as a list of Puppyscript ids. """ return [i.id for i in self.Puppyscripts] def show_puppyscript_names(self): """ Print puppyscripts as a string of Puppyscript ids. """ return ','.join([i.name for i in self.Puppyscripts]) def as_dict(self, payload=1, assessment=1): """ Return Assessment model as JSON object If you need to expose additional variables to your Puppyscript templates, this is the place to do it. """ js_dict = {} js_dict['name'] = self.name js_dict['code'] = render_template_string( self.code, hostname=app.config['CALLBACK_HOSTNAME'], callback_protocol=app.config.get('CALLBACK_PROTOCOL', 'https'), payload=payload, assessment=assessment) return js_dict def __repr__(self): return str(self.name)
class Capture(db.Model): """ Capture model contains the following parameters: assessment = assessment name(s) associated with capture url = url where cross-site scripting was triggered referrer = referrer string of request cookies = any cookies not containing the HttpOnly flag from request user_agent = user-agent string payload = to be removed screenshot = screenshot identifier pub_date = Date with which the capture was received """ __tablename__ = 'captures' id = db.Column(db.Integer, primary_key=True) assessment = db.Column(db.String(200)) url = db.Column(db.Text(), unique=False) referrer = db.Column(db.Text(), unique=False) cookies = db.Column(db.Text(), unique=False) user_agent = db.Column(db.Text(), unique=False) payload = db.Column(db.Integer) screenshot = db.Column(db.String(20), unique=False) pub_date = db.Column(db.String(512), unique=False) dom = db.Column(db.Text(), unique=False) def as_dict(self): """Return Capture model as JSON object""" return {c.name: getattr(self, c.name) for c in self.__table__.columns} def __init__(self, assessment, url, referrer, cookies, user_agent, payload, screenshot, dom, pub_date=None): self.assessment = assessment self.url = url self.referrer = referrer self.cookies = cookies self.user_agent = user_agent self.payload = payload self.screenshot = screenshot self.dom = bs(dom).prettify() # Set datetime when a capture is received if pub_date is None: pub_date = str(datetime.datetime.now()) self.pub_date = pub_date def __repr__(self): return '<Uri %r>' % self.url
class Payload(db.Model): """ Payload model contains the following parameters: payload = payload used in xss injection testing. url = url where payload is submitted to method = method of request to faciliate xss testing paramater = parameter which contains the payload notes = notes Payload provides primary key to Capture, which stores a xss capture. """ __tablename__ = 'payloads' id = db.Column(db.Integer, primary_key=True) payload = db.Column(db.String(500)) notes = db.Column(db.String(200)) ordering = db.Column(db.String(200)) # When payloads are deleted, # cascade the delete and remove associated captures # captures = db.relationship("Capture", cascade="all,delete", backref="payloads") # collection = db.relationship("GenericCollector", cascade="all,delete", backref="payloads") def as_dict(self): """ Return JSON API object """ puppyscripts = [] for item in self.ordering.split(','): my_js = Puppyscript.query.filter_by(id=int(item)).first() puppyscripts.append(my_js.name) payload_dict = { "id": self.id, "puppyscripts": puppyscripts, "payload": self.payload, "notes": self.notes } return payload_dict def __repr__(self): return str(self.id)
class Payload(db.Model): """ Payload model contains the following parameters: payload = payload used in xss injection testing. url = url where payload is submitted to method = method of request to faciliate xss testing paramater = parameter which contains the payload notes = notes Payload provides primary key to Capture, which stores a xss capture. """ __tablename__ = 'payloads' id = db.Column(db.Integer, primary_key=True) payload = db.Column(db.String(500)) url = db.Column(db.String(500)) method = db.Column(db.String(12)) parameter = db.Column(db.String(50)) notes = db.Column(db.String(200)) assessment = db.Column(db.Integer, db.ForeignKey('assessments.id')) # When payloads are deleted, cascade the delete and remove associated captures captures = db.relationship("Capture", cascade="all,delete", backref="payloads") def as_dict(self): """ Return JSON API object """ # Replace $1 template with configured hostname payload = self.payload.replace( "$1", "//{}/x?u={}".format(app.config['HOSTNAME'], str(self.id))) payload_dict = { "id": self.id, "assessments": [i.as_dict() for i in self.assessments], "payload": payload, "url": self.url, "method": self.method, "parameter": self.parameter, "notes": self.notes } return payload_dict def show_assessment_ids(self): """ Print payload assessments as a list of assessment ids. """ return [i.id for i in self.assessments] def show_assessment_names(self): """ Print payload assessments as a string of assessment names. """ return ','.join([i.name for i in self.assessments])
class AccessLog(db.Model): """ Access Log records GET requests to payloads. This can be helpful for payloads that are not executing due to namespace conflicts, client side controls, or other unexpected issues. """ id = db.Column(db.Integer, primary_key=True) payload = db.Column(db.Integer()) assessment = db.Column(db.String(512)) pub_date = db.Column(db.String(512), unique=False) referrer = db.Column(db.String(1024)) user_agent = db.Column(db.String(512)) ip_address = db.Column(db.String(80)) def __init__(self, payload, assessment, referrer, user_agent, ip_address, pub_date=None): self.payload = payload self.assessment = assessment self.referrer = referrer self.user_agent = user_agent self.ip_address = ip_address if pub_date is None: pub_date = str(datetime.datetime.now()) self.pub_date = pub_date def as_dict(self): """Return Access Log model as JSON object""" return {c.name: getattr(self, c.name) for c in self.__table__.columns}
class User(db.Model): """ User model contains the following parameters used for email notifications: email = email address to send capture notifications to. assessments = list of assessments the email address will recieve captures for. Has an association of assessments with users. """ __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(100)) assessments = relationship(Assessment, secondary=user_associations, backref="users") def __repr__(self): return self.email
class Assessment(db.Model): """ Assessemt model contains the following parameters: name = name of the assessment you are working on. payloads = payloads assocaited with the assessment """ __tablename__ = 'assessments' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(500)) payloads = db.relationship("Payload", secondary=assessment_associations, backref="assessments") def as_dict(self): """Return Assessment model as JSON object""" return {c.name: getattr(self, c.name) for c in self.__table__.columns} def __repr__(self): return str(self.name)
class Assessment(db.Model): """ Assessemt model contains the following parameters: name = name of the assessment you are working on. payloads = payloads assocaited with the assessment """ __tablename__ = 'assessments' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(500)) snooze = db.Column(db.Boolean) run_once = db.Column(db.Boolean) access_log_enabled = db.Column(db.Boolean) def as_dict(self): """Return Assessment model as JSON object""" return {c.name: getattr(self, c.name) for c in self.__table__.columns} def __repr__(self): return str(self.name)
class GenericCollector(db.Model): """ Puppyscript model contains the following parameters: name = name of javascript file. code = code that will be executed when a sleepy puppy payload is executed notes = notes Puppyscript is many to many with payload. """ __tablename__ = 'generic_collector' id = db.Column(db.Integer, primary_key=True) payload = db.Column(db.Integer, db.ForeignKey('payloads.id')) assessment = db.Column(db.String(200)) puppyscript_name = db.Column(db.String(500), nullable=False) data = db.Column(db.Text()) url = db.Column(db.Text(), unique=False) referrer = db.Column(db.Text(), unique=False) pub_date = db.Column(db.String(512), unique=False) def as_dict(self): """Return Capture model as JSON object""" return {c.name: getattr(self, c.name) for c in self.__table__.columns} def __init__(self, payload, assessment, puppyscript_name, url, referrer, data, pub_date=None): self.payload = payload self.assessment = assessment self.puppyscript_name = puppyscript_name self.url = url self.referrer = referrer self.data = data # Set datetime when a capture is received if pub_date is None: pub_date = str(datetime.datetime.now()) self.pub_date = pub_date def __repr__(self): return str(self.payload)
class Admin(db.Model): """ Admin model contols how users autheticate to Sleepy Puppy The model also automatically generates API keys for administrators. login = account for authetication password = self explanatory api_key = 40 character urandom hex encoded string """ id = db.Column(db.Integer, primary_key=True) login = db.Column(db.String(80)) password = db.Column(db.String(64)) api_key = db.Column(db.String(40)) # Integrate Admin model with Flask Login def is_authenticated(self): return True def is_active(self): return True def is_anonymous(self): return False def get_id(self): return self.id def __init__(self, login="", password=""): self.login = login self.password = password self.api_key = urandom(40).encode('hex') # Required for administrative interface def __unicode__(self): return self.username