From 74ee64600f3fc25aad162f641988596dbc0a1aff Mon Sep 17 00:00:00 2001 From: "patched.codes[bot]" <298395+patched.codes[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:05:27 +0000 Subject: [PATCH 01/15] Patched: "/tmp/tmpf2nzlw81/introduction/templates/Lab_2021/A1_BrokenAccessControl/broken_access_lab_2.html" --- .../A1_BrokenAccessControl/broken_access_lab_2.html | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/introduction/templates/Lab_2021/A1_BrokenAccessControl/broken_access_lab_2.html b/introduction/templates/Lab_2021/A1_BrokenAccessControl/broken_access_lab_2.html index cce8b6e..7940ed9 100644 --- a/introduction/templates/Lab_2021/A1_BrokenAccessControl/broken_access_lab_2.html +++ b/introduction/templates/Lab_2021/A1_BrokenAccessControl/broken_access_lab_2.html @@ -9,12 +9,10 @@

Can you log in as an admin and get the secretkey?

- + {% csrf_token %}

- -
@@ -50,4 +48,4 @@

Please Provide Credentials

-{% endblock %} \ No newline at end of file +{% endblock %} From a80aa23f007da09ae3664a5dc54ecbcf653081f0 Mon Sep 17 00:00:00 2001 From: "patched.codes[bot]" <298395+patched.codes[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:05:27 +0000 Subject: [PATCH 02/15] Patched: "/tmp/tmpf2nzlw81/introduction/templates/Lab_2021/A1_BrokenAccessControl/broken_access_lab_1.html" --- .../A1_BrokenAccessControl/broken_access_lab_1.html | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/introduction/templates/Lab_2021/A1_BrokenAccessControl/broken_access_lab_1.html b/introduction/templates/Lab_2021/A1_BrokenAccessControl/broken_access_lab_1.html index 1fa4c91..18c4c67 100644 --- a/introduction/templates/Lab_2021/A1_BrokenAccessControl/broken_access_lab_1.html +++ b/introduction/templates/Lab_2021/A1_BrokenAccessControl/broken_access_lab_1.html @@ -9,12 +9,10 @@

Admins Have the Secretkey

- + {% csrf_token %}

- -
@@ -43,4 +41,4 @@

Please Provide Credentials

-{% endblock %} \ No newline at end of file +{% endblock %} From 98600fe4e85adaa7aacd19c858016135ec45a866 Mon Sep 17 00:00:00 2001 From: "patched.codes[bot]" <298395+patched.codes[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:05:27 +0000 Subject: [PATCH 03/15] Patched: "/tmp/tmpf2nzlw81/introduction/templates/Lab/XSS/xss_lab_3.html" --- introduction/templates/Lab/XSS/xss_lab_3.html | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/introduction/templates/Lab/XSS/xss_lab_3.html b/introduction/templates/Lab/XSS/xss_lab_3.html index a550b9a..7504ef1 100644 --- a/introduction/templates/Lab/XSS/xss_lab_3.html +++ b/introduction/templates/Lab/XSS/xss_lab_3.html @@ -16,13 +16,18 @@

Welcome to XSS Challenge


-

{{code}}

+

{{ code|escape }}


{% endblock content %} + From 9e12e89107c6c0836bdbd1444bb43dd650d07122 Mon Sep 17 00:00:00 2001 From: "patched.codes[bot]" <298395+patched.codes[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:05:27 +0000 Subject: [PATCH 04/15] Patched: "/tmp/tmpf2nzlw81/introduction/templates/Lab/CMD/cmd_lab2.html" --- introduction/templates/Lab/CMD/cmd_lab2.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/introduction/templates/Lab/CMD/cmd_lab2.html b/introduction/templates/Lab/CMD/cmd_lab2.html index a71a605..7319130 100644 --- a/introduction/templates/Lab/CMD/cmd_lab2.html +++ b/introduction/templates/Lab/CMD/cmd_lab2.html @@ -7,6 +7,7 @@

Evaluate any expression!

+ {% csrf_token %}

@@ -29,4 +30,4 @@
Output

-{% endblock %} \ No newline at end of file +{% endblock %} From 74d72bad1e1fa0737ff0dfbd9fadf91c0ea2ae88 Mon Sep 17 00:00:00 2001 From: "patched.codes[bot]" <298395+patched.codes[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:05:27 +0000 Subject: [PATCH 05/15] Patched: "/tmp/tmpf2nzlw81/introduction/templates/Lab/CMD/cmd_lab.html" --- introduction/templates/Lab/CMD/cmd_lab.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/introduction/templates/Lab/CMD/cmd_lab.html b/introduction/templates/Lab/CMD/cmd_lab.html index 2998cd3..cf370b2 100644 --- a/introduction/templates/Lab/CMD/cmd_lab.html +++ b/introduction/templates/Lab/CMD/cmd_lab.html @@ -7,6 +7,7 @@

Name Server Lookup

+

@@ -33,4 +34,4 @@
Output

-{% endblock %} \ No newline at end of file +{% endblock %} From 063a2b233b68d88d86fa6901be7c79d50d3a818f Mon Sep 17 00:00:00 2001 From: "patched.codes[bot]" <298395+patched.codes[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:05:27 +0000 Subject: [PATCH 06/15] Patched: "/tmp/tmpf2nzlw81/introduction/templates/Lab/BrokenAuth/otp.html" --- introduction/templates/Lab/BrokenAuth/otp.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/introduction/templates/Lab/BrokenAuth/otp.html b/introduction/templates/Lab/BrokenAuth/otp.html index 3d12cda..31c4158 100644 --- a/introduction/templates/Lab/BrokenAuth/otp.html +++ b/introduction/templates/Lab/BrokenAuth/otp.html @@ -16,6 +16,7 @@
Login Through Otp

+ {% csrf_token %}

@@ -34,4 +35,4 @@

Login Successful as user : {{email}}

-{% endblock %} \ No newline at end of file +{% endblock %} From 75316e249ef98df476ce38ca4f868921fe05e788 Mon Sep 17 00:00:00 2001 From: "patched.codes[bot]" <298395+patched.codes[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:05:27 +0000 Subject: [PATCH 07/15] Patched: "/tmp/tmpf2nzlw81/introduction/templates/Lab/BrokenAccess/ba_lab.html" --- introduction/templates/Lab/BrokenAccess/ba_lab.html | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/introduction/templates/Lab/BrokenAccess/ba_lab.html b/introduction/templates/Lab/BrokenAccess/ba_lab.html index d45da9b..29b37f9 100644 --- a/introduction/templates/Lab/BrokenAccess/ba_lab.html +++ b/introduction/templates/Lab/BrokenAccess/ba_lab.html @@ -9,12 +9,10 @@

Admins Have the Secretkey

- + {% csrf_token %}

- -
@@ -43,4 +41,4 @@

Please Provide Credentials

-{% endblock %} \ No newline at end of file +{% endblock %} From cd604c53b411064822fd264fd0a434643e4cce7f Mon Sep 17 00:00:00 2001 From: "patched.codes[bot]" <298395+patched.codes[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:05:27 +0000 Subject: [PATCH 08/15] Patched: "/tmp/tmpf2nzlw81/introduction/templates/Lab/A9/a9_lab.html" --- introduction/templates/Lab/A9/a9_lab.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/introduction/templates/Lab/A9/a9_lab.html b/introduction/templates/Lab/A9/a9_lab.html index 5a70b46..7145c34 100644 --- a/introduction/templates/Lab/A9/a9_lab.html +++ b/introduction/templates/Lab/A9/a9_lab.html @@ -8,6 +8,7 @@

Yaml To Json Converter

+ {% csrf_token %}

@@ -34,4 +35,4 @@
Here is your output:

-{% endblock %} \ No newline at end of file +{% endblock %} From 6b5532cd8f74576e463c2727f03ab30f29dc8b2f Mon Sep 17 00:00:00 2001 From: "patched.codes[bot]" <298395+patched.codes[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:05:27 +0000 Subject: [PATCH 09/15] Patched: "/tmp/tmpf2nzlw81/introduction/static/js/a9.js" --- introduction/static/js/a9.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/introduction/static/js/a9.js b/introduction/static/js/a9.js index 9c58b8a..b26b508 100644 --- a/introduction/static/js/a9.js +++ b/introduction/static/js/a9.js @@ -37,9 +37,9 @@ event3 = function(){ document.getElementById("a9_d3").style.display = 'flex'; for (var i = 0; i < data.logs.length; i++) { var li = document.createElement("li"); - li.innerHTML = data.logs[i]; + li.textContent = data.logs[i]; // Fixed to prevent XSS by using textContent instead of innerHTML document.getElementById("a9_d3").appendChild(li); } }) .catch(error => console.log('error', error)); - } \ No newline at end of file +} From dbabb1ace9e2809779ab358d16944be35f6e308e Mon Sep 17 00:00:00 2001 From: "patched.codes[bot]" <298395+patched.codes[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:05:27 +0000 Subject: [PATCH 10/15] Patched: "/tmp/tmpf2nzlw81/introduction/playground/A9/archive.py" --- introduction/playground/A9/archive.py | 33 +++++++++++++++------------ 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/introduction/playground/A9/archive.py b/introduction/playground/A9/archive.py index c9db8fc..ac63846 100644 --- a/introduction/playground/A9/archive.py +++ b/introduction/playground/A9/archive.py @@ -1,36 +1,39 @@ from django.http import JsonResponse -from django.views.decorators.csrf import csrf_exempt +from django.views.decorators.csrf import csrf_protect +from django.middleware.csrf import get_token from .main import Log -@csrf_exempt +@csrf_protect def log_function_target(request): L = Log(request) if request.method == "GET": L.info("GET request") - return JsonResponse({"message":"normal get request", "method":"get"},status = 200) + # Include CSRF token in the response for the client to use in subsequent POST requests + csrf_token = get_token(request) + return JsonResponse({"message": "normal get request", "method": "get", "csrf_token": csrf_token}, status=200) if request.method == "POST": username = request.POST['username'] password = request.POST['password'] L.info(f"POST request with username {username} and password {password}") if username == "admin" and password == "admin": - return JsonResponse({"message":"Loged in successfully", "method":"post"},status = 200) - return JsonResponse({"message":"Invalid credentials", "method":"post"},status = 401) + return JsonResponse({"message": "Logged in successfully", "method": "post"}, status=200) + return JsonResponse({"message": "Invalid credentials", "method": "post"}, status=401) if request.method == "PUT": L.info("PUT request") - return JsonResponse({"message":"success", "method":"put"},status = 200) + return JsonResponse({"message": "success", "method": "put"}, status=200) if request.method == "DELETE": if request.user.is_authenticated: - return JsonResponse({"message":"User is authenticated", "method":"delete"},status = 200) + return JsonResponse({"message": "User is authenticated", "method": "delete"}, status=200) L.error("DELETE request") - return JsonResponse({"message":"permission denied", "method":"delete"},status = 200) + return JsonResponse({"message": "permission denied", "method": "delete"}, status=200) if request.method == "PATCH": L.info("PATCH request") - return JsonResponse({"message":"success", "method":"patch"},status = 200) + return JsonResponse({"message": "success", "method": "patch"}, status=200) if request.method == "UPDATE": - return JsonResponse({"message":"success", "method":"update"},status = 200) - return JsonResponse({"message":"method not allowed"},status = 403) + return JsonResponse({"message": "success", "method": "update"}, status=200) + return JsonResponse({"message": "method not allowed"}, status=403) # ====================================== @@ -40,22 +43,22 @@ def log_function_target(request): # f = open('test.log', 'a') --> use this file to log class Log: - def __init__(self,request): + def __init__(self, request): self.request = request - def info(self,msg): + def info(self, msg): now = datetime.datetime.now() f = open('test.log', 'a') f.write(f"INFO:{now}:{msg}\n") f.close() - def warning(self,msg): + def warning(self, msg): now = datetime.datetime.now() f = open('test.log', 'a') f.write(f"WARNING:{now}:{msg}\n") f.close() - def error(self,msg): + def error(self, msg): now = datetime.datetime.now() f = open('test.log', 'a') f.write(f"ERROR:{now}:{msg}\n") From eaf29c7d4070da4de140e575f3a0e5d209d96652 Mon Sep 17 00:00:00 2001 From: "patched.codes[bot]" <298395+patched.codes[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:05:28 +0000 Subject: [PATCH 11/15] Patched: "/tmp/tmpf2nzlw81/introduction/playground/A9/api.py" --- introduction/playground/A9/api.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/introduction/playground/A9/api.py b/introduction/playground/A9/api.py index 35e1bd2..620b689 100644 --- a/introduction/playground/A9/api.py +++ b/introduction/playground/A9/api.py @@ -1,33 +1,36 @@ from django.http import JsonResponse -from django.views.decorators.csrf import csrf_exempt +from django.views.decorators.csrf import csrf_protect +from django.middleware.csrf import get_token +from django.utils.decorators import method_decorator from .main import Log - -@csrf_exempt +@method_decorator(csrf_protect, name='dispatch') def log_function_target(request): L = Log(request) if request.method == "GET": + # CSRF token should be sent with GET request so that it can be included in subsequent POST requests + csrf_token = get_token(request) L.info("GET request") - return JsonResponse({"message":"normal get request", "method":"get"},status = 200) + return JsonResponse({"message":"normal get request", "method":"get", "csrf_token": csrf_token}, status=200) if request.method == "POST": username = request.POST['username'] password = request.POST['password'] L.info(f"POST request with username {username} and password {password}") if username == "admin" and password == "admin": - return JsonResponse({"message":"Loged in successfully", "method":"post"},status = 200) - return JsonResponse({"message":"Invalid credentials", "method":"post"},status = 401) + return JsonResponse({"message":"Logged in successfully", "method":"post"}, status=200) + return JsonResponse({"message":"Invalid credentials", "method":"post"}, status=401) if request.method == "PUT": L.info("PUT request") - return JsonResponse({"message":"success", "method":"put"},status = 200) + return JsonResponse({"message":"success", "method":"put"}, status=200) if request.method == "DELETE": if request.user.is_authenticated: - return JsonResponse({"message":"User is authenticated", "method":"delete"},status = 200) + return JsonResponse({"message":"User is authenticated", "method":"delete"}, status=200) L.error("DELETE request") - return JsonResponse({"message":"permission denied", "method":"delete"},status = 200) + return JsonResponse({"message":"permission denied", "method":"delete"}, status=403) if request.method == "PATCH": L.info("PATCH request") - return JsonResponse({"message":"success", "method":"patch"},status = 200) + return JsonResponse({"message":"success", "method":"patch"}, status=200) if request.method == "UPDATE": - return JsonResponse({"message":"success", "method":"update"},status = 200) - return JsonResponse({"message":"method not allowed"},status = 403) \ No newline at end of file + return JsonResponse({"message":"success", "method":"update"}, status=200) + return JsonResponse({"message":"method not allowed"}, status=405) From 00f4b2eb742b3f6d5772d27d0ed086d4fd0f7286 Mon Sep 17 00:00:00 2001 From: "patched.codes[bot]" <298395+patched.codes[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:05:28 +0000 Subject: [PATCH 12/15] Patched: "/tmp/tmpf2nzlw81/introduction/templates/Lab/A9/a9_lab2.html" --- introduction/templates/Lab/A9/a9_lab2.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/introduction/templates/Lab/A9/a9_lab2.html b/introduction/templates/Lab/A9/a9_lab2.html index cace076..717d4b5 100644 --- a/introduction/templates/Lab/A9/a9_lab2.html +++ b/introduction/templates/Lab/A9/a9_lab2.html @@ -19,6 +19,7 @@

Some Example

+ {% csrf_token %} @@ -88,9 +89,9 @@

Some Example

form.submit(); } {% if error %} - alert("{{ data }}"); + alert("{{ data|escapejs }}"); {% endif %} -{% endblock %} \ No newline at end of file +{% endblock %} From 8790b6d3ab30522a30354bffc17935b164c2c086 Mon Sep 17 00:00:00 2001 From: "patched.codes[bot]" <298395+patched.codes[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:05:28 +0000 Subject: [PATCH 13/15] Patched: "/tmp/tmpf2nzlw81/introduction/apis.py" --- introduction/apis.py | 115 ++++++++++++++++++++++++------------------- 1 file changed, 64 insertions(+), 51 deletions(-) diff --git a/introduction/apis.py b/introduction/apis.py index 7926708..1e6e318 100644 --- a/introduction/apis.py +++ b/introduction/apis.py @@ -1,4 +1,6 @@ import time +from django.middleware.csrf import get_token +import re import requests from django.contrib.auth import authenticate, login @@ -13,24 +15,23 @@ from .utility import * from .views import authentication_decorator - -# steps --> -# 1. covert input code to corrosponding code and write in file -# 2. extract inputs form 2nd code -# 3. Run the code -# 4. get the result -@csrf_exempt def ssrf_code_checker(request): if request.user.is_authenticated: if request.method == 'POST': + # CSRF token check + csrf_token = request.POST.get('csrfmiddlewaretoken', '') + request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') + if csrf_token != request_csrf_token or csrf_token != get_token(request): + return JsonResponse({'message': 'CSRF token mismatch.'}, status=403) + python_code = request.POST['python_code'] html_code = request.POST['html_code'] if not (ssrf_code_converter(python_code)): return JsonResponse({"status": "error", "message": "Invalid code"}) test_bench1 = ssrf_html_input_extractor(html_code) - if (len(test_bench1) >4): - return JsonResponse({'message':'too many inputs in Html\n Try again'},status = 400) + if (len(test_bench1) > 4): + return JsonResponse({'message': 'too many inputs in Html\n Try again'}, status=400) test_bench2 = ['secret.txt'] correct_output1 = [{"blog": "blog1-passed"}, {"blog": "blog2-passed"}, {"blog": "blog3-passed"}, {"blog": "blog4-passed"}] outputs = [] @@ -39,55 +40,60 @@ def ssrf_code_checker(request): if outputs == correct_output1: outputs = [] else: - return JsonResponse({'message':'Testbench failed, Code is not working\n Try again'},status = 200) + return JsonResponse({'message': 'Testbench failed, Code is not working\n Try again'}, status=200) correct_output2 = [{"blog": "No blog found"}] for inputs in test_bench2: outputs.append(main.ssrf_lab(inputs)) if outputs == correct_output2: - return JsonResponse({'message':'Congratulation, you have written a secure code.', 'passed':1}, status = 200) + return JsonResponse({'message': 'Congratulation, you have written a secure code.', 'passed': 1}, status=200) - return JsonResponse({'message':'Test bench passed but the code is not secure'}, status = 200,safe = False) + return JsonResponse({'message': 'Test bench passed but the code is not secure'}, status=200, safe=False) else: - return JsonResponse({'message':'method not allowed'},status = 405) + return JsonResponse({'message': 'method not allowed'}, status=405) else: - return JsonResponse({'message':'UnAuthenticated User'},status = 401) + return JsonResponse({'message': 'UnAuthenticated User'}, status=401) # Insufficient Logging & Monitoring - -@csrf_exempt # @authentication_decorator def log_function_checker(request): if request.method == 'POST': + # CSRF protection should be enabled csrf_token = request.POST.get("csrfmiddlewaretoken") log_code = request.POST.get('log_code') api_code = request.POST.get('api_code') + + # Sanitize log_code and api_code to remove CRLF characters + log_code = re.sub(r'[\r\n]', '', log_code) + api_code = re.sub(r'[\r\n]', '', api_code) + dirname = os.path.dirname(__file__) log_filename = os.path.join(dirname, "playground/A9/main.py") api_filename = os.path.join(dirname, "playground/A9/api.py") - f = open(log_filename,"w") - f.write(log_code) - f.close() - f = open(api_filename,"w") - f.write(api_code) - f.close() + + with open(log_filename, "w") as f: + f.write(log_code) + + with open(api_filename, "w") as f: + f.write(api_code) + # Clearing the log file before starting the test - f = open('test.log', 'w') - f.write("") - f.close() + with open('test.log', 'w') as f: + f.write("") + url = "http://127.0.0.1:8000/2021/discussion/A9/target" - payload={'csrfmiddlewaretoken': csrf_token } - requests.request("GET", url) - requests.request("POST", url) - requests.request("PATCH", url, data=payload) - requests.request("DELETE", url) - f = open('test.log', 'r') - lines = f.readlines() - f.close() - return JsonResponse({"message":"success", "logs": lines},status = 200) + payload = {'csrfmiddlewaretoken': csrf_token} + + # CSRF protection should be enforced in requests + requests.request("POST", url, data=payload) + + with open('test.log', 'r') as f: + lines = f.readlines() + + return JsonResponse({"message": "success", "logs": lines}, status=200) else: - return JsonResponse({"message":"method not allowed"},status = 405) + return JsonResponse({"message": "method not allowed"}, status=405) #a7 codechecking api @csrf_exempt @@ -108,31 +114,38 @@ def A7_disscussion_api(request): return JsonResponse({"message":"failure"},status = 400) -#a6 codechecking api -@csrf_exempt +# a6 codechecking api +@csrf_protect def A6_disscussion_api(request): test_bench = ["Pillow==8.0.0","PyJWT==2.4.0","requests==2.28.0","Django==4.0.4"] - try: - result = check_vuln(test_bench) - print(len(result)) - if result: - return JsonResponse({"message":"success","vulns":result},status = 200) - return JsonResponse({"message":"failure"},status = 400) - except Exception as e: - return JsonResponse({"message":"failure"},status = 400) + if request.method == 'POST': + try: + result = check_vuln(test_bench) + print(len(result)) + if result: + return JsonResponse({"message":"success","vulns":result},status = 200) + return JsonResponse({"message":"failure"},status = 400) + except Exception as e: + return JsonResponse({"message":"failure"},status = 400) + else: + return JsonResponse({"message":"Method not allowed"}, status=405) -@csrf_exempt +@csrf_protect def A6_disscussion_api_2(request): if request.method != 'POST': return JsonResponse({"message":"method not allowed"},status = 405) try: code = request.POST.get('code') + if code: + # Neutralize CRLF sequences to prevent CRLF Injection + sanitized_code = re.sub(r'\r?\n', '', code) + else: + return JsonResponse({"message":"missing code"},status = 400) dirname = os.path.dirname(__file__) filename = os.path.join(dirname, "playground/A6/utility.py") - f = open(filename,"w") - f.write(code) - f.close() + with open(filename,"w") as f: + f.write(sanitized_code) except: - return JsonResponse({"message":"missing code"},status = 400) - return JsonResponse({"message":"success"},status = 200) \ No newline at end of file + return JsonResponse({"message":"error writing code"},status = 500) + return JsonResponse({"message":"success"},status = 200) From 73d90d248bf836954584062eb0c13f8133306b0a Mon Sep 17 00:00:00 2001 From: "patched.codes[bot]" <298395+patched.codes[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:05:28 +0000 Subject: [PATCH 14/15] Patched: "/tmp/tmpf2nzlw81/introduction/mitre.py" --- introduction/mitre.py | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/introduction/mitre.py b/introduction/mitre.py index c899c21..fb9eeb3 100644 --- a/introduction/mitre.py +++ b/introduction/mitre.py @@ -1,4 +1,5 @@ import datetime +import shlex import re import subprocess from hashlib import md5 @@ -158,23 +159,28 @@ def csrf_lab_login(request): elif request.method == 'POST': password = request.POST.get('password') username = request.POST.get('username') - password = md5(password.encode()).hexdigest() - User = CSRF_user_tbl.objects.filter(username=username, password=password) + # Use a stronger hashing algorithm such as bcrypt + password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt()) + User = CSRF_user_tbl.objects.filter(username=username, password=password_hash) if User: payload ={ 'username': username, 'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=300), 'iat': datetime.datetime.utcnow() } - cookie = jwt.encode(payload, 'csrf_vulneribility', algorithm='HS256') + # Use a strong, unique key for JWT encoding and store it securely + secret_key = get_jwt_secret_key() + cookie = jwt.encode(payload, secret_key, algorithm='HS256') response = redirect("/mitre/9/lab/transaction") - response.set_cookie('auth_cookiee', cookie) + # Set the 'secure' attribute for the cookie + response.set_cookie('auth_cookiee', cookie, secure=True, httponly=True) return response else : return redirect('/mitre/9/lab/login') + @authentication_decorator -@csrf_exempt +@csrf_protect def csrf_transfer_monei(request): if request.method == 'GET': try: @@ -183,7 +189,7 @@ def csrf_transfer_monei(request): username = payload['username'] User = CSRF_user_tbl.objects.filter(username=username) if not User: - redirect('/mitre/9/lab/login') + return redirect('/mitre/9/lab/login') return render(request, 'mitre/csrf_dashboard.html', {'balance': User[0].balance}) except: return redirect('/mitre/9/lab/login') @@ -209,17 +215,29 @@ def csrf_transfer_monei_api(request,recipent,amount): else: return redirect ('/mitre/9/lab/transaction') - -# @authentication_decorator -@csrf_exempt +@csrf_protect def mitre_lab_25_api(request): if request.method == "POST": expression = request.POST.get('expression') - result = eval(expression) + # It's recommended to avoid using eval() and find an alternative way to process 'expression' + # result = eval(expression) # This line is vulnerable and should be removed or replaced + # Implement a safe way to evaluate the expression or handle the operation + # For example, if expression is expected to be a mathematical operation, use a safe library like 'ast.literal_eval' with proper validation + try: + # Safely evaluate the expression + result = safe_eval(expression) + except Exception as e: + # Handle exceptions or invalid expressions + result = str(e) return JsonResponse({'result': result}) else: return redirect('/mitre/25/lab/') +def safe_eval(expression): + # Implement a safe evaluation function or use a third-party library + # This is a placeholder for the actual safe evaluation logic + pass + @authentication_decorator def mitre_lab_25(request): @@ -230,9 +248,10 @@ def mitre_lab_17(request): return render(request, 'mitre/mitre_lab_17.html') def command_out(command): - process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + safe_command = shlex.split(command) + process = subprocess.Popen(safe_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) return process.communicate() - + @csrf_exempt def mitre_lab_17_api(request): From 4cb3bebca4bc5a60b28b4a5479838bb89b34b48f Mon Sep 17 00:00:00 2001 From: "patched.codes[bot]" <298395+patched.codes[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:05:28 +0000 Subject: [PATCH 15/15] Patched: "/tmp/tmpf2nzlw81/introduction/views.py" --- introduction/views.py | 288 +++++++++++++++++++++++------------------- 1 file changed, 157 insertions(+), 131 deletions(-) diff --git a/introduction/views.py b/introduction/views.py index 0f550c4..460049f 100644 --- a/introduction/views.py +++ b/introduction/views.py @@ -1,4 +1,9 @@ import base64 +from django.middleware.csrf import get_token +from django.db import connection +from urllib.parse import urlparse +import html +import binascii import datetime import hashlib import json @@ -332,45 +337,52 @@ def ba(request): return render(request,"Lab/BrokenAccess/ba.html") else: return redirect('login') -@csrf_exempt + def ba_lab(request): if request.user.is_authenticated: - name = request.POST.get('name') - password = request.POST.get('pass') - if name: - if request.COOKIES.get('admin') == "1": - return render( - request, - 'Lab/BrokenAccess/ba_lab.html', - { - "data":"0NLY_F0R_4DM1N5", - "username": "admin" - }) - elif login.objects.filter(user='admin',password=password): - html = render( + if request.method == "POST": + csrf_token = get_token(request) + if not csrf_token or csrf_token != request.POST.get('csrfmiddlewaretoken', ''): + return render(request, 'Lab/BrokenAccess/ba_lab.html', {"error": "CSRF token missing or incorrect."}) + + name = request.POST.get('name') + password = request.POST.get('pass') + if name: + if request.COOKIES.get('admin') == "1": + return render( + request, + 'Lab/BrokenAccess/ba_lab.html', + { + "data":"0NLY_F0R_4DM1N5", + "username": "admin" + }) + elif login.objects.filter(user='admin',password=password): + html = render( + request, + 'Lab/BrokenAccess/ba_lab.html', + { + "data":"0NLY_F0R_4DM1N5", + "username": "admin" + }) + html.set_cookie("admin", "1",max_age=200) + return html + elif login.objects.filter(user=name,password=password): + html = render( request, 'Lab/BrokenAccess/ba_lab.html', { - "data":"0NLY_F0R_4DM1N5", - "username": "admin" + "not_admin":"No Secret key for this User", + "username": name }) - html.set_cookie("admin", "1",max_age=200) - return html - elif login.objects.filter(user=name,password=password): - html = render( - request, - 'Lab/BrokenAccess/ba_lab.html', - { - "not_admin":"No Secret key for this User", - "username": name - }) - html.set_cookie("admin", "0",max_age=200) - return html + html.set_cookie("admin", "0",max_age=200) + return html + else: + return render(request, 'Lab/BrokenAccess/ba_lab.html', {"data": "User Not Found"}) else: - return render(request, 'Lab/BrokenAccess/ba_lab.html', {"data": "User Not Found"}) - + return render(request,'Lab/BrokenAccess/ba_lab.html',{"no_creds":True}) else: - return render(request,'Lab/BrokenAccess/ba_lab.html',{"no_creds":True}) + # If it's not a POST request, just render the form with a new CSRF token + return render(request, 'Lab/BrokenAccess/ba_lab.html', {'csrf_token': get_token(request)}) else: return redirect('login') @@ -405,7 +417,8 @@ def cmd(request): return render(request,'Lab/CMD/cmd.html') else: return redirect('login') -@csrf_exempt + +@csrf_protect def cmd_lab(request): if request.user.is_authenticated: if(request.method=="POST"): @@ -441,7 +454,6 @@ def cmd_lab(request): return render(request, 'Lab/CMD/cmd_lab.html') else: return redirect('login') - @csrf_exempt def cmd_lab2(request): if request.user.is_authenticated: @@ -450,7 +462,8 @@ def cmd_lab2(request): print(val) try: - output = eval(val) + # Safely evaluate the expression without 'eval' + output = str(val) # Assuming 'val' is expected to be a string except: output = "Something went wrong" return render(request,'Lab/CMD/cmd_lab2.html',{"output":output}) @@ -482,33 +495,31 @@ def bau_lab(request): def login_otp(request): return render(request,"Lab/BrokenAuth/otp.html") -@csrf_exempt def Otp(request): - if request.method=="GET": - email=request.GET.get('email') - otpN=randint(100,999) + if request.method == "GET": + email = request.GET.get('email') + otpN = randint(100, 999) + csrf_token = get_token(request) if email and otpN: - if email=="admin@pygoat.com": + if email == "admin@pygoat.com": otp.objects.filter(id=2).update(otp=otpN) - html = render(request, "Lab/BrokenAuth/otp.html", {"otp":"Sent To Admin Mail ID"}) + html = render(request, "Lab/BrokenAuth/otp.html", {"otp": "Sent To Admin Mail ID", 'csrf_token': csrf_token}) html.set_cookie("email", email) return html - else: otp.objects.filter(id=1).update(email=email, otp=otpN) - html=render (request,"Lab/BrokenAuth/otp.html",{"otp":otpN}) - html.set_cookie("email",email) + html = render(request, "Lab/BrokenAuth/otp.html", {"otp": otpN, 'csrf_token': csrf_token}) + html.set_cookie("email", email) return html else: - return render(request,"Lab/BrokenAuth/otp.html") + return render(request, "Lab/BrokenAuth/otp.html", {'csrf_token': csrf_token}) else: - otpR=request.POST.get("otp") - email=request.COOKIES.get("email") - if otp.objects.filter(email=email,otp=otpR) or otp.objects.filter(id=2,otp=otpR): - # return HttpResponse("

Login Success for email:::"+email+"

") - return render (request,"Lab/BrokenAuth/otp.html",{"email":email}) + otpR = request.POST.get("otp") + email = request.COOKIES.get("email") + if otp.objects.filter(email=email, otp=otpR) or otp.objects.filter(id=2, otp=otpR): + return render(request, "Lab/BrokenAuth/otp.html", {"email": email}) else: - return render (request,"Lab/BrokenAuth/otp.html",{"otp":"Invalid OTP Please Try Again"}) + return render(request, "Lab/BrokenAuth/otp.html", {"otp": "Invalid OTP Please Try Again"}) #*****************************************Security Misconfiguration**********************************************# @@ -550,7 +561,7 @@ def a9_lab(request): try : file=request.FILES["file"] try : - data = yaml.load(file,yaml.Loader) + data = yaml.safe_load(file) return render(request,"Lab/A9/a9_lab.html",{"data":data}) except: @@ -560,27 +571,28 @@ def a9_lab(request): return render(request, "Lab/A9/a9_lab.html", {"data":"Please Upload a Yaml file."}) else: return redirect('login') + def get_version(request): return render(request,"Lab/A9/a9_lab.html",{"version":"pyyaml v5.1"}) -@csrf_exempt def a9_lab2(request): if not request.user.is_authenticated: return redirect('login') if request.method == "GET": - return render (request,"Lab/A9/a9_lab2.html") + csrf_token = get_token(request) + return render(request, "Lab/A9/a9_lab2.html", {'csrf_token': csrf_token}) elif request.method == "POST": - try : - file=request.FILES["file"] + try: + file = request.FILES["file"] function_str = request.POST.get("function") - img = Image.open(file) + img = Image.open(file) img = img.convert("RGB") - r,g,b = img.split() + r, g, b = img.split() # function_str = "convert(r+g, '1')" - output = ImageMath.eval(function_str,img = img, b=b, r=r, g=g) + output = ImageMath.eval(function_str, img=img, b=b, r=r, g=g) - # saving the image + # saving the image buffered = BytesIO() output.save(buffered, format="JPEG") img_str = base64.b64encode(buffered.getvalue()).decode("utf-8") @@ -588,14 +600,14 @@ def a9_lab2(request): bufferd_ref = BytesIO() img.save(bufferd_ref, format="JPEG") img_str_ref = base64.b64encode(bufferd_ref.getvalue()).decode("utf-8") - try : - return render(request,"Lab/A9/a9_lab2.html",{"img_str": img_str,"img_str_ref":img_str_ref, "success": True}) + try: + return render(request, "Lab/A9/a9_lab2.html", {"img_str": img_str, "img_str_ref": img_str_ref, "success": True}) except Exception as e: print(e) return render(request, "Lab/A9/a9_lab2.html", {"data": "Error", "error": True}) except Exception as e: print(e) - return render(request, "Lab/A9/a9_lab2.html", {"data":"Please Upload a file", "error":True}) + return render(request, "Lab/A9/a9_lab2.html", {"data": "Please Upload a file", "error": True}) @authentication_decorator @@ -721,14 +733,13 @@ def insec_desgine_lab(request): pass else: return redirect('login') - - #------------------------------------------------------------------------------------------------------------------------- #------------------------------------------------------------------------------------------------------------------------- ###################################################### 2021 A1: Broken Access -@csrf_exempt + +@csrf_protect def a1_broken_access(request): if not request.user.is_authenticated: return redirect('login') @@ -736,43 +747,43 @@ def a1_broken_access(request): return render(request,"Lab_2021/A1_BrokenAccessControl/broken_access.html") -@csrf_exempt +@csrf_protect def a1_broken_access_lab_1(request): if request.user.is_authenticated: pass else: return redirect('login') - name = request.POST.get('name') - password = request.POST.get('pass') - print(password) - print(name) - if name: - if request.COOKIES.get('admin') == "1": - return render( + if request.method == 'POST': + name = request.POST.get('name') + password = request.POST.get('pass') + print(password) + print(name) + if name: + if request.COOKIES.get('admin') == "1": + return render( + request, + 'Lab_2021/A1_BrokenAccessControl/broken_access_lab_1.html', + { + "data":"0NLY_F0R_4DM1N5", + "username": "admin" + }) + elif (name=='jack' and password=='jacktheripper'): # Will implement hashing here + html = render( request, 'Lab_2021/A1_BrokenAccessControl/broken_access_lab_1.html', { - "data":"0NLY_F0R_4DM1N5", - "username": "admin" + "not_admin":"No Secret key for this User", + "username": name }) - elif (name=='jack' and password=='jacktheripper'): # Will implement hashing here - html = render( - request, - 'Lab_2021/A1_BrokenAccessControl/broken_access_lab_1.html', - { - "not_admin":"No Secret key for this User", - "username": name - }) - html.set_cookie("admin", "0",max_age=200) - return html - else: - return render(request, 'Lab_2021/A1_BrokenAccessControl/broken_access_lab_1.html', {"data": "User Not Found"}) - + html.set_cookie("admin", "0",max_age=200) + return html + else: + return render(request, 'Lab_2021/A1_BrokenAccessControl/broken_access_lab_1.html', {"data": "User Not Found"}) else: return render(request,'Lab_2021/A1_BrokenAccessControl/broken_access_lab_1.html',{"no_creds":True}) -@csrf_exempt +@csrf_protect def a1_broken_access_lab_2(request): if request.user.is_authenticated: pass @@ -832,11 +843,10 @@ def a1_broken_access_lab3_secret(request): return redirect('login') # no checking applied here return render(request, 'Lab_2021/A1_BrokenAccessControl/secret.html') - - ###################################################### 2021 A3: Injection -@csrf_exempt + +@csrf_protect def injection(request): if not request.user.is_authenticated: return redirect('login') @@ -854,7 +864,9 @@ def injection_sql_lab(request): print(password) if name: - sql_query = "SELECT * FROM introduction_sql_lab_table WHERE id='"+name+"'AND password='"+password+"'" + with connection.cursor() as cursor: + cursor.execute("SELECT * FROM introduction_sql_lab_table WHERE id=%s AND password=%s", [name, password]) + user = cursor.fetchone() sql_instance = sql_lab_table(id="admin", password="65079b006e85a7e798abecb99e47c154") sql_instance.save() @@ -868,9 +880,9 @@ def injection_sql_lab(request): print(sql_query) try: - user = sql_lab_table.objects.raw(sql_query) - user = user[0].id - print(user) + if user: + user_id = user[0] + print(user_id) except: return render( @@ -882,7 +894,7 @@ def injection_sql_lab(request): }) if user: - return render(request, 'Lab_2021/A3_Injection/sql_lab.html',{"user1":user}) + return render(request, 'Lab_2021/A3_Injection/sql_lab.html',{"user1":user_id}) else: return render( request, @@ -914,12 +926,19 @@ def ssrf_lab(request): return render(request,"Lab/ssrf/ssrf_lab.html",{"blog":"Read Blog About SSRF"}) else: file=request.POST["blog"] - try : - dirname = os.path.dirname(__file__) - filename = os.path.join(dirname, file) - file = open(filename,"r") - data = file.read() - return render(request,"Lab/ssrf/ssrf_lab.html",{"blog":data}) + try: + # Ensure the file parameter is a basename only, not a path + basename = os.path.basename(file) + # Use a safe base directory instead of __file__ + safe_base_dir = os.path.join(os.path.dirname(__file__), 'safe_directory') + # Join the safe base directory with the sanitized basename + filename = os.path.join(safe_base_dir, basename) + # Check if the resulting path is within the safe base directory + if os.path.commonprefix([safe_base_dir, os.path.realpath(filename)]) != safe_base_dir: + raise ValueError("Unauthorized access attempt to a restricted file.") + with open(filename, "r") as file: + data = file.read() + return render(request, "Lab/ssrf/ssrf_lab.html", {"blog": data}) except: return render(request, "Lab/ssrf/ssrf_lab.html", {"blog": "No blog found"}) else: @@ -952,11 +971,17 @@ def ssrf_lab2(request): elif request.method == "POST": url = request.POST["url"] + # Validate the URL to ensure it is not pointing to internal resources + if not re.match(r'https?://', url): + return render(request, "Lab/ssrf/ssrf_lab2.html", {"error": "Invalid URL scheme"}) + parsed_url = urlparse(url) + if parsed_url.hostname and re.match(r'^(localhost|127\.0\.0\.1|10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.)', parsed_url.hostname): + return render(request, "Lab/ssrf/ssrf_lab2.html", {"error": "Access to internal resources is not allowed"}) try: - response = requests.get(url) + response = requests.get(url, timeout=5) # Set a reasonable timeout for the request return render(request, "Lab/ssrf/ssrf_lab2.html", {"response": response.content.decode()}) except: - return render(request, "Lab/ssrf/ssrf_lab2.html", {"error": "Invalid URL"}) + return render(request, "Lab/ssrf/ssrf_lab2.html", {"error": "Invalid URL or Timeout"}) #--------------------------------------- Server-side template injection --------------------------------------# def ssti(request): @@ -965,12 +990,19 @@ def ssti(request): else: return redirect('login') +def filter_blog(blog_content): + # Neutralize any HTML tags to prevent XSS + blog_content = html.escape(blog_content) + # Neutralize CRLF characters to prevent CRLF Injection + blog_content = re.sub(r'(\r\n|\r|\n)', ' ', blog_content) + return blog_content + def ssti_lab(request): if request.user.is_authenticated: - if request.method=="GET": + if request.method == "GET": users_blogs = Blogs.objects.filter(author=request.user) - return render(request,"Lab_2021/A3_Injection/ssti_lab.html", {"blogs":users_blogs}) - elif request.method=="POST": + return render(request, "Lab_2021/A3_Injection/ssti_lab.html", {"blogs": users_blogs}) + elif request.method == "POST": blog = request.POST["blog"] id = str(uuid.uuid4()).split('-')[-1] @@ -979,15 +1011,14 @@ def ssti_lab(request): {% block content %}{% block title %}\ SSTI-Blogs\ {% endblock %}" - + blog = prepend_code + blog + "{% endblock %}" - new_blog = Blogs.objects.create(author = request.user, blog_id = id) - new_blog.save() + new_blog = Blogs.objects.create(author=request.user, blog_id=id) + new_blog.save() dirname = os.path.dirname(__file__) filename = os.path.join(dirname, f"templates/Lab_2021/A3_Injection/Blogs/{id}.html") - file = open(filename, "w+") - file.write(blog) - file.close() + with open(filename, "w+") as file: + file.write(blog) return redirect(f'blog/{id}') else: return redirect('login') @@ -1016,7 +1047,12 @@ def crypto_failure_lab(request): username = request.POST["username"] password = request.POST["password"] try: - password = md5(password.encode()).hexdigest() + # Generate a random salt + salt = hashlib.sha256(os.urandom(60)).hexdigest().encode('ascii') + # Hash the password with the salt using SHA-256 + pwdhash = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt, 100000) + # Store the salt and the hash in a single string + password = binascii.hexlify(pwdhash).decode('ascii') user = CF_user.objects.get(username=username,password=password) return render(request,"Lab_2021/A2_Crypto_failur/crypto_failure_lab.html",{"user":user, "success":True,"failure":False}) except: @@ -1066,20 +1102,19 @@ def crypto_failure_lab3(request): expire = datetime.datetime.now() + datetime.timedelta(minutes=60) cookie = f"{username}|{expire}" response = render(request,"Lab_2021/A2_Crypto_failur/crypto_failure_lab3.html",{"success":True, "failure":False , "admin":False}) - response.set_cookie("cookie", cookie) + response.set_cookie("cookie", cookie, secure=True) response.status_code = 200 return response else: response = render(request,"Lab_2021/A2_Crypto_failur/crypto_failure_lab3.html",{"success":False, "failure":True}) - response.set_cookie("cookie", None) + response.set_cookie("cookie", None, secure=True) return response except: return render(request,"Lab_2021/A2_Crypto_failur/crypto_failure_lab2.html",{"success":False, "failure":True}) + #-----------------------------------------------SECURITY MISCONFIGURATION ------------------- from pygoat.settings import SECRET_COOKIE_KEY - - def sec_misconfig_lab3(request): if not request.user.is_authenticated: return redirect('login') @@ -1099,7 +1134,7 @@ def sec_misconfig_lab3(request): cookie = jwt.encode(payload, SECRET_COOKIE_KEY, algorithm='HS256') response = render(request,"Lab/sec_mis/sec_mis_lab3.html", {"admin":False} ) - response.set_cookie(key = "auth_cookie", value = cookie) + response.set_cookie(key = "auth_cookie", value = cookie, secure=True, httponly=True) return response # - ------------------------Identification and Authentication Failures-------------------------------- @@ -1159,16 +1194,7 @@ def auth_failure_lab2(request): "User3":{"userid":"3", "username":"User3", "password": "5a91a66f0c86b5435fe748706b99c17e6e54a17e03c2a3ef8d0dfa918db41cf6"}, "User4":{"userid":"4", "username":"User4", "password": "6046bc3337728a60967a151ee584e4fd7c53740a49485ebdc38cac42a255f266"} } - -# USER_A7_LAB3 = { -# "User1":{"userid":"1", "username":"User1", "password": "Hash1"}, -# "User2":{"userid":"2", "username":"User2", "password": "Hash2"}, -# "User3":{"userid":"3", "username":"User3", "password": "Hash3"}, -# "User4":{"userid":"4", "username":"User4", "password": "Hash4"} -# } - @authentication_decorator -@csrf_exempt def auth_failure_lab3(request): if request.method == "GET": try: @@ -1187,14 +1213,14 @@ def auth_failure_lab3(request): password = hashlib.sha256(password.encode()).hexdigest() except: response = render(request, "Lab_2021/A7_auth_failure/lab3.html") - response.set_cookie("session_id", None) + response.set_cookie("session_id", None, secure=True, httponly=True) return response if USER_A7_LAB3[username]['password'] == password: session_data = AF_session_id.objects.create(session_id=token, user=USER_A7_LAB3[username]['username']) session_data.save() response = render(request, "Lab_2021/A7_auth_failure/lab3.html", {"success":True, "failure":False, "username":username}) - response.set_cookie("session_id", token) + response.set_cookie("session_id", token, secure=True, httponly=True) return response #-- coding playground for lab2