├── .coveragerc ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.rst ├── LICENSE ├── Makefile ├── README.rst ├── assets ├── __init__.py └── malicious_sql.txt ├── requirements.txt ├── sare_log.db ├── tests.py └── thanos ├── __init__.py ├── constants.py ├── create_db.py ├── gui.py ├── main.py └── utils.py /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = 3 | /home/tasdik/.virtualenvs/thanos/lib/python3.4/site-packages/termcolor.py 4 | /home/tasdik/.virtualenvs/thanos/lib/python3.4/site.py 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #####=== Python ===##### 2 | 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | env/ 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | 45 | # Translations 46 | *.mo 47 | *.pot 48 | 49 | # Django stuff: 50 | *.log 51 | 52 | # Sphinx documentation 53 | docs/_build/ 54 | 55 | # PyBuilder 56 | target/ 57 | 58 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Config file for automatic testing at travis-ci.org 2 | 3 | language: python 4 | 5 | python: 6 | - "3.4" 7 | 8 | # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors 9 | install: 10 | - "pip install -r requirements.txt" 11 | 12 | notifications: 13 | webhooks: 14 | # urls: 15 | # - https://webhooks.gitter.im/e/d0c2d8b26723845bd158 ## for gitter chat 16 | on_success: change # options: [always|never|change] default: always 17 | on_failure: always # options: [always|never|change] default: always 18 | on_start: never # options: [always|never|change] default: always 19 | 20 | # command to run tests, e.g. python setup.py test 21 | script: make tests 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | - Conform to `PEP0008 `__ 5 | - Make sure your code passes **flake8** and **pep257** 6 | 7 | .. code:: bash 8 | 9 | $ make flake8 10 | 11 | For ``pep257`` 12 | 13 | .. code:: bash 14 | 15 | $ make pep257 16 | 17 | - Running the tests 18 | 19 | .. code:: bash 20 | $ make tests 21 | 22 | - Write meaningful commit messages 23 | - Rebase your commits to one commit when making a PR 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016 Tasdik Rahman 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | # https://github.com/prodicus/python-makefile 3 | 4 | # The MIT License (MIT) 5 | 6 | # Copyright (c) 2016 Tasdik Rahman 7 | # http://tasdikrahman.me 8 | # https://twitter.com/tasdikrahman 9 | 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to deal 12 | # in the Software without restriction, including without limitation the rights 13 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | # copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | 17 | # The above copyright notice and this permission notice shall be included in all 18 | # copies or substantial portions of the Software. 19 | 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | # SOFTWARE. 27 | 28 | # Heavily influenced by 29 | # - https://github.com/aclark4life/python-project 30 | # - https://github.com/jidn/python-Makefile/blob/master/Makefile 31 | 32 | # Replace 'requirements.txt' with another filename if needed. 33 | REQUIREMENTS := $(wildcard requirements.txt) 34 | PROJECT = thanos 35 | PYTHON_VERSION = 3 36 | SYS_PYTHON = python$(PYTHON_VERSION) 37 | 38 | clean: 39 | -find . -iname "*.pyc" -exec rm "{}" \; 40 | -find . -iname "__pycache__" -exec rm -rf "{}" \; 41 | 42 | flake8: 43 | # flake8 *.py 44 | flake8 $(PROJECT)/*.py 45 | 46 | pep257: 47 | pep257 $(PROJECT)/*.py 48 | 49 | # http://stackoverflow.com/a/26339924 50 | .PHONY: help 51 | help: 52 | @echo "\nPlease call with one of these targets:\n" 53 | @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F:\ 54 | '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}'\ 55 | | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs | tr ' ' '\n' | awk\ 56 | '{print " - "$$0}' 57 | @echo "\n" 58 | 59 | install: 60 | pip$(PYTHON_VERSION) install -U virtualenv 61 | virtualenv -p /usr/bin/$(SYS_PYTHON) $(PROJECT) 62 | source venv/bin/activate 63 | pip$(PYTHON_VERSION) install -r $(REQUIREMENTS) 64 | 65 | run: 66 | # -find . -iname "*.db" -exec rm "{}" \; 67 | $(SYS_PYTHON) $(PROJECT)/create_db.py 68 | $(SYS_PYTHON) $(PROJECT)/main.py 69 | 70 | tests: 71 | python tests.py -v 72 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | thanos 2 | ====== 3 | 4 | |Build Status| |percentagecov| |grade| |Requirements Status| |License| 5 | 6 | .. image :: http://imgs.xkcd.com/comics/exploits_of_a_mom.png 7 | :target: https://xkcd.com/327/ 8 | 9 | :Author: `Tasdik Rahman `__ 10 | 11 | .. contents:: 12 | :backlinks: none 13 | 14 | .. sectnum:: 15 | 16 | About 17 | ===== 18 | 19 | `[Back to top] `__ 20 | 21 | A little taste of what can happen when you pass parameterized 22 | arguments in your query strings. 23 | 24 | Will be using a GUI as an interface between the user and the database and try out 25 | different vulnerable strings and see if we can acess the database 26 | 27 | **NOTE**: 28 | 29 | +---------------------------------------------------------------------------+------------------------------------------------------------------------------------------+ 30 | | **Vulnerabilities (demo)** | **mitigated version** | 31 | +===========================================================================+==========================================================================================+ 32 | | `thanos/vulnerable `__ | `thanos/input-validation `__ | 33 | +---------------------------------------------------------------------------+------------------------------------------------------------------------------------------+ 34 | 35 | Plan of action 36 | ~~~~~~~~~~~~~~ 37 | 38 | - [✓] Test for ``SQL Injection`` vulnerabilities 39 | - [✓] Test for ``Input validation`` techniques 40 | - [✓] Suggest fixes to the vulnerabilities found(if any) 41 | - [✓] making the GUI using tkinter 42 | - [ ] **Writing testcases** 43 | 44 | Mitigation techniques 45 | ~~~~~~~~~~~~~~~~~~~~~ 46 | 47 | - [✓] Validating email entered by using custom `regex` 48 | - [✓] Replacing the parameterized ``SQL constructs`` in the code and replace it with pythonic API 49 | 50 | DEMO 51 | ==== 52 | 53 | **NOTE** This is the secure version of the demo. Refer the `vulnerable one here `__ 54 | 55 | The database has the following user credentials in it 56 | 57 | .. code:: bash 58 | 59 | tasdik at Acer in ~/Dropbox/projects/thanos on input-validation 60 | $ sqlite3 sare_log.db 61 | -- Loading resources from /home/tasdik/.sqliterc 62 | 63 | SQLite version 3.9.2 2015-11-02 18:31:45 64 | Enter ".help" for usage hints. 65 | sqlite> select * from users; 66 | email name serial_no password 67 | --------------- ---------- ---------- ---------- 68 | admin@gmail.com Admin 1 admin123 69 | foo@outlook.com bar 2 foo123 70 | john@yahoo.com doe 3 john123 71 | sqlite> 72 | 73 | 74 | **When you enter correct user credentials which are there in the database**. 75 | 76 | .. image:: http://i.imgur.com/DwClAPm.jpg 77 | :alt: 78 | 79 | 80 | **If a wrong user details are entered**. Notice that the SQL statements don't get executed 81 | 82 | 83 | .. image:: http://i.imgur.com/wVOG85S.jpg 84 | :alt: 85 | 86 | 87 | **SQL injection anybody?** 88 | 89 | 90 | .. image:: http://i.imgur.com/42YhmpU.jpg 91 | :alt: 92 | 93 | 94 | **The threat was mitigated as the malicious SQL query was not executed** 95 | 96 | Running it 97 | ========== 98 | `[Back to top] `__ 99 | 100 | *Urm. So how do I run it?* 101 | 102 | Installing the dependencies 103 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 104 | 105 | I prefer to use `virtual environments `__ for keeping the global ``python`` interpreter clutter free. But you are free to do a system wide install for the dependencies. 106 | 107 | **You should have `make` installed on your system.** 108 | 109 | .. code:: bash 110 | 111 | $ git clone https://github.com/prodicus/thanos && cd thanos 112 | $ make install 113 | 114 | If ``make install`` gives you an error. Try this 115 | 116 | .. code:: bash 117 | 118 | $ pip install -r requirements.txt 119 | 120 | 121 | Running it! 122 | ~~~~~~~~~~~ 123 | 124 | .. code:: bash 125 | 126 | $ make run 127 | 128 | Cleaning it up 129 | 130 | .. code:: bash 131 | 132 | $ make clean 133 | 134 | When in doubt 135 | ~~~~~~~~~~~~~ 136 | 137 | .. code:: bash 138 | 139 | $ make help 140 | 141 | FAQ 142 | === 143 | `[Back to top] `__ 144 | 145 | Okay, But what does it do? 146 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 147 | 148 | - So there's this database called ``sare_log.db``, (which translates to ``all_people`` in english). We have some users details stored inside this database. 149 | 150 | - We try to exploit the database testing for some common vulnerabilities like 151 | - SQL injection 152 | - input validation 153 | 154 | - **More to come** 155 | 156 | Will I be able to run it on my PC? 157 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 158 | 159 | I have tested this on MAC and Linux based systems currently 160 | 161 | What's with the name? 162 | ~~~~~~~~~~~~~~~~~~~~~ 163 | 164 | Nothing! It's just that I read a lot of Marvel comics. 165 | 166 | The code looks messy! 167 | ~~~~~~~~~~~~~~~~~~~~~ 168 | 169 | *Well, so does your mom!* 170 | 171 | Jokes apart. As I said, this is still a work in progress. 172 | 173 | Contributing 174 | ============ 175 | `[Back to top] `__ 176 | 177 | Refer `CONTRIBUTING.rst `__ 178 | 179 | Issues 180 | ~~~~~~ 181 | 182 | `[Back to top] `__ 183 | 184 | This project is still work in progress so feel free to make PR or give 185 | suggestions by `creating an issue `__ 186 | 187 | Contributers 188 | ~~~~~~~~~~~~ 189 | `[Back to top] `__ 190 | 191 | Built with ♥ and after a lot of marshmellows by 192 | 193 | - `Tasdik Rahman `__ `(@tasdikrahman) `__ 194 | - `Nitesh Sharma `__ 195 | - `Gaurab Chakraborty `__ 196 | - `Keerthika Shekhar `__ 197 | 198 | Legal Stuff 199 | =========== 200 | `[Back to top] `__ 201 | 202 | Built and maintained by `Tasdik Rahman `__ released under the `MIT License `__. See the bundled `LICENSE `_ file for more details. 203 | 204 | .. |Build Status| image:: https://travis-ci.org/prodicus/thanos.svg?branch=input-validation 205 | :target: https://travis-ci.org/prodicus/thanos 206 | .. |Requirements Status| image:: https://requires.io/github/prodicus/thanos/requirements.svg?branch=input-validation 207 | :target: https://requires.io/github/prodicus/thanos/requirements/?branch=input-validation 208 | :alt: Requirements Status 209 | .. |License| image:: https://img.shields.io/pypi/l/pyzipcode-cli.svg 210 | .. |grade| image:: https://api.codacy.com/project/badge/grade/e2cb32eae16242f795f498d40d0d8984 211 | :target: https://www.codacy.com/app/tasdik95/thanos 212 | .. |percentagecov| image:: https://api.codacy.com/project/badge/coverage/e2cb32eae16242f795f498d40d0d8984 213 | :target: https://www.codacy.com/app/tasdik95/thanos -------------------------------------------------------------------------------- /assets/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author: Tasdik Rahman 3 | # @Date: 2016-03-19 09:05:54 4 | # @Last Modified by: Tasdik Rahman 5 | # @Last Modified time: 2016-03-19 09:49:47 6 | -------------------------------------------------------------------------------- /assets/malicious_sql.txt: -------------------------------------------------------------------------------- 1 | SELECT * FROM users WHERE username='*' AND password='' 2 | SELECT * FROM users WHERE username='admin'--' AND password='' 3 | SELECT * FROM users WHERE username='admin' AND password='' OR 1=1--' 4 | SELECT * FROM users WHERE username='';SHUTDOWN --' AND password='' 5 | SELECT * FROM Users WHERE Username='1' OR '1' = '1' AND Password='1' OR '1' = '1' 6 | SELECT * FROM users WHERE username='SELECT Username FROM Users WHERE ID=1' AND password='SELECT MD5(Password) FROM Users WHERE ID=1' 7 | SELECT * FROM users WHERE username='*' AND password='' 8 | SELECT * FROM users WHERE username='admin'#' AND password='' 9 | SELECT * FROM users WHERE username='';DROP tempTable;' AND password='' 10 | SELECT * FROM users WHERE username='admin' AND password='' OR 1=1 --IamJOE' 11 | SELECT * FROM users WHERE username='admin' AND password=' ' OR ''='' 12 | SELECT * FROM users WHERE username='admin' AND password=%27%20or%20%27%27%3D%27 13 | SELECT * FROM users WHERE username='' AND password='' UNION SELECT 1, 'anotheruser', 'doesnt matter', 1-- ' 14 | SELECT * FROM users WHERE username='' AND users NOT IN ('First User', 'Second User');--' AND password='' 15 | SELECT * FROM users WHERE username='admin';DROP myTable--' AND password='' 16 | SELECT * FROM users WHERE username='/*!32302 1/0, */' AND password='' 17 | SELECT * FROM users WHERE username='' AND password='';IF((SELECT user) = 'sa' OR (SELECT user) = 'dbo') SELECT 1 ELSE SELECT 1/0;--' 18 | SELECT * FROM users WHERE username='';waitfor delay '0:0:10'--' AND password='' 19 | SELECT * FROM users WHERE username='CAST('username' AS SIGNED INTEGER)' AND password='' 20 | SELECT * FROM users WHERE username='' UNION SELECT SUM(columntofind) FROM users--' AND password='' 21 | SELECT * FROM users WHERE username='' AND password='' ORDER BY 1;--' 22 | SELECT * FROM users WHERE username='' + (SELECT TOP 1 username FROM users ) + '' AND password='' + (SELECT TOP 1 password FROM users ) + '' 23 | SELECT * FROM users WHERE username='';SELECT name FROM syscolumns WHERE id =(SELECT id FROM sysobjects WHERE name = 'known_table_name');--' AND password='' 24 | SELECT table_name FROM information_schema.columns WHERE column_name = 'username'; 25 | SELECT table_name FROM information_schema.columns WHERE column_name LIKE '%user%'; 26 | SELECT column_name FROM information_schema.columns WHERE table_name = 'Users'; 27 | SELECT column_name FROM information_schema.columns WHERE table_name LIKE '%user%'; 28 | Status API Training Shop Blog About 29 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | coverage==4.3.4 2 | flake8==3.5.0 3 | mccabe==0.6.1 4 | pep257==0.7.0 5 | pep8==1.7.0 6 | pyflakes==1.6.0 7 | termcolor==1.1.0 8 | -------------------------------------------------------------------------------- /sare_log.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tasdikrahman/thanos/d6e49ead6434dce3534dd4fd022fdb7819fdf54f/sare_log.db -------------------------------------------------------------------------------- /tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author: Tasdik Rahman 3 | # @Date: 2016-03-23 21:53:49 4 | # @Last Modified by: Tasdik Rahman 5 | # @Last Modified time: 2016-03-23 23:51:24 6 | 7 | import os 8 | import sqlite3 9 | import unittest 10 | 11 | from thanos import * 12 | 13 | 14 | BASE_DIR = os.path.abspath(os.path.join('.', os.pardir)) 15 | PROJECT_DIR = os.path.join(BASE_DIR, 'thanos') 16 | 17 | 18 | DB_NAME = "sare_log.db" 19 | 20 | SCHEMA = "CREATE TABLE users(" \ 21 | " email TEXT," \ 22 | " name TEXT," \ 23 | " serial_no INTEGER," \ 24 | " password TEXT" \ 25 | ")" 26 | 27 | VALUES = ( 28 | ("admin@gmail.com", "Admin", 1, "admin123"), 29 | ("foo@outlook.com", "bar", 2, "foo123"), 30 | ("john@yahoo.com", "doe", 3, "john123"), 31 | ) 32 | 33 | class TestDatabase(unittest.TestCase): 34 | 35 | """ 36 | Defining all kinds of obstenity to be done with the database in 37 | question 38 | """ 39 | 40 | def _connect(self): 41 | connection = sqlite3.connect(DB_NAME) 42 | cursor = connection.cursor() 43 | return (connection ,cursor) 44 | 45 | def set_up(self): 46 | """ 47 | Sets up the database 48 | """ 49 | test = os.path.isfile(DB_NAME) 50 | connection.close() 51 | 52 | self.assertEqual(test, True) 53 | 54 | def test_db_schema_correct(self): 55 | """checks for the similarity of the schema""" 56 | connection, cursor = self._connect() 57 | ## insert crap 58 | cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") 59 | test = cursor.fetchall() 60 | result = [('users',)] 61 | self.assertEqual(test, result) 62 | 63 | connection.close() 64 | 65 | def test_db_schema_incorrect(self): 66 | connection, cursor = self._connect() 67 | ## insert crap 68 | cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") 69 | test = False 70 | self.assertFalse(test) 71 | 72 | def test_db_values_correct(self): 73 | connection, cursor = self._connect() 74 | test = cursor.execute('select * from users;').fetchall() 75 | result = [ 76 | ('admin@gmail.com', 'Admin', 1, 'admin123'), 77 | ('foo@outlook.com', 'bar', 2, 'foo123'), 78 | ('john@yahoo.com', 'doe', 3, 'john123') 79 | ] 80 | self.assertEqual(test, result) 81 | 82 | connection.close() 83 | 84 | def tear_down(self): 85 | os.remove(DB_NAME) 86 | test = os.path.isfile(DB_NAME) 87 | self.assertEqual(test, False) 88 | 89 | 90 | if __name__ == "__main__": 91 | unittest.main() -------------------------------------------------------------------------------- /thanos/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author: Tasdik Rahman 3 | # @Date: 2016-03-18 21:53:56 4 | # @Last Modified by: Tasdik Rahman 5 | # @Last Modified time: 2016-03-19 09:07:35 6 | 7 | 8 | __name__ = "thanos" 9 | __version__ = "0.0.1" 10 | __email__ = "prodicus@outlook.com" 11 | __author__ = "Tasdik Rahman" 12 | __license__ = "MIT" 13 | -------------------------------------------------------------------------------- /thanos/constants.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author: Tasdik Rahman 3 | # @Date: 2016-03-18 21:53:09 4 | # @Last Modified by: Tasdik Rahman 5 | # @Last Modified time: 2016-03-20 10:34:42 6 | 7 | DB_NAME = "sare_log.db" 8 | 9 | SCHEMA = "CREATE TABLE users(" \ 10 | " email TEXT," \ 11 | " name TEXT," \ 12 | " serial_no INTEGER," \ 13 | " password TEXT" \ 14 | ")" 15 | 16 | VALUES = ( 17 | ("admin@gmail.com", "Admin", 1, "admin123"), 18 | ("foo@outlook.com", "bar", 2, "foo123"), 19 | ("john@yahoo.com", "doe", 3, "john123"), 20 | ) 21 | -------------------------------------------------------------------------------- /thanos/create_db.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author: Tasdik Rahman 3 | # @Date: 2016-03-18 20:21:56 4 | # @Last Modified by: Tasdik Rahman 5 | # @Last Modified time: 2016-03-23 22:37:27 6 | 7 | import sqlite3 8 | 9 | from constants import DB_NAME, SCHEMA, VALUES 10 | 11 | 12 | connection = sqlite3.connect(DB_NAME) 13 | cursor = connection.cursor() 14 | 15 | 16 | def initialize_db(): 17 | """ 18 | Sets up the initial database file and populates it with some random users. 19 | Calls insert_values_to_db() for inserting values inside the DB file 20 | """ 21 | try: 22 | cursor.execute(SCHEMA) 23 | except sqlite3.OperationalError as msg: 24 | return msg 25 | 26 | 27 | def insert_values_to_db(): 28 | """ 29 | Populates the database with 'VALUES' 30 | """ 31 | try: 32 | cursor.executemany("INSERT INTO users VALUES (?, ?, ?, ?)", VALUES) 33 | connection.commit() 34 | connection.close() 35 | except sqlite3.OperationalError as msg: 36 | return msg 37 | 38 | 39 | def main(): 40 | initialize_db() 41 | insert_values_to_db() 42 | 43 | 44 | if __name__ == "__main__": 45 | main() 46 | -------------------------------------------------------------------------------- /thanos/gui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author: Tasdik Rahman 3 | # @Date: 2016-03-19 00:10:33 4 | # @Last Modified by: Tasdik Rahman 5 | # @Last Modified time: 2016-03-21 09:28:07 6 | 7 | """ 8 | Contains the class 'GuiLogin()' which will be imported by 'main.py' to be run 9 | 10 | References: 11 | [1]: http://www.python-course.eu/tkinter_variable_classes.php 12 | [2]: https://pymotw.com/2/sqlite3/#row-objects 13 | [3]: http://stackoverflow.com/a/1301369/3834059 14 | """ 15 | 16 | from tkinter import * 17 | import sqlite3 18 | 19 | from termcolor import colored 20 | 21 | from constants import DB_NAME 22 | from utils import email_validator, password_validator 23 | 24 | 25 | class GuiLogin(Frame): 26 | 27 | """ 28 | The tkinter class which defines the structure and functions of th GUI 29 | """ 30 | 31 | def __init__(self): 32 | """ 33 | Initializes the tkinter object and aggregates the data to be displayed 34 | """ 35 | # Create and add GUI components to the screen 36 | Frame.__init__(self) 37 | self.master.title("Login Screen") 38 | 39 | self.master.minsize(300, 200) 40 | self.pack() 41 | 42 | self._usernameLabel = Label(self, text="Enter email") 43 | self._usernameLabel.pack() 44 | 45 | """StringVar() makes self._usernameVar store "" by default 46 | Ref: [1] 47 | """ 48 | self._usernameVar = StringVar() 49 | self._usernameEntry = Entry( 50 | self, textvariable=self._usernameVar, width=30) 51 | self._usernameEntry.pack() 52 | 53 | self._passwordLabel = Label(self, text="Enter password") 54 | self._passwordLabel.pack() 55 | 56 | self._passwordVar = StringVar() 57 | self._passwordEntry = Entry( 58 | self, textvariable=self._passwordVar, width=30) 59 | self._passwordEntry.pack() 60 | 61 | self._loginButton = Button(self, text="Login", command=self._login) 62 | self._loginButton.pack() 63 | 64 | self._resultVar = StringVar() 65 | self._resultLabel = Label( 66 | self, text=" \n ", textvariable=self._resultVar) 67 | self._resultLabel.pack() 68 | 69 | self._quitButton = Button(self, text="Quit", command=self._quit) 70 | self._quitButton.pack() 71 | 72 | def _quit(self): 73 | """ 74 | Exits from the GUI that we are running 75 | """ 76 | exit(0) 77 | 78 | def _db_connect(self): 79 | """ 80 | Called by the '_authenticate()' method. 81 | 82 | Connects to the database and returns the cursor object. 83 | 84 | :returns: The cursor object to the databas 'DB_NAME' 85 | """ 86 | connection = sqlite3.connect(DB_NAME) 87 | # Using row objects 88 | # ref: [2] 89 | connection.row_factory = sqlite3.Row 90 | """ 91 | row_factory will allow us to refer to the columns by their names 92 | instead of their index numbers 93 | """ 94 | return (connection, connection.cursor()) 95 | 96 | # more on private and protected classes 97 | # ref: [3] 98 | def _authenticate(self, email, password): 99 | """ 100 | Called by the method '_login()' 101 | 102 | Unpacks the **kwargs key pair value to get email and password 103 | and query it to the database in an unsecure way to demonstrate SQL 104 | injection 105 | 106 | :param email: email entered by the user 107 | :param password: Password entered by the user 108 | :returns: None or a result from the database based on the success of 109 | the user query 110 | """ 111 | print( 112 | colored("Attempting to login with email:'{0}' " 113 | "password:'{1}'".format(email, password), 114 | "yellow" 115 | ) 116 | ) 117 | 118 | connection, cursor = self._db_connect() 119 | 120 | # validating username and password entered by the user 121 | if not email_validator(email) and password_validator(password): 122 | self._resultVar.set("Gotcha you invalid Input!") 123 | 124 | else: 125 | # Defining the vulnerable SQL query which will be used to exploit the database 126 | # usign SQL injection 127 | # SQL_QUERY = '''SELECT name FROM users WHERE email = '%s' and password = '%s' ''' % (email, password) 128 | 129 | # --- Secure method --- 130 | ## parameterized SQL query 131 | cursor.execute("""SELECT name FROM users 132 | WHERE 133 | email=? and password=? 134 | """,(email, password) 135 | ) 136 | 137 | # print("Executing the SQL query") 138 | # print(colored(SQL_QUERY, "yellow")) 139 | 140 | 141 | # Will assume here that the login failed, if no rows are returned back 142 | # by the database 143 | response = None 144 | # This loop won't run if no results are returned. 145 | for row in cursor: 146 | response = row['name'] # Extract name from first row 147 | break 148 | 149 | connection.close() 150 | return response 151 | 152 | def _login(self): 153 | """ 154 | Calls the 155 | 156 | parses the user input for email and password and calls the 157 | '_authenticate()' 158 | 159 | 160 | 161 | TO-DO: To add input validation using WTForms, which will address the 162 | issue(I guess!) 163 | """ 164 | kwargs = { 165 | "email": self._usernameVar.get(), 166 | "password": self._passwordVar.get() 167 | } 168 | 169 | response = self._authenticate(**kwargs) 170 | 171 | if response is None: # 'is' checks for object similarity. 172 | result_of_query = "email or password was incorrect" 173 | else: 174 | result_of_query = "Logged in! :)" 175 | 176 | self._resultVar.set(result_of_query) 177 | -------------------------------------------------------------------------------- /thanos/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author: Tasdik Rahman 3 | # @Date: 2016-03-18 18:59:22 4 | # @Last Modified by: Tasdik Rahman 5 | # @Last Modified time: 2016-03-19 19:42:22 6 | 7 | import os 8 | 9 | from gui import GuiLogin 10 | 11 | 12 | PARENT_DIR = os.path.abspath(os.path.join('.', os.pardir)) 13 | PROJECT_DIR = os.path.join(PARENT_DIR, 'thanos') 14 | 15 | 16 | def main(): 17 | """ 18 | Makes an instance of the class 'GuiLogin()'' and runs the mainloop 19 | """ 20 | GuiLogin().mainloop() 21 | 22 | if __name__ == "__main__": 23 | main() 24 | -------------------------------------------------------------------------------- /thanos/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author: Tasdik Rahman 3 | # @Date: 2016-03-20 10:52:15 4 | # @Last Modified by: Tasdik Rahman 5 | # @Last Modified time: 2016-04-15 19:17:35 6 | 7 | """ 8 | Tries to validate the email address entered by the user to the GUI. 9 | 10 | References: 11 | [1]: http://stackoverflow.com/q/3217682/3834059 12 | [*]: http://stackoverflow.com/q/201323/3834059 13 | """ 14 | 15 | import re 16 | import string 17 | 18 | # ref: [1] 19 | REGEX_EXP = "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$" 20 | PUNCTUATIONS = string.punctuation 21 | 22 | def email_validator(email): 23 | """ 24 | A simple regex which checks whether the entered user email is a valid 25 | email address or not 26 | """ 27 | if len(email) > 6: 28 | if re.match(REGEX_EXP, email) != None: 29 | return True 30 | return False 31 | 32 | def password_validator(password): 33 | """ 34 | Rejects a password if the password has special characters in it 35 | """ 36 | if list(PUNCTUATIONS) in password: 37 | """ 38 | >>> list(string.punctuation) 39 | ['!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', 40 | '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', 41 | '{', '|', '}', '~'] 42 | >>> 43 | """ 44 | return False 45 | else: 46 | return True --------------------------------------------------------------------------------