Initial commit

Paul Wagener 11 years ago
commit 904cf04b4f
  1. 4
      .gitignore
  2. 10
      manage.py
  3. 0
      quiz/__init__.py
  4. 4
      quiz/admin.py
  5. 14
      quiz/models.py
  6. 3
      quiz/tests.py
  7. 3
      quiz/views.py
  8. 0
      securityquiz/__init__.py
  9. 10
      securityquiz/secrets.py.template
  10. 102
      securityquiz/settings.py
  11. 13
      securityquiz/urls.py
  12. 20
      securityquiz/wsgi.py
  13. 9
      static/css/bootstrap.min.css
  14. 29
      static/css/style.css
  15. BIN
      static/img/bank_schema.png
  16. BIN
      static/img/poespas.png
  17. BIN
      static/img/webshop_schema.png
  18. 139
      templates/index.html
  19. 84
      views.py

4
.gitignore vendored

@ -0,0 +1,4 @@
.DS_Store
*.pyc
db.sqlite3
securityquiz/secrets.py

@ -0,0 +1,10 @@
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "securityquiz.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)

@ -0,0 +1,4 @@
from django.contrib import admin
import models
admin.site.register(models.Answer)

@ -0,0 +1,14 @@
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Answer(models.Model):
user = models.ForeignKey(User)
question = models.CharField(max_length=128)
string = models.TextField()
class Meta:
unique_together = ('user', 'question')
def __str__(self):
return self.question + ": " + self.string

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

@ -0,0 +1,10 @@
DB_NAME = ''
DB_USER = ''
DB_PASSWORD = ''
# Can be obtained at https://publicapi.avans.nl/newconsumer/
AVANS_KEY = ''
AVANS_SECRET = ''
SECRET_KEY = '

@ -0,0 +1,102 @@
"""
Django settings for securityquiz project.
For more information on this file, see
https://docs.djangoproject.com/en/1.6/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.6/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os, secrets, sys
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = secrets.SECRET_KEY
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
TEMPLATE_DEBUG = False
if 'runserver' in sys.argv:
DEBUG = True
TEMPLATE_DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'quiz'
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
ROOT_URLCONF = 'securityquiz.urls'
WSGI_APPLICATION = 'securityquiz.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.6/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': secrets.DB_NAME,
'USER': secrets.DB_USER,
'PASSWORD': secrets.DB_PASSWORD,
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
# Internationalization
# https://docs.djangoproject.com/en/1.6/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.6/howto/static-files/
STATIC_URL = '/static/'
PROJECT_PATH = os.path.realpath(os.path.dirname(__file__)) + '/..'
MEDIA_ROOT = PROJECT_PATH + '/media/'
# Additional locations of static files
TEMPLATE_DIRS = (
PROJECT_PATH + '/templates'
)
STATICFILES_DIRS = (
PROJECT_PATH + '/static',
)

@ -0,0 +1,13 @@
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Examples:
url(r'^$', 'views.home', name='home'),
url(r'^callback$', 'views.avans_callback'),
url(r'^logout$', 'views.avans_logout'),
url(r'^admin/', include(admin.site.urls)),
)

@ -0,0 +1,20 @@
"""
WSGI config for securityquiz project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/
"""
import os, sys
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "securityquiz.settings")
path = '/var/www/security.aardappelschilmesje.nl'
if path not in sys.path:
sys.path.append(path)
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

File diff suppressed because one or more lines are too long

@ -0,0 +1,29 @@
body {
background-color: #e8eef7;
}
form {
display: block;
margin: 0.5em auto 2.5em;
padding: 1em;
width: 45em;
background-color: white;
border: 1px solid #ccc;
}
.question {
margin: 3em;
}
.question-string {
font-weight: bold;
}
textarea {
width: 75%;
height: 7em;
}
input {
width: 75%;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

@ -0,0 +1,139 @@
<!DOCTYPE html>
<html>
<head>
<title>Security 1</title>
<link href="/static/css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="/static/css/style.css" rel="stylesheet" type="text/css">
</head>
<body>
Ingelogd als <strong>{{ user }}</strong>. <a href="/logout">Uitloggen</a>
<form method="POST">
{% csrf_token %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-info">{{ message }}</div>
{% endfor %}
{% endif %}
<h1>SQL Injection</h1>
<h2>Bank</h2>
<p>Bob is al jaren trouwe klant en gebruikt de site dagelijks om te kijken hoeveel geld er op zijn rekening staat. Achter op zijn poespas pas heeft hij met een viltstift „Niet vergeten: Bob 123456” geschreven. Gebruik de site om te kijken hoeveel geld Bob op zijn rekening heeft staan.</p>
<p>Alice is ook klant van de bank en wij willen ook graag weten hoeveel geld zij op haar rekening heeft staan. We gaan daarom haar rekening hacken met behulp van SQL.</p>
<p>Lees op deze website de verschillende SQL injectie technieken: <a href="http://www.sqltutorial.nl/artikelen/sqlinjections/soorten_sql_injection.html">http://www.sqltutorial.nl/artikelen/sqlinjections/soorten_sql_injection.html</a>
<p>Ga nu aan de slag en hack het account van Alice!</p>
<p><strong>Hint 1:</strong> Kijk eerst eens wat er gebeurt als je inlogt met een enkele quote in de gebruikersnaam (').</p>
<p><strong>Hint 2:</strong> Met -- (twee streepjes gevolgd door een spatie) kan je commentaar achter een regel zetten in SQL.</p>
<p><strong>Hint 3:</strong> Bekijk de broncode achter de site: <a href="https://github.com/Avans/Security-Workshop/blob/master/bank/index.php#L51">https://github.com/Avans/Security-Workshop/blob/master/bank/index.php#L51</a>
De code beschouwt een gebruiker als ingelogd als de query een rij uit de gebruikerstabel teruggeeft. Manipuleer de query zodat deze de gegevens van Alice teruggeeft, zonder dat je het wachtwoord hoeft te weten.</p>
<img src="/static/img/poespas.png" style="width: 70%">
<div class="question">
<span class="question-string">Hoeveel geld heeft Alice op haar rekening staan?</span>
<div class="points"><span class="question-points">5</span> punten</div>
<input class="question-input" name="answer_sql_money_alice" value="{{ answers.answer_sql_money_alice }}"></input>
</div>
<div class="question">
<span class="question-string">Wat heb je als gebruikersnaam ingevuld om zonder wachtwoord in te loggen als Alice?</span>
<div class="points"><span class="question-points">10</span> punten</div>
<input class="question-input" name="answer_sql_username_alice" value="{{answers.answer_sql_username_alice}}"></input>
</div>
<p>Waarschijnlijk heb je SQL commentaar (--) gebruikt in de vorige opdracht. Voer nu een andere SQL injectie uit door alleen het wachtwoord veld te gebruiken. Gebruik niet de SQL commentaar techniek maar verander nu de logica van de query (AND, OR) zodat er niet meer gecontroleerd wordt op het wachtwoord.</p>
<div class="question">
<span class="question-string">Met welk 'wachtwoord' lukt het altijd om in te loggen?</span>
<div class="points"><span class="question-points">10</span> punten</div>
<input class="question-input" name="answer_sql_always_password" value="{{answers.answer_sql_always_password}}"></input>
</div>
<div class="question">
<span class="question-string">Bekijk de PHP broncode en los het probleem op. Type de regels code die je verbeterd hebt in onderstaand tekstveld. (denk terug aan je mysql WEBS2 practicum)</span>
<div class="points"><span class="question-points">15</span> punten</div>
<textarea class="question-input" name="answer_sql_fix_query">{{answers.answer_sql_fix_query}}</textarea>
</div>
<p>Open de "Bank (multi_query)" pagina. Op deze pagina werken ook SQL Injection technieken die gebruik maken van meerdere queries (queries gescheiden door een ; ).</p>
<div class="question">
<span class="question-string">Met welke gebruikersnaam kan je (alleen) Bob miljonair maken? (Het saldo staat in een kolom "balans")</span>
<div class="points"><span class="question-points">10</span> punten</div>
<input class="question-input" name="answer_sql_bob_millionaire" value="{{answers.answer_sql_bob_millionaire}}"></input>
</div>
<img src="/static/img/bank_schema.png">
<h2>Webshop</h2>
<p>Inloggen in een ander account is leuk. Maar echte hackers stelen kostbare data uit een website. Dat gaan we nu doen met de webshop van Leaky's.</p>
<p>Je kan de broncode vinden op: <a href="https://github.com/Avans/Security-Workshop/blob/master/webshop/product_detail.php#L62">https://github.com/Avans/Security-Workshop/blob/master/webshop/product_detail.php#L62</a>
<p>Zoals je ziet hebben ze hier gebruik gemaakt van mysql_real_escape_string(). Je kan dus geen gebruik meer maken van rare quotejes om de query aan te passen.</p>
<p>Maar met behulp van de UNION techniek kunnen we alsnog data stelen uit de website. Lees in de tutorial hoe je deze techniek kan toepassen om data uit andere tabellen te lezen.</p>
<p>In de database is er nog een tabel "gebruikers" waar gebruikersnamen en wachtwoorden in staan. Steel deze informatie uit de database!</p>
<p><strong>Hint:</strong> Verander het cijfer in de url van de product_details.php pagina in de letter 'a' zodat je de query kan lezen.</p>
<img src="/static/img/webshop_schema.png">
<div class="question">
<span class="question-string">Wat zijn de gebruikersnamen en wachtwoorden van de 4 gebruikers in de database? (de id's van de gebruikers zijn 1,2,3 en 4)</span>
<div class="points"><span class="question-points">5</span> punten</div>
<textarea class="question-input" name="answer_sql_usernames_passwords_webshop">{{answers.answer_sql_usernames_passwords_webshop}}</textarea>
</div>
<div class="question">
<span class="question-string">Met welke URL heb je het wachtwoord van Marco achterhaald?</span>
<div class="points"><span class="question-points">10</span> punten</div>
<input class="question-input" name="answer_sql_url_marco_password" value="{{answers.answer_sql_url_marco_password}}"></input>
</div>
<div class="question">
<span class="question-string">Bekijk de broncode en verbeter deze zodat je geen SQL injection meer kan gebruiken.</span>
<div class="points"><span class="question-points">15</span> punten</div>
<textarea class="question-input" name="answer_sql_fix_injection_webshop">{{answers.answer_sql_fix_injection_webshop}}</textarea>
</div>
<p>Open de pagina "Webshop (replace)". De maker van deze website heeft extra maatregelen genomen en woorden als SELECT en UNION uit de invoer gefilterd.</p>
<p><strong>Hint:</strong> SELSELECTECT</p>
<div class="question">
<span class="question-string">Met welke URL kan je nu het wachtwoord van Marco achterhalen?</span>
<div class="points"><span class="question-points">5</span> punten</div>
<input class="question-input" name="answer_sql_url_marco_replace_password" value="{{answers.answer_sql_url_marco_replace_password}}"></input>
</div>
<h2>Hacking Lab</h2>
<p>Ga aan de slag met hacking-lab.com. Volg de instructies op de site en begin met de A1 Injection opdracht. Deze staat in de OWASP Top Ten event.</p>
<div class="question">
<span class="question-string">Wat is het creditcardnummer van "hacker10"?</span>
<div class="points"><span class="question-points">5</span> punten</div>
<input class="question-input" name="answer_sql_hackinglab_creditcardnumber" value="{{answers.answer_sql_hackinglab_creditcardnumber}}"></input>
</div>
<div class="question">
<span class="question-string">Beschrijf hoe je de aanval hebt uitgevoerd.</span>
<div class="points"><span class="question-points">10</span> punten</div>
<textarea class="question-input" name="answer_sql_hackinglab_explain">{{answers.answer_sql_hackinglab_explain}}</textarea>
</div>
<button class="btn-primary" type="submit">Opslaan</button>
</form>
<body>
</html>

@ -0,0 +1,84 @@
from django.shortcuts import render
from django.http import HttpResponse
from django.http import HttpResponseRedirect
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User
from django.contrib import messages
from quiz.models import Answer
import oauth2 as oauth, cgi, json
import securityquiz.secrets as secrets
AVANS_KEY = secrets.AVANS_KEY
AVANS_SECRET = secrets.AVANS_SECRET
REQUEST_TOKEN_URL = 'https://publicapi.avans.nl/oauth/request_token?oauth_callback=http://%s/callback'
ACCESS_TOKEN_URL = 'https://publicapi.avans.nl/oauth/access_token'
AUTHORIZE_URL = 'https://publicapi.avans.nl/oauth/saml.php?oauth_token=%s'
consumer = oauth.Consumer(AVANS_KEY, AVANS_SECRET)
client = oauth.Client(consumer)
def avans_login(request):
resp, content = client.request(REQUEST_TOKEN_URL % request.get_host(), "GET")
if resp['status'] != '200':
raise Exception("Invalid response from oauth")
request.session['request_token'] = dict(cgi.parse_qsl(content))
url = AUTHORIZE_URL % (request.session['request_token']['oauth_token'])
return HttpResponseRedirect(url)
def avans_callback(request):
token = oauth.Token(request.session['request_token']['oauth_token'], request.session['request_token']['oauth_token_secret'])
token.set_verifier(request.GET['oauth_verifier'])
client = oauth.Client(consumer, token)
resp, content = client.request(ACCESS_TOKEN_URL, "GET")
if resp['status'] != '200':
raise Exception("Invalid response from Avans.")
access_token = dict(cgi.parse_qsl(content))
token = oauth.Token(access_token['oauth_token'], access_token['oauth_token_secret'])
client = oauth.Client(consumer, token)
resp, content = client.request('https://publicapi.avans.nl/oauth/studentnummer/', 'GET')
data = json.loads(content)[0]
studentnummer = data['studentnummer']
inlognaam = data['inlognaam']
try:
user = User.objects.get(username=inlognaam)
except User.DoesNotExist:
user = User.objects.create_user(inlognaam, studentnummer, 'secret')
user = authenticate(username=inlognaam, password='secret')
login(request, user)
return HttpResponseRedirect('/')
def avans_logout(request):
logout(request)
return HttpResponse('Je bent nu uitgelogd... <a href="/">Opnieuw inloggen</a>')
def home(request):
if not request.user.is_authenticated():
return avans_login(request)
if request.method == 'POST':
for key in request.POST:
if key.startswith('answer'):
answer, created = Answer.objects.get_or_create(user=request.user, question=key)
answer.string = request.POST[key]
answer.save()
messages.add_message(request, messages.INFO, 'Je antwoorden zijn opgeslagen')
return HttpResponseRedirect('/')
answers = Answer.objects.filter(user=request.user)
answers_dict = {}
for answer in answers:
answers_dict[answer.question] = answer.string
return render(request, 'index.html', {'answers': answers_dict})
Loading…
Cancel
Save