Advertisement
Guest User

Untitled

a guest
Jun 17th, 2017
238
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.41 KB | None | 0 0
  1. """Main application."""
  2.  
  3. import base64
  4. import hashlib
  5. import hmac
  6. import logging
  7. import os
  8. import textwrap
  9. import time
  10. import urllib
  11. import webapp2
  12.  
  13. from google.appengine.api import datastore_errors
  14. from google.appengine.api import memcache
  15. from google.appengine.ext import ndb
  16.  
  17. HANDICAP = 10 * 2
  18.  
  19. FLAG_LENGTH = 64
  20.  
  21. BAN = 30 * 60 / HANDICAP
  22.  
  23.  
  24. class QUOTAS(object):
  25.   HITS = 13
  26.   ERRS = 2
  27.  
  28.  
  29. class WINDOWS(object):
  30.   HITS = 10 * 60 / HANDICAP
  31.   ERRS = 10 * 60 / HANDICAP
  32.   MAX = FLAG_LENGTH * (5 + 10 * 60 / HANDICAP)
  33.  
  34.  
  35. class QuotaModel(ndb.Model):
  36.   start = ndb.FloatProperty()
  37.   banned = ndb.FloatProperty()
  38.   hits = ndb.FloatProperty(repeated=True)
  39.   errs = ndb.FloatProperty(repeated=True)
  40.  
  41.  
  42. class UserModel(ndb.Model):
  43.   user = ndb.StringProperty()
  44.   password = ndb.StringProperty()
  45.  
  46.  
  47. class Key(ndb.Model):
  48.   secret = ndb.StringProperty()
  49.  
  50.  
  51. class Login(webapp2.RequestHandler):
  52.   """Login servlet with abuse detection signals."""
  53.   key = Key.get_or_insert("key", namespace="default").secret.encode("utf-8")
  54.  
  55.   def PrintQuotaError(self):
  56.     self.response.write(
  57.         textwrap.dedent("""
  58.      <h1>Abuse detection system triggered!</h1>
  59.      <h3>You have been banned for %s seconds.</h3>
  60.      <p>
  61.        <b>
  62.          If you believe this is a mistake, contact your system administrator.
  63.        </b>
  64.        Possible reasons include:
  65.        <ul>
  66.          <li>Generating too many errors too quickly
  67.            <!--DEBUG: %s queries / %s seconds--></li>
  68.          <li>Making too many requests too quickly
  69.            <!--DEBUG: %s queries / %s seconds--></li>
  70.          <li>Spending too much time without authenticating
  71.            <!--DEBUG: %s seconds--></li>
  72.        </ul>
  73.      </p>
  74.    """) % (BAN, QUOTAS.ERRS, WINDOWS.ERRS, QUOTAS.HITS, WINDOWS.HITS,
  75.             WINDOWS.MAX))
  76.     self.response.set_status(400)
  77.  
  78.   @ndb.transactional
  79.   def dispatch(self):
  80.     try:
  81.       hostname = self.request.host.split("-")[0]
  82.       ban = memcache.get("ban:%s" % hostname)
  83.       if ban and ban > time.time():
  84.         return self.PrintQuotaError()
  85.       flag = "CTF{%s-%s}" % (
  86.           hostname, base64.b64encode(hmac.new(
  87.               self.key, hostname, hashlib.sha512
  88.           ).digest()[:(6*FLAG_LENGTH/8)], "-_"))
  89.       self.quota = QuotaModel.get_or_insert(hostname, start=time.time())
  90.       self.user = UserModel.get_or_insert(
  91.           "user", parent=self.quota.key, user="admin", password=flag)
  92.       time_limit = self.quota.start + WINDOWS.MAX
  93.       if self.quota.banned > time.time() or time_limit < time.time():
  94.         return self.PrintQuotaError()
  95.       hit_window = time.time() - WINDOWS.HITS
  96.       self.quota.hits = [hit for hit in self.quota.hits if hit > hit_window]
  97.       err_window = time.time() - WINDOWS.ERRS
  98.       self.quota.errs = [err for err in self.quota.errs if err > err_window]
  99.     except Exception as e:  # pylint: disable=broad-except
  100.       logging.exception("Dispatch error: %s", e)
  101.       self.abort(500)
  102.     try:
  103.       self.quota.hits.append(time.time())
  104.       super(Login, self).dispatch()
  105.     except datastore_errors.TransactionFailedError:
  106.       raise
  107.     except Exception as e:  # pylint: disable=broad-except
  108.       self.quota.errs.append(time.time())
  109.       logging.exception("Handler error: %s", e)
  110.       self.redirect("/index.html?e=%s" % urllib.quote(str(e)))
  111.     finally:
  112.       if (len(self.quota.hits) > QUOTAS.HITS or
  113.           len(self.quota.errs) > QUOTAS.ERRS):
  114.         self.quota.banned = time.time() + BAN
  115.         memcache.add(key="ban:%s" % hostname, value=self.quota.banned, time=BAN)
  116.       self.quota.put()
  117.  
  118.   def post(self):
  119.     sql = "SELECT password FROM UserModel WHERE ANCESTOR IS :1 AND user = '%s'"
  120.     query = ndb.gql(sql % self.request.get("user"), self.quota.key)
  121.     result = query.fetch(1)
  122.     if not result:
  123.       self.redirect("/index.html?e=%s" % urllib.quote("Wrong username"))
  124.     elif result[0].password != self.request.get("password"):
  125.       raise Exception("Wrong password")
  126.     else:
  127.       self.response.write(self.request.get("password"))
  128.  
  129.   def get(self):
  130.     if self.request.host.startswith("qu0t45"):
  131.       self.redirect("/")
  132.     else:
  133.       self.redirect("//qu0t45%swww-%s/login" %
  134.                     (base64.b64encode(os.urandom(6 * 16 / 8), "__"),
  135.                      "abuse.web.ctfcompetition.com"))
  136.  
  137.  
  138. app = webapp2.WSGIApplication(
  139.     [
  140.         ("/login", Login),
  141.     ], debug=False)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement