diff --git a/.all-contributorsrc b/.all-contributorsrc new file mode 100644 index 0000000..09fbc7f --- /dev/null +++ b/.all-contributorsrc @@ -0,0 +1,98 @@ +{ + "files": [ + "README.md" + ], + "imageSize": 100, + "commit": false, + "contributors": [ + { + "login": "pwned-17", + "name": "pwned-17", + "avatar_url": "https://avatars.githubusercontent.com/u/61360833?v=4", + "profile": "https://github.com/pwned-17", + "contributions": [ + "code" + ] + }, + { + "login": "prince-7", + "name": "Aman Singh", + "avatar_url": "https://avatars.githubusercontent.com/u/53997924?v=4", + "profile": "https://github.com/prince-7", + "contributions": [ + "code" + ] + }, + { + "login": "adeyosemanputra", + "name": "adeyosemanputra", + "avatar_url": "https://avatars.githubusercontent.com/u/24958168?v=4", + "profile": "https://github.com/adeyosemanputra", + "contributions": [ + "code", + "doc" + ] + }, + { + "login": "gaurav618618", + "name": "gaurav618618", + "avatar_url": "https://avatars.githubusercontent.com/u/29380890?v=4", + "profile": "https://github.com/gaurav618618", + "contributions": [ + "code", + "doc" + ] + }, + { + "login": "kUSHAL0601", + "name": "MajAK", + "avatar_url": "https://avatars.githubusercontent.com/u/29600964?v=4", + "profile": "https://github.com/kUSHAL0601", + "contributions": [ + "code" + ] + }, + { + "login": "JustinDPerkins", + "name": "JustinPerkins", + "avatar_url": "https://avatars.githubusercontent.com/u/60413733?v=4", + "profile": "https://github.com/JustinDPerkins", + "contributions": [ + "code" + ] + }, + { + "login": "Hkakashi", + "name": "Liu Peng", + "avatar_url": "https://avatars.githubusercontent.com/u/43193113?v=4", + "profile": "https://github.com/Hkakashi", + "contributions": [ + "code" + ] + }, + { + "login": "RupakBiswas-2304", + "name": "Metaphor", + "avatar_url": "https://avatars.githubusercontent.com/u/75058161?v=4", + "profile": "https://github.com/RupakBiswas-2304", + "contributions": [ + "code" + ] + }, + { + "login": "whokilleddb", + "name": "whokilleddb", + "avatar_url": "https://avatars.githubusercontent.com/u/56482137?v=4", + "profile": "https://whokilleddb.github.io", + "contributions": [ + "code" + ] + } + ], + "contributorsPerLine": 7, + "projectName": "pygoat", + "projectOwner": "adeyosemanputra", + "repoType": "github", + "repoHost": "https://github.com", + "skipCi": true +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fee5a0c --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.env/ +*.pyc +env +pygoat/db.sqlite3 +venv +*.sqlite3 +*db.sqlite3* +app.log +bin diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..2b7e46d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.formatting.provider": "yapf" +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0e71c70 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,34 @@ +FROM python:3.11.0b1-buster + +# set work directory +WORKDIR /app + + +# dependencies for psycopg2 +RUN apt-get update && apt-get install --no-install-recommends -y dnsutils=1:9.11.5.P4+dfsg-5.1+deb10u9 libpq-dev=11.16-0+deb10u1 python3-dev=3.7.3-1 \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + + +# Set environment variables +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 + + +# Install dependencies +RUN python -m pip install --no-cache-dir pip==22.0.4 +COPY requirements.txt requirements.txt +RUN pip install --no-cache-dir -r requirements.txt + + +# copy project +COPY . /app/ + + +# install pygoat +EXPOSE 8000 + + +RUN python3 /app/manage.py migrate +WORKDIR /app/pygoat/ +CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers","6", "pygoat.wsgi"] diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..bb10166 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: gunicorn pygoat.wsgi --log-file - \ No newline at end of file diff --git a/PyGoatBot.py b/PyGoatBot.py new file mode 100644 index 0000000..7ab6324 --- /dev/null +++ b/PyGoatBot.py @@ -0,0 +1,64 @@ +from chatterbot import ChatBot +from chatterbot.trainers import ListTrainer +from chatterbot.logic import BestMatch + +# Dataset generated by ChatGPT +training_data = [ + 'What is OWASP PyGoat?', + 'OWASP PyGoat is an intentionally vulnerable web application used for learning web security testing.', + 'Why should I learn web security testing?', + 'Learning web security testing can help you understand how to identify and prevent web application attacks.', + 'What types of vulnerabilities can PyGoat help me learn about?', + 'PyGoat can help you learn about various types of web application vulnerabilities, including injection attacks, cross-site scripting (XSS), and broken authentication and session management.', + 'How can I use PyGoat to learn web security testing?', + 'PyGoat includes a series of lessons and challenges designed to teach you about web security testing techniques and common vulnerabilities.', + 'Is PyGoat suitable for beginners?', + 'Yes, PyGoat is designed to be accessible to beginners and experienced professionals alike.', + 'Where can I download PyGoat?', + 'You can download PyGoat from the official GitHub repository at https://github.com/OWASP/PyGoat', + 'Are there any resources available to help me get started with PyGoat?', + 'Yes, the PyGoat documentation includes a Getting Started guide and a list of additional resources to help you learn about web security testing.', + 'Can I contribute to PyGoat?', + 'Yes, PyGoat is an open-source project and welcomes contributions from anyone interested in improving the application.', +] + +chatbot = ChatBot( + "PyGoatBot", + storage_adapter="chatterbot.storage.SQLStorageAdapter", + database_uri="sqlite:///database.sqlite3", + logic_adapters=[ + { + "import_path": "chatterbot.logic.BestMatch", + "default_response": "I'm sorry, I'm not sure", + "maximum_similarity_threshold": 0.80, + } + ], +) + +trainer = ListTrainer(chatbot) +trainer.train(training_data) + +print("Welcome to PyGoatBot! Type 'q' or 'exit' to quit.") +while True: + try: + user_input = input("You: ") + if user_input.lower() == "exit" or user_input.lower() == "q": + break + + print("Available questions:") + for i, question in enumerate(training_data[::2], start=1): + print(f"{i}. {question}") + + while True: + try: + question_index = int(input("Enter a number to select a question: ")) + break + except ValueError: + print("Please enter a valid number.") + + question = training_data[(question_index - 1) * 2] + response = chatbot.get_response(question) + print(f"PyGoatBot: {response}") + + except (KeyboardInterrupt, EOFError): + break diff --git a/README.md b/README.md new file mode 100644 index 0000000..a66cf06 --- /dev/null +++ b/README.md @@ -0,0 +1,128 @@ +# PyGoat + +[![All Contributors](https://img.shields.io/badge/all_contributors-9-orange.svg?style=flat-square)](#contributors-) + + +intentionally vuln web Application Security in django. +our roadmap build intentionally vuln web Application in django. The Vulnerability can based on OWASP top ten +
+ +Table of Contents +================= + +* [pygoat](#pygoat) + * [Installation](#installation) + * [From Sources](#from-sources) + * [Docker Container](#docker-container) + * [Installation Video](#installation-video) + * [Uninstallation](#uninstallation) + * [Solutions](/Solutions/solution.md) + * [For Developers](/docs/dev_guide.md) + +## Installation + +### From Sources + +To setup the project on your local machine: +
+ +First, Clone the repository using GitHub website or git in Terminal +``` + git clone https://github.com/adeyosemanputra/pygoat.git + ### To Download a specific branch + git clone -b https://github.com/adeyosemanputra/pygoat.git +``` + +#### Method 1 + +1. Install all app and python requirements using installer file - `bash installer.sh` +2. Apply the migrations `python3 manage.py migrate`.
+3. Finally, run the development server `python3 manage.py runserver`.
+4. The project will be available at + +#### Method 2 + +1. Install python3 requirements `pip install -r requirements.txt`.
+2. Apply the migrations `python3 manage.py migrate`.
+3. Finally, run the development server `python3 manage.py runserver`.
+4. The project will be available at + +#### Method 3 + +1. Install all app and python requirements using `setup.py` file - `pip3 install .` +2. Apply the migrations `python3 manage.py migrate`.
+3. Finally, run the development server `python3 manage.py runserver`.
+4. The project will be available at + +### Docker Container +1. Install [Docker](https://www.docker.com) +2. Run `docker pull pygoat/pygoat` or `docker pull pygoat/pygoat:latest` +3. Run `docker run --rm -p 8000:8000 pygoat/pygoat:latest` +4. Browse to +5. Remove existing image using `docker image rm pygoat/pygoat` and pull again incase of any error + +### From Docker-Compose +1. Install [Docker](https://www.docker.com) +2. Run `docker-compose up` or `docker-compose up -d` + +### Build Docker Image and Run +1. Clone the repository   `git clone https://github.com/adeyosemanputra/pygoat.git` +2. Build the docker image from Dockerfile using   `docker build -f Dockerfile -t pygoat .` +3. Run the docker image  `docker run --rm -p 8000:8000 pygoat:latest` +4. Browse to or + +### Installation video + +1. From Source using `installer.sh` + - [Installing PyGoat from Source](https://www.youtube.com/watch?v=7bYBJXG3FRQ) +2. Without using `installer.sh` + - [![](http://img.youtube.com/vi/rfzQiMeiwso/0.jpg)](http://www.youtube.com/watch?v=rfzQiMeiwso "Installation Pygoat") + +## Uninstallation + +### On Debian/Ubuntu Based Systems +- On Debian/Ubuntu based systems, you can use the `uninstaller.sh` script to uninstall `pygoat` along with all it's dependencies. +- To uninstall `pygoat`, simply run: +```bash +$ bash ./uninstaller.sh +``` + +### On Other Systems +- On other systems, you can use the `uninstaller.py` script to uninstall `pygoat` along with all it's dependencies +- To uninstall `pygoat`, simply run: +```bash +$ python3 uninstaller.py +``` + +## Solutions +Solutions to all challenges + +## Contributors โœจ + +Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + + + + + + + + + + + + + + + + +

pwned-17

๐Ÿ’ป

Aman Singh

๐Ÿ’ป

adeyosemanputra

๐Ÿ’ป ๐Ÿ“–

gaurav618618

๐Ÿ’ป ๐Ÿ“–

MajAK

๐Ÿ’ป

JustinPerkins

๐Ÿ’ป

Liu Peng

๐Ÿ’ป

Metaphor

๐Ÿ’ป

whokilleddb

๐Ÿ’ป
+ + + + + + +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! diff --git a/Solutions/img/img4.png b/Solutions/img/img4.png new file mode 100644 index 0000000..eaf7593 Binary files /dev/null and b/Solutions/img/img4.png differ diff --git a/Solutions/img/pic1.png b/Solutions/img/pic1.png new file mode 100644 index 0000000..092a7d8 Binary files /dev/null and b/Solutions/img/pic1.png differ diff --git a/Solutions/img/pic2.png b/Solutions/img/pic2.png new file mode 100644 index 0000000..6edc017 Binary files /dev/null and b/Solutions/img/pic2.png differ diff --git a/Solutions/img/pic3.png b/Solutions/img/pic3.png new file mode 100644 index 0000000..8234348 Binary files /dev/null and b/Solutions/img/pic3.png differ diff --git a/Solutions/solution.md b/Solutions/solution.md new file mode 100644 index 0000000..769ee62 --- /dev/null +++ b/Solutions/solution.md @@ -0,0 +1,546 @@ +# Solutions to all the Lab Exercise + + +## A1: Injection +### Sql Injection +The user on accessing the lab is given with a login page,which challenges the user to login as admin. +The user now has to identify some mechanism to login as admin. +To test for sql injection ,the user can begin with a `'` or `"` based on the error generated he can confirm that it is an sql injection. +Search for common sql injections payloads in google and try using them to break the functionality of the backend code. + +Since the challenge requires yout to login as admin, enter the `username` as `admin` . The user now can use a very common sql injection paylaod to bypass the login validation +`anything' OR '1' ='1`. +Click login and now you will see that you have successfully logged into admins account. + +#### Login : + +![image](https://user-images.githubusercontent.com/61360833/118371215-27758800-b5c9-11eb-8591-212f448ddc13.png) + +On Successful injection + +![image](https://user-images.githubusercontent.com/61360833/118371252-5986ea00-b5c9-11eb-9efb-6beedd558f56.png) + + +### Command Injection Lab 1 +The user on accessing the lab is provided with a feature to perform a name server lookup on the given domain. The user has to give a domain name and the server would perform a ns lookup and return back to the client. If the user is running the lab, based on the OS he can select Windows or Linux. + +The user can cause the server to execute commands ,because of the lack of input validation. + +The user can give a domain say `google.com && [any cmd]` or `google.com; [any cmd]` + +If the OS is windows, lets give input as `google.com && ipconfig` and choose windows. + +If the OS is linux (Ubuntu, Kali, etc), lets give input as `google.com && ifconfig` and choose linux. + +This should give you the output for both`ns lookup` as well as for the `ifconfig`. + +![cmd_inj_1](https://user-images.githubusercontent.com/70275323/154504352-4833e37c-dcd2-4097-8f33-2c6a4c36cb76.png) + +![cmd_inj_2](https://user-images.githubusercontent.com/70275323/154504361-4baa73cb-f73b-44a8-8769-0af2e7b53c24.png) + +### Command Injection Lab 2 +We are given an input form where we can calculate basic arithmetic expressions. Our task is to exploit this functionality and achieve code execution. + +This lab is using `eval()` function in backend which is used to evaluate expression in python. If the expression is a legal python statement, then it will be executed. + +If we submit the expression `1 + 1`, we get the output as `2`. Similarly, on submitting the expression `7 * 7`, we get the output as `49`. + +Now, if we submit `os.system("id")`, we get nothing in the output. But if we check the terminal, we will see that the command gets executed and the result is printed on the terminal screen. You can also verify this by submitting `os.system("sleep 30")`, and you will notice that the request completes after 30 seconds. + +## A2:Broken Authentication + +The main aim of this lab is to login as admin, and to achieve this, exploit the lack of `rate limiting` feature in the otp verification flow. You can see that the otp is only of 3 digit(for demo purposes) and neither does the application have any captcha nor any restriction on number of tries for the otp. + +Now to send the otp to admins mail you need to figure out the admins mail id. Luckily the admin has left his email id for the developers in the page source. Admin's email id is `admin@pygoat.com` Enter this email in the send otp input box and hit send,you can see that the page says that otp is sent to the email id of the admin. + +In order to exploit the lack of rate limiting , we can try to Brute-force the 3 digit otp. + +#### Steps to Brute force: + +* Open Burpsuite and configure your browser to intercept the web trafic, but dont turn intercept on. +* Send the otp to the admins mail id with the help of send otp feature. +* In the enter the otp box enter a random 3 digit number. +* Before your press login , turn intercept on on Burp suite and then press log in +* Now you can see that the traffic is captured in Burpsuite. +* Now use the send to intruder feature and send this request to the intruder. +* Set the position of the payload to the otp= parameter. +* Go to the payloads session and choose the payload type to number list +* Fill the range to 100 to 999 with step 1. +* Now click attack and you can see that the burp suite tries different combinations of otp and collects it response. +* You can figure out if it has guessed the correct opt by seeing the difference in length of the response for each request. +* The correct otp will have a small response length . +* Using this otp you will be able to login into admins account. + +#### Brute forcing using BurpSuite + +After sending OTP to admins EmailID, start up, Start up `BurpSuite`, turn intercept on and send any randon OTP in send OTP box + +![bau_6](https://user-images.githubusercontent.com/70275323/154610459-92ccc2be-236d-4cb2-acc7-af9bd68b49a6.png) + +Once request is intercepted by burpsuite, click on `actions` and then `send to intruder` + +![bau_1](https://user-images.githubusercontent.com/70275323/154610104-a831f913-4374-49cf-8f2b-dcbaae1e0533.png) + +Your intruder screen should look something like this. Parameters enclosed by the `ยง` symbol will be brute forced. + +![bau_2](https://user-images.githubusercontent.com/70275323/154610112-39cc5fec-d407-4190-bd3f-9f4ee33f6c69.png) + +Select payload type as Numbers, enter range as 100-999 and step as 1. Then start attack. + +![bau_3](https://user-images.githubusercontent.com/70275323/154610117-7505d2fc-f1a0-418e-b87a-b676e3ecd791.png) + +When attack is going on, the correct OTP will have a different response length. In this case its smaller. + +We see that OTP value 136 gives us a different lenght. + +![bau_4](https://user-images.githubusercontent.com/70275323/154610121-29a2abc5-b3b8-49e2-9028-a5850cbaf9d9.png) + +It can also be found out by ordering by length + +![bau_5](https://user-images.githubusercontent.com/70275323/154610124-2d8d267a-a198-47af-9baa-5b632617e186.png) + +Lab 2 + + +## A3:Senstive Data Exposure + +The user has to find a way to trigger server error , so that the server throws some sensitive data in its error . +Here the developer has forgoten to turn ```debug to false``` which resulted in showing the ```settings.py``` file whihc has some sensitive data. +Try entering a ```random route``` to trigger the error and go through the settings.py file to find the sensitive data. + +##### Triggering Error: + +![image](https://user-images.githubusercontent.com/61360833/118371395-1da05480-b5ca-11eb-9d70-8a6d7708d039.png) + +##### Finding the routes: + +![image](https://user-images.githubusercontent.com/61360833/118371562-be8f0f80-b5ca-11eb-937f-b877ebfcc3a1.png) + +##### Finding the flag : + +![image](https://user-images.githubusercontent.com/61360833/118371534-a919e580-b5ca-11eb-8f7d-02d0c9322a94.png) + + +## A4:XML External Entities + +When the user clicks the button to save his comments, the data is sent to the server in th from of xml post request. This can be seen , by intercepting the request done to the server by that button using BurpSuite. +Sending data to the server in the form of XML is not actually vulnerable, the vulnerability lies in the way the xml is being parsed. An xml parsers which allows the DTD retrival is said to vulnerable to XXE injection if there arent any input validation done on the xml data. + +##### Exploiting the XML Parser + +* Open Burpsuite and make sure it is ready to capture the web traffic. +* Enter your comments in the input box provided. +* Before hiting the Let the world see button go to burpsuite and turn on intercept. +* Now you should be able to see a post request containing a xml data with your comment inside your the text tag. +* Now we need to introduce a DTD, which tries to fetch files from its server. +* This can be done by using the document tag and defining the Entity. + +##### The Payload + +``` + + + +]> + +&xxe; + +``` + +* Incase if the server is running linux then use file path `file:///etc/passwd` and if its running windows, use `C:\windows\system32\drivers\etc\hosts`. This will dump sensitive data about all users. +* Forward the request and turn off intercept. +* Go to the see comments option and click view comments this should show you the requested files in your payload if the vulnerability exists. + +#### Solving with BurpSuite + +Enter a random Input + +![xee_1](https://user-images.githubusercontent.com/70275323/154611625-18372ba9-e9b8-49d0-8615-8483812e5ccd.png) + +The request is then intercepted in BurpSuite + +![xee_2](https://user-images.githubusercontent.com/70275323/154611629-6a27aecb-1986-480c-a562-5f5871ee9fc7.png) + +Change the XML to the Malicious Payload + +![xee_3](https://user-images.githubusercontent.com/70275323/154611636-7ae40776-091b-41d0-89d0-89ebbd364375.png) + +After forwarding and turning off the Intercept, return to browser and click on button to see your comments. Sensitive password data has been leaked. + +![xee_4](https://user-images.githubusercontent.com/70275323/154611640-dfbb7d37-95d7-4e52-9f06-56b978cd9209.png) + + +## A5:Broken Access Control + +On accessing the lab the user is provided with a simple login in page which requires a username and password. + +The credentials for the user Jack is `jack:jacktheripper` + +Use the above info to log in. + +The main aim of this lab is to login with admin privileges to get the secret key. + +#### Exploiting the Broken Access + +Every time a valid user logs in,the user session is set with a cookie called `admin` +When you notice the cookie value when logged in as jack it is set to `0` +Use BurpSuite to intercept the request change the value of the admin cookie from `0` to `1` +This should log you in as a admin user and display the `secret key` + +#### Solving Using BurpSuite + +We can log in as `jack:jacktheripper` and admin cookie is set to 0. This does not give us the secret key + +![bac_1](https://user-images.githubusercontent.com/70275323/154612894-cb5e0dfa-f6d4-426a-8b3e-e92d300951fd.png) + +To change admin cookie in request, we open up burpsuite and after logging in, refresh the page and change value of admin cookie to 1 + +![bac_2](https://user-images.githubusercontent.com/70275323/154612900-a2903776-ac60-4f40-9654-760869dc4eb7.png) + +This results as being logged in as Admin + +![bac_3](https://user-images.githubusercontent.com/70275323/154612904-917c1501-1a8a-49db-90d0-7879235e7eee.png) + +#### Solving using Browser + +Once again, we log in as `jack:jacktheripper` + +![ba_1](https://user-images.githubusercontent.com/70275323/154613752-e2fc76a1-669b-46b2-a622-62c13c513d5d.png) + +In inspect section, change value of admin cookie to 1 and refresh the page. + +![ba_2](https://user-images.githubusercontent.com/70275323/154613760-6abaa18a-8f27-4c39-bb89-7c0dd320b5f6.png) + +![ba_3](https://user-images.githubusercontent.com/70275323/154613762-16b4d637-0bfc-4196-8fdd-70458bd46994.png) + + +## A6:Security Misconfiguration + +The user is provided with a button which, on clicking, says that `"Only admin.localhost:8000 can access, Your X-Host is None"` + +With this information we can conclude that we need to have a header called `X-Host:` and its value should be ` admin.localhost:8000`. + +In order to add this header we can capture the requet of the button in `BurpSuite` and add the header to the request and forward it . + +This should give you the secret key. + +#### Solving with BurpSuite + +When request is initially intercepted in BurpSuite, the interceptor tab at the right of the screen should look like this + +![sec_1](https://user-images.githubusercontent.com/70275323/154617589-adc11cdb-5a18-49e3-a445-b68442cbc4e0.png) + +Click the small `+` button to add a header + +![sec_2](https://user-images.githubusercontent.com/70275323/154617594-1c54e141-c39e-4002-8438-18d9b79a74aa.png) + +After header `X-host: admin.localhost:8000` has been added the interceptor tab and request data tab should show the new header + +![sec_3](https://user-images.githubusercontent.com/70275323/154617597-b3098967-183b-4b49-b163-cb1a06fde967.png) +![sec_4](https://user-images.githubusercontent.com/70275323/154617598-b5331bd6-cf6b-4d2c-8c7b-e94fe1a3b9b7.png) + +Now, click forward and turn off intercept to see Secret Key + +![sec_5](https://user-images.githubusercontent.com/70275323/154617602-8838dd71-45f4-4756-bbb2-fef2985c1a04.png) + + +## A7:Cross Site Scripting + +* Instead of giving a search term try giving a html tag, ```

Hello

.``` +* Now you can see that the word Hello has been parsed as a Heading in the page. +* This shows that the page is able to render the user given html tags. +* In order to get an xss , the user needs to execute javascript code in the browser. +* This can be acheived by using a script tag and malicious javascript code. +* For now let's just use a basic javascript code to alert a text to prove that xss is possible . +`` +* Now when a search query is performed with the above payload you can see that the browser is able to render the script tag and execute the javascript , thus alerting โ€œxssโ€ with a pop up. + +#### Solving XSS in Browser + +Entering input with `h4` and `font color` tags to check for XSS + +![xss_1](https://user-images.githubusercontent.com/70275323/154513165-672255a5-8c67-4bc3-924d-1848de072b3a.png) + +Results page contains the word `TEXT` in Heading as well as Green color hence XSS Vulnerability is confirmed. + +![xss_2](https://user-images.githubusercontent.com/70275323/154513170-53ec9273-f310-45fd-b30a-b09794604f3a.png) + +Now you can go ahead and enter `` once XSS is confirmed. + +To see results on screen, make sure your browser has JavaScript enabled. + +**Lab 3** +- ##### [ step- 1 ] Checking user input is being reflected or not + - Though alphanumeric characters are being escaped we can still write js code with these 6 character `![]()+` + - check [jsfuck](http://www.jsfuck.com/) + + +## A8:Insecure Deserialization + +This Lab consists of a Page that has some content only available to for the admin to see, How can we access that page as admin? How is our role defined? + +If we check the cookie we see that it is base64 encoded, on decoding we realise it is pickle serialised and we can see some attributes, can you change the attributes to make the page readable? + +Try to flip the bit of the admin from ```...admin\x94K\x00... to ...admin\x94K\x00...``` + +## A9:Using Components with Know Vulnerability + +The user on accessing the lab is provided with a feature to convert yaml files into json objects. The user needs to choose an yaml file and click upload to get the json data. There is also a get version feature which tells the user the version of the library the app uses. + +##### Exploiting the vulnerability. + +* The app uses```pyyaml 5.1 ``` Which is vulnerable to code execution. +* You can google the library with the version to get the poc and vulnerability details +* Create An yaml file with this payload: + +``` +!!python/object/apply:subprocess.check_output +- ls +``` + +* On Uploading this file the user should be able to see the output of the command executed. + + +## A10:Insufficient Logging & Monitoring + +The user on accessing the lab is given with a login page which says the log have been leaked. The user needs to find the leak and try to gain the credentials that have been leaked in the logs. + +##### Finding the Log + +* The log has been exposed in ```/debug route``` +* This can be found out with subdomain brute-forcing or just by guess +* On seeing the Log try to get the required login details as there is a leak and the logging is improperly handled. +* On looking at the log we can see a get request ot the server that has a username and password to it +``` INFO "GET /a10_lab?username=Hacker&password=Hacker HTTP/1.1" 301 0 ``` +* Now use the credentials to log in . + +#### Solving using WebBrowser + Route used is +![a10_1](https://user-images.githubusercontent.com/70275323/154619101-d1c4d744-098b-4500-b705-a21841f8b0e4.png) + +The Sensitive info is `INFO "GET /a10_lab?username=Hacker&password=Hacker HTTP/1.1" 301 0` + +And this info can be used to log in with credentials `Hacker:Hacker` +![a10_2](https://user-images.githubusercontent.com/70275323/154619295-7d390db2-b047-4fae-8ff5-d34dcb9dad7f.png) + + +# OWASP TOP 10 2021 + +## A4 : Insecure Design +This website is giving everyone free tickets ( upto 5 per person ). And the movie will be public when all the tickets will be sold. + +Now, the ticket generating system is quite secure itself, and one can't get more than 5 tickets for free. +But there is a large design flaw. One can get all the tickets by creating multiple accounts. In this particular case, 5 tickets per page, and a total 60 required, so we need to create 12 accounts only and claim 5 tickets from each. + +If the sign up process is lame, then this process can be automated. Strong verification/kyc verification needs to be taken in such situations . + +## A10 : SSRF +This websites serves some vlog, user need to figuer it out how this process is going + +* open dev tool and inspect the buttons +![ssrf_pic1](./img/pic1.png) +* Here we can see there is a hidden input tag which is taking file path of the blog as a parameter. +* now, if the path is not filltered correctly we can put file path of any file and access that.We just have to change the value. +* some example -- + +![url.py](./img/pic2.png) +![url_img](./img/pic3.png) + +#### Now about our main Objective, finding the .env file +* normaly .env file is used to store all important credentials and configurations +* Usally this hidden file is saved a base directory +* So , this an trial and error method of searching +* example : .env , ../.env, ../../.env +* solution : ( ../.env) +![img4](./img/img4.png) + + +# Solutions to 2021 Challenges + + +## 2021-A1:Broken Access Control + +**Lab 1** + +On accessing the lab the user is provided with a simple login in page which requires a username and password. + +The credentials for the user Jack is `jack:jacktheripper` + +Use the above info to log in. + +The main aim of this lab is to login with admin privileges to get the secret key. + +#### Exploiting the Broken Access + +Every time a valid user logs in,the user session is set with a cookie called `admin` +When you notice the cookie value when logged in as jack it is set to `0` +Use BurpSuite to intercept the request change the value of the admin cookie from `0` to `1` +This should log you in as a admin user and display the `secret key` + +#### Solving Using BurpSuite + +We can log in as `jack:jacktheripper` and admin cookie is set to 0. This does not give us the secret key + +![bac_1](https://user-images.githubusercontent.com/70275323/154612894-cb5e0dfa-f6d4-426a-8b3e-e92d300951fd.png) + +To change admin cookie in request, we open up burpsuite and after logging in, refresh the page and change value of admin cookie to 1 + +![bac_2](https://user-images.githubusercontent.com/70275323/154612900-a2903776-ac60-4f40-9654-760869dc4eb7.png) + +This results as being logged in as Admin + +![bac_3](https://user-images.githubusercontent.com/70275323/154612904-917c1501-1a8a-49db-90d0-7879235e7eee.png) + +#### Solving using Browser + +Once again, we log in as `jack:jacktheripper` + +![ba_1](https://user-images.githubusercontent.com/70275323/154613752-e2fc76a1-669b-46b2-a622-62c13c513d5d.png) + +In inspect section, change value of admin cookie to 1 and refresh the page. + +![ba_2](https://user-images.githubusercontent.com/70275323/154613760-6abaa18a-8f27-4c39-bb89-7c0dd320b5f6.png) + +![ba_3](https://user-images.githubusercontent.com/70275323/154613762-16b4d637-0bfc-4196-8fdd-70458bd46994.png) + +**Lab 2** + +#### Exploiting the Broken Access + +In this lab the broken access control is that an Admin field is Authenticated by the user agent field that can easily be changed +Use BurpSuite to intercept the request change the value of the `user-agent` to `pygoat_admin` +This should log you in as a admin user and display the `secret key` + +#### Solving Using BurpSuite + +We log in with `jack:jacktheripper` with request capturing on in Burpsuite. + +![brokenaccess21](https://user-images.githubusercontent.com/70275323/163706569-dc3dc3e7-af3d-428d-8d80-58f431f541a0.png) +![brokenaccess22](https://user-images.githubusercontent.com/70275323/163706575-b58db6b5-01e0-47b7-acdd-ccbb8139802b.png) + +We find a comment that leads us to finding critical info related to login + +![brokenaccess26](https://user-images.githubusercontent.com/70275323/163707600-6fd747a8-fbb3-4bc5-8d46-425fc118c057.png) + +Then Change the user Agent Field. + +![brokenaccess23](https://user-images.githubusercontent.com/70275323/163707610-438393d5-d4b2-4882-bb1b-31cbfebab82a.png) +![brokenaccess24](https://user-images.githubusercontent.com/70275323/163707613-a97349ce-04e7-4f8a-be0e-f206e3f57831.png) + +This results as being logged in as Admin + +![brokenaccess25](https://user-images.githubusercontent.com/70275323/163707622-8cb3f1d7-2185-43b1-84c1-0c66591bc2f6.png) + +**Lab 3** +#### We have an admin credential and a normal user credentails +- We can 1st login using admin credential, then we can see there is a page at /broken_access_controle/secret containing secret +- ![image](https://user-images.githubusercontent.com/75058161/177593540-c299ac0a-35a7-41d1-b64e-5ef143a927bb.png) +- ![image](https://user-images.githubusercontent.com/75058161/177593818-2adfa56e-05e7-4315-acc0-e90ed93aaefe.png) +- Now if we logout from admin account and login to user account, we can't see the option for secret anymore. +- Unfortunately if we browse to /broken_access_controle/secret we can still access the page because no authentication check was implemented at that page. +#### If real case senario hacker won't have admin credential, but he can still brute force with some existing text-list or common path dictionary +- Some tools to bruteforce file path + - [GoBuster](https://www.kali.org/tools/gobuster/) + - [Burpsuit](https://portswigger.net/burp) + +## 2021-A2:Cryptographic Failure + +**Lab 1** +- Give material --> some user id and hash +- ##### [ step- 1 ] Identification of the hash + - the hash is 32 charecter long + - most probably the hash is from MD* family + - which is pretty weak hash ( weak in the sense , it have hash collision ) + - we can use [hash_identifier](https://hashes.com/en/tools/hash_identifier) to identify the hash +- ##### [ step - 2 ] Search the hash in google + - Got the hash of admin password, ie : `admin1234` +- ##### Using online Hash lookup service + - Using online hash decoder we can serach for commmon hash password. +- Final output + - ![image](https://user-images.githubusercontent.com/75058161/177600545-bdbad8bc-f884-4ffe-b0f2-15ff555d95a4.png) +# +**Lab 2** +- Given material --> some user id and hash +- ##### [ step- 1 ] Identification of the hash + - the hash is 64 charecter long + - most probably the hash is SHA256 + - we can use [hash_identifier](https://hashes.com/en/tools/hash_identifier) to identify the hash + - ![image](https://user-images.githubusercontent.com/75058161/177693254-6b3bf112-e1f6-4c71-972a-b04f54c4c90a.png) +- ##### [ step - 2 ] Search the hash in google + - Didn't got any result + - ![image](https://user-images.githubusercontent.com/75058161/177693323-a915bf6a-0df0-44b6-8573-ade92b6a64d8.png) +- ##### Using online Hash lookup service + - Using online hash decoder we can serach for commmon hash password. + - No result found [ in this case ] +- ##### Using some password cracking tools [ Jhon the ripper ] or [ hashcat ] + - No result +- ##### From the code we can see a custom function is used + - After reversing the admin hash and searching in online dictionary + - ![image](https://user-images.githubusercontent.com/75058161/177696721-7587bcc8-d483-47ac-a0cb-a3cab07ca868.png) + - So `password777` is passowrd for admin, this gives use the admin access +- ##### Other solution ( bcause it quite difficult to guess custom hash function ) : + - Brute force the login page ( no delay implemented so it would be better idea) using burp, Zed etc. +# +**Lab 3** +- Given material --> Normal user credential +- admin user name --> unkown, password --> unkown +- ##### Some ovservation + - ![image](https://user-images.githubusercontent.com/75058161/177697795-aa7071d9-b672-4527-af55-231f3612dad7.png) + - there is a cookie named `cookie` with a value `"User|2022-07-07 06:24:08.802299"` in the format "{username}|{timestamp}" + - We can chage the cookie value with `"Admin|2022-07-07 06:24:08.802299"` ( Admin/admin/some other common admin name ) + - after some guessing we got "admin|2022-07-07 06:24:08.802299" is the admin cookie , which gives us admin access. + - ![image](https://user-images.githubusercontent.com/75058161/177698238-b564faa9-7a98-4333-8498-0069c41a85d1.png) +# +## 2021-A6:Using Components with Known Vulnerabilities + +**lab-2** +- Given an utility to apply some math expression on an image +- ![image](https://user-images.githubusercontent.com/75058161/178036849-aae96b02-9633-47e5-a605-0a07ffb17919.png) +- From the lab descripting we found this module uses pillow 8 +- After some OSINT and dorking +- ![image](https://user-images.githubusercontent.com/75058161/178037399-7ac55275-6af8-45d6-a0da-e679a2744cd8.png) +- Let's try `exec(exit())` +- ![image](https://user-images.githubusercontent.com/75058161/178037554-e8935a19-538d-41ae-9a1e-59d31e50c080.png) +- ![image](https://user-images.githubusercontent.com/75058161/178037626-4925debd-5c96-4e10-83b8-267df7199488.png) +- Successfully triggerd a server error. + + + + +### 2021-A3:Server side Template Injection + +`{% load log %} +{% get_admin_log 5 as log %} +{% for e in log %} + {{e.user.get_username}} : {{e.user.password}} +{% endfor %}` + +add a post which includes this content + +The result would look like this --> +![Screenshot from 2022-06-10 21-04-29](https://user-images.githubusercontent.com/75058161/173106213-9e218e81-d4b2-4447-9570-4aa8de3dea88.png) + +### 2021-A8: Software and Data Integrity failure +This data is a demonstration that how an XSS attack can deceive users to download any malicious file. The lab consists of a page to download a file, and a direct link to that page is also given (from a hacker). Let's download both files and compare the hash before opening that. +![image](https://user-images.githubusercontent.com/75058161/190912308-1d26fb2e-2c6c-4c67-bf2a-9bb0f4abbfd0.png) +So as we can see the hashes don't match. So as a user we should always cross-check signatures for verification of Data Integrity. + +More more information about the attack itself you can look into the url --> +```http://127.0.0.1:8000/2021/A8/lab2?username=user+%3Cscript%3Edocument.getElementById%28%22download_link%22%29.setAttribute%28%22href%22%2C%22%2Fstatic%2Ffake.txt%22%29%3B%3C%2Fscript%3Euser+%3Cscript%3Edocument.getElementById%28%22download_link%22%29.setAttribute%28%22href%22%2C%22%2Fstatic%2Ffake.txt%22%29%3B%3C%2Fscript%3E``` +It have a file url and XXS attack to replace the actual file url. + +### 2021-A9: Insufficient Logging & Monitoring +This lab have active logging and have a login page ( we don't have credential ) +So every fake entry is logged so the user name is printed in the file itself.. +```ERROR:root:2022-07-04 07:21:50.906938:127.0.0.1:User1:Hash1``` +this is a sample hash .. +So we can Enter user name anything and password = ```pass\nERROR:root:2022-07-04 07:21:50.906938:127.0.0.1:User1:Hash1``` +It will create one fake log and also it can cause log overflow also by passing lots of data in injection. + +### 2021:A10 : SSRF lab2 +This lab have a local page at ```/ssrf_target``` that can be only accesed from localhost. Now if we do ```python manage.py runserver``` that page will be accisible +but if we start the server by ```python manage.py runserver 0:8000``` the page wont be accessble from ```http://[your ip]/ssrf_target``` + +Now comes the utility that takes the URL and fetch the data, if we give the localhost url to this utility it can fetch the data easily and we can see the page from outside localhost. + diff --git a/chatbot/README.md b/chatbot/README.md new file mode 100644 index 0000000..8f26e5a --- /dev/null +++ b/chatbot/README.md @@ -0,0 +1,12 @@ +# How to run PyGoatBot in Google Colab + +Follow these steps to run the PyGoatBot code in Google Colab: +1. Open a new Google Colab notebook. +2. Install the ChatterBot library by running the following command: `!pip install chatterbot` +3. Copy and paste the code into a new cell. +4. Run the code cell. + +## Usage +1. The PyGoatBot will prompt you to select a question from a list of available questions. +2. Type the number of the question you want to ask, and the chatbot will respond. +3. To exit the chatbot, type 'q' or 'exit' when prompted. diff --git a/chatbot/pygoatbot.ipynb b/chatbot/pygoatbot.ipynb new file mode 100644 index 0000000..4b7c1c4 --- /dev/null +++ b/chatbot/pygoatbot.ipynb @@ -0,0 +1,410 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyMFbN9Hl74O897o7MFKnACj", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + }, + "gpuClass": "standard" + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "code", + "source": [ + "pip install chatterbot==1.0.2\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "uYnWRxB0KzVe", + "outputId": "f2994ae9-d748-4c3c-d7dd-6bcb4d144ff8" + }, + "execution_count": 1, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Collecting chatterbot==1.0.2\n", + " Downloading ChatterBot-1.0.2-py2.py3-none-any.whl (65 kB)\n", + "\u001b[2K \u001b[90mโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\u001b[0m \u001b[32m65.8/65.8 KB\u001b[0m \u001b[31m2.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hCollecting sqlalchemy<1.3,>=1.2\n", + " Downloading SQLAlchemy-1.2.19.tar.gz (5.7 MB)\n", + "\u001b[2K \u001b[90mโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\u001b[0m \u001b[32m5.7/5.7 MB\u001b[0m \u001b[31m33.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + "Requirement already satisfied: nltk<4.0,>=3.2 in /usr/local/lib/python3.9/dist-packages (from chatterbot==1.0.2) (3.8.1)\n", + "Collecting mathparse<0.2,>=0.1\n", + " Downloading mathparse-0.1.2-py3-none-any.whl (7.2 kB)\n", + "Collecting pymongo<4.0,>=3.3\n", + " Downloading pymongo-3.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (515 kB)\n", + "\u001b[2K \u001b[90mโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\u001b[0m \u001b[32m515.5/515.5 KB\u001b[0m \u001b[31m9.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hCollecting python-dateutil<2.8,>=2.7\n", + " Downloading python_dateutil-2.7.5-py2.py3-none-any.whl (225 kB)\n", + "\u001b[2K \u001b[90mโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\u001b[0m \u001b[32m225.7/225.7 KB\u001b[0m \u001b[31m12.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hCollecting pint>=0.8.1\n", + " Downloading Pint-0.20.1-py3-none-any.whl (269 kB)\n", + "\u001b[2K \u001b[90mโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\u001b[0m \u001b[32m269.5/269.5 KB\u001b[0m \u001b[31m4.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hCollecting chatterbot-corpus<1.3,>=1.2\n", + " Downloading chatterbot_corpus-1.2.0-py2.py3-none-any.whl (117 kB)\n", + "\u001b[2K \u001b[90mโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\u001b[0m \u001b[32m117.3/117.3 KB\u001b[0m \u001b[31m4.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hCollecting PyYAML<4.0,>=3.12\n", + " Downloading PyYAML-3.13.tar.gz (270 kB)\n", + "\u001b[2K \u001b[90mโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\u001b[0m \u001b[32m270.6/270.6 KB\u001b[0m \u001b[31m13.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + "Requirement already satisfied: regex>=2021.8.3 in /usr/local/lib/python3.9/dist-packages (from nltk<4.0,>=3.2->chatterbot==1.0.2) (2022.10.31)\n", + "Requirement already satisfied: tqdm in /usr/local/lib/python3.9/dist-packages (from nltk<4.0,>=3.2->chatterbot==1.0.2) (4.65.0)\n", + "Requirement already satisfied: joblib in /usr/local/lib/python3.9/dist-packages (from nltk<4.0,>=3.2->chatterbot==1.0.2) (1.1.1)\n", + "Requirement already satisfied: click in /usr/local/lib/python3.9/dist-packages (from nltk<4.0,>=3.2->chatterbot==1.0.2) (8.1.3)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.9/dist-packages (from python-dateutil<2.8,>=2.7->chatterbot==1.0.2) (1.16.0)\n", + "Building wheels for collected packages: sqlalchemy, PyYAML\n", + " Building wheel for sqlalchemy (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + " Created wheel for sqlalchemy: filename=SQLAlchemy-1.2.19-cp39-cp39-linux_x86_64.whl size=1157816 sha256=922b29a3390946efcb35b47ccdfe5d923eeb8a2052229f7e2b11130708e7c628\n", + " Stored in directory: /root/.cache/pip/wheels/12/75/ee/52355e3658b18c812a419a7fdf581ab885b01c0675e25e9b01\n", + " Building wheel for PyYAML (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + " Created wheel for PyYAML: filename=PyYAML-3.13-cp39-cp39-linux_x86_64.whl size=43098 sha256=59a2dbcb61dc3619f01f5798fde2819e7f5314a91a2486497a6bc9521f1d3afa\n", + " Stored in directory: /root/.cache/pip/wheels/81/6e/87/725bed1db7f86e1c7091ef5f4a4f11b0fcf7023c2be4fc29db\n", + "Successfully built sqlalchemy PyYAML\n", + "Installing collected packages: sqlalchemy, PyYAML, mathparse, python-dateutil, pymongo, pint, chatterbot-corpus, chatterbot\n", + " Attempting uninstall: sqlalchemy\n", + " Found existing installation: SQLAlchemy 1.4.47\n", + " Uninstalling SQLAlchemy-1.4.47:\n", + " Successfully uninstalled SQLAlchemy-1.4.47\n", + " Attempting uninstall: PyYAML\n", + " Found existing installation: PyYAML 6.0\n", + " Uninstalling PyYAML-6.0:\n", + " Successfully uninstalled PyYAML-6.0\n", + " Attempting uninstall: python-dateutil\n", + " Found existing installation: python-dateutil 2.8.2\n", + " Uninstalling python-dateutil-2.8.2:\n", + " Successfully uninstalled python-dateutil-2.8.2\n", + "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n", + "prophet 1.1.2 requires python-dateutil>=2.8.0, but you have python-dateutil 2.7.5 which is incompatible.\n", + "pandas 1.4.4 requires python-dateutil>=2.8.1, but you have python-dateutil 2.7.5 which is incompatible.\n", + "pandas-profiling 3.2.0 requires PyYAML>=5.0.0, but you have pyyaml 3.13 which is incompatible.\n", + "flax 0.6.8 requires PyYAML>=5.4.1, but you have pyyaml 3.13 which is incompatible.\n", + "dask 2022.12.1 requires pyyaml>=5.3.1, but you have pyyaml 3.13 which is incompatible.\u001b[0m\u001b[31m\n", + "\u001b[0mSuccessfully installed PyYAML-3.13 chatterbot-1.0.2 chatterbot-corpus-1.2.0 mathparse-0.1.2 pint-0.20.1 pymongo-3.13.0 python-dateutil-2.7.5 sqlalchemy-1.2.19\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "pip install nltk" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Dgn025lMxOLq", + "outputId": "5de3b172-ff9c-4d54-f723-34d3c9ed8318" + }, + "execution_count": 2, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Requirement already satisfied: nltk in /usr/local/lib/python3.9/dist-packages (3.8.1)\n", + "Requirement already satisfied: regex>=2021.8.3 in /usr/local/lib/python3.9/dist-packages (from nltk) (2022.10.31)\n", + "Requirement already satisfied: tqdm in /usr/local/lib/python3.9/dist-packages (from nltk) (4.65.0)\n", + "Requirement already satisfied: joblib in /usr/local/lib/python3.9/dist-packages (from nltk) (1.1.1)\n", + "Requirement already satisfied: click in /usr/local/lib/python3.9/dist-packages (from nltk) (8.1.3)\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "pip install logger" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "aCCtNKLj6J8a", + "outputId": "fba612a7-0870-41e4-b670-751d1490319b" + }, + "execution_count": 34, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Collecting logger\n", + " Downloading logger-1.4.tar.gz (1.2 kB)\n", + " Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + "Building wheels for collected packages: logger\n", + " Building wheel for logger (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + " Created wheel for logger: filename=logger-1.4-py3-none-any.whl size=1780 sha256=375578a39f0783a695470050f7bfeed4759edc359a2f928ea57bbcf181fe7a17\n", + " Stored in directory: /root/.cache/pip/wheels/d6/2c/20/0bf3428f60a053875adaf43bee20695fff6e5d5a2cffaceaad\n", + "Successfully built logger\n", + "Installing collected packages: logger\n", + "Successfully installed logger-1.4\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "training_data = [\n", + " 'What is OWASP PyGoat?',\n", + " 'OWASP PyGoat is an intentionally vulnerable web application used for learning web security testing.',\n", + " 'Why should I learn web security testing?',\n", + " 'Learning web security testing can help you understand how to identify and prevent web application attacks.',\n", + " 'What types of vulnerabilities can PyGoat help me learn about?',\n", + " 'PyGoat can help you learn about various types of web application vulnerabilities, including injection attacks, cross-site scripting (XSS), and broken authentication and session management.',\n", + " 'How can I use PyGoat to learn web security testing?',\n", + " 'PyGoat includes a series of lessons and challenges designed to teach you about web security testing techniques and common vulnerabilities.',\n", + " 'Is PyGoat suitable for beginners?',\n", + " 'Yes, PyGoat is designed to be accessible to beginners and experienced professionals alike.',\n", + " 'Where can I download PyGoat?',\n", + " 'You can download PyGoat from the official GitHub repository at https://github.com/OWASP/PyGoat',\n", + " 'Are there any resources available to help me get started with PyGoat?',\n", + " 'Yes, the PyGoat documentation includes a Getting Started guide and a list of additional resources to help you learn about web security testing.',\n", + " 'Can I contribute to PyGoat?',\n", + " 'Yes, PyGoat is an open-source project and welcomes contributions from anyone interested in improving the application.',\n", + "]\n" + ], + "metadata": { + "id": "o0XoIqiSxHDt" + }, + "execution_count": 35, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "import nltk\n", + "import logging\n", + "from collections import Counter\n", + "from operator import itemgetter\n", + "from chatterbot import ChatBot\n", + "from chatterbot.trainers import ListTrainer\n", + "from chatterbot.logic import BestMatch\n", + "from nltk.tokenize import word_tokenize\n", + "from nltk.corpus import stopwords\n", + "\n", + "# Download the required NLTK packages\n", + "nltk.download(\"punkt\")\n", + "nltk.download(\"averaged_perceptron_tagger\")\n", + "nltk.download(\"maxent_ne_chunker\")\n", + "nltk.download(\"words\")\n", + "\n", + "# Define your training data here\n", + "\n", + "# Create a new chatbot\n", + "logging.getLogger('chatterbot').setLevel(logging.ERROR)\n", + "chatbot = ChatBot(\n", + " \"PyGoatBot\",\n", + " storage_adapter=\"chatterbot.storage.SQLStorageAdapter\",\n", + " database_uri=\"sqlite:///database.sqlite3\",\n", + " logic_adapters=[\n", + " {\n", + " \"import_path\": \"chatterbot.logic.BestMatch\",\n", + " \"default_response\": \"I'm sorry, I'm not sure I understand.\",\n", + " \"maximum_similarity_threshold\": 0.90,\n", + " }\n", + " ],\n", + ")\n", + "\n", + "# Train the chatbot with the training data\n", + "trainer = ListTrainer(chatbot)\n", + "trainer.train(training_data)\n", + "nltk.download('stopwords')\n", + "\n", + "print(\"Welcome to PyGoatBot! Type 'q or exit' to quit.\")\n", + "print()\n", + "print(\"How can I help?\")\n", + "while True:\n", + " try:\n", + " user_input = input(\"You: \")\n", + " if user_input.lower() == \"exit\" or user_input.lower()==\"q\":\n", + " break\n", + " sentence = user_input\n", + " sentence = sentence.lower()\n", + " words = word_tokenize(sentence)\n", + " stop_words = set(stopwords.words('english'))\n", + " words = [word for word in words if not word in stop_words]\n", + " tagged_words = nltk.pos_tag(words)\n", + " keywords = []\n", + " for word, tag in tagged_words:\n", + " if tag.startswith('N') or tag.startswith('J'):\n", + " keywords.append(word)\n", + "\n", + "\n", + " if not keywords:\n", + " print(\"I'm sorry, I didn't find any important keywords in your input.\")\n", + " continue\n", + "\n", + " dict_que={}\n", + " for i in range(0, len(training_data), 2):\n", + " keyword_counts = 0\n", + " for keyword in keywords:\n", + " if keyword.lower() in training_data[i].lower():\n", + " keyword_counts += 1\n", + " dict_que[training_data[i]]=keyword_counts\n", + "\n", + " sorted_dict = sorted(dict_que.items(), key=lambda x: x[1], reverse=True)\n", + " top_questions=sorted_dict[0:4]\n", + "\n", + " if not top_questions:\n", + " print(\"I'm sorry, I couldn't find any relevant questions in my database.\")\n", + " continue\n", + " print()\n", + " print(\"--Available questions:--\")\n", + " for i, question in enumerate(top_questions):\n", + " print(f\" {i+1}. {question[0]}\")\n", + " print(\" 5. Main Menu\")\n", + " print()\n", + "\n", + " while True:\n", + " try:\n", + " question_index = int(input(\"Enter a number to select a question: \"))\n", + " if 1 <= question_index <= 4:\n", + " break\n", + " elif question_index==5:\n", + " print(\"Taking you to the main menu\")\n", + " break\n", + " \n", + " else:\n", + " print(\"Please enter a number between 1 and 4.\")\n", + "\n", + " except ValueError:\n", + " print(\"Please enter a valid number.\")\n", + "\n", + " if question_index!=5:\n", + " question = top_questions[question_index - 1][0]\n", + " response = chatbot.get_response(question)\n", + "\n", + " # Output\n", + " print(f\"PyGoatBot: {response}\")\n", + "\n", + " except (KeyboardInterrupt, EOFError):\n", + " break\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "dklscBXxWCUB", + "outputId": "6953214c-1855-4b9f-9f7c-026c43f12850" + }, + "execution_count": 46, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "List Trainer: [####################] 100%" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "[nltk_data] Downloading package punkt to /root/nltk_data...\n", + "[nltk_data] Package punkt is already up-to-date!\n", + "[nltk_data] Downloading package averaged_perceptron_tagger to\n", + "[nltk_data] /root/nltk_data...\n", + "[nltk_data] Package averaged_perceptron_tagger is already up-to-\n", + "[nltk_data] date!\n", + "[nltk_data] Downloading package maxent_ne_chunker to\n", + "[nltk_data] /root/nltk_data...\n", + "[nltk_data] Package maxent_ne_chunker is already up-to-date!\n", + "[nltk_data] Downloading package words to /root/nltk_data...\n", + "[nltk_data] Package words is already up-to-date!\n", + "[nltk_data] Downloading package averaged_perceptron_tagger to\n", + "[nltk_data] /root/nltk_data...\n", + "[nltk_data] Package averaged_perceptron_tagger is already up-to-\n", + "[nltk_data] date!\n", + "[nltk_data] Downloading package punkt to /root/nltk_data...\n", + "[nltk_data] Package punkt is already up-to-date!\n", + "[nltk_data] Downloading package stopwords to /root/nltk_data...\n", + "[nltk_data] Package stopwords is already up-to-date!\n", + "[nltk_data] Downloading package stopwords to /root/nltk_data...\n", + "[nltk_data] Package stopwords is already up-to-date!\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\r\n", + "Welcome to PyGoatBot! Type 'q or exit' to quit.\n", + "You: How to contribute in pygoat?\n", + "\n", + "--Available questions:--\n", + " 1. Can I contribute to PyGoat?\n", + " 2. What is OWASP PyGoat?\n", + " 3. What types of vulnerabilities can PyGoat help me learn about?\n", + " 4. How can I use PyGoat to learn web security testing?\n", + " 5. Main Menu\n", + "\n", + "Enter a number to select a question: 1\n", + "PyGoatBot: Yes, PyGoat is an open-source project and welcomes contributions from anyone interested in improving the application.\n", + "You: How to download pygoat?\n", + "\n", + "--Available questions:--\n", + " 1. Where can I download PyGoat?\n", + " 2. What is OWASP PyGoat?\n", + " 3. What types of vulnerabilities can PyGoat help me learn about?\n", + " 4. How can I use PyGoat to learn web security testing?\n", + " 5. Main Menu\n", + "\n", + "Enter a number to select a question: how to download?\n", + "Please enter a valid number.\n", + "Enter a number to select a question: 1\n", + "PyGoatBot: You can download PyGoat from the official GitHub repository at https://github.com/OWASP/PyGoat\n", + "You: what is web security testing?\n", + "\n", + "--Available questions:--\n", + " 1. Why should I learn web security testing?\n", + " 2. How can I use PyGoat to learn web security testing?\n", + " 3. What is OWASP PyGoat?\n", + " 4. What types of vulnerabilities can PyGoat help me learn about?\n", + " 5. Main Menu\n", + "\n", + "Enter a number to select a question: 2\n", + "PyGoatBot: PyGoat includes a series of lessons and challenges designed to teach you about web security testing techniques and common vulnerabilities.\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "jpYCc8FL6Gzi" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..3d39f83 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,29 @@ +version: "3.3" + +services: + db: + image: postgres + volumes: + - ./data/db:/var/lib/postgresql/data + environment: + - POSTGRES_DB=postgres + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=postgres + web: + build: . + image: pygoat/pygoat + command: gunicorn --bind 0.0.0.0:8000 --workers 6 pygoat.wsgi + ports: + - "8000:8000" + volumes: + - .:/app + depends_on: + - migration + - db + migration: + image: pygoat/pygoat + command: python pygoat/manage.py migrate --noinput + volumes: + - .:/app + depends_on: + - db diff --git a/docs/dev_guide.md b/docs/dev_guide.md new file mode 100644 index 0000000..3497ff7 --- /dev/null +++ b/docs/dev_guide.md @@ -0,0 +1,207 @@ +# Developer's Guide + +PyGoat is an intentionally vulnerable web application written using the Python-Django Framework. We welcome Developers to contribute to the project. + +## Project Structure + +![image](https://user-images.githubusercontent.com/70275323/154626667-be93c711-47ca-45db-be8d-4ce62e7fbfbb.png) + +`installer.sh` is the installer bash file. It downloads and installs requirements that are necessary for the project. + +`uninstaller.sh` is the uninstaller bash file. It will uninstall the project and and requirements that were installed along with it. + +`requirements.txt` is the python3 requirements file. + +### Django Folder Structure + +The `pygoat` folder is the main folder that contains the Django Project. The project has 2 apps - `introduction` and `pygoat`, and both of them have their own folders. Apart from them there's another folder - `Solutions` which contains solutions to all scenarios. + +* The Inroduction folder contains the main workings of the project and consists of HTML templates, CSS files, and Python code that forms the backend of the application +* The pygoat folder is the Django default folder and it contains all important settings/configurations essential to running the apps. +* The Solutions folder has `solutions.md` and has solutions to all scenarios presented in application + +### Contents of the `introdution` folder + +The `introduction` folder has a few more folders and files + +![image](https://user-images.githubusercontent.com/70275323/154636031-c5bd01de-82ac-4fff-836a-b44e01c0e415.png) + +#### Folders + +* `lab_code` - This contains `test.py` which can be used to test a piece of code before implementing it in the app. +* `static` - Contains CSS files that give the pages styling +* `templates` - Contains all HTML templates used by the we app. This has 3 folders +* * `introduction` - Contains the base html code that is used throughout the app. +* * `lab` - contains HTML code for the 10 Scenarios that can be solved +* * `registration` - Contains HTML code for registration and login pages +* +#### Files + +* `models.py` - Has different models eg - FAANG, login, etc +* `urls.py` - List of URLS and how to route them +* `views.py` - Main Backend Code that runs the Web App + +## Understanding how the templates work + +All templates are located in `pygoat/introduction/templates` and main CSS used for the project is located in `pygoat/introduction/static/introduction/style4.css` + +There are 3 folders in templates +- introduction - Contains `base.html` and `home.html` +- Lab - contains 12 folders. All folders except AUTH contain templates that will be displayed for the 10 labs +- registration - contains templates for registration, login and logout + +`base.html` - Contains Base layout for the entire website. This is extended by most other templates and the base layout, CSS and formatting will be dictated by this template. CSS that is included for this template is automatically applied to the all other templates that extend this one. + +The following image shows a few parts that `base.html` defines in the website. + +![front_1](https://user-images.githubusercontent.com/70275323/154678332-ada4935f-a970-4ca3-a8be-f4babda8cb3b.png) + +The different lab folders inside `Lab` contain templates related to labs + +![image](https://user-images.githubusercontent.com/70275323/154682348-d51c521f-e885-4b81-958d-38c2f73ba9be.png) + +## Understanding how `views.py` works (Working of Backend) + +Navigate to `views.py` located in the introduction folder of the Django Project. This file will be your main concern when it comes to backend development + +How views.py works - + +The python file is divided into sections depending on which purpose they're being used for. + +For example lets take the function `cmd_lab` + +The function is as follows + +```python3 +def cmd_lab(request): + if request.user.is_authenticated: # checks if the user is authenticated + if(request.method=="POST"): + domain=request.POST.get('domain') # this is the input of the user + domain=domain.replace("https://www.",'') + os=request.POST.get('os') + print(os) + if(os=='win'): + command="nslookup {}".format(domain) + else: + command = "dig {}".format(domain) + + try: + # output=subprocess.check_output(command,shell=True,encoding="UTF-8") + process = subprocess.Popen( + command, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = process.communicate() + data = stdout.decode('utf-8') + stderr = stderr.decode('utf-8') + # res = json.loads(data) + # print("Stdout\n" + data) + output = data + stderr + print(data + stderr) + except: + output = "Something went wrong" + return render(request,'Lab/CMD/cmd_lab.html',{"output":output}) # this renders the template - cmd_lab.html + print(output) + return render(request,'Lab/CMD/cmd_lab.html',{"output":output}) # this renders the template - cmd_lab.html + else: + return render(request, 'Lab/CMD/cmd_lab.html') # this renders the template - cmd_lab.html + else: + return redirect('login') # if user wasn't logged in the first if statement of the function then redirect to login +``` + +The first statement checks if the user is authenticated. If not, it directs to the login page. + +The syntax to take input from user through a web page using POST request is + +```python3 +value=request.POST.get('value_name') +``` +This syntax is used twice in the above function + +```python3 +domain=request.POST.get('domain') +os=request.POST.get('os') +``` + +The function usually ends with rendering a particular template along with giving it a few values. Lets see how this works. + +Lets take the snippet + +```python3 +output = "Something went wrong" +return render(request,'Lab/CMD/cmd_lab.html',{"output":output}) +``` + +And lets take the snippet from `'Lab/CMD/cmd_lab.html'` that will display the `output` variable + +```html +
+ {% if output %} +
Output

+ +
{{output}}
+
+ {% endif %} +
+``` + +Lets see what these two snippets acheive + +The python3 code from views.py renders this template and a variable 'output' with value of output ( which in this case is "Something went wrong") is made available in the HTML template + +The `output` variable can be accessed from the HTML template by using tags provided in the the [Django Template Language](https://docs.djangoproject.com/en/4.0/ref/templates/language/) (the link contains vital info. It's recommended to check it out) + +What this achieves in this case, is - +- Checking if output variable exists +- If it exists, displays value of output variable in preformatted way + +## Understanding request authentication + +To ensure every page is rendered to an authenticated user, all functions in `views.py` begin with an authentication check that looks something like + +```python3 +if request.user.is_authenticated: + # Logic of the program here! + else: + return redirect('login') + # Rediects to login page if a request is not authenticated +``` + +To Add a new function to views.py, please make sure to include a check for authentication. + +## Understanding routing with `urls.py` + +There are 2 `urls.py` files in the project. + +These are located in `pygoat/pygoat` and `pygoat/introduction` + +These files are responsibele for routing the website urls to the correct template and backend function. + +Let's take an example from a code snippet from `pygoat/introduction/urls.py` + +```python3 + path('', views.home, name='homepage'), + path('xss', views.xss,name="xss"), + path('xssL',views.xss_lab,name='xss_lab'), +``` + +What this code does - + +- When user navigates to 127.0.0.1/ in web browser, function views.home is executed +- When user navigates to 127.0.0.1/xss in web browser, function views.xss is executed +- When user navigates to 127.0.0.1/xssL in web browser, function views.xss_lab is executed + +Let's take an example from a code snippet from `pygoat/pygoat/urls.py` + +```python3 + path('', views.home, name='homepage'), + path('xss', views.xss,name="xss"), + path('xssL',views.xss_lab,name='xss_lab'), +``` + +There are a few lines in urls.py that do not look like these. They're for special purposes like implementing django-allAuth and other features + +If theres any doubt or issue feel free to raise an Issue, or correct an existing issue and send PR. Feel free to join the [PyGoat Devs channel](https://t.me/+WpqLBwviT00xZDI1) on telegram + +Happy Coding! diff --git a/gh-md-toc b/gh-md-toc new file mode 100755 index 0000000..ef389e7 --- /dev/null +++ b/gh-md-toc @@ -0,0 +1,361 @@ +#!/usr/bin/env bash + +# +# Steps: +# +# 1. Download corresponding html file for some README.md: +# curl -s $1 +# +# 2. Discard rows where no substring 'user-content-' (github's markup): +# awk '/user-content-/ { ... +# +# 3.1 Get last number in each row like ' ... sitemap.js.*<\/h/)+2, RLENGTH-5) +# +# 5. Find anchor and insert it inside "(...)": +# substr($0, match($0, "href=\"[^\"]+?\" ")+6, RLENGTH-8) +# + +gh_toc_version="0.7.0" + +gh_user_agent="gh-md-toc v$gh_toc_version" + +# +# Download rendered into html README.md by its url. +# +# +gh_toc_load() { + local gh_url=$1 + + if type curl &>/dev/null; then + curl --user-agent "$gh_user_agent" -s "$gh_url" + elif type wget &>/dev/null; then + wget --user-agent="$gh_user_agent" -qO- "$gh_url" + else + echo "Please, install 'curl' or 'wget' and try again." + exit 1 + fi +} + +# +# Converts local md file into html by GitHub +# +# -> curl -X POST --data '{"text": "Hello world github/linguist#1 **cool**, and #1!"}' https://api.github.com/markdown +#

Hello world github/linguist#1 cool, and #1!

'" +gh_toc_md2html() { + local gh_file_md=$1 + URL=https://api.github.com/markdown/raw + + if [ ! -z "$GH_TOC_TOKEN" ]; then + TOKEN=$GH_TOC_TOKEN + else + TOKEN_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/token.txt" + if [ -f "$TOKEN_FILE" ]; then + TOKEN="$(cat $TOKEN_FILE)" + fi + fi + if [ ! -z "${TOKEN}" ]; then + AUTHORIZATION="Authorization: token ${TOKEN}" + fi + + # echo $URL 1>&2 + OUTPUT=$(curl -s \ + --user-agent "$gh_user_agent" \ + --data-binary @"$gh_file_md" \ + -H "Content-Type:text/plain" \ + -H "$AUTHORIZATION" \ + "$URL") + + if [ "$?" != "0" ]; then + echo "XXNetworkErrorXX" + fi + if [ "$(echo "${OUTPUT}" | awk '/API rate limit exceeded/')" != "" ]; then + echo "XXRateLimitXX" + else + echo "${OUTPUT}" + fi +} + + +# +# Is passed string url +# +gh_is_url() { + case $1 in + https* | http*) + echo "yes";; + *) + echo "no";; + esac +} + +# +# TOC generator +# +gh_toc(){ + local gh_src=$1 + local gh_src_copy=$1 + local gh_ttl_docs=$2 + local need_replace=$3 + local no_backup=$4 + local no_footer=$5 + + if [ "$gh_src" = "" ]; then + echo "Please, enter URL or local path for a README.md" + exit 1 + fi + + + # Show "TOC" string only if working with one document + if [ "$gh_ttl_docs" = "1" ]; then + + echo "Table of Contents" + echo "=================" + echo "" + gh_src_copy="" + + fi + + if [ "$(gh_is_url "$gh_src")" == "yes" ]; then + gh_toc_load "$gh_src" | gh_toc_grab "$gh_src_copy" + if [ "${PIPESTATUS[0]}" != "0" ]; then + echo "Could not load remote document." + echo "Please check your url or network connectivity" + exit 1 + fi + if [ "$need_replace" = "yes" ]; then + echo + echo "!! '$gh_src' is not a local file" + echo "!! Can't insert the TOC into it." + echo + fi + else + local rawhtml=$(gh_toc_md2html "$gh_src") + if [ "$rawhtml" == "XXNetworkErrorXX" ]; then + echo "Parsing local markdown file requires access to github API" + echo "Please make sure curl is installed and check your network connectivity" + exit 1 + fi + if [ "$rawhtml" == "XXRateLimitXX" ]; then + echo "Parsing local markdown file requires access to github API" + echo "Error: You exceeded the hourly limit. See: https://developer.github.com/v3/#rate-limiting" + TOKEN_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/token.txt" + echo "or place GitHub auth token here: ${TOKEN_FILE}" + exit 1 + fi + local toc=`echo "$rawhtml" | gh_toc_grab "$gh_src_copy"` + echo "$toc" + if [ "$need_replace" = "yes" ]; then + if grep -Fxq "" $gh_src && grep -Fxq "" $gh_src; then + echo "Found markers" + else + echo "You don't have or in your file...exiting" + exit 1 + fi + local ts="<\!--ts-->" + local te="<\!--te-->" + local dt=`date +'%F_%H%M%S'` + local ext=".orig.${dt}" + local toc_path="${gh_src}.toc.${dt}" + local toc_footer="" + # http://fahdshariff.blogspot.ru/2012/12/sed-mutli-line-replacement-between-two.html + # clear old TOC + sed -i${ext} "/${ts}/,/${te}/{//!d;}" "$gh_src" + # create toc file + echo "${toc}" > "${toc_path}" + if [ "${no_footer}" != "yes" ]; then + echo -e "\n${toc_footer}\n" >> "$toc_path" + fi + + # insert toc file + if [[ "`uname`" == "Darwin" ]]; then + sed -i "" "/${ts}/r ${toc_path}" "$gh_src" + else + sed -i "/${ts}/r ${toc_path}" "$gh_src" + fi + echo + if [ "${no_backup}" = "yes" ]; then + rm ${toc_path} ${gh_src}${ext} + fi + echo "!! TOC was added into: '$gh_src'" + if [ -z "${no_backup}" ]; then + echo "!! Origin version of the file: '${gh_src}${ext}'" + echo "!! TOC added into a separate file: '${toc_path}'" + fi + echo + fi + fi +} + +# +# Grabber of the TOC from rendered html +# +# $1 - a source url of document. +# It's need if TOC is generated for multiple documents. +# +gh_toc_grab() { + common_awk_script=' + modified_href = "" + split(href, chars, "") + for (i=1;i <= length(href); i++) { + c = chars[i] + res = "" + if (c == "+") { + res = " " + } else { + if (c == "%") { + res = "\\x" + } else { + res = c "" + } + } + modified_href = modified_href res + } + print sprintf("%*s", (level-1)*3, "") "* [" text "](" gh_url modified_href ")" + ' + if [ `uname -s` == "OS/390" ]; then + grepcmd="pcregrep -o" + echoargs="" + awkscript='{ + level = substr($0, length($0), 1) + text = substr($0, match($0, /a>.*<\/h/)+2, RLENGTH-5) + href = substr($0, match($0, "href=\"([^\"]+)?\"")+6, RLENGTH-7) + '"$common_awk_script"' + }' + else + grepcmd="grep -Eo" + echoargs="-e" + awkscript='{ + level = substr($0, length($0), 1) + text = substr($0, match($0, /a>.*<\/h/)+2, RLENGTH-5) + href = substr($0, match($0, "href=\"[^\"]+?\"")+6, RLENGTH-7) + '"$common_awk_script"' + }' + fi + href_regex='href=\"[^\"]+?\"' + + # if closed is on the new line, then move it on the prev line + # for example: + # was: The command foo1 + # + # became: The command foo1 + sed -e ':a' -e 'N' -e '$!ba' -e 's/\n<\/h/<\/h/g' | + + # find strings that corresponds to template + $grepcmd '//g' | sed 's/<\/code>//g' | + + # remove g-emoji + sed 's/]*[^<]*<\/g-emoji> //g' | + + # now all rows are like: + # ... / placeholders" + echo " $app_name - Create TOC for markdown from STDIN" + echo " $app_name --help Show help" + echo " $app_name --version Show version" + return + fi + + if [ "$1" = '--version' ]; then + echo "$gh_toc_version" + echo + echo "os: `lsb_release -d | cut -f 2`" + echo "kernel: `cat /proc/version`" + echo "shell: `$SHELL --version`" + echo + for tool in curl wget grep awk sed; do + printf "%-5s: " $tool + echo `$tool --version | head -n 1` + done + return + fi + + if [ "$1" = "-" ]; then + if [ -z "$TMPDIR" ]; then + TMPDIR="/tmp" + elif [ -n "$TMPDIR" -a ! -d "$TMPDIR" ]; then + mkdir -p "$TMPDIR" + fi + local gh_tmp_md + if [ `uname -s` == "OS/390" ]; then + local timestamp=$(date +%m%d%Y%H%M%S) + gh_tmp_md="$TMPDIR/tmp.$timestamp" + else + gh_tmp_md=$(mktemp $TMPDIR/tmp.XXXXXX) + fi + while read input; do + echo "$input" >> "$gh_tmp_md" + done + gh_toc_md2html "$gh_tmp_md" | gh_toc_grab "" + return + fi + + if [ "$1" = '--insert' ]; then + need_replace="yes" + shift + fi + + if [ "$1" = '--no-backup' ]; then + need_replace="yes" + no_backup="yes" + shift + fi + + if [ "$1" = '--hide-footer' ]; then + need_replace="yes" + no_footer="yes" + shift + fi + + for md in "$@" + do + echo "" + gh_toc "$md" "$#" "$need_replace" "$no_backup" "$no_footer" + done + + echo "" + echo "Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)" +} + +# +# Entry point +# +gh_toc_app "$@" + diff --git a/installer.sh b/installer.sh new file mode 100755 index 0000000..3e8d1b7 --- /dev/null +++ b/installer.sh @@ -0,0 +1,12 @@ +#!/bin/bash +apt-get -y -qq update + +apt-get -y -qq install software-properties-common # installation of python3 and python3-pip +add-apt-repository ppa:deadsnakes/ppa +apt-get -y -qq update +apt-get -y -qq install python3 +apt-get -y -qq install python3-pip # python3 and pip installed + +apt-get -y -qq install git # installing git + +python3 -m pip install -r requirements.txt #installing pip requirements \ No newline at end of file diff --git a/introduction/__init__.py b/introduction/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/introduction/admin.py b/introduction/admin.py new file mode 100644 index 0000000..41ae950 --- /dev/null +++ b/introduction/admin.py @@ -0,0 +1,14 @@ +from django.contrib import admin +from .models import FAANG,info,login,comments,otp,tickits,CF_user,AF_admin,AF_session_id +from .models import CSRF_user_tbl +# Register your models here. +admin.site.register(FAANG) +admin.site.register(info) +admin.site.register(login) +admin.site.register(comments) +admin.site.register(otp) +admin.site.register(tickits) +admin.site.register(CF_user) +admin.site.register(AF_admin) +admin.site.register(AF_session_id) +admin.site.register(CSRF_user_tbl) \ No newline at end of file diff --git a/introduction/apis.py b/introduction/apis.py new file mode 100644 index 0000000..a434539 --- /dev/null +++ b/introduction/apis.py @@ -0,0 +1,133 @@ +from django.http import JsonResponse +from django.shortcuts import redirect +from introduction.playground.ssrf import main +from introduction.playground.A9.main import Log +from introduction.playground.A6.utility import check_vuln +from django.contrib.auth import login,authenticate +from .utility import * +from django.views.decorators.csrf import csrf_exempt +import time +from .views import authentication_decorator +import requests +# 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': + 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) + test_bench2 = ['secret.txt'] + correct_output1 = [{"blog": "blog1-passed"}, {"blog": "blog2-passed"}, {"blog": "blog3-passed"}, {"blog": "blog4-passed"}] + outputs = [] + for inputs in test_bench1: + outputs.append(main.ssrf_lab(inputs)) + if outputs == correct_output1: + outputs = [] + else: + 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':'Test bench passed but the code is not secure'}, status = 200,safe = False) + else: + return JsonResponse({'message':'method not allowed'},status = 405) + else: + return JsonResponse({'message':'UnAuthenticated User'},status = 401) + +# Insufficient Logging & Monitoring + + +@csrf_exempt +# @authentication_decorator +def log_function_checker(request): + if request.method == 'POST': + csrf_token = request.POST.get("csrfmiddlewaretoken") + log_code = request.POST.get('log_code') + api_code = request.POST.get('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() + # Clearing the log file before starting the test + f = open('test.log', 'w') + f.write("") + f.close() + 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) + else: + return JsonResponse({"message":"method not allowed"},status = 405) + +#a7 codechecking api +@csrf_exempt +def A7_disscussion_api(request): + if request.method != 'POST': + return JsonResponse({"message":"method not allowed"},status = 405) + + try: + code = request.POST.get('code') + except: + return JsonResponse({"message":"missing code"},status = 400) + + search_snipet = "AF_session_id.objects.get(sesssion_id = cookie).delete()" + search_snipet2 = "AF_session_id.objects.get(sesssion_id=cookie).delete()" + + if (search_snipet in code) or (search_snipet2 in code): + return JsonResponse({"message":"success"},status = 200) + + return JsonResponse({"message":"failure"},status = 400) + +#a6 codechecking api +@csrf_exempt +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) + +@csrf_exempt +def A6_disscussion_api_2(request): + if request.method != 'POST': + return JsonResponse({"message":"method not allowed"},status = 405) + try: + code = request.POST.get('code') + dirname = os.path.dirname(__file__) + filename = os.path.join(dirname, "playground/A6/utility.py") + f = open(filename,"w") + f.write(code) + f.close() + except: + return JsonResponse({"message":"missing code"},status = 400) + return JsonResponse({"message":"success"},status = 200) \ No newline at end of file diff --git a/introduction/apps.py b/introduction/apps.py new file mode 100644 index 0000000..1710c5b --- /dev/null +++ b/introduction/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class IntroductionConfig(AppConfig): + name = 'introduction' diff --git a/introduction/forms.py b/introduction/forms.py new file mode 100644 index 0000000..f65fbf5 --- /dev/null +++ b/introduction/forms.py @@ -0,0 +1,20 @@ +from django import forms +from django.contrib.auth.forms import UserCreationForm +from django.contrib.auth.models import User + + +# Create your forms here. + +class NewUserForm(UserCreationForm): + email = forms.EmailField(required=True) + + class Meta: + model = User + fields = ("username", "email", "password1", "password2") + + def save(self, commit=True): + user = super(NewUserForm, self).save(commit=False) + user.email = self.cleaned_data['email'] + if commit: + user.save() + return user \ No newline at end of file diff --git a/introduction/lab_code/test.py b/introduction/lab_code/test.py new file mode 100644 index 0000000..71eda68 --- /dev/null +++ b/introduction/lab_code/test.py @@ -0,0 +1,29 @@ +''' +import subprocess, json + + +cmd_str = "pwd; ls" +process = subprocess.Popen( + cmd_str, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) +stdout, stderr = process.communicate() +data = stdout.decode('utf-8') +stderr = stderr.decode('utf-8') +# res = json.loads(data) +# print("Stdout\n" + data) +print(data + stderr) +''' +import yaml, subprocess +stream = open('/home/fox/test.yaml', 'r') +data = yaml.load(stream) + +''' +stdout, stderr = data.communicate() +stdout = stdout.decode('utf-8') +stderr = stderr.decode('utf-8') +''' +print(data + "\n") +# print(stdout + "\n") +# print(stderr + "\n") \ No newline at end of file diff --git a/introduction/migrations/0001_initial.py b/introduction/migrations/0001_initial.py new file mode 100644 index 0000000..6186a16 --- /dev/null +++ b/introduction/migrations/0001_initial.py @@ -0,0 +1,23 @@ +# Generated by Django 3.0.6 on 2021-04-13 18:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='FAANG', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('company', models.CharField(max_length=200)), + ('ceo', models.CharField(max_length=200)), + ('about', models.CharField(max_length=200)), + ], + ), + ] diff --git a/introduction/migrations/0002_auto_20210414_1510.py b/introduction/migrations/0002_auto_20210414_1510.py new file mode 100644 index 0000000..0b3b7ee --- /dev/null +++ b/introduction/migrations/0002_auto_20210414_1510.py @@ -0,0 +1,31 @@ +# Generated by Django 3.0.6 on 2021-04-14 09:40 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='faang', + name='about', + ), + migrations.RemoveField( + model_name='faang', + name='ceo', + ), + migrations.CreateModel( + name='info', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('ceo', models.CharField(max_length=200)), + ('about', models.CharField(max_length=200)), + ('faang', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='introduction.FAANG')), + ], + ), + ] diff --git a/introduction/migrations/0003_password_user.py b/introduction/migrations/0003_password_user.py new file mode 100644 index 0000000..a78e9f2 --- /dev/null +++ b/introduction/migrations/0003_password_user.py @@ -0,0 +1,29 @@ +# Generated by Django 3.0.6 on 2021-04-15 10:50 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0002_auto_20210414_1510'), + ] + + operations = [ + migrations.CreateModel( + name='user', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('user', models.CharField(max_length=200)), + ], + ), + migrations.CreateModel( + name='password', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=300)), + ('username', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='introduction.user')), + ], + ), + ] diff --git a/introduction/migrations/0004_auto_20210415_1722.py b/introduction/migrations/0004_auto_20210415_1722.py new file mode 100644 index 0000000..075fb54 --- /dev/null +++ b/introduction/migrations/0004_auto_20210415_1722.py @@ -0,0 +1,22 @@ +# Generated by Django 3.0.6 on 2021-04-15 11:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0003_password_user'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='password', + field=models.CharField(default=0, max_length=300), + preserve_default=False, + ), + migrations.DeleteModel( + name='password', + ), + ] diff --git a/introduction/migrations/0005_auto_20210415_1748.py b/introduction/migrations/0005_auto_20210415_1748.py new file mode 100644 index 0000000..1dc836f --- /dev/null +++ b/introduction/migrations/0005_auto_20210415_1748.py @@ -0,0 +1,17 @@ +# Generated by Django 3.0.6 on 2021-04-15 12:18 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0004_auto_20210415_1722'), + ] + + operations = [ + migrations.RenameModel( + old_name='user', + new_name='login', + ), + ] diff --git a/introduction/migrations/0006_comments.py b/introduction/migrations/0006_comments.py new file mode 100644 index 0000000..e5f09f3 --- /dev/null +++ b/introduction/migrations/0006_comments.py @@ -0,0 +1,21 @@ +# Generated by Django 3.0.6 on 2021-04-17 08:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0005_auto_20210415_1748'), + ] + + operations = [ + migrations.CreateModel( + name='comments', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('comment', models.CharField(max_length=400)), + ], + ), + ] diff --git a/introduction/migrations/0007_auto_20210418_0022.py b/introduction/migrations/0007_auto_20210418_0022.py new file mode 100644 index 0000000..1208434 --- /dev/null +++ b/introduction/migrations/0007_auto_20210418_0022.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.6 on 2021-04-17 18:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0006_comments'), + ] + + operations = [ + migrations.AlterField( + model_name='comments', + name='comment', + field=models.CharField(max_length=600), + ), + ] diff --git a/introduction/migrations/0008_otp.py b/introduction/migrations/0008_otp.py new file mode 100644 index 0000000..b7b961c --- /dev/null +++ b/introduction/migrations/0008_otp.py @@ -0,0 +1,21 @@ +# Generated by Django 3.0.6 on 2021-04-24 06:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0007_auto_20210418_0022'), + ] + + operations = [ + migrations.CreateModel( + name='otp', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('email', models.CharField(max_length=200)), + ('otp', models.IntegerField(max_length=300)), + ], + ), + ] diff --git a/introduction/migrations/0009_auto_20210517_2047.py b/introduction/migrations/0009_auto_20210517_2047.py new file mode 100644 index 0000000..14cd525 --- /dev/null +++ b/introduction/migrations/0009_auto_20210517_2047.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.6 on 2021-05-17 15:17 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0008_otp'), + ] + + operations = [ + migrations.AlterField( + model_name='otp', + name='otp', + field=models.IntegerField(validators=[django.core.validators.MaxValueValidator(300)]), + ), + ] diff --git a/introduction/migrations/0010_authlogin.py b/introduction/migrations/0010_authlogin.py new file mode 100644 index 0000000..fe7a7d0 --- /dev/null +++ b/introduction/migrations/0010_authlogin.py @@ -0,0 +1,22 @@ +# Generated by Django 3.1.13 on 2022-02-10 08:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0009_auto_20210517_2047'), + ] + + operations = [ + migrations.CreateModel( + name='authLogin', + fields=[ + ('username', models.CharField(max_length=200, unique=True)), + ('name', models.CharField(max_length=200)), + ('password', models.CharField(max_length=200)), + ('userid', models.AutoField(primary_key=True, serialize=False)), + ], + ), + ] diff --git a/introduction/migrations/0011_tickits.py b/introduction/migrations/0011_tickits.py new file mode 100644 index 0000000..3279db0 --- /dev/null +++ b/introduction/migrations/0011_tickits.py @@ -0,0 +1,22 @@ +# Generated by Django 4.0.3 on 2022-03-19 11:21 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0010_authlogin'), + ] + + operations = [ + migrations.CreateModel( + name='tickits', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('tickit', models.CharField(max_length=40, unique=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='introduction.authlogin')), + ], + ), + ] diff --git a/introduction/migrations/0012_alter_tickits_user.py b/introduction/migrations/0012_alter_tickits_user.py new file mode 100644 index 0000000..76c0e0a --- /dev/null +++ b/introduction/migrations/0012_alter_tickits_user.py @@ -0,0 +1,21 @@ +# Generated by Django 4.0.3 on 2022-03-19 12:06 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('introduction', '0011_tickits'), + ] + + operations = [ + migrations.AlterField( + model_name='tickits', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/introduction/migrations/0013_alter_comments_id_alter_faang_id_alter_info_id_and_more.py b/introduction/migrations/0013_alter_comments_id_alter_faang_id_alter_info_id_and_more.py new file mode 100644 index 0000000..bb01a3e --- /dev/null +++ b/introduction/migrations/0013_alter_comments_id_alter_faang_id_alter_info_id_and_more.py @@ -0,0 +1,43 @@ +# Generated by Django 4.0.2 on 2022-03-21 21:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0012_alter_tickits_user'), + ] + + operations = [ + migrations.AlterField( + model_name='comments', + name='id', + field=models.AutoField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='faang', + name='id', + field=models.AutoField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='info', + name='id', + field=models.AutoField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='login', + name='id', + field=models.AutoField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='otp', + name='id', + field=models.AutoField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='tickits', + name='id', + field=models.AutoField(primary_key=True, serialize=False), + ), + ] diff --git a/introduction/migrations/0014_sql_lab_table.py b/introduction/migrations/0014_sql_lab_table.py new file mode 100644 index 0000000..1dbda83 --- /dev/null +++ b/introduction/migrations/0014_sql_lab_table.py @@ -0,0 +1,20 @@ +# Generated by Django 4.0.3 on 2022-04-23 09:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0013_alter_comments_id_alter_faang_id_alter_info_id_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='sql_lab_table', + fields=[ + ('id', models.CharField(max_length=200, primary_key=True, serialize=False)), + ('password', models.CharField(max_length=200)), + ], + ), + ] diff --git a/introduction/migrations/0015_blogs.py b/introduction/migrations/0015_blogs.py new file mode 100644 index 0000000..9f9f2e9 --- /dev/null +++ b/introduction/migrations/0015_blogs.py @@ -0,0 +1,24 @@ +# Generated by Django 4.0.2 on 2022-06-07 12:40 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('introduction', '0014_sql_lab_table'), + ] + + operations = [ + migrations.CreateModel( + name='Blogs', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('blog_id', models.CharField(max_length=15)), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/introduction/migrations/0016_alter_blogs_blog_id.py b/introduction/migrations/0016_alter_blogs_blog_id.py new file mode 100644 index 0000000..55c7d6e --- /dev/null +++ b/introduction/migrations/0016_alter_blogs_blog_id.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.2 on 2022-06-07 12:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0015_blogs'), + ] + + operations = [ + migrations.AlterField( + model_name='blogs', + name='blog_id', + field=models.CharField(max_length=15, unique=True), + ), + ] diff --git a/introduction/migrations/0017_cf_user.py b/introduction/migrations/0017_cf_user.py new file mode 100644 index 0000000..2aee465 --- /dev/null +++ b/introduction/migrations/0017_cf_user.py @@ -0,0 +1,21 @@ +# Generated by Django 4.0.2 on 2022-06-15 09:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0016_alter_blogs_blog_id'), + ] + + operations = [ + migrations.CreateModel( + name='CF_user', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('username', models.CharField(max_length=200)), + ('password', models.CharField(max_length=200)), + ], + ), + ] diff --git a/introduction/migrations/0018_cf_user_password2.py b/introduction/migrations/0018_cf_user_password2.py new file mode 100644 index 0000000..3ff76b2 --- /dev/null +++ b/introduction/migrations/0018_cf_user_password2.py @@ -0,0 +1,19 @@ +# Generated by Django 4.0.2 on 2022-06-17 07:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0017_cf_user'), + ] + + operations = [ + migrations.AddField( + model_name='cf_user', + name='password2', + field=models.CharField(default='ok', max_length=64), + preserve_default=False, + ), + ] diff --git a/introduction/migrations/0019_af_admin.py b/introduction/migrations/0019_af_admin.py new file mode 100644 index 0000000..2044375 --- /dev/null +++ b/introduction/migrations/0019_af_admin.py @@ -0,0 +1,27 @@ +# Generated by Django 4.0.4 on 2022-06-28 15:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0018_cf_user_password2'), + ] + + operations = [ + migrations.CreateModel( + name='AF_admin', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('username', models.CharField(max_length=200)), + ('password', models.CharField(max_length=200)), + ('session_id', models.CharField(max_length=200)), + ('last_login', models.DateTimeField(blank=True, null=True)), + ('logged_in', models.BooleanField(default=False)), + ('is_locked', models.BooleanField(default=False)), + ('failattempt', models.IntegerField(default=0)), + ('lockout_cooldown', models.DateField(blank=True, null=True)), + ], + ), + ] diff --git a/introduction/migrations/0020_af_session_id_alter_af_admin_lockout_cooldown.py b/introduction/migrations/0020_af_session_id_alter_af_admin_lockout_cooldown.py new file mode 100644 index 0000000..d264a83 --- /dev/null +++ b/introduction/migrations/0020_af_session_id_alter_af_admin_lockout_cooldown.py @@ -0,0 +1,26 @@ +# Generated by Django 4.0.4 on 2022-06-30 13:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0019_af_admin'), + ] + + operations = [ + migrations.CreateModel( + name='AF_session_id', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('session_id', models.CharField(max_length=200)), + ('user', models.CharField(max_length=200)), + ], + ), + migrations.AlterField( + model_name='af_admin', + name='lockout_cooldown', + field=models.DateTimeField(blank=True, null=True), + ), + ] diff --git a/introduction/migrations/0021_csrf_user_tbl.py b/introduction/migrations/0021_csrf_user_tbl.py new file mode 100644 index 0000000..41875dd --- /dev/null +++ b/introduction/migrations/0021_csrf_user_tbl.py @@ -0,0 +1,23 @@ +# Generated by Django 4.0.4 on 2022-08-18 12:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('introduction', '0020_af_session_id_alter_af_admin_lockout_cooldown'), + ] + + operations = [ + migrations.CreateModel( + name='CSRF_user_tbl', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('username', models.CharField(max_length=200)), + ('password', models.CharField(max_length=200)), + ('balance', models.IntegerField(default=0)), + ('is_loggedin', models.BooleanField(default=False)), + ], + ), + ] diff --git a/introduction/migrations/__init__.py b/introduction/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/introduction/mitre.py b/introduction/mitre.py new file mode 100644 index 0000000..419bfb8 --- /dev/null +++ b/introduction/mitre.py @@ -0,0 +1,244 @@ +from django.http import HttpResponse, HttpResponseBadRequest, JsonResponse +from django.shortcuts import render, redirect +from .views import authentication_decorator +from hashlib import md5 +import jwt +import datetime +import re +import subprocess +from .models import CSRF_user_tbl +from django.views.decorators.csrf import csrf_exempt +# import os + +## Mitre top1 | CWE:787 + +# target zone +FLAG = "NOT_SUPPOSED_TO_BE_ACCESSED" + +# target zone end + + +@authentication_decorator +def mitre_top1(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top1.html') + +@authentication_decorator +def mitre_top2(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top2.html') + +@authentication_decorator +def mitre_top3(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top3.html') + +@authentication_decorator +def mitre_top4(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top4.html') + +@authentication_decorator +def mitre_top5(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top5.html') + +@authentication_decorator +def mitre_top6(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top6.html') + +@authentication_decorator +def mitre_top7(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top7.html') + +@authentication_decorator +def mitre_top8(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top8.html') + +@authentication_decorator +def mitre_top9(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top9.html') + +@authentication_decorator +def mitre_top10(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top10.html') + +@authentication_decorator +def mitre_top11(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top11.html') + +@authentication_decorator +def mitre_top12(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top12.html') + +@authentication_decorator +def mitre_top13(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top13.html') + +@authentication_decorator +def mitre_top14(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top14.html') + +@authentication_decorator +def mitre_top15(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top15.html') + +@authentication_decorator +def mitre_top16(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top16.html') + +@authentication_decorator +def mitre_top17(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top17.html') + +@authentication_decorator +def mitre_top18(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top18.html') + +@authentication_decorator +def mitre_top19(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top19.html') + + +@authentication_decorator +def mitre_top20(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top20.html') + + +@authentication_decorator +def mitre_top21(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top21.html') + + +@authentication_decorator +def mitre_top22(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top22.html') + + +@authentication_decorator +def mitre_top23(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top23.html') + + +@authentication_decorator +def mitre_top24(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top24.html') + +@authentication_decorator +def mitre_top25(request): + if request.method == 'GET': + return render(request, 'mitre/mitre_top25.html') + +@authentication_decorator +def csrf_lab_login(request): + if request.method == 'GET': + return render(request, 'mitre/csrf_lab_login.html') + 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) + 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') + response = redirect("/mitre/9/lab/transaction") + response.set_cookie('auth_cookiee', cookie) + return response + else : + return redirect('/mitre/9/lab/login') + +@authentication_decorator +@csrf_exempt +def csrf_transfer_monei(request): + if request.method == 'GET': + try: + cookie = request.COOKIES['auth_cookiee'] + payload = jwt.decode(cookie, 'csrf_vulneribility', algorithms=['HS256']) + username = payload['username'] + User = CSRF_user_tbl.objects.filter(username=username) + if not User: + redirect('/mitre/9/lab/login') + return render(request, 'mitre/csrf_dashboard.html', {'balance': User[0].balance}) + except: + return redirect('/mitre/9/lab/login') + +def csrf_transfer_monei_api(request,recipent,amount): + if request.method == "GET": + cookie = request.COOKIES['auth_cookiee'] + payload = jwt.decode(cookie, 'csrf_vulneribility', algorithms=['HS256']) + username = payload['username'] + User = CSRF_user_tbl.objects.filter(username=username) + if not User: + return redirect('/mitre/9/lab/login') + if int(amount) > 0: + if int(amount) <= User[0].balance: + recipent = CSRF_user_tbl.objects.filter(username=recipent) + if recipent: + recipent = recipent[0] + recipent.balance = recipent.balance + int(amount) + recipent.save() + User[0].balance = User[0].balance - int(amount) + User[0].save() + return redirect('/mitre/9/lab/transaction') + else: + return redirect ('/mitre/9/lab/transaction') + + +# @authentication_decorator +@csrf_exempt +def mitre_lab_25_api(request): + if request.method == "POST": + expression = request.POST.get('expression') + result = eval(expression) + return JsonResponse({'result': result}) + else: + return redirect('/mitre/25/lab/') + + +@authentication_decorator +def mitre_lab_25(request): + return render(request, 'mitre/mitre_lab_25.html') + +@authentication_decorator +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) + return process.communicate() + + +@csrf_exempt +def mitre_lab_17_api(request): + if request.method == "POST": + ip = request.POST.get('ip') + command = "nmap " + ip + res, err = command_out(command) + res = res.decode() + err = err.decode() + pattern = "STATE SERVICE.*\\n\\n" + ports = re.findall(pattern, res,re.DOTALL)[0][14:-2].split('\n') + return JsonResponse({'raw_res': str(res), 'raw_err': str(err), 'ports': ports}) \ No newline at end of file diff --git a/introduction/models.py b/introduction/models.py new file mode 100644 index 0000000..ab1ca4e --- /dev/null +++ b/introduction/models.py @@ -0,0 +1,96 @@ +from django.db import models +from django.core.validators import MaxValueValidator +from django.conf import settings +# Create your models here. + +class FAANG (models.Model): + id = models.AutoField(primary_key=True) + company=models.CharField(max_length=200); + def __str__(self): + return self.company; + +class info(models.Model): + id = models.AutoField(primary_key=True) + faang=models.ForeignKey(to=FAANG,on_delete=models.CASCADE) + + ceo=models.CharField(max_length=200) + about=models.CharField(max_length=200) + +class login(models.Model): + id = models.AutoField(primary_key=True) + user=models.CharField(max_length=200) + password=models.CharField(max_length=300) + +class comments(models.Model): + id = models.AutoField(primary_key=True) + name=models.CharField(max_length=200) + comment=models.CharField(max_length=600) + +class authLogin(models.Model): + username=models.CharField(max_length=200, unique = True) + name=models.CharField(max_length=200) + password=models.CharField(max_length=200) + userid = models.AutoField(primary_key=True) + +class otp(models.Model): + id = models.AutoField(primary_key=True) + email=models.CharField(max_length=200) + otp=models.IntegerField(validators=[MaxValueValidator(300)]) + +class tickits(models.Model): + id = models.AutoField(primary_key=True) + user=models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE) + tickit=models.CharField(max_length=40, unique = True) + + def __str__(self): + return self.tickit+ " " + self.user.username; + +class sql_lab_table(models.Model): + id = models.CharField(primary_key = True, max_length=200) + password = models.CharField(max_length=200) + +class Blogs(models.Model): + id = models.AutoField(primary_key=True) + author = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE) + blog_id = models.CharField(max_length=15, unique=True) + def __str__(self): + return self.blog_id + +class CF_user(models.Model): + id = models.AutoField(primary_key=True) + username = models.CharField(max_length=200) + password = models.CharField(max_length=200) + password2 = models.CharField(max_length=64) + def __str__(self): + return self.username + +class AF_admin(models.Model): + id = models.AutoField(primary_key=True) + username = models.CharField(max_length=200) + password = models.CharField(max_length=200) + session_id = models.CharField(max_length=200) + last_login = models.DateTimeField(blank= True, null = True) + logged_in = models.BooleanField(default=False) + is_locked = models.BooleanField(default=False) + failattempt = models.IntegerField(default=0) + lockout_cooldown = models.DateTimeField(blank= True, null = True) + + def __str__(self): + return self.username + +class AF_session_id(models.Model): + id = models.AutoField(primary_key=True) + session_id = models.CharField(max_length=200) + user = models.CharField(max_length=200) + def __str__(self): + return self.user + +class CSRF_user_tbl(models.Model): + id = models.AutoField(primary_key=True) + username = models.CharField(max_length=200) + password = models.CharField(max_length=200) + balance = models.IntegerField(default=0) + is_loggedin = models.BooleanField(default=False) + + def __str__(self): + return self.username \ No newline at end of file diff --git a/introduction/playground/A6/soln.py b/introduction/playground/A6/soln.py new file mode 100644 index 0000000..694ac35 --- /dev/null +++ b/introduction/playground/A6/soln.py @@ -0,0 +1,14 @@ +import requests + +def check_vuln(list_of_modules)->list: + vulns = [] + for i in list_of_modules: + k = i.split("==") + url = f"https://pypi.org/pypi/{k[0]}/{k[1]}/json" + response = requests.get(url) + response.raise_for_status() + info = response.json() + existing_vuln = info['vulnerabilities'] + if len(existing_vuln) > 0: + vulns.append(existing_vuln) + return vulns \ No newline at end of file diff --git a/introduction/playground/A6/utility.py b/introduction/playground/A6/utility.py new file mode 100644 index 0000000..dd8694e --- /dev/null +++ b/introduction/playground/A6/utility.py @@ -0,0 +1,14 @@ +import requests + +def check_vuln(list_of_modules)->list: + vulns = [] + for i in list_of_modules: + k = i.split("==") + url = f"https://pypi.org/pypi/{k[0]}/{k[1]}/json" + response = requests.get(url) + response.raise_for_status() + info = response.json() + existing_vuln = info['vulnerabilities'] + if len(existing_vuln) > 0: + vulns.append(existing_vuln) + return vulns \ No newline at end of file diff --git a/introduction/playground/A9/api.py b/introduction/playground/A9/api.py new file mode 100644 index 0000000..4d352a4 --- /dev/null +++ b/introduction/playground/A9/api.py @@ -0,0 +1,31 @@ +from django.http import JsonResponse +from django.views.decorators.csrf import csrf_exempt +from .main import Log + +@csrf_exempt +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) + 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) + if request.method == "PUT": + L.info("PUT request") + 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) + L.error("DELETE request") + 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) + 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 diff --git a/introduction/playground/A9/archive.py b/introduction/playground/A9/archive.py new file mode 100644 index 0000000..9358038 --- /dev/null +++ b/introduction/playground/A9/archive.py @@ -0,0 +1,58 @@ +from django.http import JsonResponse +from django.views.decorators.csrf import csrf_exempt +from .main import Log + +@csrf_exempt +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) + 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) + if request.method == "PUT": + L.info("PUT request") + 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) + L.error("DELETE request") + 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) + if request.method == "UPDATE": + return JsonResponse({"message":"success", "method":"update"},status = 200) + return JsonResponse({"message":"method not allowed"},status = 403) + + +# ====================================== + +import datetime +# f = open('test.log', 'a') --> use this file to log +class Log: + def __init__(self,request): + self.request = request + + 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): + now = datetime.datetime.now() + f = open('test.log', 'a') + f.write(f"WARNING:{now}:{msg}\n") + f.close() + + def error(self,msg): + now = datetime.datetime.now() + f = open('test.log', 'a') + f.write(f"ERROR:{now}:{msg}\n") + f.close() diff --git a/introduction/playground/A9/main.py b/introduction/playground/A9/main.py new file mode 100644 index 0000000..934b58d --- /dev/null +++ b/introduction/playground/A9/main.py @@ -0,0 +1,14 @@ +import datetime +# f = open('test.log', 'a') --> use this file to log +class Log: + def __init__(self,request): + self.request = request + + def info(self,msg): + pass + + def warning(self,msg): + pass + + def error(self,msg): + pass \ No newline at end of file diff --git a/introduction/playground/__init__.py b/introduction/playground/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/introduction/playground/readme.md b/introduction/playground/readme.md new file mode 100644 index 0000000..e69de29 diff --git a/introduction/playground/ssrf/__init__.py b/introduction/playground/ssrf/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/introduction/playground/ssrf/main.py b/introduction/playground/ssrf/main.py new file mode 100644 index 0000000..f95edd8 --- /dev/null +++ b/introduction/playground/ssrf/main.py @@ -0,0 +1,10 @@ +import os +def ssrf_lab(file): + try: + dirname = os.path.dirname(__file__) + filename = os.path.join(dirname, file) + file = open(filename,"r") + data = file.read() + return {"blog":data} + except: + return {"blog": "No blog found"} \ No newline at end of file diff --git a/introduction/playground/ssrf/secret.txt b/introduction/playground/ssrf/secret.txt new file mode 100644 index 0000000..e4d7046 --- /dev/null +++ b/introduction/playground/ssrf/secret.txt @@ -0,0 +1 @@ +Failed \ No newline at end of file diff --git a/introduction/playground/ssrf/templates/Lab/ssrf/blogs/blog1.txt b/introduction/playground/ssrf/templates/Lab/ssrf/blogs/blog1.txt new file mode 100644 index 0000000..d994caf --- /dev/null +++ b/introduction/playground/ssrf/templates/Lab/ssrf/blogs/blog1.txt @@ -0,0 +1 @@ +blog1-passed \ No newline at end of file diff --git a/introduction/playground/ssrf/templates/Lab/ssrf/blogs/blog2.txt b/introduction/playground/ssrf/templates/Lab/ssrf/blogs/blog2.txt new file mode 100644 index 0000000..9884fed --- /dev/null +++ b/introduction/playground/ssrf/templates/Lab/ssrf/blogs/blog2.txt @@ -0,0 +1 @@ +blog2-passed \ No newline at end of file diff --git a/introduction/playground/ssrf/templates/Lab/ssrf/blogs/blog3.txt b/introduction/playground/ssrf/templates/Lab/ssrf/blogs/blog3.txt new file mode 100644 index 0000000..df0152e --- /dev/null +++ b/introduction/playground/ssrf/templates/Lab/ssrf/blogs/blog3.txt @@ -0,0 +1 @@ +blog3-passed \ No newline at end of file diff --git a/introduction/playground/ssrf/templates/Lab/ssrf/blogs/blog4.txt b/introduction/playground/ssrf/templates/Lab/ssrf/blogs/blog4.txt new file mode 100644 index 0000000..de88946 --- /dev/null +++ b/introduction/playground/ssrf/templates/Lab/ssrf/blogs/blog4.txt @@ -0,0 +1 @@ +blog4-passed \ No newline at end of file diff --git a/introduction/playground/ssrf/test.py b/introduction/playground/ssrf/test.py new file mode 100644 index 0000000..5fbdffc --- /dev/null +++ b/introduction/playground/ssrf/test.py @@ -0,0 +1,33 @@ +## input +''' +def ssrf_lab(request): + if request.user.is_authenticated: + if request.method=="GET": + 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}) + except: + return render(request, "Lab/ssrf/ssrf_lab.html", {"blog": "No blog found"}) + else: + return redirect('login')''' + +## output +''' +def ssrf_lab(file): + try : + dirname = os.path.dirname(__file__) + filename = os.path.join(dirname, file) + file = open(filename,"r") + data = file.read() + print(data) + return {"blog":data} + except: + return {"blog": "No blog found"} + +''' \ No newline at end of file diff --git a/introduction/static/Lab/icons/pygoat-mini.png b/introduction/static/Lab/icons/pygoat-mini.png new file mode 100644 index 0000000..0189bb0 Binary files /dev/null and b/introduction/static/Lab/icons/pygoat-mini.png differ diff --git a/introduction/static/Lab/icons/pygoat-mini.svg b/introduction/static/Lab/icons/pygoat-mini.svg new file mode 100644 index 0000000..47e5808 --- /dev/null +++ b/introduction/static/Lab/icons/pygoat-mini.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/introduction/static/Lab/icons/pygoat-small.png b/introduction/static/Lab/icons/pygoat-small.png new file mode 100644 index 0000000..a26ce35 Binary files /dev/null and b/introduction/static/Lab/icons/pygoat-small.png differ diff --git a/introduction/static/Lab/icons/pygoat-small.svg b/introduction/static/Lab/icons/pygoat-small.svg new file mode 100644 index 0000000..f64e636 --- /dev/null +++ b/introduction/static/Lab/icons/pygoat-small.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/introduction/static/Lab/icons/pygoat.png b/introduction/static/Lab/icons/pygoat.png new file mode 100644 index 0000000..5637dcc Binary files /dev/null and b/introduction/static/Lab/icons/pygoat.png differ diff --git a/introduction/static/Lab/icons/pygoat.svg b/introduction/static/Lab/icons/pygoat.svg new file mode 100644 index 0000000..990c010 --- /dev/null +++ b/introduction/static/Lab/icons/pygoat.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/introduction/static/Lab/image/xxe.jpg b/introduction/static/Lab/image/xxe.jpg new file mode 100644 index 0000000..08ec4e5 Binary files /dev/null and b/introduction/static/Lab/image/xxe.jpg differ diff --git a/introduction/static/Lab/ssrf.css b/introduction/static/Lab/ssrf.css new file mode 100644 index 0000000..18acafc --- /dev/null +++ b/introduction/static/Lab/ssrf.css @@ -0,0 +1,148 @@ +@import url('https://fonts.googleapis.com/css2?family=Ubuntu+Mono&display=swap'); + +.playground{ + background-color: rgb(214, 252, 255); + padding: 10px; + padding-top: 20px; + padding-bottom: 20px; + border-radius: 10px; + /* visibility: hidden; */ +} + +#ssrf-progress-bar { + margin-top : 30px; + position: relative; + width: 100%; + height: 30px; + background-color: #d5ecff; + display: none; + flex-direction: row; + border-radius: 15px; + border: 2px solid #4B8BBE; +} + + +.circle{ + /* width: 5%; */ + border: 5px solid #033157; + border-radius: 100px; + height: auto; + width : 26px +} +.ssrf-progress-element{ + width: 30%; + background-color: #d5ecee; + border-radius: 15px; +} + +.ssrf-bar-status{ + height: 90%; + background-color: #033157; + border-radius: 15px; + margin: 1px; +} + +#ssrf-frame-1{ + display: flex; + flex-direction: row; + justify-content: space-between; +} +#ssrf-frame-2{ + display: none; + margin-top: 20px; + flex-direction: column; + align-items: center; +} + +.code{ + background-color: #fafafa; + border-radius: 10px; + padding: 0; +} + +.code-bar{ + background-color: #d5ecee; + width: 100%; + height: 30px; + border-radius: 10px 10px 0px 0px; + display: flex; + justify-content: space-between +} + +.code form { + margin: 30px; + margin-top: 10px; + margin-bottom: 10px; + font-family: 'Ubuntu Mono', monospace; +} + +.code-circle { + height: 18px; + width: 18px; + border-radius: 10px; + border : 0px solid; + margin: 5px; +} +.red { + background-color: red; +} +.green{ + background-color: green; +} +.yellow{ + background-color: yellow; +} + +#ssrf-frame-3{ + display: none; + margin-top: 20px; + flex-direction: column; + align-items: center; +} + +/* frame 4 */ + +#ssrf-frame-4{ + display: none; + margin-top: 20px; + flex-direction: column; + align-items: center; +} + +textarea { + min-height: 250px; + overflow: scroll; + margin: 20px; + display: inline-block; + background: #f4f4f9; + outline: none; + font-family: Courier, sans-serif; + min-width: 500px; + height: 500px; + border-radius: 10px; + font-size: 13px; + padding: 10px; + + } +#textarea-container{ + display: flex; + flex-direction: row; + margin : 10px; + flex-wrap: wrap +} + +#textarea1{ + display: flex; + flex-direction: column; +} +.problem-Statement-desc{ + margin-left: 50px; + margin-right: 50px; +} + +#ssrf-frame-5{ + display: none; + margin-top: 20px; + flex-direction: column; + align-items: center; +} \ No newline at end of file diff --git a/introduction/static/Lab/ssrf.js b/introduction/static/Lab/ssrf.js new file mode 100644 index 0000000..63aae84 --- /dev/null +++ b/introduction/static/Lab/ssrf.js @@ -0,0 +1,84 @@ + +function frame1to2(){ + // frame 1 to 2 + document.getElementById('ssrf-frame-1').style.display = 'none'; + document.getElementById('ssrf-frame-2').style.display = 'flex'; + document.getElementById('ssrf-progress-bar').style.display = 'flex'; +} + +function frame2to3(){ + var markedCheckbox = document.querySelectorAll('input[type="checkbox"]:checked'); + var arr = []; + for (var checkbox of markedCheckbox){ + arr.push(parseInt(checkbox.value)); + } + var score = 0; + var result = [8,9,10,11,12]; + for (var items of arr){ + if(result.includes(items)){ + score++; + } + else{ + score--; + } + } + if( score >= 4 ){ + document.getElementById('ssrf-frame-2').style.display = 'none'; + document.getElementById('ssrf-bar-status1').classList.add('ssrf-bar-status') + alert('Congratulation! You have figure this out !!'); + document.getElementById('ssrf-frame-3').style.display = 'flex'; + } +} + +function frame3to4(){ + var markedCheckbox = document.querySelectorAll('input[name="form2"]:checked'); + var arr = []; + for (var checkbox of markedCheckbox){ + arr.push(parseInt(checkbox.value)); + } + var score = 0; + var result = [3,7,11,15]; + for (var items of arr){ + if(result.includes(items)){ + score++; + } + else{ + score--; + } + } + if( score >=4 ){ + document.getElementById('ssrf-frame-3').style.display = 'none'; + document.getElementById('ssrf-bar-status2').classList.add('ssrf-bar-status') + alert('Congratulation! you have detected defective codes in html'); + document.getElementById('ssrf-frame-4').style.display = 'flex'; + } +} + + +function checkcode(){ + var python_code = document.getElementById('python').value + var html_code = document.getElementById('html').value + + var formdata = new FormData(); + formdata.append('python_code', python_code); + formdata.append('html_code', html_code); + var requestOptions = { + method: 'POST', + body: formdata, + redirect: 'follow' + }; + + fetch("api/ssrf", requestOptions) + .then(response => response.text()) + .then((result) => { + console.log(result); + var obj = JSON.parse(result); + alert(obj.message); + if (obj.passed == 1 ){ + document.getElementById('ssrf-frame-4').style.display = 'none'; + document.getElementById('ssrf-bar-status3').classList.add('ssrf-bar-status') + document.getElementById('ssrf-frame-5').style.display = 'flex'; + } + }) + .catch(error => console.log('error', error)); +} \ No newline at end of file diff --git a/introduction/static/Lab/ssti.css b/introduction/static/Lab/ssti.css new file mode 100644 index 0000000..57136c4 --- /dev/null +++ b/introduction/static/Lab/ssti.css @@ -0,0 +1,26 @@ +.container{align-items: center; +max-width: 720px; +display: flex; +flex-direction: column;} + +#ssti-inner-div2{ + display: flex; + flex-direction: column; + align-items: center; +} + +.ssti-form{ + display: flex; + flex-direction: column; + align-items: center; +} +ul{ + padding: 5px; +} +li{ + list-style-type: none; +} + +.code{ + background-color: #fafafaaa; +} \ No newline at end of file diff --git a/introduction/static/Lab/xss.js b/introduction/static/Lab/xss.js new file mode 100644 index 0000000..99d0a09 --- /dev/null +++ b/introduction/static/Lab/xss.js @@ -0,0 +1,40 @@ +var coll = document.getElementsByClassName("coll"); +var coll2 = document.getElementsByClassName("coll2"); +var i; + +for (i = 0; i < coll.length; i++) { + coll[i].addEventListener("click", function() { + this.classList.toggle("active"); + var content = this.nextElementSibling; + if (content.style.display === "block") { + content.style.display = "none"; + } else { + content.style.display = "block"; + } + }); +} +for (i = 0; i < coll2.length; i++) { + coll2[i].addEventListener("click", function() { + this.classList.toggle("active"); + var content = this.nextElementSibling; + if (content.style.display === "block") { + content.style.display = "none"; + } else { + content.style.display = "block"; + } + }); +} +function SendToServer(){ + + comment=document.getElementById("comment").value; + + + var xhr; + xhr = new XMLHttpRequest(); + xml=""+""+""+comment+""+""; + var url = $("#Url").attr("data-url"); + xhr.open("POST", url, true); + xhr.setRequestHeader("Content-Type", "text/xml"); + xhr.send(xml); + +} \ No newline at end of file diff --git a/introduction/static/css/common.css b/introduction/static/css/common.css new file mode 100644 index 0000000..e69de29 diff --git a/introduction/static/css/dark-theme.css b/introduction/static/css/dark-theme.css new file mode 100644 index 0000000..417fa03 --- /dev/null +++ b/introduction/static/css/dark-theme.css @@ -0,0 +1,530 @@ +/* + DEMO STYLE +*/ + +@import "https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700"; +body { + font-family: "Poppins", sans-serif; + background: #151414; + color: #fff +} + +body::-webkit-scrollbar { + display: none; +} +body { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} + +p { + font-family: "Poppins", sans-serif; + font-size: 1.1em; + font-weight: 300; + line-height: 1.7em; + color: #ffffff; +} + +a, +a:hover, +a:focus { + color: inherit; + text-decoration: none; + transition: all 0.3s; +} + +.navbar { + padding: 15px 10px; + background-image: linear-gradient(45deg, hsl(205.7, 14.9%, 18.4%), #3a5b75); + border: 0px solid; + border-radius: 0px 10px 0px 0px; + margin-bottom: 40px; + /* box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1); */ +} + +.navbar-btn { + box-shadow: none; + outline: none !important; + border: none; +} + +.line { + width: 100%; + height: 1px; + border-bottom: 1px dashed #ddd; + margin: 40px 0; +} + +i, +span { + display: inline-block; +} +.login-form { + margin-left: 10px; + margin-right: 10px; +} +.card { + border: #306998; + border-radius: 10px; +} +/* --------------------------------------------------- + SIDEBAR STYLE +----------------------------------------------------- */ +.sidebar-list-items { + background-color: #79a9cf40; +} +.wrapper { + display: flex; + align-items: stretch; + margin: 10px; + background-color: #26282B; + height: 97vh; + border-radius: 20px; +} + +#sidebar { + height: 97vh; + overflow: scroll; + min-width: 315px; + max-width: 315px; + background: #373c40; + color: #fff; + transition: all 0.3s; + border-radius: 20px 0px 20px 0px; +} + +.sidebarClass::-webkit-scrollbar { + display: none; +} +.sidebarClass { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} + +#sidebar.active { + min-width: 80px; + max-width: 80px; + text-align: center; + height: 97vh; + overflow: scroll; +} + +#sidebar.active .sidebar-header div h3, +#sidebar.active .sidebar-header div img, +#sidebar.active .CTAs { + display: none; +} + +#sidebar.active .sidebar-header strong { + display: block; +} + +#sidebar.active ul li a { + padding: 20px 10px; + text-align: center; + font-size: 0.85em; +} + +#sidebar.active ul li a i { + margin-right: 0; + display: block; + font-size: 1.8em; + /* margin-bottom: 5px; */ +} + +#sidebar.active ul ul a { + padding: 10px !important; +} + +#sidebar.active .dropdown-toggle::after { + top: auto; + bottom: 10px; + right: 50%; + -webkit-transform: translateX(50%); + -ms-transform: translateX(50%); + transform: translateX(50%); +} + +#sidebar .sidebar-header { + padding: 20px; + background: #283036; +} + +#sidebar .sidebar-header strong { + display: none; + font-size: 1.8em; +} + +#sidebar ul.components { + padding: 20px 0; + border-bottom: 1px solid #4b8bbe; +} + +#sidebar ul li a { + padding: 10px; + font-size: 1.1em; + display: block; +} + +#sidebar ul li a:hover { + color: #306998; + background: #fff; +} + +#sidebar ul li a i { + margin-right: 10px; +} + +#sidebar ul li.active > a, +a[aria-expanded="true"] { + color: #fff; + background: #4b8bbe; +} + +a[data-toggle="collapse"] { + position: relative; +} + +.dropdown-toggle::after { + display: block; + position: absolute; + top: 50%; + right: 20px; + transform: translateY(-50%); +} + +ul ul a { + font-size: 0.9em !important; + padding-left: 30px !important; + background: #ffd43b; +} + +ul.CTAs { + padding: 20px; +} + +ul.CTAs a { + text-align: center; + font-size: 0.9em !important; + display: block; + border-radius: 5px; + margin-bottom: 5px; +} + +/* a.download { + background: #fff; + color: #7386D5; +} */ + +/* a.article, +a.article:hover { + background: #6d7fcc !important; + color: #fff !important; +} */ + +/* --------------------------------------------------- + CONTENT STYLE +----------------------------------------------------- */ + +#content { + width: 100%; + padding: 20px; + /* min-height: cal(100vh -20px); */ + transition: all 0.3s; + overflow: scroll; + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; +} + +#content::-webkit-scrollbar { + display: none; +} + +.box { + margin-top: 2rem; + border-radius: 10px; + padding: 2rem; + background-color: #373c40; + color: aliceblue; +} +.bp { + font-size: 1em; + color: rgb(255, 255, 255); +} +.coll { + background-color: #159c80; + color: black; + cursor: pointer; + padding: auto; + width: auto; + margin-bottom: 20px; + text-align: center; + outline: none; + font-size: 20px; +} + +/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */ +.active, +.coll:hover { + background-color: #bfb051; +} + +/* Style the collapsible content. Note: hidden by default */ +.lab { + padding: 18px; + display: none; + overflow: hidden; + background-color: #444c53; + border-radius: 1rem; +} +.display { + padding: 20px; +} +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + background-color: #f9f2f4; + border-radius: 4px; +} +.img { + border-radius: 8px; + display: block; + margin-left: auto; + margin-right: auto; + width: 50%; +} +.pg{ + display: none; +} + +ul, li { + color:#ffffff +} +/* --------------------------------------------------- + MEDIAQUERIES +----------------------------------------------------- */ + +@media (max-width: 768px) { + #sidebar { + min-width: 242px; + } + .pg{ + display: block; + position: fixed; + font-size: 35px; + z-index: 1000; + color: #fff; + font-weight: 500; + left: 29px; + top: 36px; + } + .pg.active{ + display: none; + } + .dropdown-toggle::after { + top: auto; + bottom: 10px; + right: 50%; + -webkit-transform: translateX(50%); + -ms-transform: translateX(50%); + transform: translateX(50%); + } + #sidebar.active { + margin-left: -95px !important; + } + #sidebar .sidebar-header{ + display: flex; + flex-direction: row; + align-items: center; + } + + #sidebar .sidebar-header h3, + #sidebar .CTAs { + display: none; + } + #sidebar .sidebar-header strong { + display: block; + } + #sidebar ul li a { + padding: 20px 10px; + } + #sidebar ul li a span { + font-size: 0.85em; + } + #sidebar ul li a i { + margin-right: 0; + display: block; + } + #sidebar ul ul a { + padding: 10px !important; + } + #sidebar ul li a i { + font-size: 1.3em; + } + #sidebar { + margin-left: 0; + } + #sidebarCollapse span { + display: none; + } + .navbar{ + margin-right: -17px; + } +} + +code { + padding: 2px 4px; + font-size: 90%; + color: #94edfa; + border-radius: 4px; + background-color: #159c8100; +} + +.code { + /* background-image: linear-gradient(to right, #000000, #30989a); */ + background-color: #8dc2ed; + padding: 30px; + margin-top: 30px; +} + +#sidebarCollapse { + display: none; +} + +.h2, +h2 { + font-size: 4rem; +} + +#owasp10_2021 { + width: 90%; + background: #283036; + margin-top: 15px; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0 0 0; +} +#owasp10_2017 { + width: 90%; + margin-top: 15px; + background: #283036; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0 0 0; +} + +#sidebar li ul a #owasp10_2021 { + padding: 13% 0 0 0; +} + +#OWASP10_2021 { + width: 95%; + padding-left: 5%; +} +#OWASP10_2017 { + width: 95%; + padding-left: 5%; +} + +#sidebar-home { + width: 90%; + margin-top: 15px; + background: #283036; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0 0 0; +} + +#homeSubmenu { + width: 95%; + padding-left: 5%; +} + +.active, +.coll:hover { + background-color: #bfb05100; +} + +#challengeMenu { + width: 90%; + margin-top: 15px; + background: #283036; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0% 0% 0%; +} +#challengeSubmenu { + width: 95%; + padding-left: 5%; +} +#Mitre25 { + width: 95%; + padding-left: 5%; +} +#sans25 { + width: 95%; + padding-left: 5%; +} + +#help { + width: 90%; + margin-top: 15px; + background: #283036; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0% 0% 0%; +} +#mitre25 { + width: 90%; + margin-top: 15px; + background: #283036; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0% 0% 0%; +} + +#stylesheet-toggle{ + background: #f0f8ff8a; + border: 0px; + border-radius: 2px; + margin-right: 5px; +} + +.Mitigation li { + list-style-type: disc; +} + +.requiredField { + color: #26282B +} + +.jumbotron { + color:#26282B +} + +.container li { + color: #6c757d!important +} + +pre { + color: #ffffff +} diff --git a/introduction/static/css/home.css b/introduction/static/css/home.css new file mode 100644 index 0000000..96fa7fe --- /dev/null +++ b/introduction/static/css/home.css @@ -0,0 +1,12 @@ + +#home-section1 { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + flex-wrap: wrap; +} +#home-section1-img{ + opacity: .25; + width: 400px; +} diff --git a/introduction/static/css/light.css b/introduction/static/css/light.css new file mode 100644 index 0000000..652349f --- /dev/null +++ b/introduction/static/css/light.css @@ -0,0 +1,524 @@ +/* + DEMO STYLE +*/ + +@import "https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700"; +body { + font-family: "Poppins", sans-serif; + /* background: #000000; */ + background: #fff; +} + +body::-webkit-scrollbar { + display: none; +} +body { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} + +p{ + font-family: "Poppins", sans-serif; + font-size: 1.1em; + font-weight: 300; + line-height: 1.7em; + color: #999; +} + +a, +a:hover, +a:focus { + color: inherit; + text-decoration: none; + transition: all 0.3s; +} + +.navbar { + padding: 15px 10px; + background-image: linear-gradient(45deg, hsl(0deg 0% 95%), #80a9c9); + border: 0px solid; + border-radius: 0px 10px 0px 0px; + margin-bottom: 40px; + /* box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1); */ +} + +.navbar-btn { + box-shadow: none; + outline: none !important; + border: none; +} + +.line { + width: 100%; + height: 1px; + border-bottom: 1px dashed #ddd; + margin: 40px 0; +} + +i, +span { + display: inline-block; +} +.login-form { + margin-left: 10px; + margin-right: 10px; +} +.card { + border: #306998; + border-radius: 10px; +} +/* --------------------------------------------------- + SIDEBAR STYLE +----------------------------------------------------- */ +.sidebar-list-items { + background-color: #79a9cf40; + color : #0b446e; +} +.wrapper { + display: flex; + align-items: stretch; + margin: 10px; + background-color: #424242; + background-color: #f1f1f1; + height: 97vh; + border-radius: 20px; +} + +#sidebar { + height: 97vh; + overflow: scroll; + min-width: 315px; + max-width: 315px; + background: #373c40; + background: #c5cfd7; + color: #fff; + transition: all 0.3s; + border-radius: 20px 0px 20px 0px; +} + +.sidebarClass::-webkit-scrollbar { + display: none; +} +.sidebarClass { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} + +#sidebar.active { + min-width: 80px; + max-width: 80px; + text-align: center; + height: 97vh; + overflow: scroll; +} + +#sidebar.active .sidebar-header div h3, +#sidebar.active .sidebar-header div img, +#sidebar.active .CTAs { + display: none; +} + +#sidebar.active .sidebar-header strong { + display: block; +} + +#sidebar.active ul li a { + padding: 20px 10px; + text-align: center; + font-size: 0.85em; +} + +#sidebar.active ul li a i { + margin-right: 0; + display: block; + font-size: 1.8em; + /* margin-bottom: 5px; */ +} + +#sidebar.active ul ul a { + padding: 10px !important; +} + +#sidebar.active .dropdown-toggle::after { + top: auto; + bottom: 10px; + right: 50%; + -webkit-transform: translateX(50%); + -ms-transform: translateX(50%); + transform: translateX(50%); +} + +#sidebar .sidebar-header { + padding: 20px; + /* background: #283036; */ + background: #4e93c7 +} + +#sidebar .sidebar-header strong { + display: none; + font-size: 1.8em; +} + +#sidebar ul.components { + padding: 20px 0; + border-bottom: 1px solid #4b8bbe; +} + +#sidebar ul li a { + padding: 10px; + font-size: 1.1em; + display: block; +} + +#sidebar ul li a:hover { + color: #306998; + background: #fff; +} + +#sidebar ul li a i { + margin-right: 10px; +} + +#sidebar ul li.active > a, +a[aria-expanded="true"] { + color: #fff; + background: #4b8bbe; +} + +a[data-toggle="collapse"] { + position: relative; +} + +.dropdown-toggle::after { + display: block; + position: absolute; + top: 50%; + right: 20px; + transform: translateY(-50%); +} + +ul ul a { + font-size: 0.9em !important; + padding-left: 30px !important; + background: #ffd43b; +} + +ul.CTAs { + padding: 20px; +} + +ul.CTAs a { + text-align: center; + font-size: 0.9em !important; + display: block; + border-radius: 5px; + margin-bottom: 5px; +} + +/* a.download { + background: #fff; + color: #7386D5; +} */ + +/* a.article, +a.article:hover { + background: #6d7fcc !important; + color: #fff !important; +} */ + +/* --------------------------------------------------- + CONTENT STYLE +----------------------------------------------------- */ + +#content { + width: 100%; + padding: 20px; + /* min-height: cal(100vh -20px); */ + transition: all 0.3s; + overflow: scroll; + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; +} + +#content::-webkit-scrollbar { + display: none; +} + +.box { + margin-top: 2rem; + border-radius: 10px; + padding: 2rem; + background-color: #f8ede345; + color: #20303e +} +.bp { + font-size: 1em; + font-height: 1.2em; + color: black; +} +.coll { + background-color: #159c80; + color: black; + cursor: pointer; + padding: auto; + width: auto; + margin-bottom: 20px; + text-align: center; + outline: none; + font-size: 20px; +} + +/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */ +.active, +.coll:hover { + background-color: #bfb051; +} + +/* Style the collapsible content. Note: hidden by default */ +.lab { + padding: 18px; + display: none; + overflow: hidden; + background-color: #f1f1f1; + border-radius: 1rem; +} +.display { + padding: 20px; +} +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + background-color: #f9f2f4; + border-radius: 4px; +} +.img { + border-radius: 8px; + display: block; + margin-left: auto; + margin-right: auto; + width: 50%; +} + +.pg{ + display: none; +} +/* --------------------------------------------------- + MEDIAQUERIES +----------------------------------------------------- */ + +@media (max-width: 768px) { + #sidebar { + min-width: 242px; + } + + .pg{ + display: block; + position: fixed; + font-size: 35px; + z-index: 1000; + color: #397aab; + font-weight: 500; + left: 29px; + top: 36px; + } + .pg.active{ + display: none; + } + + .dropdown-toggle::after { + top: auto; + bottom: 10px; + right: 50%; + -webkit-transform: translateX(50%); + -ms-transform: translateX(50%); + transform: translateX(50%); + } + #sidebar.active { + margin-left: -95px !important; + } + #sidebar .sidebar-header{ + display: flex; + flex-direction: row; + align-items: center; + } + + #sidebar .sidebar-header h3, + #sidebar .CTAs { + display: none; + } + #sidebar .sidebar-header strong { + display: block; + } + #sidebar ul li a { + padding: 20px 10px; + } + #sidebar ul li a span { + font-size: 0.85em; + } + #sidebar ul li a i { + margin-right: 0; + display: block; + } + #sidebar ul ul a { + padding: 10px !important; + } + #sidebar ul li a i { + font-size: 1.3em; + } + #sidebar { + margin-left: 0; + } + #sidebarCollapse span { + display: none; + } + .navbar{ + margin-right: -17px; + } +} + +code { + padding: 2px 4px; + font-size: 90%; + color: #033157; + border-radius: 4px; + background-color: #159c8100; +} + +.code { + /* background-image: linear-gradient(to right, #000000, #30989a); */ + background-color: #8dc2ed; + padding: 30px; + margin-top: 30px; +} + +#sidebarCollapse { + display: none; +} + +.h2, +h2 { + font-size: 4rem; +} + +#owasp10_2021 { + width: 90%; + background: #283036; + background: #4e93c7; + margin-top: 15px; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0 0 0; +} +#owasp10_2017 { + width: 90%; + margin-top: 15px; + background: #283036; + background: #4e93c7; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0 0 0; +} + +#sidebar li ul a #owasp10_2021 { + padding: 13% 0 0 0; +} + +#OWASP10_2021 { + width: 95%; + padding-left: 5%; +} +#OWASP10_2017 { + width: 95%; + padding-left: 5%; +} + +#sidebar-home { + width: 90%; + margin-top: 15px; + background: #283036; + background: #4e93c7; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0 0 0; +} + +#homeSubmenu { + width: 95%; + padding-left: 5%; +} + +.active, +.coll:hover { + background-color: #bfb05100; +} + +#challengeMenu { + width: 90%; + margin-top: 15px; + background: #283036; + background: #4e93c7; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0% 0% 0%; +} +#challengeSubmenu { + width: 95%; + padding-left: 5%; +} +#Mitre25 { + width: 95%; + padding-left: 5%; +} +#sans25 { + width: 95%; + padding-left: 5%; +} + +#help { + width: 90%; + margin-top: 15px; + background: #283036; + background: #4e93c7; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0% 0% 0%; +} +#mitre25 { + width: 90%; + margin-top: 15px; + background: #283036; + background: #4e93c7; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0% 0% 0%; +} + +#stylesheet-toggle{ + background: #f0f8ff8a; + border: 0px; + border-radius: 2px; + margin-right: 5px; +} + +.Mitigation li { + list-style-type: disc; +} \ No newline at end of file diff --git a/introduction/static/css/playground.css b/introduction/static/css/playground.css new file mode 100644 index 0000000..0ca0cf4 --- /dev/null +++ b/introduction/static/css/playground.css @@ -0,0 +1,1477 @@ +/*This was all taken from https://tympanus.net/Development/ButtonStylesInspiration/ but I needed to see it in CodePen +*/ +@import url(https://fonts.googleapis.com/css?family=Raleway:200,300,400,500,600); +@font-face { + font-weight: normal; + font-style: normal; + font-family: 'codropsicons'; + src: url("../fonts/codropsicons/codropsicons.eot"); + src: url("../fonts/codropsicons/codropsicons.eot?#iefix") format("embedded-opentype"), url("../fonts/codropsicons/codropsicons.woff") format("woff"), url("../fonts/codropsicons/codropsicons.ttf") format("truetype"), url("../fonts/codropsicons/codropsicons.svg#codropsicons") format("svg"); +} +/* Common button styles */ +.button2 { + float: left; + min-width: 150px; + max-width: 250px; + /* display: block; */ + margin: 1em; + padding: 1em 2em; + border: none; + background: none; + color: inherit; + vertical-align: middle; + position: relative; + z-index: 1; + -webkit-backface-visibility: hidden; + -moz-osx-font-smoothing: grayscale; +} +.button2:focus { + outline: none; +} +.button2 > span { + vertical-align: middle; +} + +/* Text color adjustments (we could stick to the "inherit" but that does not work well in Safari) */ +.bg-1 .button2 { + color: #37474f; + border-color: #37474f; +} +.bg-2 .button2 { + color: #ECEFF1; + border-color: #ECEFF1; +} +.bg-3 .button2 { + color: #fff; + border-color: #fff; +} + +/* Sizes */ +.button--size-s { + font-size: 14px; +} +.button--size-m { + font-size: 16px; +} +.button--size-l { + font-size: 18px; +} + +/* Typography and Roundedness */ +.button--text-upper { + letter-spacing: 2px; + text-transform: uppercase; +} +.button--text-thin { + font-weight: 300; +} +.button--text-medium { + font-weight: 500; +} +.button--text-thick { + font-weight: 600; +} +.button--round-s { + border-radius: 5px; +} +.button--round-m { + border-radius: 15px; +} +.button--round-l { + border-radius: 40px; +} + +/* Borders */ +.button--border-thin { + border: 1px solid; +} +.button--border-medium { + border: 2px solid; +} +.button--border-thick { + border: 3px solid; +} + +/* Individual button styles */ + +/* Winona */ +.button--winona { + overflow: hidden; + padding: 0; + -webkit-transition: border-color 0.3s, background-color 0.3s; + transition: border-color 0.3s, background-color 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); + transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); +} +.button--winona::after { + content: attr(data-text); + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + opacity: 0; + color: #4e93c7; + -webkit-transform: translate3d(0, 25%, 0); + transform: translate3d(0, 25%, 0); +} +.button--winona > span { + display: block; +} +.button--winona.button--inverted { + color: #7986cb; +} +.button--winona.button--inverted:after { + color: #fff; +} +.button--winona::after, +.button--winona > span { + padding: 1em 2em; + -webkit-transition: -webkit-transform 0.3s, opacity 0.3s; + transition: transform 0.3s, opacity 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); + transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); +} +.button--winona:hover { + border-color: #4e93c7; + background-color: rgba(63, 81, 181, 0.1); +} +.button--winona.button--inverted:hover { + border-color: #21333C; + background-color: #21333C; +} +.button--winona:hover::after { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +.button--winona:hover > span { + opacity: 0; + -webkit-transform: translate3d(0, -25%, 0); + transform: translate3d(0, -25%, 0); +} + +/* Ujarak */ +.button--ujarak { + -webkit-transition: border-color 0.4s, color 0.4s; + transition: border-color 0.4s, color 0.4s; +} +.button--ujarak::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: #37474f; + z-index: -1; + opacity: 0; + -webkit-transform: scale3d(0.7, 1, 1); + transform: scale3d(0.7, 1, 1); + -webkit-transition: -webkit-transform 0.4s, opacity 0.4s; + transition: transform 0.4s, opacity 0.4s; + -webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); + transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); +} +.button--ujarak.button--round-s::before { + border-radius: 2px; +} +.button--ujarak.button--inverted::before { + background: #7986CB; +} +.button--ujarak, +.button--ujarak::before { + -webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); + transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); +} +.button--ujarak:hover { + color: #fff; + border-color: #37474f; +} +.button--ujarak.button--inverted:hover { + color: #37474F; + border-color: #fff; +} +.button--ujarak:hover::before { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} + +/* Wayra */ +.button--wayra { + overflow: hidden; + width: 245px; + -webkit-transition: border-color 0.3s, color 0.3s; + transition: border-color 0.3s, color 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); + transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); +} +.button--wayra::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 150%; + height: 100%; + background: #37474f; + z-index: -1; + -webkit-transform: rotate3d(0, 0, 1, -45deg) translate3d(0, -3em, 0); + transform: rotate3d(0, 0, 1, -45deg) translate3d(0, -3em, 0); + -webkit-transform-origin: 0% 100%; + transform-origin: 0% 100%; + -webkit-transition: -webkit-transform 0.3s, opacity 0.3s, background-color 0.3s; + transition: transform 0.3s, opacity 0.3s, background-color 0.3s; +} +.button--wayra:hover { + color: #fff; + border-color: #3f51b5; +} +.button--wayra.button--inverted:hover { + color: #3f51b5; + border-color: #fff; +} +.button--wayra:hover::before { + opacity: 1; + background-color: #3f51b5; + -webkit-transform: rotate3d(0, 0, 1, 0deg); + transform: rotate3d(0, 0, 1, 0deg); + -webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); + transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); +} +.button--wayra.button--inverted:hover::before { + background-color: #fff; +} + +/* Tamaya */ +.button--tamaya { + overflow: hidden; + color: #7986cb; + min-width: 180px; +} +.button--tamaya.button--inverted { + color: #37474f; + border-color: #37474f; +} +.button--tamaya::before, +.button--tamaya::after { + content: attr(data-text); + position: absolute; + width: 100%; + height: 50%; + left: 0; + background: #7986cb; + color: #fff; + overflow: hidden; + -webkit-transition: -webkit-transform 0.3s; + transition: transform 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); + transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); +} +.button--tamaya.button--inverted::before, +.button--tamaya.button--inverted::after { + background: #fff; + color: #37474f; +} +.button--tamaya::before { + top: 0; + padding-top: 1em; +} +.button--tamaya::after { + bottom: 0; + line-height: 0; +} +.button--tamaya > span { + display: block; + -webkit-transform: scale3d(0.2, 0.2, 1); + transform: scale3d(0.2, 0.2, 1); + opacity: 0; + -webkit-transition: -webkit-transform 0.3s, opacity 0.3s; + transition: transform 0.3s, opacity 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); + transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); +} +.button--tamaya:hover::before { + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); +} +.button--tamaya:hover::after { + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); +} +.button--tamaya:hover > span { + opacity: 1; + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); +} + +/* Rayen */ +.button--rayen { + overflow: hidden; + padding: 0; + width: 230px; +} +.button--rayen.button--inverted { + color: #fff; +} +.button--rayen::before { + content: attr(data-text); + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: #7986cb; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); +} +.button--rayen.button--inverted::before { + background: #fff; + color: #37474f; +} +.button--rayen > span { + display: block; +} +.button--rayen::before, +.button--rayen > span { + padding: 1em 2em; + -webkit-transition: -webkit-transform 0.3s; + transition: transform 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); + transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); +} +.button--rayen:hover::before { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +.button--rayen:hover > span { + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); +} + +/* Pipaluk */ +.button--pipaluk { + width: 240px; + padding: 1.5em 3em; + color: #fff; +} +.button--pipaluk.button--inverted { + color: #7986cb; +} +.button--pipaluk::before, +.button--pipaluk::after { + content: ''; + border-radius: inherit; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: -1; + -webkit-transition: -webkit-transform 0.3s, background-color 0.3s; + transition: transform 0.3s, background-color 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.25, 0, 0.3, 1); + transition-timing-function: cubic-bezier(0.25, 0, 0.3, 1); +} +.button--pipaluk::before { + border: 2px solid #7986cb; +} +.button--pipaluk.button--inverted::before { + border-color: #fff; +} +.button--pipaluk::after { + background: #7986cb; +} +.button--pipaluk.button--inverted::after { + background: #fff; +} +.button--pipaluk:hover::before { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); +} +.button--pipaluk::before, +.button--pipaluk:hover::after { + -webkit-transform: scale3d(0.7, 0.7, 1); + transform: scale3d(0.7, 0.7, 1); +} +.button--pipaluk:hover::after { + background-color: #3f51b5; +} +.button--pipaluk.button--inverted:hover::after { + background-color: #fff; +} + +/* Nuka */ +.button--nuka { + margin: 1em 2em; + -webkit-transition: color 0.3s; + transition: color 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); + transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); +} +.button--nuka.button--inverted { + color: #37474f; +} +.button--nuka::before, +.button--nuka::after { + content: ''; + position: absolute; + border-radius: inherit; + background: #7986cb; + z-index: -1; +} +.button--nuka::before { + top: -4px; + bottom: -4px; + left: -4px; + right: -4px; + opacity: 0.2; + -webkit-transform: scale3d(0.7, 1, 1); + transform: scale3d(0.7, 1, 1); + -webkit-transition: -webkit-transform 0.3s, opacity 0.3s; + transition: transform 0.3s, opacity 0.3s; +} +.button--nuka::after { + top: 0; + left: 0; + width: 100%; + height: 100%; + -webkit-transform: scale3d(1.1, 1, 1); + transform: scale3d(1.1, 1, 1); + -webkit-transition: -webkit-transform 0.3s, background-color 0.3s; + transition: transform 0.3s, background-color 0.3s; +} +.button--nuka::before, +.button--nuka::after { + -webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); + transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); +} +.button--nuka.button--inverted::before, +.button--nuka.button--inverted::after { + background: #fff; +} +.button--nuka:hover { + color: #fff; +} +.button--nuka:hover::before { + opacity: 1; +} +.button--nuka:hover::after { + background-color: #37474f; +} +.button--nuka.button--inverted:hover::after { + background-color: #7986cb; +} +.button--nuka:hover::after, +.button--nuka:hover::before { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); +} + +/* Moema */ +.button--moema { + padding: 1.5em 3em; + border-radius: 50px; + background: #7986cb; + color: #fff; + -webkit-transition: background-color 0.3s, color 0.3s; + transition: background-color 0.3s, color 0.3s; +} +.button--moema.button--inverted { + background: #ECEFF1; + color: #37474f; +} +.button--moema::before { + content: ''; + position: absolute; + top: -20px; + left: -20px; + bottom: -20px; + right: -20px; + background: inherit; + border-radius: 50px; + z-index: -1; + opacity: 0.4; + -webkit-transform: scale3d(0.8, 0.5, 1); + transform: scale3d(0.8, 0.5, 1); +} +.button--moema:hover { + -webkit-transition: background-color 0.1s 0.3s, color 0.1s 0.3s; + transition: background-color 0.1s 0.3s, color 0.1s 0.3s; + color: #ECEFF1; + background-color: #3f51b5; + -webkit-animation: anim-moema-1 0.3s forwards; + animation: anim-moema-1 0.3s forwards; +} +.button--moema.button--inverted:hover { + color: #ECEFF1; + background-color: #7986cb; +} +.button--moema:hover::before { + -webkit-animation: anim-moema-2 0.3s 0.3s forwards; + animation: anim-moema-2 0.3s 0.3s forwards; +} +@-webkit-keyframes anim-moema-1 { + 60% { + -webkit-transform: scale3d(0.8, 0.8, 1); + transform: scale3d(0.8, 0.8, 1); + } + 85% { + -webkit-transform: scale3d(1.1, 1.1, 1); + transform: scale3d(1.1, 1.1, 1); + } + 100% { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} +@keyframes anim-moema-1 { + 60% { + -webkit-transform: scale3d(0.8, 0.8, 1); + transform: scale3d(0.8, 0.8, 1); + } + 85% { + -webkit-transform: scale3d(1.1, 1.1, 1); + transform: scale3d(1.1, 1.1, 1); + } + 100% { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} +@-webkit-keyframes anim-moema-2 { + to { + opacity: 0; + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} +@keyframes anim-moema-2 { + to { + opacity: 0; + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +/* Isi */ +.button--isi { + padding: 1.2em 2em; + color: #fff; + background: #7986cb; + overflow: hidden; +} +.button--isi::before { + content: ''; + z-index: -1; + position: absolute; + top: 50%; + left: 100%; + margin: -15px 0 0 1px; + width: 30px; + height: 30px; + border-radius: 50%; + background: #3f51b5; + -webkit-transform-origin: 100% 50%; + transform-origin: 100% 50%; + -webkit-transform: scale3d(1, 2, 1); + transform: scale3d(1, 2, 1); + -webkit-transition: -webkit-transform 0.3s, opacity 0.3s; + transition: transform 0.3s, opacity 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.7,0,0.9,1); + transition-timing-function: cubic-bezier(0.7,0,0.9,1); +} +.button--isi .button__icon { + vertical-align: middle; +} +.button--isi > span { + vertical-align: middle; + padding-left: 0.75em; +} +.button--isi:hover::before { + -webkit-transform: scale3d(9, 9, 1); + transform: scale3d(9, 9, 1); +} + +/* Aylen */ +.button.button--aylen { + background: #fff; + color: #37474f; + overflow: hidden; + -webkit-transition: color 0.3s; + transition: color 0.3s; +} +.button--aylen.button--inverted { + background: none; + color: #fff; +} +.button--aylen::before, +.button--aylen::after { + content: ''; + position: absolute; + height: 100%; + width: 100%; + bottom: 100%; + left: 0; + z-index: -1; + -webkit-transition: -webkit-transform 0.3s; + transition: transform 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); + transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); +} +.button--aylen::before { + background: #7986cb; +} +.button--aylen::after { + background: #3f51b5; +} +.button--aylen:hover { + color: #fff; +} +.button--aylen:hover::before, +.button--aylen:hover::after { + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); +} +.button--aylen:hover::after { + -webkit-transition-delay: 0.175s; + transition-delay: 0.175s; +} + +/* Saqui */ +.button.button--saqui { + overflow: hidden; + color: #fff; + background: #37474f; + -webkit-transition: background-color 0.3s ease-in, color 0.3s ease-in; + transition: background-color 0.3s ease-in, color 0.3s ease-in; +} +.button--saqui.button--inverted { + background: #fff; + color: #37474f; +} +.button--saqui::after { + content: attr(data-text); + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + padding: 1em 2em; + color: #37474f; + -webkit-transform-origin: -25% 50%; + transform-origin: -25% 50%; + -webkit-transform: rotate3d(0, 0, 1, 45deg); + transform: rotate3d(0, 0, 1, 45deg); + -webkit-transition: -webkit-transform 0.3s ease-in; + transition: transform 0.3s ease-in; +} +.button--saqui.button--inverted::after { + color: #fff; +} +.button--saqui:hover::after, +.button--saqui:hover { + -webkit-transition-timing-function: ease-out; + transition-timing-function: ease-out; +} +.button--saqui:hover { + background-color: #7986cb; + color: #7986cb; +} +.button--saqui.button--inverted:hover { + background-color: #3f51b5; + color: #3f51b5; +} +.button--saqui:hover::after { + -webkit-transform: rotate3d(0, 0, 1, 0deg); + transform: rotate3d(0, 0, 1, 0deg); +} + +/* Wapasha */ +.button.button--wapasha { + background: #37474f; + color: #fff; + -webkit-transition: background-color 0.3s, color 0.3s; + transition: background-color 0.3s, color 0.3s; +} +.button--wapasha.button--inverted { + background: #fff; + color: #37474f; +} +.button--wapasha::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: 2px solid #3f51b5; + z-index: -1; + border-radius: inherit; + opacity: 0; + -webkit-transform: scale3d(0.6, 0.6, 1); + transform: scale3d(0.6, 0.6, 1); + -webkit-transition: -webkit-transform 0.3s, opacity 0.3s; + transition: transform 0.3s, opacity 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); + transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); +} +.button--wapasha.button--inverted::before { + border-color: #7986cb; +} +.button--wapasha:hover { + background-color: #fff; + color: #3f51b5; +} +.button--wapasha.button--inverted:hover { + background-color: #37474f; + color: #7986cb; +} +.button--wapasha:hover::before { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + opacity: 1; +} + +/* Nina */ +.button--nina { + padding: 0 2em; + background: #7986cb; + color: #fff; + overflow: hidden; + -webkit-transition: background-color 0.3s; + transition: background-color 0.3s; +} +.button--nina.button--inverted { + background: #fff; + color: #7986cb; +} +.button--nina > span { + display: inline-block; + padding: 1em 0; + opacity: 0; + color: #fff; + -webkit-transform: translate3d(0, -10px, 0); + transform: translate3d(0, -10px, 0); + -webkit-transition: -webkit-transform 0.3s, opacity 0.3s; + transition: transform 0.3s, opacity 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); + transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); +} +.button--nina::before { + content: attr(data-text); + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + padding: 1em 0; + -webkit-transition: -webkit-transform 0.3s, opacity 0.3s; + transition: transform 0.3s, opacity 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); + transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); +} +.button--nina:hover { + background-color: #3f51b5; +} +.button--nina:hover::before { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); +} +.button--nina:hover > span { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +.button--nina:hover > span:nth-child(1) { + -webkit-transition-delay: 0.045s; + transition-delay: 0.045s; +} +.button--nina:hover > span:nth-child(2) { + -webkit-transition-delay: 0.09s; + transition-delay: 0.09s; +} +.button--nina:hover > span:nth-child(3) { + -webkit-transition-delay: 0.135s; + transition-delay: 0.135s; +} +.button--nina:hover > span:nth-child(4) { + -webkit-transition-delay: 0.18s; + transition-delay: 0.18s; +} +.button--nina:hover > span:nth-child(5) { + -webkit-transition-delay: 0.225s; + transition-delay: 0.225s; +} +.button--nina:hover > span:nth-child(6) { + -webkit-transition-delay: 0.27s; + transition-delay: 0.27s; +} +.button--nina:hover > span:nth-child(7) { + -webkit-transition-delay: 0.315s; + transition-delay: 0.315s; +} +.button--nina:hover > span:nth-child(8) { + -webkit-transition-delay: 0.36s; + transition-delay: 0.36s; +} +.button--nina:hover > span:nth-child(9) { + -webkit-transition-delay: 0.405s; + transition-delay: 0.405s; +} +.button--nina:hover > span:nth-child(10) { + -webkit-transition-delay: 0.45s; + transition-delay: 0.45s; +} + +/* Nanuk */ +.button--nanuk { + padding: 0 2em; + overflow: hidden; + background: #7986cb; + -webkit-transition: background-color 0.3s; + transition: background-color 0.3s; +} +.button--nanuk.button--inverted { + background: #fff; + color: #7986cb; +} +.button--nanuk > span { + display: inline-block; + padding: 1em 0; +} +.button--nanuk:hover { + background-color: #3f51b5; +} +.button--nanuk:hover > span:nth-child(odd) { + -webkit-animation: anim-nanuk-1 0.5s forwards; + animation: anim-nanuk-1 0.5s forwards; +} +.button--nanuk:hover > span:nth-child(even) { + -webkit-animation: anim-nanuk-2 0.5s forwards; + animation: anim-nanuk-2 0.5s forwards; +} +.button--nanuk:hover > span:nth-child(odd), +.button--nanuk:hover > span:nth-child(even) { + -webkit-animation-timing-function: cubic-bezier(0.75, 0, 0.125, 1); + transition-animation-function: cubic-bezier(0.75, 0, 0.125, 1); +} +@-webkit-keyframes anim-nanuk-1 { + 0%, + 100% { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + 49% { + opacity: 1; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } + 50% { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + color: inherit; + } + 51% { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + color: #fff; + } + 100% { + color: #fff; + } +} +@keyframes anim-nanuk-1 { + 0%, + 100% { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + 49% { + opacity: 1; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } + 50% { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + color: inherit; + } + 51% { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + color: #fff; + } + 100% { + color: #fff; + } +} +@-webkit-keyframes anim-nanuk-2 { + 0%, + 100% { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + 49% { + opacity: 1; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } + 50% { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + color: inherit; + } + 51% { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + color: #fff; + } + 100% { + color: #fff; + } +} +@keyframes anim-nanuk-2 { + 0%, + 100% { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + 49% { + opacity: 1; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } + 50% { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + color: inherit; + } + 51% { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + color: #fff; + } + 100% { + color: #fff; + } +} +.button--nanuk:hover > span:nth-child(1) { + -webkit-animation-delay: 0s; + animation-delay: 0s; +} +.button--nanuk:hover > span:nth-child(2) { + -webkit-animation-delay: 0.05s; + animation-delay: 0.05s; +} +.button--nanuk:hover > span:nth-child(3) { + -webkit-animation-delay: 0.1s; + animation-delay: 0.1s; +} +.button--nanuk:hover > span:nth-child(4) { + -webkit-animation-delay: 0.15s; + animation-delay: 0.15s; +} +.button--nanuk:hover > span:nth-child(5) { + -webkit-animation-delay: 0.2s; + animation-delay: 0.2s; +} +.button--nanuk:hover > span:nth-child(6) { + -webkit-animation-delay: 0.25s; + animation-delay: 0.25s; +} +.button--nanuk:hover > span:nth-child(7) { + -webkit-animation-delay: 0.3s; + animation-delay: 0.3s; +} +.button--nanuk:hover > span:nth-child(8) { + -webkit-animation-delay: 0.35s; + animation-delay: 0.35s; +} +.button--nanuk:hover > span:nth-child(9) { + -webkit-animation-delay: 0.4s; + animation-delay: 0.4s; +} +.button--nanuk:hover > span:nth-child(10) { + -webkit-animation-delay: 0.45s; + animation-delay: 0.45s; +} +.button--nanuk:hover > span:nth-child(11) { + -webkit-animation-delay: 0.5s; + animation-delay: 0.5s; +} + +/* Antiman */ +.button--antiman { + background: none; + border: none; + height: 60px; +} +.button--antiman.button--inverted, +.button--antiman.button--inverted-alt { + -webkit-transition: color 0.3s; + transition: color 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); + transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); +} +.button--antiman > span { + padding-left: 0.35em; +} +.button--antiman::before, +.button--antiman::after { + content: ''; + z-index: -1; + border-radius: inherit; + pointer-events: none; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + -webkit-backface-visibility: hidden; + -webkit-transition: -webkit-transform 0.3s, opacity 0.3s; + transition: transform 0.3s, opacity 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); + transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); +} +.button--antiman::before { + border: 2px solid #37474f; + opacity: 0; + -webkit-transform: scale3d(1.2, 1.2, 1); + transform: scale3d(1.2, 1.2, 1); +} +.button--antiman.button--border-thin::before { + border-width: 1px; +} +.button--antiman.button--border-medium::before { + border-width: 2px; +} +.button--antiman.button--border-thick::before { + border-width: 3px; +} +.button--antiman.button--inverted::before { + border-color: #7986cb; +} +.button--antiman.button--inverted-alt::before { + border-color: #3f51b5; +} +.button--antiman::after { + background: #fff; +} +.button--antiman.button--inverted::after { + background: #7986cb; +} +.button--antiman.button--inverted-alt::after { + background: #3f51b5; +} +.button--antiman.button--inverted:hover { + color: #7986cb; +} +.button--antiman.button--inverted-alt:hover { + color: #3f51b5; +} +.button--antiman:hover::before { + opacity: 1; + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); +} +.button--antiman:hover::after { + opacity: 0; + -webkit-transform: scale3d(0.8, 0.8, 1); + transform: scale3d(0.8, 0.8, 1); +} + +/* Itzel */ +.button--itzel { + border: none; + padding: 0px; + overflow: hidden; + width: 255px; +} +.button--itzel::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: 2px solid; + border-radius: inherit; + -webkit-clip-path: polygon(0% 0%, 0% 100%, 35% 100%, 35% 60%, 65% 60%, 65% 100%, 100% 100%, 100% 0%); + clip-path: url(../index.html#clipBox); + -webkit-transform: translate3d(0, 100%, 0) translate3d(0, -2px, 0); + transform: translate3d(0, 100%, 0) translate3d(0, -2px, 0); + -webkit-transform-origin: 50% 100%; + transform-origin: 50% 100%; +} + +.button--itzel.button--border-thin::before { + border: 1px solid; + -webkit-transform: translate3d(0, 100%, 0) translate3d(0, -1px, 0); + transform: translate3d(0, 100%, 0) translate3d(0, -1px, 0); +} +.button--itzel.button--border-thick::before { + border: 3px solid; + -webkit-transform: translate3d(0, 100%, 0) translate3d(0, -3px, 0); + transform: translate3d(0, 100%, 0) translate3d(0, -3px, 0); +} + +.button--itzel::before, +.button--itzel .button__icon { + -webkit-transition: -webkit-transform 0.3s; + transition: transform 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); + transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); +} +.button--itzel .button__icon { + position: absolute; + top: 100%; + left: 50%; + padding: 20px; + font-size: 20px; + -webkit-transform: translate3d(-50%, 0, 0); + transform: translate3d(-50%, 0, 0); +} +.button--itzel > span { + display: block; + padding: 20px; + -webkit-transition: -webkit-transform 0.3s, opacity 0.3s; + transition: transform 0.3s, opacity 0.3s; + -webkit-transition-delay: 0.3s; + transition-delay: 0.3s; +} +.button--itzel:hover::before { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +.button--itzel:hover .button__icon { + -webkit-transition-delay: 0.1s; + transition-delay: 0.1s; + -webkit-transform: translate3d(-50%, -100%, 0); + transform: translate3d(-50%, -100%, 0); +} +.button--itzel:hover > span { + opacity: 0; + -webkit-transform: translate3d(0, -50%, 0); + transform: translate3d(0, -50%, 0); + -webkit-transition-delay: 0s; + transition-delay: 0s; +} + +/* Naira */ +.button--naira { + padding: 0; + overflow: hidden; + -webkit-transition: background-color 0.3s; + transition: background-color 0.3s; +} +.button--naira::before { + content: ''; + position: absolute; + left: -50%; + width: 200%; + height: 200%; + background: #37474f; + top: -50%; + z-index: -1; + -webkit-transform: translate3d(0, -100%, 0) rotate3d(0, 0, 1, -10deg); + transform: translate3d(0, -100%, 0) rotate3d(0, 0, 1, -10deg); +} +.button--naira.button--inverted::before { + background: #7986cb; +} +.button--naira-up::before { + -webkit-transform: translate3d(0, 100%, 0) rotate3d(0, 0, 1, 10deg); + transform: translate3d(0, 100%, 0) rotate3d(0, 0, 1, 10deg); +} +.button--naira > span { + display: block; +} +.button--naira .button__icon { + position: absolute; + top: 0; + width: 100%; + left: 0; + color: #fff; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); +} +.button--naira-up .button__icon { + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); +} +.button--naira > span, +.button--naira .button__icon { + padding: 1em 2em; + -webkit-transition: -webkit-transform 0.3s; + transition: transform 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); + transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); +} +.button--naira:hover::before { + -webkit-animation: anim-naira-1 0.3s forwards ease-in; + animation: anim-naira-1 0.3s forwards ease-in; +} +.button--naira-up:hover::before { + -webkit-animation: anim-naira-2 0.3s forwards ease-in; + animation: anim-naira-2 0.3s forwards ease-in; +} +@-webkit-keyframes anim-naira-1 { + 50% { + -webkit-transform: translate3d(0, -50%, 0) rotate3d(0, 0, 1, -10deg); + transform: translate3d(0, -50%, 0) rotate3d(0, 0, 1, -10deg); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + 100% { + -webkit-transform: translate3d(0, 0%, 0) rotate3d(0, 0, 1, 0deg); + transform: translate3d(0, 0%, 0) rotate3d(0, 0, 1, 0deg); + } +} +@keyframes anim-naira-1 { + 50% { + -webkit-transform: translate3d(0, -50%, 0) rotate3d(0, 0, 1, -10deg); + transform: translate3d(0, -50%, 0) rotate3d(0, 0, 1, -10deg); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + 100% { + -webkit-transform: translate3d(0, 0%, 0) rotate3d(0, 0, 1, 0deg); + transform: translate3d(0, 0%, 0) rotate3d(0, 0, 1, 0deg); + } +} +@-webkit-keyframes anim-naira-2 { + 50% { + -webkit-transform: translate3d(0, 50%, 0) rotate3d(0, 0, 1, 10deg); + transform: translate3d(0, 50%, 0) rotate3d(0, 0, 1, 10deg); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + 100% { + -webkit-transform: translate3d(0, 0%, 0) rotate3d(0, 0, 1, 0deg); + transform: translate3d(0, 0%, 0) rotate3d(0, 0, 1, 0deg); + } +} +@keyframes anim-naira-2 { + 50% { + -webkit-transform: translate3d(0, 50%, 0) rotate3d(0, 0, 1, 10deg); + transform: translate3d(0, 50%, 0) rotate3d(0, 0, 1, 10deg); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + 100% { + -webkit-transform: translate3d(0, 0%, 0) rotate3d(0, 0, 1, 0deg); + transform: translate3d(0, 0%, 0) rotate3d(0, 0, 1, 0deg); + } +} +.button--naira:hover { + background-color: #37474f; + -webkit-transition: background-color 0s 0.3s; + transition: background-color 0s 0.3s; +} +.button--naira.button--inverted:hover { + background-color: #7986cb; +} +.button--naira:hover .button__icon { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +.button--naira:hover > span { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); +} +.button--naira-up:hover > span { + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); +} + +/* Quidel */ +.button--quidel { + background: #7986cb; + color: #7986cb; + overflow: hidden; + -webkit-transition: color 0.3s; + transition: color 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); + transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); +} +.button--quidel.button--inverted { + background: #fff; + color: #fff; +} +.button--quidel::before, +.button--quidel::after { + content: ''; + position: absolute; + z-index: -1; + border-radius: inherit; +} +.button--quidel::after { + top: 2px; + left: 2px; + right: 2px; + bottom: 2px; + background: #fff; +} +.button--quidel.button--inverted::after { + background: #37474f; +} +.button--quidel::before { + background: #37474f; + top: 0; + left: 0; + width: 100%; + height: 100%; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + -webkit-transition: -webkit-transform 0.3s; + transition: transform 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); + transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); +} +.button--quidel.button--inverted::before { + background: #7986cb; +} +.button--round-s.button--quidel::after { + border-radius: 3px; +} +.button--round-m.button--quidel::after { + border-radius: 13px; +} +.button--round-l.button--quidel::after { + border-radius: 40px; +} +.button--quidel > span { + padding-left: 0.35em; +} +.button--quidel:hover { + color: #37474f; +} +.button--quidel.button--inverted:hover { + color: #7986cb; +} +.button--quidel:hover::before { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} + +/* Sacnite */ +.button.button--sacnite { + width: 70px; + height: 70px; + min-width: 0; + padding: 0; + color: #fff; + -webkit-transition: color 0.3s; + transition: color 0.3s; +} +.button--scanite.button--round-l { + border-radius: 50%; +} +.button--sacnite.button--inverted { + color: #37474f; +} +.button--sacnite::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border-radius: inherit; + z-index: -1; + box-shadow: inset 0 0 0 35px #37474f; + -webkit-transform: scale3d(0.9, 0.9, 1); + transform: scale3d(0.9, 0.9, 1); + -webkit-transition: box-shadow 0.3s, -webkit-transform 0.3; + transition: box-shadow 0.3s, transform 0.3s; +} +.button--sacnite.button--inverted::before { + box-shadow: inset 0 0 0 35px #fff; +} +.button--sacnite .button__icon { + font-size: 22px; + width: 22px; +} +.button--sacnite > span { + position: absolute; + opacity: 0; + pointer-events: none; +} +.button--sacnite:hover { + color: #37474f; +} +.button--sacnite.button--inverted:hover { + color: #fff; +} +.button--sacnite:hover::before { + box-shadow: inset 0 0 0 2px #37474f; + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); +} +.button--sacnite.button--inverted:hover::before { + box-shadow: inset 0 0 0 2px #fff; +} + +/* Shikoba */ +.button.button--shikoba { + padding: 1em 30px 1em 50px; + overflow: hidden; + background: #fff; + color: #37474f; + border-color: #37474f; + -webkit-transition: background-color 0.3s, border-color 0.3s, color 0.3s; + transition: background-color 0.3s, border-color 0.3s, color 0.3s; +} +.button--shikoba.button--inverted { + color: #fff; + background: #7986cb; +} +.button--shikoba > span { + display: inline-block; + -webkit-transform: translate3d(-10px, 0, 0); + transform: translate3d(-10px, 0, 0); + -webkit-transition: -webkit-transform 0.3s; + transition: transform 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); + transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); +} +.button--shikoba .button__icon { + position: absolute; + left: 20px; + font-size: 18px; + -webkit-transform: translate3d(-40px, 2.5em, 0); + transform: translate3d(-40px, 2.5em, 0); + -webkit-transition: -webkit-transform 0.3s; + transition: transform 0.3s; + -webkit-transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); + transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1); +} +.button--shikoba:hover .button__icon, +.button--shikoba:hover > span { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +.button--shikoba:hover { + background: #3f51b5; + border-color: #3f51b5; + color: #fff; +} + +.clist{ + list-style-type: circle; +} \ No newline at end of file diff --git a/introduction/static/css/style.css b/introduction/static/css/style.css new file mode 100644 index 0000000..62a37d5 --- /dev/null +++ b/introduction/static/css/style.css @@ -0,0 +1,491 @@ +/* + DEMO STYLE +*/ + +@import "https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700"; +body { + font-family: "Poppins", sans-serif; + /* background: #000000; */ + background: #fff; +} + +body::-webkit-scrollbar { + display: none; +} +body { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} + +p { + font-family: "Poppins", sans-serif; + font-size: 1.1em; + font-weight: 300; + line-height: 1.7em; + color: #999; +} + +a, +a:hover, +a:focus { + color: inherit; + text-decoration: none; + transition: all 0.3s; +} + +.navbar { + padding: 15px 10px; + background-image: linear-gradient(45deg, hsl(0deg 0% 95%), #80a9c9); + border: 0px solid; + border-radius: 0px 10px 0px 0px; + margin-bottom: 40px; + /* box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1); */ +} + +.navbar-btn { + box-shadow: none; + outline: none !important; + border: none; +} + +.line { + width: 100%; + height: 1px; + border-bottom: 1px dashed #ddd; + margin: 40px 0; +} + +i, +span { + display: inline-block; +} +.login-form { + margin-left: 10px; + margin-right: 10px; +} +.card { + border: #306998; + border-radius: 10px; +} +/* --------------------------------------------------- + SIDEBAR STYLE +----------------------------------------------------- */ +.sidebar-list-items { + background-color: #79a9cf40; + color : #0b446e; +} +.wrapper { + display: flex; + align-items: stretch; + margin: 10px; + background-color: #424242; + background-color: #f1f1f1; + height: 97vh; + border-radius: 20px; +} + +#sidebar { + height: 97vh; + overflow: scroll; + min-width: 315px; + max-width: 315px; + background: #373c40; + background: #c5cfd7; + color: #fff; + transition: all 0.3s; + border-radius: 20px 0px 20px 0px; +} + +.sidebarClass::-webkit-scrollbar { + display: none; +} +.sidebarClass { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} + +#sidebar.active { + min-width: 80px; + max-width: 80px; + text-align: center; + height: 97vh; + overflow: scroll; +} + +#sidebar.active .sidebar-header div h3, +#sidebar.active .sidebar-header div img, +#sidebar.active .CTAs { + display: none; +} + +#sidebar.active .sidebar-header strong { + display: block; +} + +#sidebar.active ul li a { + padding: 20px 10px; + text-align: center; + font-size: 0.85em; +} + +#sidebar.active ul li a i { + margin-right: 0; + display: block; + font-size: 1.8em; + /* margin-bottom: 5px; */ +} + +#sidebar.active ul ul a { + padding: 10px !important; +} + +#sidebar.active .dropdown-toggle::after { + top: auto; + bottom: 10px; + right: 50%; + -webkit-transform: translateX(50%); + -ms-transform: translateX(50%); + transform: translateX(50%); +} + +#sidebar .sidebar-header { + padding: 20px; + /* background: #283036; */ + background: #4e93c7 +} + +#sidebar .sidebar-header strong { + display: none; + font-size: 1.8em; +} + +#sidebar ul.components { + padding: 20px 0; + border-bottom: 1px solid #4b8bbe; +} + +#sidebar ul li a { + padding: 10px; + font-size: 1.1em; + display: block; +} + +#sidebar ul li a:hover { + color: #306998; + background: #fff; +} + +#sidebar ul li a i { + margin-right: 10px; +} + +#sidebar ul li.active > a, +a[aria-expanded="true"] { + color: #fff; + background: #4b8bbe; +} + +a[data-toggle="collapse"] { + position: relative; +} + +.dropdown-toggle::after { + display: block; + position: absolute; + top: 50%; + right: 20px; + transform: translateY(-50%); +} + +ul ul a { + font-size: 0.9em !important; + padding-left: 30px !important; + background: #ffd43b; +} + +ul.CTAs { + padding: 20px; +} + +ul.CTAs a { + text-align: center; + font-size: 0.9em !important; + display: block; + border-radius: 5px; + margin-bottom: 5px; +} + +/* a.download { + background: #fff; + color: #7386D5; +} */ + +/* a.article, +a.article:hover { + background: #6d7fcc !important; + color: #fff !important; +} */ + +/* --------------------------------------------------- + CONTENT STYLE +----------------------------------------------------- */ + +#content { + width: 100%; + padding: 20px; + /* min-height: cal(100vh -20px); */ + transition: all 0.3s; + overflow: scroll; + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; +} + +#content::-webkit-scrollbar { + display: none; +} + +.box { + margin-top: 2rem; + border-radius: 10px; + padding: 2rem; + background-color: #f8ede345; + color: #20303e +} +.bp { + font-size: 1em; + font-height: 1.2em; + color: black; +} +.coll { + background-color: #159c80; + color: black; + cursor: pointer; + padding: auto; + width: auto; + margin-bottom: 20px; + text-align: center; + outline: none; + font-size: 20px; +} + +/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */ +.active, +.coll:hover { + background-color: #bfb051; +} + +/* Style the collapsible content. Note: hidden by default */ +.lab { + padding: 0 18px; + display: none; + overflow: hidden; + background-color: #f1f1f1; + border-radius: 1rem; +} +.display { + padding: 20px; +} +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + background-color: #f9f2f4; + border-radius: 4px; +} +.img { + border-radius: 8px; + display: block; + margin-left: auto; + margin-right: auto; + width: 50%; +} +/* --------------------------------------------------- + MEDIAQUERIES +----------------------------------------------------- */ + +@media (max-width: 768px) { + #sidebar { + min-width: 80px; + max-width: 80px; + text-align: center; + margin-left: -95px !important; + height: 100vh; + overflow: scroll; + } + .dropdown-toggle::after { + top: auto; + bottom: 10px; + right: 50%; + -webkit-transform: translateX(50%); + -ms-transform: translateX(50%); + transform: translateX(50%); + } + #sidebar.active { + margin-left: 0 !important; + } + #sidebar .sidebar-header h3, + #sidebar .CTAs { + display: none; + } + #sidebar .sidebar-header strong { + display: block; + } + #sidebar ul li a { + padding: 20px 10px; + } + #sidebar ul li a span { + font-size: 0.85em; + } + #sidebar ul li a i { + margin-right: 0; + display: block; + } + #sidebar ul ul a { + padding: 10px !important; + } + #sidebar ul li a i { + font-size: 1.3em; + } + #sidebar { + margin-left: 0; + } + #sidebarCollapse span { + display: none; + } +} + +code { + padding: 2px 4px; + font-size: 90%; + color: #033157; + border-radius: 4px; + background-color: #159c8100; +} + +.code { + /* background-image: linear-gradient(to right, #000000, #30989a); */ + background-color: #8dc2ed; + padding: 30px; + margin-top: 30px; +} + +#sidebarCollapse { + display: none; +} + +.h2, +h2 { + font-size: 4rem; +} + +#owasp10_2021 { + width: 90%; + background: #283036; + background: #4e93c7; + margin-top: 15px; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0 0 0; +} +#owasp10_2017 { + width: 90%; + margin-top: 15px; + background: #283036; + background: #4e93c7; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0 0 0; +} + +#sidebar li ul a #owasp10_2021 { + padding: 13% 0 0 0; +} + +#OWASP10_2021 { + width: 95%; + padding-left: 5%; +} +#OWASP10_2017 { + width: 95%; + padding-left: 5%; +} + +#sidebar-home { + width: 90%; + margin-top: 15px; + background: #283036; + background: #4e93c7; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0 0 0; +} + +#homeSubmenu { + width: 95%; + padding-left: 5%; +} + +.active, +.coll:hover { + background-color: #bfb05100; +} + +#challengeMenu { + width: 90%; + margin-top: 15px; + background: #283036; + background: #4e93c7; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0% 0% 0%; +} +#challengeSubmenu { + width: 95%; + padding-left: 5%; +} +#Mitre25 { + width: 95%; + padding-left: 5%; +} +#sans25 { + width: 95%; + padding-left: 5%; +} + +#help { + width: 90%; + margin-top: 15px; + background: #283036; + background: #4e93c7; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0% 0% 0%; +} +#mitre25 { + width: 90%; + margin-top: 15px; + background: #283036; + background: #4e93c7; + left: 5%; + height: 110px; + padding: 17px; + border-radius: 10px; + text-align: center; + padding: 13% 0% 0% 0%; +} + diff --git a/introduction/static/fake.txt b/introduction/static/fake.txt new file mode 100644 index 0000000..a709404 --- /dev/null +++ b/introduction/static/fake.txt @@ -0,0 +1 @@ +this is malicious file \ No newline at end of file diff --git a/introduction/static/google.jpg b/introduction/static/google.jpg new file mode 100644 index 0000000..caf2e87 Binary files /dev/null and b/introduction/static/google.jpg differ diff --git a/introduction/static/js/a6.js b/introduction/static/js/a6.js new file mode 100644 index 0000000..cbe7d8d --- /dev/null +++ b/introduction/static/js/a6.js @@ -0,0 +1,54 @@ +event5 = function(){ + var code = document.getElementById('a6_t1').value + var myHeaders = new Headers(); + var formdata = new FormData(); + + formdata.append("code", code); + var requestOptions = { + method: 'POST', + headers: myHeaders, + body: formdata, + redirect: 'follow' + }; + fetch("/2021/discussion/A6/api2", requestOptions) + .then(response => response.text()) + .then(result => { + let data = JSON.parse(result); + if (data.message == "success"){ + alert("code saved"); + } // parse JSON string into object + }) + .catch(error => console.log('error', error)); +} + +event6 = function(){ + var code = document.getElementById('a6_t1').value + var myHeaders = new Headers(); + var formdata = new FormData(); + + formdata.append("code", code); + var requestOptions = { + method: 'POST', + headers: myHeaders, + body: formdata, + redirect: 'follow' + }; + fetch("/2021/discussion/A6/api", requestOptions) + .then(response => response.text()) + .then(result => { + let data = JSON.parse(result); // parse JSON string into object + console.log(data.vulns); + document.getElementById("a6_d5").style.display = 'flex'; + // document.getElementById("a6_d5").innerText = data.vulns; + + for (var i = 0; i < data.vulns.length; i++) { + var vuln = data.vulns[i]; + var vuln_div = document.createElement("div"); + vuln_div.innerText = JSON.stringify(vuln) ; + document.getElementById("a6_d5").appendChild(vuln_div); + } + + }) + .catch(error => console.log('error', error)); +} + diff --git a/introduction/static/js/a7.js b/introduction/static/js/a7.js new file mode 100644 index 0000000..48f6553 --- /dev/null +++ b/introduction/static/js/a7.js @@ -0,0 +1,27 @@ +event4 = function(){ + var code = document.getElementById('a7_input').value + var myHeaders = new Headers(); + // myHeaders.append("Cookie", "csrftoken=5fVOTXh2HNahtvJFJNRSrKkwPAgPM9YCHlrCGprAxhAAKOUWMxqMnWm8BUomv0Yd; jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjUzMzEzMDIxLCJpYXQiOjE2NTMzMDk0MjF9.dh2gfP9wKD8GKu1J-jVs2jJUYMgKu_kMaJjrD0hHP-I"); + + var formdata = new FormData(); + // formdata.append("csrfmiddlewaretoken", "5fVOTXh2HNahtvJFJNRSrKkwPAgPM9YCHlrCGprAxhAAKOUWMxqMnWm8BUomv0Yd"); + formdata.append("code", code); + + var requestOptions = { + method: 'POST', + headers: myHeaders, + body: formdata, + redirect: 'follow' + }; + + fetch("/2021/discussion/A7/api", requestOptions) + .then(response => response.text()) + .then(result => { + let data = JSON.parse(result); // parse JSON string into object + console.log(data); + document.getElementById("a7_d4").style.display = 'flex'; + document.getElementById("a7_d4").innerText = "Result: " + data.message; + + } + ).catch(error => console.log('error', error)); +} \ No newline at end of file diff --git a/introduction/static/js/a9.js b/introduction/static/js/a9.js new file mode 100644 index 0000000..9c58b8a --- /dev/null +++ b/introduction/static/js/a9.js @@ -0,0 +1,45 @@ +// console.log("imported a9.js"); + +event1 = function(){ + document.getElementById("a9_b1").style.display = 'none'; + document.getElementById("a9_d1").style.display = 'flex'; +} + +event2 = function(){ + document.getElementById("a9_b2").style.display = 'none'; + document.getElementById("a9_d2").style.display = 'flex'; +} + +event3 = function(){ + var log_code = document.getElementById('a9_log').value + var target_code = document.getElementById('a9_api').value + + var myHeaders = new Headers(); + myHeaders.append("Cookie", "csrftoken=5fVOTXh2HNahtvJFJNRSrKkwPAgPM9YCHlrCGprAxhAAKOUWMxqMnWm8BUomv0Yd; jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjUzMzEzMDIxLCJpYXQiOjE2NTMzMDk0MjF9.dh2gfP9wKD8GKu1J-jVs2jJUYMgKu_kMaJjrD0hHP-I"); + + var formdata = new FormData(); + formdata.append("csrfmiddlewaretoken", "5fVOTXh2HNahtvJFJNRSrKkwPAgPM9YCHlrCGprAxhAAKOUWMxqMnWm8BUomv0Yd"); + formdata.append("log_code", log_code); + formdata.append("api_code", target_code); + + var requestOptions = { + method: 'POST', + headers: myHeaders, + body: formdata, + redirect: 'follow' + }; + + fetch("/2021/discussion/A9/api", requestOptions) + .then(response => response.text()) + .then(result => { + let data = JSON.parse(result); // parse JSON string into object + console.log(data.logs); + 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]; + document.getElementById("a9_d3").appendChild(li); + } + }) + .catch(error => console.log('error', error)); + } \ No newline at end of file diff --git a/introduction/static/real.txt b/introduction/static/real.txt new file mode 100644 index 0000000..bcfe693 --- /dev/null +++ b/introduction/static/real.txt @@ -0,0 +1 @@ +This is real file \ No newline at end of file diff --git a/introduction/templates/Lab/A10/a10.html b/introduction/templates/Lab/A10/a10.html new file mode 100644 index 0000000..9b11d04 --- /dev/null +++ b/introduction/templates/Lab/A10/a10.html @@ -0,0 +1,70 @@ +{% extends 'introduction/base.html' %} +{% block content %} +{% block title %} +Insufficient Logging & Monitoring +{% endblock %} +
+

Insufficient Logging & Monitoring

+
+

What does Insufficient Logging & Monitoring means?

+

+ Exploitation of insufficient logging and monitoring is the bedrock of nearly every major incident. Attackers rely + on the lack of monitoring and timely response to achieve their goals without being detected.
+ Most successful attacks start with vulnerability probing. Allowing such probes to continue can raise the + likelihood of successful exploit to nearly 100%.
+ In 2016, identifying a breach took an average of 191 days โ€“ plenty of time for damage to be inflicted. +

+ +
+

+ This lab helps you to get an idea of how sometimes improper logging can result in information disclosure. + + The user on accessing the lab is given with a login page which tells us that the logs have been leaked. + The user needs to find the leak and try to gain the credentials that have been leaked in the logs. + +
Finding the Log +

    +
  • The log has been exposed in /debug route
  • +
  • This can be found out with subdomain brute-forcing or just by guess
  • +
  • On seeing the Log try to get the required login details as there is a leak and the logging is improperly + handled.
  • + +
+ +

+
+
+
+ +
+

+ It seems this application is logging every action performed in this logging page. + But is there a way to inject some fake logs to the application? + +
+ Login credentials are same as lab1 +

+
+
+
+

Mitigation

+

+

    +
  • Ensure that logs are created in a format that can be easily used by central log management tools.
  • +
  • High-value transactions should have an audit trail with integrity controls to prevent manipulation or + deletion.
  • +
  • Effective monitoring and alerting should be established so that suspicious activities can be detected and + responded to in a timely manner.
  • +
  • Make sure that there aren't any sensitive information like passwords are being logged
  • +
+

+
+
+
+
+
+ + + {% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/A10/a10_lab.html b/introduction/templates/Lab/A10/a10_lab.html new file mode 100644 index 0000000..d4e905c --- /dev/null +++ b/introduction/templates/Lab/A10/a10_lab.html @@ -0,0 +1,44 @@ +{% extends "introduction/base.html" %} +{% load static %} +{% block content %} +{% block title %} +Insufficient Logging & Monitoring +{% endblock %} + + +
+

The Logs have been Leaked.

+ + + +
+ +
+ {% if name %} +

Success! Logged in as +
{{name}}
+

+ {% else %} +

+
{{error}}
+

+ {% endif %} + +
+ +
+
+ +

+ +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/A10/a10_lab2.html b/introduction/templates/Lab/A10/a10_lab2.html new file mode 100644 index 0000000..d0acadb --- /dev/null +++ b/introduction/templates/Lab/A10/a10_lab2.html @@ -0,0 +1,78 @@ +{% extends "introduction/base.html" %} +{% load static %} +{% block content %} +{% block title %} +Insufficient Logging & Monitoring +{% endblock %} + + +
+

Logs are strickty monitored

+ + + +
+ +
+ {% if name %} +

Success! Logged in as +
{{name}}
+

+ {% else %} +

+
{{error}}
+

+ {% endif %} + +
+ +
+ +
+ + logging.basicConfig(level=logging.DEBUG,filename='app.log')
+
+ @authentication_decorator
+ def a10_lab2(request):
+  now = datetime.datetime.now()
+  if request.method == "GET":
+   x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
+
+   if x_forwarded_for:
+    ip = x_forwarded_for.split(',')[0]
+   else:
+    ip = request.META.get('REMOTE_ADDR')
+   logging.info(f"{now}:{ip}")
+   return render (request,"Lab/A10/a10_lab2.html")
+  else:
+   user=request.POST.get("name")
+   password=request.POST.get("pass")
+   x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
+
+   if x_forwarded_for:
+    ip = x_forwarded_for.split(',')[0]
+   else:
+    ip = request.META.get('REMOTE_ADDR')
+
+   if login.objects.filter(user=user,password=password):
+    if ip != '127.0.0.1':
+     logging.warning(f"{now}:{ip}:{user}")
+    logging.info(f"{now}:{ip}:{user}")
+    return render(request,"Lab/A10/a10_lab2.html",{"name":user})
+   else:
+    logging.error(f"{now}:{ip}:{user}")
+    return render(request, "Lab/A10/a10_lab2.html", {"error": " Wrong username or Password"})
+
+

+
+
+ +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/A10/debug.log b/introduction/templates/Lab/A10/debug.log new file mode 100644 index 0000000..7e28b53 --- /dev/null +++ b/introduction/templates/Lab/A10/debug.log @@ -0,0 +1,317 @@ +INFO "GET /static/admin/css/dashboard.css HTTP/1.1" 304 0 +INFO "GET /static/admin/css/base.css HTTP/1.1" 304 0 +INFO "GET /static/admin/css/responsive.css HTTP/1.1" 304 0 +INFO "GET /static/admin/css/fonts.css HTTP/1.1" 304 0 +INFO "GET /static/admin/img/icon-addlink.svg HTTP/1.1" 304 0 +INFO "GET /static/admin/img/icon-changelink.svg HTTP/1.1" 304 0 +INFO "GET /static/admin/fonts/Roboto-Light-webfont.woff HTTP/1.1" 304 0 +INFO "GET /static/admin/fonts/Roboto-Regular-webfont.woff HTTP/1.1" 304 0 +INFO "GET /static/admin/fonts/Roboto-Bold-webfont.woff HTTP/1.1" 304 0 +INFO "GET /admin/logout/ HTTP/1.1" 200 1207 +INFO "GET /admin/logout/ HTTP/1.1" 302 0 +INFO "GET /admin/ HTTP/1.1" 302 0 +INFO "GET /admin/login/?next=/admin/ HTTP/1.1" 200 1913 +INFO "GET /static/admin/css/login.css HTTP/1.1" 304 0 +INFO Watching for file changes with StatReloader +INFO "GET / HTTP/1.1" 200 8157 +INFO "GET /static/introduction/style4.css HTTP/1.1" 304 0 +WARNING Not Found: /favicon.ico +WARNING "GET /favicon.ico HTTP/1.1" 404 9350 +INFO "GET /login HTTP/1.1" 301 0 +INFO "GET /login/ HTTP/1.1" 200 7978 +INFO "GET /a10_lab?username=Hacker&password=Hacker HTTP/1.1" 301 0 +INFO "GET /logout HTTP/1.1" 301 0 +INFO "GET /logout/ HTTP/1.1" 200 1207 +INFO "GET /static/admin/css/base.css HTTP/1.1" 304 0 +INFO "GET /static/admin/css/responsive.css HTTP/1.1" 304 0 +INFO "GET /static/admin/css/fonts.css HTTP/1.1" 200 423 +INFO "GET /static/admin/fonts/Roboto-Regular-webfont.woff HTTP/1.1" 200 85876 +INFO "GET /static/admin/fonts/Roboto-Light-webfont.woff HTTP/1.1" 200 85692 +INFO "GET /admin/ HTTP/1.1" 302 0 +INFO "GET /admin/login/?next=/admin/ HTTP/1.1" 200 1913 +INFO "GET /static/admin/css/login.css HTTP/1.1" 200 1233 +INFO "GET /logout/ HTTP/1.1" 200 1207 +INFO "GET /login/ HTTP/1.1" 200 7978 +INFO A:\wsl\Pygoat\pygoat\pygoat\pygoat\urls.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +ERROR Internal Server Error: /register +Traceback (most recent call last): + File "A:\wsl\Pygoat\venv\lib\site-packages\django\core\handlers\exception.py", line 34, in inner + response = get_response(request) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\core\handlers\base.py", line 124, in _get_response + raise ValueError( +ValueError: The view introduction.views.register didn't return an HttpResponse object. It returned None instead. +ERROR "GET /register HTTP/1.1" 500 63038 +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO "GET /register HTTP/1.1" 200 18 +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO "GET /register HTTP/1.1" 200 9207 +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO "GET /register HTTP/1.1" 200 9341 +INFO "POST /register HTTP/1.1" 302 0 +INFO "GET /login/ HTTP/1.1" 200 7978 +INFO "GET / HTTP/1.1" 200 8157 +INFO "GET /admin HTTP/1.1" 301 0 +INFO "GET /admin/ HTTP/1.1" 302 0 +INFO A:\wsl\Pygoat\pygoat\pygoat\pygoat\settings.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO A:\wsl\Pygoat\pygoat\pygoat\pygoat\settings.py changed, reloading. +INFO Watching for file changes with StatReloader +ERROR Internal Server Error: /register +Traceback (most recent call last): + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\backends\django.py", line 61, in render + return self.template.render(context) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\base.py", line 171, in render + return self._render(context) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\base.py", line 163, in _render + return self.nodelist.render(context) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\base.py", line 936, in render + bit = node.render_annotated(context) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\base.py", line 903, in render_annotated + return self.render(context) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\loader_tags.py", line 150, in render + return compiled_parent._render(context) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\base.py", line 163, in _render + return self.nodelist.render(context) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\base.py", line 936, in render + bit = node.render_annotated(context) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\base.py", line 903, in render_annotated + return self.render(context) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\loader_tags.py", line 62, in render + result = block.nodelist.render(context) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\base.py", line 936, in render + bit = node.render_annotated(context) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\base.py", line 903, in render_annotated + return self.render(context) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\base.py", line 986, in render + output = self.filter_expression.resolve(context) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\base.py", line 697, in resolve + new_obj = func(obj, *arg_vals) + File "A:\wsl\Pygoat\venv\lib\site-packages\crispy_forms\templatetags\crispy_forms_filters.py", line 61, in as_crispy_form + template = uni_form_template(template_pack) + File "A:\wsl\Pygoat\venv\lib\site-packages\crispy_forms\templatetags\crispy_forms_filters.py", line 22, in uni_form_template + return get_template("%s/uni_form.html" % template_pack) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\loader.py", line 19, in get_template + raise TemplateDoesNotExist(template_name, chain=chain) +django.template.exceptions.TemplateDoesNotExist: boostrap4/uni_form.html + +The above exception was the direct cause of the following exception: + +Traceback (most recent call last): + File "A:\wsl\Pygoat\venv\lib\site-packages\django\core\handlers\exception.py", line 34, in inner + response = get_response(request) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response + response = self.process_exception_by_middleware(e, request) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response + response = wrapped_callback(request, *callback_args, **callback_kwargs) + File "A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py", line 32, in register + return render(request,"registration/register.html",{"form":form}) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\shortcuts.py", line 19, in render + content = loader.render_to_string(template_name, context, request, using=using) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\loader.py", line 62, in render_to_string + return template.render(context, request) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\backends\django.py", line 63, in render + reraise(exc, self.backend) + File "A:\wsl\Pygoat\venv\lib\site-packages\django\template\backends\django.py", line 84, in reraise + raise new from exc +django.template.exceptions.TemplateDoesNotExist: boostrap4/uni_form.html +ERROR "GET /register HTTP/1.1" 500 176529 +INFO A:\wsl\Pygoat\pygoat\pygoat\pygoat\settings.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO "GET /register HTTP/1.1" 200 9946 +INFO "GET /register HTTP/1.1" 200 9928 +INFO "GET /register HTTP/1.1" 200 9928 +INFO "GET /login HTTP/1.1" 301 0 +INFO "GET /login/ HTTP/1.1" 200 8931 +INFO "POST /login/ HTTP/1.1" 302 0 +WARNING Not Found: /accounts/profile/ +WARNING "GET /accounts/profile/ HTTP/1.1" 404 9497 +INFO "GET /login/ HTTP/1.1" 200 8931 +INFO "POST /login/ HTTP/1.1" 200 9120 +INFO "GET /login/ HTTP/1.1" 200 8993 +INFO "GET /login/ HTTP/1.1" 200 9004 +INFO "GET /register HTTP/1.1" 200 9928 +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO "GET /register HTTP/1.1" 200 9928 +INFO "GET / HTTP/1.1" 200 8157 +INFO "GET /logout HTTP/1.1" 301 0 +INFO "GET /logout/ HTTP/1.1" 200 1207 +INFO "GET /admin/ HTTP/1.1" 302 0 +INFO "GET /admin/login/?next=/admin/ HTTP/1.1" 200 1913 +INFO "GET /logout/ HTTP/1.1" 200 1207 +INFO "GET / HTTP/1.1" 200 8303 +INFO "GET / HTTP/1.1" 200 8303 +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO "GET / HTTP/1.1" 302 0 +INFO "GET /login/ HTTP/1.1" 200 9004 +INFO "GET /register HTTP/1.1" 200 9928 +INFO "GET / HTTP/1.1" 302 0 +INFO "GET /login/ HTTP/1.1" 200 9004 +INFO "POST /login/ HTTP/1.1" 302 0 +WARNING Not Found: /accounts/profile/ +WARNING "GET /accounts/profile/ HTTP/1.1" 404 9497 +INFO A:\wsl\Pygoat\pygoat\pygoat\pygoat\settings.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO "GET /login/ HTTP/1.1" 200 9004 +INFO "POST /login/ HTTP/1.1" 302 0 +WARNING Not Found: /home +WARNING "GET /home HTTP/1.1" 404 9458 +INFO "GET /login/ HTTP/1.1" 200 9004 +INFO "GET / HTTP/1.1" 200 8157 +INFO "GET / HTTP/1.1" 200 8157 +INFO "GET / HTTP/1.1" 200 8157 +INFO A:\wsl\Pygoat\pygoat\pygoat\pygoat\settings.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO "GET /login/ HTTP/1.1" 200 9004 +INFO "GET /logout/ HTTP/1.1" 200 1207 +INFO "GET /admin/ HTTP/1.1" 302 0 +INFO "GET /admin/login/?next=/admin/ HTTP/1.1" 200 1913 +INFO "GET /logout/ HTTP/1.1" 200 1207 +INFO "GET /admin/ HTTP/1.1" 302 0 +INFO "GET /admin/login/?next=/admin/ HTTP/1.1" 200 1913 +INFO "GET /logout/ HTTP/1.1" 200 1207 +INFO "GET / HTTP/1.1" 302 0 +INFO "GET /login/ HTTP/1.1" 200 9004 +INFO "POST /login/ HTTP/1.1" 302 0 +INFO "GET / HTTP/1.1" 200 8157 +INFO "GET / HTTP/1.1" 200 8170 +INFO "GET /register HTTP/1.1" 200 9941 +INFO "GET /login/ HTTP/1.1" 200 9017 +INFO "GET / HTTP/1.1" 200 8170 +INFO "GET / HTTP/1.1" 200 8170 +INFO "GET / HTTP/1.1" 200 8170 +INFO "GET /login/ HTTP/1.1" 200 9017 +INFO "GET /register HTTP/1.1" 200 9941 +INFO "POST /register HTTP/1.1" 302 0 +INFO "GET /login/ HTTP/1.1" 200 9017 +INFO "POST /login/ HTTP/1.1" 302 0 +INFO "GET / HTTP/1.1" 200 8170 +INFO "GET / HTTP/1.1" 200 8170 +INFO "GET /admin/ HTTP/1.1" 302 0 +INFO "GET /admin/login/?next=/admin/ HTTP/1.1" 200 2069 +INFO "POST /admin/login/?next=/admin/ HTTP/1.1" 302 0 +INFO "GET /admin/ HTTP/1.1" 200 8514 +INFO "GET /admin/auth/user/ HTTP/1.1" 200 7858 +INFO "GET /admin/jsi18n/ HTTP/1.1" 200 3223 +INFO "GET /admin/jsi18n/ HTTP/1.1" 200 3223 +INFO "POST /admin/auth/user/ HTTP/1.1" 200 3468 +INFO "GET /static/admin/js/cancel.js HTTP/1.1" 200 409 +INFO "GET /static/admin/js/cancel.js HTTP/1.1" 200 409 +INFO "POST /admin/auth/user/ HTTP/1.1" 302 0 +INFO "GET /admin/auth/user/ HTTP/1.1" 200 7147 +INFO "GET /admin/jsi18n/ HTTP/1.1" 200 3223 +INFO "GET /admin/jsi18n/ HTTP/1.1" 200 3223 +INFO "GET /admin/auth/user/1/change/ HTTP/1.1" 200 15887 +INFO "GET /admin/jsi18n/ HTTP/1.1" 200 3223 +INFO "GET /admin/jsi18n/ HTTP/1.1" 200 3223 +INFO Watching for file changes with StatReloader +INFO "GET / HTTP/1.1" 200 8170 +WARNING Not Found: /favicon.ico +WARNING "GET /favicon.ico HTTP/1.1" 404 9479 +INFO "GET /login/ HTTP/1.1" 200 9017 +INFO "GET /login/ HTTP/1.1" 200 9017 +INFO "GET /logout/ HTTP/1.1" 200 1207 +INFO "GET /login/ HTTP/1.1" 200 9017 +INFO "GET / HTTP/1.1" 302 0 +INFO "GET /login/ HTTP/1.1" 200 9017 +INFO "GET /bau HTTP/1.1" 200 13044 +INFO "GET /bau_lab HTTP/1.1" 302 0 +INFO "GET /login/ HTTP/1.1" 200 9017 +INFO "GET /register HTTP/1.1" 200 9941 +INFO "GET /sec_mis HTTP/1.1" 200 10652 +INFO "GET /sec_mis_lab HTTP/1.1" 302 0 +INFO "GET /login/ HTTP/1.1" 200 9017 +INFO "GET /a10 HTTP/1.1" 200 8674 +INFO "GET /a10_lab HTTP/1.1" 302 0 +INFO "GET /login/ HTTP/1.1" 200 9017 +INFO "GET /login/ HTTP/1.1" 200 9072 +INFO "GET / HTTP/1.1" 302 0 +INFO "GET /login/ HTTP/1.1" 200 9072 +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO "GET /login/ HTTP/1.1" 200 9072 +INFO "GET / HTTP/1.1" 200 8170 +INFO "GET /cmd HTTP/1.1" 200 11401 +INFO "GET /cmd_lab HTTP/1.1" 302 0 +INFO "GET /login/ HTTP/1.1" 200 9072 +INFO "GET /register HTTP/1.1" 200 9941 +INFO "GET /sql HTTP/1.1" 200 11784 +INFO "GET /sql HTTP/1.1" 200 11876 +INFO "GET /sql HTTP/1.1" 200 11876 +INFO "GET /data_exp HTTP/1.1" 200 9800 +INFO "GET / HTTP/1.1" 200 8262 +INFO Watching for file changes with StatReloader +INFO "GET / HTTP/1.1" 200 8262 +INFO "GET /register HTTP/1.1" 200 10033 +INFO "GET /login/ HTTP/1.1" 200 9164 +INFO "GET /xxe HTTP/1.1" 200 13098 +INFO "GET /xxe_lab HTTP/1.1" 302 0 +INFO "GET /login/ HTTP/1.1" 200 9164 +INFO "GET /login/ HTTP/1.1" 200 9157 +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO "GET / HTTP/1.1" 200 8255 +INFO A:\wsl\Pygoat\pygoat\pygoat\introduction\views.py changed, reloading. +INFO Watching for file changes with StatReloader +INFO "GET / HTTP/1.1" 200 8255 +INFO "GET /sql HTTP/1.1" 200 11869 +INFO "GET /sql_lab HTTP/1.1" 302 0 +INFO "GET /login/ HTTP/1.1" 200 9157 +INFO "GET /register HTTP/1.1" 200 10026 +INFO "GET /login/ HTTP/1.1" 200 9157 +INFO "GET /register HTTP/1.1" 200 10026 +INFO "GET /login/ HTTP/1.1" 200 9157 +INFO "GET /register HTTP/1.1" 200 10026 +INFO "GET /login/ HTTP/1.1" 200 9157 +INFO "GET /register HTTP/1.1" 200 10026 +INFO "GET /sql HTTP/1.1" 200 11869 +INFO "GET /sql_lab HTTP/1.1" 302 0 +INFO "GET /login/ HTTP/1.1" 200 9157 +INFO "POST /login/ HTTP/1.1" 200 9350 +INFO "GET /register HTTP/1.1" 200 10026 +INFO "POST /register HTTP/1.1" 302 0 +INFO "GET /login/ HTTP/1.1" 200 9157 +INFO "POST /login/ HTTP/1.1" 302 0 +INFO "GET / HTTP/1.1" 200 8081 +INFO "GET /sql HTTP/1.1" 200 11695 +INFO "GET /bau HTTP/1.1" 200 12955 +INFO "GET /data_exp HTTP/1.1" 200 9619 +INFO "GET /xxe HTTP/1.1" 200 12917 +INFO "GET /ba HTTP/1.1" 200 10505 +INFO "GET /sec_mis HTTP/1.1" 200 10563 +INFO "GET /sql HTTP/1.1" 200 11695 +INFO "GET /bau HTTP/1.1" 200 12955 +INFO "GET /data_exp HTTP/1.1" 200 9619 +INFO "GET /sql HTTP/1.1" 200 11695 +INFO "GET /logout/ HTTP/1.1" 200 1207 +INFO "GET /sql HTTP/1.1" 200 11869 +INFO "GET /login/ HTTP/1.1" 200 9157 +INFO "POST /login/ HTTP/1.1" 302 0 +INFO "GET / HTTP/1.1" 200 8081 diff --git a/introduction/templates/Lab/A11/a11.html b/introduction/templates/Lab/A11/a11.html new file mode 100644 index 0000000..075e9cd --- /dev/null +++ b/introduction/templates/Lab/A11/a11.html @@ -0,0 +1,57 @@ +{% extends 'introduction/base.html' %} {% block content %} {% block title %} +Insecure Design +{% endblock %} +
+

Insecure Design

+
+

What is Insecure Design

+

+ Insecure design is a broad category representing different weaknesses, + expressed as โ€œmissing or ineffective control design.โ€ Insecure design is + not the source for all other Top 10 risk categories. There is a difference + between insecure design and insecure implementation. We differentiate + between design flaws and implementation defects for a reason, they have + different root causes and remediation. A secure design can still have + implementation defects leading to vulnerabilities that may be exploited. + An insecure design cannot be fixed by a perfect implementation as by + definition, needed security controls were never created to defend against + specific attacks. One of the factors that contribute to insecure design is + the lack of business risk profiling inherent in the software or system + being developed, and thus the failure to determine what level of security + design is required. +

+ +
+

+ This lab helps you to get an idea of how Insecure Design can result in major Security flaw. + + In the next page,user can get 5 free tickets for a Movie. But he/she have to wait untill all the tickets are sold out. + For this particular situation, we can get advantage of the Insecure Design and somehow get all the tickets for the movie. + +

    Hint
+
    Logout and then think.
+ +
+
+
+
+
+

Mitigation

+

+

    +
  • Establish and use a secure development lifecycle with AppSec professionals to help evaluate and design security and privacy-related controls
  • +
  • Establish and use a library of secure design patterns or paved road ready to use components
  • +
  • Use threat modeling for critical authentication, access control, business logic, and key flows
  • +
  • Integrate security language and controls into user stories
  • +
  • Integrate plausibility checks at each tier of your application (from frontend to backend)
  • +
  • Write unit and integration tests to validate that all critical flows are resistant to the threat model. Compile use-cases and misuse-cases for each tier of your application.s
  • +
  • Segregate tier layers on the system and network layers depending on the exposure and protection needs
  • +
  • Segregate tenants robustly by design throughout all tiers
  • +
  • Limit resource consumption by user or service
  • +
+

+
+
+ +{% endblock %} diff --git a/introduction/templates/Lab/A11/a11_lab.html b/introduction/templates/Lab/A11/a11_lab.html new file mode 100644 index 0000000..7e7543f --- /dev/null +++ b/introduction/templates/Lab/A11/a11_lab.html @@ -0,0 +1,53 @@ +{% extends "introduction/base.html" %} +{% load static %} +{% block content %} +{% block title %} +Insecure Design Lab +{% endblock %} +{% block header %} + +{% endblock %} +
+
+
+

My Tickets

+ +
+
+
+
+ {{error}} +
+
+
+

Claim Upto 5 Free Tickits

+ +
+
+
+

Watch Movie

+ +
+
+
+ +
+ +{% endblock %} diff --git a/introduction/templates/Lab/A9/a9.html b/introduction/templates/Lab/A9/a9.html new file mode 100644 index 0000000..840fedc --- /dev/null +++ b/introduction/templates/Lab/A9/a9.html @@ -0,0 +1,94 @@ +{% extends 'introduction/base.html' %} +{% block content %} +{% block title %} +Using Components with Known Vulnerabilities +{% endblock %} +
+

Using Components with Known Vulnerabilities

+
+ +

What does Using Components with Know Vulnerability means?

+

When a developer uses a piece of code or library which already has a known vulnerability, then + this may result in compromise of the entire application. This occurs when the components such as libraries + and frameworks used within the app mostly execute with full privileges. If a vulnerable component is + exploited, it makes the hackerโ€™s job easier to cause a serious data loss or server takeover. + +

+

+ +
+

+ This lab helps us to understand why components with known vulnerabilities can be a serious issue. +
+ The user on accessing the lab is provided with a feature to convert yaml files into json objects. + A yaml file needs to be chosen and uploaded to get the json data. + There is also a get version feature which tells the user the version of the library the app uses. + + Exploiting the vulnerability. +

    +
  • The app uses pyyaml 5.1 Which is vulnerable to code execution.
  • +
  • You can google the library with the version to get the poc and vulnerability details
  • +
  • Libraries known for the infamous code injection vulnerabilities are PyYAML 5.4 and Log4J
  • +
  • Create An yaml file with this payload:
  • + !!python/object/apply:subprocess.Popen
    + - ls +
    +
  • On Uploading this file the user should be able to see the output of the command executed in the + Terminal running Django.
  • + +
+ +

+

+ +
+
+ +

+
+ +
+

+ This lab helps us to understand why components with known vulnerabilities can be a serious issue. +
+ This is website for some image manupulation. + + Exploiting the vulnerability. +

    +
  • The app uses Pillow 8.0.0 Which is vulnerable to code execution.
  • +
  • You can google the library with the version to get the poc and vulnerability details
  • +
+ +

+
+
+ +

+
+
+

Mitigation

+

+

    +
  • Remove unused dependencies, unnecessary features, components, files, and documentation.
  • +
  • Only obtain components from official sources over secure links. Prefer signed packages to reduce the + chance of including a modified, malicious component.
  • +
  • Monitor for libraries and components that are unmaintained or do not create security patches for older + versions. If patching is not possible, consider deploying a virtual patch to monitor, detect, or protect + against the discovered issue.
  • +
  • Use Library scanners to test for Vulnerabilities in packages.
  • + + + +
+

+ + + +
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/A9/a9_lab.html b/introduction/templates/Lab/A9/a9_lab.html new file mode 100644 index 0000000..5a70b46 --- /dev/null +++ b/introduction/templates/Lab/A9/a9_lab.html @@ -0,0 +1,37 @@ +{% extends "introduction/base.html" %} +{% load static %} +{% block content %} +{% block title %} +A9 +{% endblock %} + +
+

Yaml To Json Converter

+
+
+
+ +
+

+
+
+ {% if data %} +
Here is your output:

+
{{data}}

+ Check Django Terminal for Command's output + {% endif %} +
+
+
+ {{version}} + +
+ +
+
+ +

+ +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/A9/a9_lab2.html b/introduction/templates/Lab/A9/a9_lab2.html new file mode 100644 index 0000000..cace076 --- /dev/null +++ b/introduction/templates/Lab/A9/a9_lab2.html @@ -0,0 +1,96 @@ +{% extends "introduction/base.html" %} +{% load static %} +{% block content %} +{% block title %} +A9 +{% endblock %} + +
+

In this page you can upload a image and apply different math equation on it's rgb layer



+

Varriable reffernence

+ img --> actual image file | r --> red chennel | g --> green chennel + b --> blue chennel | g --> green chennel

+ +

Some Example

+
    +
  • convert(r, '1')
  • +
  • convert(r+g+b, 'L')
  • +
  • convert(r-g, '1')
  • +
+ +
+ + + +


+ + {% if success %} +
+ + +
+ {% endif %} + +
+ + +
+ This lab uses pillow==8.0.0 package, google for vulnerability +
+ + + +
+ + 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")
+  elif request.method == "POST":
+   try :
+    file=request.FILES["file"]
+    function_str = request.POST.get("function")
+    img = Image.open(file)
+    img = img.convert("RGB")
+    r,g,b = img.split()
+    output = ImageMath.eval(function_str,img = img, b=b, r=r, g=g)
+ +    # saving the image
+    buffered = BytesIO()
+    output.save(buffered, format="JPEG")
+    img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
+ +    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})
+    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})
+
+ +
+
+ +
+ + + +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/AUTH/auth_home.html b/introduction/templates/Lab/AUTH/auth_home.html new file mode 100644 index 0000000..28422e3 --- /dev/null +++ b/introduction/templates/Lab/AUTH/auth_home.html @@ -0,0 +1,54 @@ +{% extends 'introduction/base.html' %} +{% block content %} +{% block title %} +Broken Authentication +{% endblock %} +
+

Description

+
+ +

What is Broken Authentication

+

+ Broken authentication is an umbrella term for several vulnerabilities that attackers exploit to impersonate + legitimate users online. Broadly, broken authentication refers to weaknesses in two areas: session management + and credential management. Both are classified as broken authentication because attackers can use either + avenue to masquerade as a user: hijacked session IDs or stolen login credentials. +
+

Broken Authentication errors occur when:

+
    +
  • Permits automated attacks such as credential stuffing, where the attacker has a list of valid usernames + and passwords.
  • +
  • Permits brute force or other automated attacks.
  • +
  • Permits default, weak, or well-known passwords, such as โ€œPassword1โ€ or โ€œadmin/adminโ€œ.
  • +
  • Uses weak or ineffective credential recovery and forgot-password processes, such as โ€œknowledge-based + answersโ€, which cannot be made safe.
  • +
  • Uses plain text, encrypted, or weakly hashed passwords.
  • +
  • Has missing or ineffective multi-factor authentication.
  • +
  • Exposes Session IDs in the URL (e.g., URL rewriting).
  • +
  • Does not rotate Session IDs after successful login.
  • +
  • Does not properly invalidate Session IDs. User sessions or authentication tokens (particularly single + sign-on (SSO) tokens) arenโ€™t properly invalidated during logout or a period of inactivity.
  • +
+
+

The main consequences are: +
    +
  • Unauthorized users can acess the system.
  • +
  • User information is leaked
  • +
+ +
+
+

+

+

Mitigation

+

Try thinking about cookies and how they can expose secrets !!!!

+ + + +

+
+ + + +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/AUTH/auth_lab.html b/introduction/templates/Lab/AUTH/auth_lab.html new file mode 100644 index 0000000..7bde3b8 --- /dev/null +++ b/introduction/templates/Lab/AUTH/auth_lab.html @@ -0,0 +1,20 @@ +{% extends "introduction/base.html" %} +{% block content %} +{% block title %} +BROKEN AUTH LAB +{% endblock %} + +
+

Can You Log in as other user?

+ +
+
+ +
{{ err_msg }}
+
+{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/AUTH/auth_lab_login.html b/introduction/templates/Lab/AUTH/auth_lab_login.html new file mode 100644 index 0000000..6b57460 --- /dev/null +++ b/introduction/templates/Lab/AUTH/auth_lab_login.html @@ -0,0 +1,23 @@ +{% extends "introduction/base.html" %} +{% block content %} +{% block title %} +BROKEN AUTH LAB +{% endblock %} + +
+ +
+
+ +
+
+ +{{ err_msg }} +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/AUTH/auth_lab_signup.html b/introduction/templates/Lab/AUTH/auth_lab_signup.html new file mode 100644 index 0000000..b9de6c9 --- /dev/null +++ b/introduction/templates/Lab/AUTH/auth_lab_signup.html @@ -0,0 +1,25 @@ +{% extends "introduction/base.html" %} +{% block content %} +{% block title %} +BROKEN AUTH LAB +{% endblock %} + +
+ +
+
+ +
+
+ +{{ err_msg }} + +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/AUTH/auth_success.html b/introduction/templates/Lab/AUTH/auth_success.html new file mode 100644 index 0000000..2f19e7f --- /dev/null +++ b/introduction/templates/Lab/AUTH/auth_success.html @@ -0,0 +1,24 @@ +{% extends "introduction/base.html" %} +{% block content %} +{% block title %} +BROKEN AUTH LAB +{% endblock %} + +
+

Your Information

+ +
+
+ +
+
+ +
{{err_msg}}
+
+{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/BrokenAccess/ba.html b/introduction/templates/Lab/BrokenAccess/ba.html new file mode 100644 index 0000000..5f0dc37 --- /dev/null +++ b/introduction/templates/Lab/BrokenAccess/ba.html @@ -0,0 +1,66 @@ +{% extends 'introduction/base.html' %} +{% block content %} +{% block title %} +Broken Access Control +{% endblock %} +
+

Broken Access Control

+
+ +

What is Broken Access Control

+

Access control, sometimes called authorization, is how a web application grants access to content + and functions to some users and not others. These checks are performed after authentication, and govern what + โ€˜authorizedโ€™ users are allowed to do. A web applicationโ€™s access control model is closely tied to the + content and functions that the site provides. In addition, the users may fall into a number of groups or + roles with different abilities or privileges. + +

+ +
+

+

+ This lab helps us to understand one of the authentication flaws which leads to an attacker gaining + unauthorized control of an account. + On accessing the lab the user is provided with a simple login in page which requires a username and + password. +
The credentials for the user Jack is jack:jacktheripper. +
Use the above info to log in.
+ The main aim of this lab is to login with admin privileges to get the secret key. + +

Exploiting the Broken Access +

    +
  • Every time a valid user logs in,the user session is set with a cookie called admin +
  • +
  • When you notice the cookie value when logged in as jack it is set to 0
  • +
  • Use BurpSuite to intercept the request change the value of the admin cookie from 0 to 1
  • +
  • This should log you in as a admin user and display the secret key
  • + +
+

+

+ +
+
+ +

+
+

Mitigation

+

+

    +
  • Using proper Session management techniques
  • +
  • Using Tokens such as JWT to authorize the users.
  • +
  • Unless a resource is intended to be publicly accessible, deny access by default
  • +
  • Thoroughly audit and test access controls to ensure they are working as designed
  • + +
+

+ + + +
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/BrokenAccess/ba_lab.html b/introduction/templates/Lab/BrokenAccess/ba_lab.html new file mode 100644 index 0000000..d45da9b --- /dev/null +++ b/introduction/templates/Lab/BrokenAccess/ba_lab.html @@ -0,0 +1,46 @@ +{% extends "introduction/base.html" %} +{% load static %} +{% block content %} +{% block title %} +Broken Access Control. +{% endblock %} + +
+

Admins Have the Secretkey

+ +
+
+ {% if username %} +

Logged in as user: {{username}}

+ {% endif %} + + {% if data %} +

Your Secret Key is {{data}}

+ {% endif %} + + {% if not_admin %} +

{{not_admin}}

+ {% endif %} + + {% if no_creds %} +

Please Provide Credentials

+ {% endif %} + +
+ +
+
+ +

+ +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/BrokenAuth/bau.html b/introduction/templates/Lab/BrokenAuth/bau.html new file mode 100644 index 0000000..9d5af43 --- /dev/null +++ b/introduction/templates/Lab/BrokenAuth/bau.html @@ -0,0 +1,104 @@ +{% extends 'introduction/base.html' %} +{% block content %} +{% block title %} +Command Injection +{% endblock %} +
+

Broken Authentication

+
+ +

What is Broken Authentication

+

Broken authentication is an umbrella term for several vulnerabilities that attackers exploit to + impersonate legitimate users online. Broadly, broken authentication refers to weaknesses in two areas: + session management and credential management. Both are classified as broken authentication because attackers + can use either avenue to masquerade as a user: hijacked session IDs or stolen login credentials. + + Attackers employ a wide variety of strategies to take advantage of these weaknesses, ranging from huge + credential stuffing attacks to highly targeted schemes aimed at gaining access to a specific personโ€™s + credentials. +

+ +
+

+ + +

+ The lab consists of a login page, which request users for their username and password. + If you don't know the password ,there is also a feature for login with otp! + When the users clicks the login with otp feature, user is directed to a page, which asks + users email id to send the otp. + When the user provides an email id , you can see that the 3 digit opt is sent back to the page itself. + This is not the general scenario , usually the code is sent to the registered email of the user. +
The user on receiving the 3 digit code can now enter the code in the input box that says + Enter your OTP + On entering the valid OTP the user gets a page which says Login Successful as user : email + . + If the Otp is wrong then the user gets a message saying Invalid OTP +

+ + + The Bug + +

+ The main aim of this lab is to login as admin, for that you are gonna exploit the lack of rate + limiting feature in the otp verification flow. + You can see that the otp is only of 3 digit(for demo purposes) and the application doesnt have any + captcha (To disallow any automated scripts or bots) or any restrictionds on the number of + tries for the otp. +

+ +

Now to send the otp to the admin's mail you need to figure out the admins mail id. + Luckily the admin has left his email id for the developers in the page source. + Admins email id admin@pygoat.com + After entering this email in the send otp input box and hit send, you can see that the page says that + otp has been sent to the email id of the admin. + In order to exploit the lack of rate limiting , we can try to Brute-force the 3 digit otp. +

+ +

+ Steps to Brute force: +

    +
  • Open Burpsuite and configure your browser to intercept the web trafic, but dont turn intercept on. +
  • +
  • Send the otp to the admins mail id with the help of send otp feature.
  • +
  • In the enter the otp box enter a random 3 digit number.
  • +
  • Before your press login , turn intercept on on Burp suite and then press log in
  • +
  • Now you can see that the traffic is captured in Burpsuite.
  • +
  • Now use the send to intruder feature and send this request to the intruder.
  • +
  • Set the position of the payload to the otp= parameter.
  • +
  • Go to the payloads session and choose the payload type to number list
  • +
  • Fill the range to 100 to 999 with step 1.
  • +
  • Now click attack and you can see that the burp suite tries different combinations of otp and + collects it response.
  • +
  • You can figure out if it has guessed the correct opt by seeing the difference in length of the + response for each request.
  • +
  • The correct otp will have a small response length .
  • +
+

+ +

Using this otp you will be able to login into admins account.

+

+ +
+
+ +

+

+
+

Mitigation

+

+ This type of authentication flaw can be mitigated by: +

    +
  • Using captcha
  • +
  • Rate Limiting by reducing the number of tries for a particular user, based on session or ip
  • +
  • Blocking multiple request form the same IP
  • +
+

+ +
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/BrokenAuth/bau_lab.html b/introduction/templates/Lab/BrokenAuth/bau_lab.html new file mode 100644 index 0000000..c92736b --- /dev/null +++ b/introduction/templates/Lab/BrokenAuth/bau_lab.html @@ -0,0 +1,36 @@ +{% extends "introduction/base.html" %} +{% block content %} +{% block title %} +Broken Authentication Lab +{% endblock %} + +
+

Login as Admin

+ +
+ +
+ {% if wrongpass %} +

Wrong Password Try Using Login With OTP

+ {% endif %} + + +
+ +
+
+ +

+ +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/BrokenAuth/otp.html b/introduction/templates/Lab/BrokenAuth/otp.html new file mode 100644 index 0000000..3d12cda --- /dev/null +++ b/introduction/templates/Lab/BrokenAuth/otp.html @@ -0,0 +1,37 @@ +{% extends "introduction/base.html" %} +{% block content %} +{% block title %} +Broken Authentication Lab +{% endblock %} +
+
+
Login Through Otp

+
+ + + +
+ +
+
+
+
+ +

+ +
+

+
+ {% if otp %} +

Your 3 Digit Verification Code:{{otp}}

+ {% endif %} + + {% if email %} +

Login Successful as user : {{email}}

+ {% endif %} + + + +
+ +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/CMD/cmd.html b/introduction/templates/Lab/CMD/cmd.html new file mode 100644 index 0000000..bfea591 --- /dev/null +++ b/introduction/templates/Lab/CMD/cmd.html @@ -0,0 +1,134 @@ +{% extends 'introduction/base.html' %} +{% block content %} +{% block title %} +Command Injection +{% endblock %} +
+

Command Injection

+
+ +

What is Command Injection

+

Command injection is an attack where the goal is execution of arbitrary commands on the host + operating system via a vulnerable application. Command injection attacks are possible when an application + passes unsafe user supplied data (forms, cookies, HTTP headers etc.) to a system shell. In this attack, the + attacker-supplied operating system commands are usually executed with the privileges of the vulnerable + application. Command injection attacks are possible largely due to insufficient input validation. +

+ +
+

+ This lab helps us to understand how command injection is exploitable in scenarios where inputs are sent + to exec,eval,sys etc. + +
+ + The user on accessing the lab is provided with a feature to perform a name server lookup on the given + domain. + A domain name has to be provided after which the server would perform a ns lookup and return back to the + client. + If the user is running the lab, based on the OS they can select Windows or Linux. + +
+ +
Exploiting the Bug +

    +
  1. Method 1
  2. +
      +
    • The user can cause the server to execute commands ,because of the lack of input validation.
    • +
    • The user can give a domain say domain && [any cmd]
    • +
    • In This case lets give google.com && dir and choose windows.
    • +
    • This should give you the output for both ns lookup as well as for the dir
    • +
    +
  3. Method 2
  4. +
      +
    • The user can give a domain say domain; [any cmd]
    • +
    • In This case lets give google.com; dir and choose windows.
    • +
    • This should give you the output for both ns lookup as well as for the dir
    • +
    +
+
+ Understanding the cause
+

+ Lets first see how the name server lookup is performed +
+ command="nslookup {}".format(domain) +
+ Here the domain is the user input domain. This command variable is then sent to exec function and the + output is displayed. + If the user inputs google.com the command variable will hold nslookup google.com. + +

+ How CMD injection works + Method 1 + Now when the user enters google.com && dir The command variable will hold + nslookup google.com && dir. + The && means and.
The system will execute nslookup google.com + first and then dir
+ + Method 2 + When the user enters google.com ; dir The command variable will hold + nslookup google.com ; dir. + The ; implies the completion of the command before it, in this case the nslookup + command.
The system will execute nslookup google.com first and then dir
+ +

+ +

+ +
+
+ +

+
+ + +
+

+ This is another lab to understand code execution. There are some functions in python such as eval(), exec() which can be used to achieve code execution. +

+ In this lab, we will be learning about the eval() function in python3. The eval() function evaluates the specified expression, if the expression is a legal Python statement, it will be executed. + +
+ +
Challenge Description:
+ In this challenge, we are given an input box, where we can calculate any arithmetic expression such as 1 + 1 or 5 * 5 etc. + Your task is to exploit this input form and achieve command execution on the system. +

+ Challenge Solution:
+ We know that this application is using the eval() function in the backend to calculate the output. Instead of submitting arithmetic expressions, we can also submit python3 commands, which will be executed by the eval() function. +

+ First, if we submit the expression 1 + 1, we get the output as 2. Similarly, on submitting the expression 7 * 7, we get the output as 49. +

+ Now, if we submit os.system("id"), we get nothing in the output. But if we check the terminal, we will see that the command gets executed and the result is printed on the terminal screen. You can also verify this by submitting os.system("sleep 30"), and you will notice that the request completes after 30 seconds. +

+

+ +
+
+ +

+
+ +
+

Mitigation

+

+

    +
  • Input validation
  • +
  • Parameterization of user input
  • +
  • Do not call os commands directly.
  • +
  • Validating against a whitelist of permitted values.
  • + + +
+

+ + + +
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/CMD/cmd_lab.html b/introduction/templates/Lab/CMD/cmd_lab.html new file mode 100644 index 0000000..2998cd3 --- /dev/null +++ b/introduction/templates/Lab/CMD/cmd_lab.html @@ -0,0 +1,36 @@ +{% extends "introduction/base.html" %} +{% block content %} +{% block title %} +Command Injection +{% endblock %} +
+
+

Name Server Lookup

+
+

+ + + +
+ +
+
+
+
+ {% if output %} +
Output

+ +
{{output}}
+
+ {% endif %} +
+ + +
+
+ +

+ + +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/CMD/cmd_lab2.html b/introduction/templates/Lab/CMD/cmd_lab2.html new file mode 100644 index 0000000..a71a605 --- /dev/null +++ b/introduction/templates/Lab/CMD/cmd_lab2.html @@ -0,0 +1,32 @@ +{% extends "introduction/base.html" %} +{% block content %} +{% block title %} +Command Injection +{% endblock %} +
+
+

Evaluate any expression!

+
+

+
+
+
+
+
+ {% if output %} +
Output

+ +
{{output}}
+
+ {% endif %} +
+ + +
+
+ +

+ + +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/DataExp/data_exp.html b/introduction/templates/Lab/DataExp/data_exp.html new file mode 100644 index 0000000..8dc0ccc --- /dev/null +++ b/introduction/templates/Lab/DataExp/data_exp.html @@ -0,0 +1,49 @@ +{% extends 'introduction/base.html' %} +{% block content %} +{% block title %} +Sensitive Data Exposure +{% endblock %} +
+

Senstive Data Exposure

+
+ +

What is Sensitive Data Exposure

+

+ Information disclosure, also known as information leakage, is when a website unintentionally reveals sensitive + information to its users. Depending on the context, websites may leak all kinds of information to a potential + attacker, including: +

    +
  • Data about other users, such as usernames or financial information
  • +
  • Sensitive commercial or business data
  • +
  • Technical details about the website and its infrastructure
  • +
+

+ +
+

+ One of the features of having DEBUG=True is dumping lots of metadata from your environment, including the whole + settings.py configurations, when a exception occurs. +

+ +
+
+
+

Mitigation

+

Even though you will never be using DEBUG=True, you need extra care when naming the configurations in + the settings.py module. Make sure all sensitive variables use one of the keywords: +

    +
  • API
  • +
  • KEY
  • +
  • PASS
  • +
  • SECRET
  • +
  • SIGNATURE
  • +
  • TOKEN
  • +
+

+
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/DataExp/data_exp_lab.html b/introduction/templates/Lab/DataExp/data_exp_lab.html new file mode 100644 index 0000000..1e8e0c8 --- /dev/null +++ b/introduction/templates/Lab/DataExp/data_exp_lab.html @@ -0,0 +1,21 @@ +{% extends "introduction/base.html" %} +{% load static %} +{% block content %} +{% block title %} +Sensitive Data Exposure +{% endblock %} + +
+

Sensitive Data Exposure

+
+
+ Can you find a page to trigger 500 error? Can you find 'SENSITIVE_DATA'? +
+ +
+
+ +

+ +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/DataExp/robots.txt b/introduction/templates/Lab/DataExp/robots.txt new file mode 100644 index 0000000..507e78f --- /dev/null +++ b/introduction/templates/Lab/DataExp/robots.txt @@ -0,0 +1,3 @@ +User-Agent: * + +Disallow: /500error \ No newline at end of file diff --git a/introduction/templates/Lab/SQL/sql.html b/introduction/templates/Lab/SQL/sql.html new file mode 100644 index 0000000..e486ab3 --- /dev/null +++ b/introduction/templates/Lab/SQL/sql.html @@ -0,0 +1,100 @@ +{% extends 'introduction/base.html' %} +{% block content %} +{% block title %} +SQL Injection +{% endblock %} +
+

Sql Injection

+
+ +

What is SQL Injection

+

A SQL injection attack consists of insertion or โ€œinjectionโ€ of a SQL query via the input data + from the client to the application. A successful SQL injection exploit can read sensitive data from the + database, modify database data (Insert/Update/Delete), execute administration operations on the database + (such as shutdown the DBMS), recover the content of a given file present on the DBMS file system and in some + cases issue commands to the operating system. SQL injection attacks are a type of injection attack, in which + SQL commands are injected into data-plane input in order to affect the execution of predefined SQL commands. + +

+ +
+

+ + SQL injection errors occur when: + + Data enters a program from an untrusted source. + The data used to dynamically construct a SQL query + The main consequences are: + +

+ This lab helps you to exploit the common type of sql injection vulnerability, caused due to the lack of + input validation and directly exposing input into the query.
+ + The user on accessing the lab is given a log in page . The user has to try to login in as admin. + SQL Injection vulnerability can be identified by injecting a ' in any of the fields. If it + results in an SQL error, SQL injection vulnerability is identified +
+ + Exploiting SQL Injection Vulnerability +

    +
  • Enter the user name as admin
  • +
  • Enter the password as anything' OR '1' ='1
  • +
  • This should log you in as admin, without knowing the admins password.
  • +

+ Understanding the Exploit
+
+

+ The website logs a user in by checking the entered username and password against the ones stored in the + database. If they match, the user is logged in. + Lets first analyse the sql query used to compare the username and password in the database. +
"SELECT * FROM introduction_login WHERE user='"+name+"'AND password='"+password+"'"
+ The name and password parameters are the ones you give as input, which is directly inserted into the + query.
+ +
Why the error?

+ + When we inserted a ' in the input it threw an error , this is because the sql query was not + balanced and it threw an error. +
SELECT * FROM introduction_login WHERE user='admin' AND password='''
+ The query quotes in the password field are unbalanced, this can be balanced by adding another quote to + it. + +

Lets just plug our payload into the query and see what it looks like. +
SELECT * FROM introduction_login WHERE user='admin' AND password='anything' OR '1' ='1'
+ + Now the query means select username = admin where password is anything OR '1'='1' .
+ '1'='1' will always result in TRUE and the query fetches the user with name admin and + password=TRUE. + +
Thus allowing us to login in as admin. + +

+

+

+ +
+
+ +

+
+
+

Mitigation

+

+

    +
  • Use of Prepared Statements (with Parameterized Queries)
  • +
  • Use of Stored Procedures
  • +
  • Allow-list Input Validation
  • +
  • Escaping All User Supplied Input.
  • +
+ +

+ + + +
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/SQL/sql_lab.html b/introduction/templates/Lab/SQL/sql_lab.html new file mode 100644 index 0000000..43af47a --- /dev/null +++ b/introduction/templates/Lab/SQL/sql_lab.html @@ -0,0 +1,48 @@ +{% extends "introduction/base.html" %} +{% block content %} +{% block title %} +SQL LAB +{% endblock %} + +
+

Can You Log in as Admin

+ +
+ +
+ {% if user1 %} +

Logged in as: +
{{user1}}
+

+ + {% elif wrongpass %} +

The password you have entered doesnt match the username!

+

The SQL query being submitted is +
{{ sql_error }}
+

+ + {% elif no %} +

User Not Found

+ {% else %} + + {% endif %} + + +
+ +
+
+ +

+ +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/XSS/xss.html b/introduction/templates/Lab/XSS/xss.html new file mode 100644 index 0000000..c70f08c --- /dev/null +++ b/introduction/templates/Lab/XSS/xss.html @@ -0,0 +1,205 @@ +{% extends "introduction/base.html" %} +{% block content %} + +
+

Cross Site Scripting

+
+ +

What is Cross Site Scripting or XSS?

+

+ Cross site scripting or XSS is a form of client side code injection.
In this type of attack the attacker + tries to inject malicious script into a trusted site. The malicious script is usually a piece of javascript + code, which helps the attacker to perform malicious activities, like redirecting the victim to an attacker + site, stealing cookies etc. Some times XSS vulnerability can be chained with other vulnerabilities to create + great impact . + Talking about XSS, we have 3 different types:

+
    +
  • Reflected XSS
  • +
  • Stored XSS
  • +
  • DOM XSS
  • +
+ +

Reflected XSS

+

Reflected XSS occurs when user input is immediately returned by a web application in an error + message, search result, or any other response that includes some or all of the input provided by the user as + part of the request, without that data being made safe to render in the browser, and without permanently + storing the user provided data.

+ +

Stored XSS

+

Stored XSS generally occurs when user input is stored on the target server, such as in a database, + in a message forum, visitor log, comment field, etc. And then a victim is able to retrieve the stored data + from the web application without that data being made safe to render in the browser.Blog comments sessions + are places which can be vulnerable to stored xss , once a vulnerable xss payload is posted then every user + that visits the blog comment session would have the impact of the vulnerability.

+ +

DOM XSS

+

This type of XSS is possible when javascript takes in an user controllable code and passes it to a + sink ,for code execution . Examples of sinks are window.location , innerhtml , document.write .When the + attacker tries to inject malicious code into a sink , then this type of XSS is called the DOM Xss

+ + +
+
+ +
+

+ This lab will help you to understand the Reflective Type of XSS. + +

The lab consists of a Search page called FAANG IT.Which helps you to get some + information about Facebook, Apple ,Amazon ,Netflix, Google. The user can input one of the + companies into the search bar and see the information related to it.

+

If a user searches for something else , he can see a message saying that the search term is + not part of the Company.

+ +

What can go wrong Here? Yes, this html page reflects the search query back to the page when + the user enters something which is not part of the FAANG.

+

Exploiting the Reflection of the search query

+
    +
  • Instead of giving a search term try giving a html tag, <h4 >Hello </h4>.
  • +
  • Now you can see that the word Hello has been parsed as a Heading in the page.
  • +
  • This shows that the page is able to render the user given html tags.
  • +
  • In order to get an xss , the user needs to execute javascript code in the browser.
  • +
  • This can be acheived by using a script tag and malicious javascript code.
  • +
  • For now let's just use a basic javascript code to alert a text to prove that xss is possible .
  • + +
    <script >alert(โ€œxssโ€) </script >
    + + +
  • Now when a search query is performed with the above payload you can see that the browser is able to + render the script tag and execute the javascript , thus alerting โ€œxssโ€ with a pop up.
  • + + +
+ + + + +

+ +
+
+ +

+
+ + +
+

+ This lab a demonstration of a stored XSS vulnerability. The challenge is to change the value of flag that is being stored as a cookie on the user's browser. The user input is taken as a POST parameter in the URL and is displayed on the page. The code tries to escape the user input to prevent XSS attacks, but there might still be a way for the attacker to inject malicious code into the page. +

+

The goal of this challenge is for the attacker to find a way to execute arbitrary JavaScript code on the page and retrieve the data stored in the cookie. The attacker must be able to bypass the escaping mechanism and find a way to inject their own code into the page. +

+

But the problem is <script > tag is sanitised by the server so we have to use another method to bypass this.

+
<img src=x onerror=alert(document.cookie) >
+

Try changing the value of cookie set flag=success

+
<img src=x onerror=document.cookie="flag=success"; >
+

Now when a search query is performed with the above payload you can see that the browser is able to render the script tag and execute the javascript , thus alerting โ€œxssโ€ with a pop up

+ +
+
+
+ + +
+

+ This lab is a demonstration of a Reflected XSS +

+

The goal of this challenge is to trigger an alert, User input is being Reflected on script Tag, but the real challenge lies in the fact that all alphanumeric characters are escaped. Can you find way to pop an alert ? +

+ + +
+
+
+
+ + +

Mitigation


+

First let's analyse what part of the code has resulted in this vulnerability. + + +
#code in views.py
+ return render(request,'Lab/XSS/xss_lab.html',{'query': q})
+
#code in html template
+ <h3> The company '{query|safe}' You searched for is not Part of FAANG </h3> +

+ +

In the above code the q variable holds the users input . This input is stored in a variable called + โ€˜queryโ€™ , which is sent to a html template which renders a html along with the value of the query. +

+

The query received from the user is considered to be safe which resulted in the template rendering + the user input without escaping the input. This can be seen by using the keyword 'safe' in the html + template.

+ +
+

+

What happens without the safe keyword?


+ + +

Without the safe keyword Django would automatically escape the malicious string in the query + context variable.

+ +

It does this by passing all string data through Pythonโ€™s html.escape() function. This + function will:

+
    +
  • Replace any & with an & amp; ampersand HTML character-reference
  • +
  • Replace any < or> with an & lt; or & gt; HTML character-reference
  • +
  • Replace any " with an escaped \"
  • +
  • Replace any ' with an escaped \'
  • + + +
+ +

+

+ + +
+

Now talking about the mitigation

+ +
+
    +
  1. Encode the following characters with HTML entity encoding to prevent switching into any execution + context, such as script, style, or event handlers. Using hex entities is recommended in the spec. The 5 + characters significant in XML. + +
      +
    • & --> & amp;
    • +
    • + < --> & lt; +
    • +
    • --> & gt;
    • +
    • " --> & quot;
    • +
    • ' --> &# x27;
    • +
    +
  2. + +
  3. CSS Encode And Strictly Validate Before Inserting Untrusted Data into HTML Style Property Values
  4. +
  5. JavaScript Encode Before Inserting Untrusted Data into JavaScript Data Values
  6. + + +
  7. HTML Encode JSON values in an HTML context and read the data with JSON.parse
  8. + +
  9. URL Encode Before Inserting Untrusted Data into HTML URL Parameter Values
  10. +
  11. Implement Content Security Policy
  12. +
  13. Use HTTPOnly cookie flag
  14. + + +
+ +

+ + + + + +
+
+ + + + +{% endblock content %} \ No newline at end of file diff --git a/introduction/templates/Lab/XSS/xss_lab.html b/introduction/templates/Lab/XSS/xss_lab.html new file mode 100644 index 0000000..0309cc0 --- /dev/null +++ b/introduction/templates/Lab/XSS/xss_lab.html @@ -0,0 +1,41 @@ +{% extends "introduction/base.html" %} +{% block content %} +{% block title %} +XSS LAB +{% endblock %} + + + +
+
+

FAANG IT

+
+ + + + +
+

+
+ {% if company %} +

Company Name : {{company}}

+

Ceo Name : {{ceo}}

+

About : {{about}}

+ {% elif query %} +

The company '{{query|safe}}' You searched for is not Part of FAANG

+ {% else %} + + {% endif %} + + +
+ +
+
+ +

+ +{% endblock content %} \ No newline at end of file diff --git a/introduction/templates/Lab/XSS/xss_lab_2.html b/introduction/templates/Lab/XSS/xss_lab_2.html new file mode 100644 index 0000000..9560390 --- /dev/null +++ b/introduction/templates/Lab/XSS/xss_lab_2.html @@ -0,0 +1,52 @@ +{% extends "introduction/base.html" %} +{% block content %} +{% block title %} + +XSS LAB 2 +{% endblock %} +

Welcome to XSS Challenge

+
+ {% csrf_token %} +
+ + + +
+ +
+
+

Hello, {{ username|safe }}

+ + +
+
+ +
+{% endblock content %} diff --git a/introduction/templates/Lab/XSS/xss_lab_3.html b/introduction/templates/Lab/XSS/xss_lab_3.html new file mode 100644 index 0000000..a550b9a --- /dev/null +++ b/introduction/templates/Lab/XSS/xss_lab_3.html @@ -0,0 +1,28 @@ +{% extends "introduction/base.html" %} +{% block content %} +{% block title %} + +XSS LAB 2 +{% endblock %} +

Welcome to XSS Challenge

+
+ {% csrf_token %} +
+ + +
+ +
+
+

{{code}}

+ +
+
+ +
+{% endblock content %} diff --git a/introduction/templates/Lab/XXE/xxe.html b/introduction/templates/Lab/XXE/xxe.html new file mode 100644 index 0000000..a59d478 --- /dev/null +++ b/introduction/templates/Lab/XXE/xxe.html @@ -0,0 +1,98 @@ +{% extends 'introduction/base.html' %} +{% block content %} +{% block title %} +XXE Injection +{% endblock %} +
+

XXE Injection

+
+ +

What is XML External Entity Injection

+

XML External Entity injection (also known as XXE) is a web security vulnerability that allows an + attacker to interfere with an application's processing of XML data. It is a type of attack against an + application that parses XML input. This attack occurs when XML input containing a reference to an external + entity is processed by a weakly configured XML parser.
+ It often allows an attacker to view files on the application server filesystem, and to interact with any + back-end or external systems that the application itself can access.
+ In some situations, an attacker can escalate an XXE attack to compromise the underlying server or other + back-end infrastructure, by leveraging the XXE vulnerability to perform server-side request forgery (SSRF) + attacks. +

+ +
+

+ +

+ This lab helps us to understand how xxe vulnerabilities can be exploited in the wild. + The lab consists of a commenting feature which asks the user to enter his/her thoughts about a picture + show! + Once he enters his comments, he is also given a feature to see how his comments are stored in the + database. + This can be done by clicking the click here button . +

+

+ What could go wrong here?
+ When the user clicks the button to save his comments, the data is sent to the server in the from of xml + post request. + This can be seen by intercepting the request done to the server by that button using BurpSuite.
+ Sending data to the server in the form of XML is not actually vulnerable, the vulnerability lies in the + way the xml is being parsed. + An xml parser which allows the DTD retrival is vulnerable to XXE injection if there aren't any input + validations done on the xml data. + +

+

+ Exploiting the XML Parser +

    +
  • Open Burpsuite and make sure it is ready to capture the web traffic.
  • +
  • Enter your comments in the input box provided.
  • +
  • Before hiting the Let the world see button go to burpsuite and turn on intercept.
  • +
  • Now you should be able to see a post request containing a xml data with your comment inside your the + text tag.
  • +
  • Now we need to introduce a DTD, which tries to fetch files from its server.
  • +
  • This can be done by using the document tag and defining the Entity.
  • +
  • The Payload

  • + + <?xml version='1.0'?>
    + <!DOCTYPE comm [
    + <!ELEMENT comm (#PCDATA)>
    + <!ENTITY xxe SYSTEM "File_Path_Here">
    + ]>
    + <comm>
    + <text>&xxe;</text>
    + </comm>
    +

    +
  • Incase if the server is runnning linux then use file path file:///etc/passwd and if its + running windows, use C:\windows\system32\drivers\etc\hosts. This will dump sensitive + data about all users
  • +
  • Forward the request and turn of intercept.
  • +
  • Go to the see comments option and click view comments this should show you the requested files in + your payload if the vulnerability exists.
  • +
+

+ + +

+ +
+
+ +

+
+

Mitigation

+

+

    +
  • DTD and XML external entity features must be disabled.
  • +
  • All XML processors and libraries used in the application must be patched and updated always.
  • +
  • Ensure that the user inputs are validated before being parsed
  • +
  • Make use of a good xml parsers, which arent vulnerable by default.
  • +
+

+
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/XXE/xxe_lab.html b/introduction/templates/Lab/XXE/xxe_lab.html new file mode 100644 index 0000000..6153c1f --- /dev/null +++ b/introduction/templates/Lab/XXE/xxe_lab.html @@ -0,0 +1,37 @@ +{% extends "introduction/base.html" %} +{% load static %} +{% block content %} +{% block title %} +XXE LAB +{% endblock %} + + + +
+ +

+ + +
+ + + + +
+
+
+

To see your comments

+

+
+
Your comments :
+
{{com}}
+
+ + +
+
+ +

+ +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/insec_des/insec_des.html b/introduction/templates/Lab/insec_des/insec_des.html new file mode 100644 index 0000000..3712c38 --- /dev/null +++ b/introduction/templates/Lab/insec_des/insec_des.html @@ -0,0 +1,82 @@ +{% extends 'introduction/base.html' %} +{% block content %} +{% block title %} +Insecure Deserialization +{% endblock %} +
+

Insecure Deserialization

+
+

What is Insecure Deserialization

+

+ Exploitation of deserialization is somewhat difficult, as off the shelf exploits rarely work without changes or + tweaks to the underlying exploit code. + This issue is included in the Top 10 based on an industry survey and not on quantifiable data. + Some tools can discover deserialization flaws, but human assistance is frequently needed to validate the problem. + It is expected that prevalence data for deserialization flaws will increase as tooling is developed to help + identify and address it. + The impact of deserialization flaws cannot be overstated. These flaws can lead to remote code execution attacks, + one of the most serious attacks possible. + The business impact depends on the protection needs of the application and data. +

+ + +
+

+ This Lab consists of a Page that has some content only available to for the admin to see, How can we access that + page as admin? How is our role defined? +

+

If we check the cookie we see that it is base64 encoded, on decoding we realise it is pickle + serialised and we can see some attributes, can you change the attributes to make the page readable? +

+

Hint: try to flip the bit of the admin from ...admin\x94K\x00... to ...admin\x94K\x00... +

+
+
+ +
+
+

Insecure Deserialization

+

+ Applications and APIs will be vulnerable if they deserialize hostile or tampered objects supplied by an attacker. + This can result in two primary types of attacks: +

+
    +
  • Object and data structure related attacks where the attacker modifies application logic or achieves arbitrary + remote code execution if there are classes available to the application that can change behavior during or after + deserialization.
  • +
  • Typical data tampering attacks such as access-control-related attacks where existing data structures are used + but the content is changed.
  • +
+

+ Serialization may be used in applications for: +

+
    +
  • Remote- and inter-process communication (RPC/IPC)
  • +
  • Wire protocols, web services, message brokers
  • +
  • Caching/Persistence
  • +
  • Databases, cache servers, file systems
  • +
  • HTTP cookies, HTML form parameters, API authentication tokens
  • +
+

+ How to Prevent +

+

The only safe architectural pattern is not to accept serialized objects from untrusted sources or to + use serialization mediums that only permit primitive data types. If that is not possible, consider one of more of + the following: +

+
    +
  • Implementing integrity checks such as digital signatures on any serialized objects to prevent hostile object + creation or data tampering.
  • +
  • Enforcing strict type constraints during deserialization before object creation as the code typically expects + a definable set of classes. Bypasses to this technique have been demonstrated, so reliance solely on this is not + advisable.
  • +
  • Isolating and running code that deserializes in low privilege environments when possible.
  • +
  • Log deserialization exceptions and failures, such as where the incoming type is not the expected type, or the + deserialization throws exceptions.
  • +
  • Restricting or monitoring incoming and outgoing network connectivity from containers or servers that + deserialize. + Monitoring deserialization, alerting if a user deserializes constantly.
  • +
+
+
+{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/insec_des/insec_des_lab.html b/introduction/templates/Lab/insec_des/insec_des_lab.html new file mode 100644 index 0000000..43900ec --- /dev/null +++ b/introduction/templates/Lab/insec_des/insec_des_lab.html @@ -0,0 +1,19 @@ +{% extends "introduction/base.html" %} +{% block content %} +{% block title %} +INSECURE DESERIALIZATION LAB +{% endblock %} + +
+
+
{{message}}
+
+
+ +
+
+ +

+ +{% endblock content %} \ No newline at end of file diff --git a/introduction/templates/Lab/sec_mis/sec_mis.html b/introduction/templates/Lab/sec_mis/sec_mis.html new file mode 100644 index 0000000..b90e19c --- /dev/null +++ b/introduction/templates/Lab/sec_mis/sec_mis.html @@ -0,0 +1,85 @@ +{% extends 'introduction/base.html' %} +{% block content %} +{% block title %} +Security Misconfiguration +{% endblock %} +
+

+
+

What is Security Misconfiguration

+

+ Security misconfiguration can happen at any level of an application stack, including the network services, + platform, web server, application server, database, frameworks, custom code, and pre-installed virtual machines, + containers, or storage. Automated scanners are useful for detecting misconfigurations, use of default accounts or + configurations, unnecessary services, legacy options, etc. +

+

+ Such flaws frequently give attackers unauthorized access to some system data or functionality. Occasionally, such + flaws result in a complete system compromise. + The business impact depends on the protection needs of the application and data. +

+ + +
+

+ This lab has a Security misconfiguration. It has a button which reveal the secret key but it is only accessible + if the admin is accessing it. How to checkin as admin? Is there a cookie, OR A request header? + + Hint: +

    +
  • Clicking on the Secret Key button gives an error message, try using the hint to change the request.
  • +
+

+
+
+ +
+
+ + +
+

+ One of the features of having DEBUG=True is dumping lots of metadata from your environment, including the whole settings.py configurations, when a exception occurs. +
Can u trigger a 500 error and get the SENSITIVE_DATA ? +

+
+
+ +
+
+ + +
+

+ Solve lab2 before solving this.
+

Can you login as admin ?

+
For hint you can see the code in the lab page.. +

+
+
+ +
+
+ + +

Security Misconfiguration

+

+ The application might be vulnerable if the application is: +

    +
  • Missing appropriate security hardening across any part of the application stack, or improperly configured + permissions on cloud services.
  • +
  • Unnecessary features are enabled or installed (e.g. unnecessary ports, services, pages, accounts, or + privileges).
  • +
  • Default accounts and their passwords still enabled and unchanged.
  • +
  • Error handling reveals stack traces or other overly informative error messages to users.
  • +
  • For upgraded systems, latest security features are disabled or not configured securely.
  • +
  • The security settings in the application servers, application frameworks (e.g. Struts, Spring, ASP.NET), + libraries, databases, etc. not set to secure values.
  • +
  • The server does not send security headers or directives or they are not set to secure values.
  • +
  • The software is out of date or vulnerable (see A9:2017-Using Components with Known Vulnerabilities). + Without a concerted, repeatable application security configuration process, systems are at a higher risk.
  • +
+

+
+
+{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/sec_mis/sec_mis_lab.html b/introduction/templates/Lab/sec_mis/sec_mis_lab.html new file mode 100644 index 0000000..25b410b --- /dev/null +++ b/introduction/templates/Lab/sec_mis/sec_mis_lab.html @@ -0,0 +1,32 @@ +{% extends "introduction/base.html" %} +{% load static %} +{% block content %} +{% block title %} +Security Misconfiguration +{% endblock %} + + +
+

+ + + {% if secret %} +

Success. You have the secret +
{{secret}}
+

+ {% endif %} + + {% if no_secret %} +

{{no_secret}}

+ {% endif %} + +
+ + +
+
+ +

+ +{% endblock content %} \ No newline at end of file diff --git a/introduction/templates/Lab/sec_mis/sec_mis_lab3.html b/introduction/templates/Lab/sec_mis/sec_mis_lab3.html new file mode 100644 index 0000000..5e1b2d4 --- /dev/null +++ b/introduction/templates/Lab/sec_mis/sec_mis_lab3.html @@ -0,0 +1,53 @@ +{% extends "introduction/base.html" %} +{% load static %} +{% block content %} +{% block title %} +Security Misconfiguration +{% endblock %} +
+ {% if admin %} +

loggedin as Admin +

+ {% else %} + +

+ User Not allowed. [ Admin Only ] +

+ {% endif %} + +
+ + + +
+ + from pygoat.settings import SECRET_COOKIE_KEY

+def sec_misconfig_lab3(request):
+ if not request.user.is_authenticated:
+  return redirect('login')
+ try:
+  cookie = request.COOKIES["auth_cookie"]
+  payload = jwt.decode(cookie, SECRET_COOKIE_KEY, algorithms=['HS256'])
+  if payload['user'] == 'admin':
+   return render(request,"Lab/sec_mis/sec_mis_lab3.html", {"admin":True} )
+ except:
+  payload = {
+   'user':'not_admin',
+   'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=60),
+   'iat': datetime.datetime.utcnow(),
+  }
+
+  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)
+  return response
+
+ +
+ +
+ +

+ +{% endblock content %} \ No newline at end of file diff --git a/introduction/templates/Lab/ssrf/blogs/blog1.txt b/introduction/templates/Lab/ssrf/blogs/blog1.txt new file mode 100644 index 0000000..87940b7 --- /dev/null +++ b/introduction/templates/Lab/ssrf/blogs/blog1.txt @@ -0,0 +1,9 @@ +Overview + +This category is added from the Top 10 community survey (#1). The data shows a relatively low incidence rate with above average testing coverage and above-average Exploit and Impact potential ratings. As new entries are likely to be a single or small cluster of Common Weakness Enumerations (CWEs) for attention and awareness, the hope is that they are subject to focus and can be rolled into a larger category in a future edition. + +Description + +SSRF flaws occur whenever a web application is fetching a remote resource without validating the user-supplied URL. It allows an attacker to coerce the application to send a crafted request to an unexpected destination, even when protected by a firewall, VPN, or another type of network access control list (ACL). + +As modern web applications provide end-users with convenient features, fetching a URL becomes a common scenario. As a result, the incidence of SSRF is increasing. Also, the severity of SSRF is becoming higher due to cloud services and the complexity of architectures. \ No newline at end of file diff --git a/introduction/templates/Lab/ssrf/blogs/blog2.txt b/introduction/templates/Lab/ssrf/blogs/blog2.txt new file mode 100644 index 0000000..d214055 --- /dev/null +++ b/introduction/templates/Lab/ssrf/blogs/blog2.txt @@ -0,0 +1,28 @@ +How to Prevent ? +Developers can prevent SSRF by implementing some or all the following defense in depth controls: + +From Network layer +Segment remote resource access functionality in separate networks to reduce the impact of SSRF + +Enforce โ€œdeny by defaultโ€ firewall policies or network access control rules to block all but essential intranet traffic. +Hints: +~ Establish an ownership and a lifecycle for firewall rules based on applications. +~ Log all accepted and blocked network flows on firewalls (see A09:2021-Security Logging and Monitoring Failures). + +From Application layer: +Sanitize and validate all client-supplied input data + +Enforce the URL schema, port, and destination with a positive allow list + +Do not send raw responses to clients + +Disable HTTP redirections + +Be aware of the URL consistency to avoid attacks such as DNS rebinding and โ€œtime of check, time of useโ€ (TOCTOU) race conditions + +Do not mitigate SSRF via the use of a deny list or regular expression. Attackers have payload lists, tools, and skills to bypass deny lists. + +Additional Measures to consider: +Don't deploy other security relevant services on front systems (e.g. OpenID). Control local traffic on these systems (e.g. localhost) + +For frontends with dedicated and manageable user groups use network encryption (e.g. VPNs) on independent systems to consider very high protection needs \ No newline at end of file diff --git a/introduction/templates/Lab/ssrf/blogs/blog3.txt b/introduction/templates/Lab/ssrf/blogs/blog3.txt new file mode 100644 index 0000000..13ef764 --- /dev/null +++ b/introduction/templates/Lab/ssrf/blogs/blog3.txt @@ -0,0 +1,28 @@ +How to Prevent +Developers can prevent SSRF by implementing some or all the following defense in depth controls: + +From Network layer +Segment remote resource access functionality in separate networks to reduce the impact of SSRF + +Enforce โ€œdeny by defaultโ€ firewall policies or network access control rules to block all but essential intranet traffic. +Hints: +~ Establish an ownership and a lifecycle for firewall rules based on applications. +~ Log all accepted and blocked network flows on firewalls (see A09:2021-Security Logging and Monitoring Failures). + +From Application layer: +Sanitize and validate all client-supplied input data + +Enforce the URL schema, port, and destination with a positive allow list + +Do not send raw responses to clients + +Disable HTTP redirections + +Be aware of the URL consistency to avoid attacks such as DNS rebinding and โ€œtime of check, time of useโ€ (TOCTOU) race conditions + +Do not mitigate SSRF via the use of a deny list or regular expression. Attackers have payload lists, tools, and skills to bypass deny lists. + +Additional Measures to consider: +Don't deploy other security relevant services on front systems (e.g. OpenID). Control local traffic on these systems (e.g. localhost) + +For frontends with dedicated and manageable user groups use network encryption (e.g. VPNs) on independent systems to consider very high protection needs \ No newline at end of file diff --git a/introduction/templates/Lab/ssrf/blogs/blog4.txt b/introduction/templates/Lab/ssrf/blogs/blog4.txt new file mode 100644 index 0000000..01dc013 --- /dev/null +++ b/introduction/templates/Lab/ssrf/blogs/blog4.txt @@ -0,0 +1,2 @@ +The purpose is to give both developers and testers a platform for learning how to test applications and how to code securely. PyGoat is written in python and used Django web framework as a platform. It has both traditional web application vulnerabilities (i.e. XSS, SQLi) as well. +PyGoat also has an area where you can see the source code to determine where the mistake was made that caused the vulnerability and allows you to make changes to secure it. \ No newline at end of file diff --git a/introduction/templates/Lab/ssrf/secret.txt b/introduction/templates/Lab/ssrf/secret.txt new file mode 100644 index 0000000..58e6f9e --- /dev/null +++ b/introduction/templates/Lab/ssrf/secret.txt @@ -0,0 +1 @@ +bla bla \ No newline at end of file diff --git a/introduction/templates/Lab/ssrf/ssrf.html b/introduction/templates/Lab/ssrf/ssrf.html new file mode 100644 index 0000000..af73bb0 --- /dev/null +++ b/introduction/templates/Lab/ssrf/ssrf.html @@ -0,0 +1,65 @@ +{% extends 'introduction/base.html' %} {% block content %} {% block title %} +SSRF +{% endblock %} +
+

Server-Side Request Forgery

+
+

What is Server-Side Request Forgery (SSRF)

+

+ SSRF flaws occur whenever a web application is fetching a remote resource without validating the user-supplied URL. It allows an attacker to coerce the application to send a crafted request to an unexpected destination, even when protected by a firewall, VPN, or another type of network access control list (ACL). + + As modern web applications provide end-users with convenient features, fetching a URL becomes a common scenario. As a result, the incidence of SSRF is increasing. Also, the severity of SSRF is becoming higher due to cloud services and the complexity of architectures. +

+ +
+

+ This lab helps you to get an idea of how SSRF can result in major Security flaw. + + The next pages shows some blog, but can you figure out how the blogs are presented? + +
+

+
+ +
+

+ This website sends a request to the given url and displays the page withing the page. + now there is a page at /ssrf_target which only allowes request from localhost ( ie 127.0.0.1 ) +
+ now start the server using python manage.py runserver 0:8000
+ get your network ip using ifconfig or ipcofig(in windows)
+ now go to http://[your ip]/ssrf_target +
+ Now you can't access the page because it is not from localhost. + Try to get access to this page content now using the utility. +

+
+
+
+
+
+

Mitigation

+

+

    + From Network layer +
  • Segment remote resource access functionality in separate networks to reduce the impact of SSRF
  • +
  • Enforce โ€œdeny by defaultโ€ firewall policies or network access control rules to block all but essential intranet traffic.
  • + From Application layer +
  • Sanitize and validate all client-supplied input data
  • +
  • Enforce the URL schema, port, and destination with a positive allow list
  • +
  • Do not send raw responses to clients
  • +
  • Disable HTTP redirections
  • +
  • Be aware of the URL consistency to avoid attacks such as DNS rebinding and โ€œtime of check, time of useโ€ (TOCTOU) race conditions
  • + Additional Measures to consider +
  • Don't deploy other security relevant services on front systems (e.g. OpenID). Control local traffic on these systems (e.g. localhost)
  • +
  • For frontends with dedicated and manageable user groups use network encryption (e.g. VPNs) on independent systems to consider very high protection needs
  • +
+

+ +
+
+
+ +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/ssrf/ssrf_discussion.html b/introduction/templates/Lab/ssrf/ssrf_discussion.html new file mode 100644 index 0000000..7dc6678 --- /dev/null +++ b/introduction/templates/Lab/ssrf/ssrf_discussion.html @@ -0,0 +1,157 @@ +{% extends 'introduction/base.html' %} {% block content %} {% block title %} +SSRF +{% endblock %} + +

Discussion page

+
+
+

Lets fix the code in lab 1 of SSRF

+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
Choose the lines with insecure/defective code
+
+
+
+
+
+
+
+ +
+
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
+ +
+
+ + +
+
Some insecure codes in frontend side also ...
+
+
+
+
+
+
+
+ +
+
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+
  
+ +
+
+
+
+

Now Lets fix the code :)

+

+ Problem Statement : + We need to share file content ( not the file itself ) + Previous method had ssrf valuribility issue. Fix the code so that it can share file content securely. +

+
+
+
views.py
+ +
+
+
ssrf_lab.html
+ +
+
+ +
+
+

Congratulation you have secured the code.

+
+
+ +
+{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/ssrf/ssrf_lab.html b/introduction/templates/Lab/ssrf/ssrf_lab.html new file mode 100644 index 0000000..ab6977e --- /dev/null +++ b/introduction/templates/Lab/ssrf/ssrf_lab.html @@ -0,0 +1,72 @@ +{% extends "introduction/base.html" %} +{% block content %} +{% block title %} +SSRF LAB +{% endblock %} + +
+
+

Read Blog

+
+
+
+
+ {% csrf_token %} + + +
+
+ {% csrf_token %} + + +
+
+ {% csrf_token %} + + +
+
+ {% csrf_token %} + + +
+
+
+ {{ blog }} +
+
+ + +
+ Try to find a .env file +
+ + + +
+ + def ssrf_lab(request):
+ if request.user.is_authenticated:
+  if request.method=="GET":
+   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})
+   except:
+    return render(request, "Lab/ssrf/ssrf_lab.html", {"blog": "No blog found"})
+ else:
+  return redirect('login')
+
+ +
+
+ +
+ +{% endblock %} \ No newline at end of file diff --git a/introduction/templates/Lab/ssrf/ssrf_lab2.html b/introduction/templates/Lab/ssrf/ssrf_lab2.html new file mode 100644 index 0000000..5245899 --- /dev/null +++ b/introduction/templates/Lab/ssrf/ssrf_lab2.html @@ -0,0 +1,52 @@ +{% extends "introduction/base.html" %} +{% block content %} +{% block title %} +SSRF LAB +{% endblock %} + +
+ {% if error %} +