commit
904cf04b4f
@ -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%; |
||||
} |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 105 KiB |
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…
Reference in new issue