{"id":13739634,"url":"https://github.com/anxolerd/dvpwa","last_synced_at":"2025-04-04T12:08:10.084Z","repository":{"id":39615642,"uuid":"98656877","full_name":"anxolerd/dvpwa","owner":"anxolerd","description":"Damn Vulnerable Python Web App","archived":false,"fork":false,"pushed_at":"2024-05-21T18:50:44.000Z","size":989,"stargazers_count":168,"open_issues_count":11,"forks_count":602,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-28T11:10:32.891Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anxolerd.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-07-28T14:22:09.000Z","updated_at":"2025-02-19T21:10:44.000Z","dependencies_parsed_at":"2023-02-14T11:15:20.834Z","dependency_job_id":"e43fd775-ad17-44aa-aca1-9743cafcb8bd","html_url":"https://github.com/anxolerd/dvpwa","commit_stats":{"total_commits":15,"total_committers":1,"mean_commits":15.0,"dds":0.0,"last_synced_commit":"a1d8f89fac2e57093189853c6527c2b01fc1d9c1"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anxolerd%2Fdvpwa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anxolerd%2Fdvpwa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anxolerd%2Fdvpwa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anxolerd%2Fdvpwa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anxolerd","download_url":"https://codeload.github.com/anxolerd/dvpwa/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247174419,"owners_count":20896078,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T04:00:35.971Z","updated_at":"2025-04-04T12:08:10.057Z","avatar_url":"https://github.com/anxolerd.png","language":"Python","funding_links":[],"categories":["Hacking Playground"],"sub_categories":[],"readme":"===============================================\nDVPWA -- Damn Vulnerable Python Web Application\n===============================================\n\n.. image:: https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg\n   :alt: StandWithUkraine\n   :align: center\n   :target: https://stand-with-ukraine.pp.ua\n\nDescription\n===========\n\nDVPWA was inspired by famous `dvwa`_ project and `bobby-tables xkcd comics`_.\nThe purpose of this project is to implement real-world like application in\nPython with as many vulnerabilities as possible while having a good design and\nintentions.\n\nThis project was used as demonstration of vulnerabilities during my\n`Web vulnerabilities`_ presentation at EVO Summer Python Lab'17.\n\nRunning\n=======\n\nDocker-compose\n--------------\n\nDVPWA is packaged into docker container. All the dependencies described in\n:code:`docker-compose.yml`. You can easiliy run it and its dependencies\nusing a simple command:\n\n.. code-block :: bash\n\n    docker-compose up\n\nThen visit http://localhost:8080 in your favorite browser.\n\nTo rebuild the container, please use ``./recreate.sh`` script, which will\ndelete old container and create new from scratch. This script is primarly used\nin order to rebuild application image.\n\nIf you have screwed up the database (i.e. with ``DROP TABLE students;``, please\nissue the following commands to recreate database container:\n\n.. code-block :: bash\n\n    docker-compose stop postgres\n    docker-compose rm  # make sure, you remove only images you want to recreate\n    docker-compose up postgres  # recreate container and run\n\nNatively\n--------\n\nIf for some reasons you cannot use docker or docker-compose you can run the\napplication on your host system.\n\nRequirements\n~~~~~~~~~~~~\n\n- Python3.6.2\n- PostgreSQL database for data storage\n- Redis for session storage\n\nInstalling and running\n~~~~~~~~~~~~~~~~~~~~~~\n\n.. code-block :: bash\n\n    # Install application dependencies.\n    pip install -r requirements.txt\n\n    # Set up postgresql database Further I assume your db user\n    # is named postgres and database name is sqli\n\n    # Create database schema by applying migration 000\n    psql -U postgres --d sqli --host localhot --port 5432 \\\n         -f migrations/000-init-schema.sql\n\n    # Load fixtures into database\n    psql -U postgres --d sqli --host localhot --port 5432 \\\n         -f migrations/001-fixtures.sql\n\n    # Modify config/dev.yaml\n    cat config/dev.yaml \u003c\u003cEOF\n    db:\n      user: postgres\n      password: postgres\n      host: localhost\n      port: 5432\n      database: sqli\n\n    redis:\n      host: localhost\n      port: 6379\n      db: 0\n\n    app:\n      host: 0.0.0.0\n      port: 8080\n    EOF\n\n    # Run application\n    python run.py\n\nThen visit http://localhost:8080 in your favorite browser.\n\n\nVulnerabilities\n===============\n\nSession fixation\n----------------\n\nSteps to reproduce\n~~~~~~~~~~~~~~~~~~\n\n1. Open http://localhost:8080.\n2. Open browser devtools.\n3. Get value for ``AIOHTTP_SESSION`` cookie.\n4. Open http://localhost:8080 in the incognito tab.\n5. In the incognito tab, change cookie value to the one, obtained in step 3.\n6. In the normal tab (the one from steps 1-3) log in as any user.\n7. Refresh page in the incognito tab.\n\nResult\n~~~~~~\n\nYou are now logged in the incognito tab as user from step 6 as well.\n\nMitigation\n~~~~~~~~~~\n\nRotate session identifiers on every single login and logout. Rotate session\nidentifiers on every user_id and/or permissions change.\n\nSQL Injection\n-------------\n\nSteps to reproduce\n~~~~~~~~~~~~~~~~~~\n\n1. Open http://localhost:8080.\n2. Log in as ``superadmin:superadmin``.\n3. Go to http://localhost:8080/students/.\n4. Add new student with the name ``Robert'); DROP TABLE students CASCADE; --``.\n\nResult\n~~~~~~\n\nTable \"students\" is deleted from database. You observe error message, which\nsays: _\"relation \\\"students\\\" does not exist\"_.\n\nMitigation\n~~~~~~~~~~\n\nNever construct database queries using string concatenation. Use\nlibrary-provided way to pass parameters and query separated. Use ORM.\n\nStored XSS\n----------\n\nSteps to reproduce\n~~~~~~~~~~~~~~~~~~\n\n1. Open http://localhost:8080/courses/1/review.\n2. Fill in review content with the following payload:\n\n   .. code-block:: html\n\n      \u003cb\u003eIs this bold?\u003c/b\u003e Yes!\n\n3. Submit the review by clicking \"Save\" button.\n4. Observe the newly created review. Note that text \"Is it bold?\" is bold,\n   which means review content is probably neither sanitized on input nor\n   escaped on output.\n5. Open  http://localhost:8080/courses/1/review.\n6. Fill in review content with the following payload:\n\n   .. code-block:: html\n      \n      \u003cscript\u003e\n        alert('I am a stored XSS. Your cookies are: ' + document.cookie);\n      \u003c/script\u003e\n\n7. Submit the review by clicking \"Save\" button.\n8. Observe the result.\n\nResult\n~~~~~~\n\nNow whenever you load http://localhost:8080/courses/1, you will receive an\nalert, which displays your cookie. You can play with different ways to inject\nyour custom javascript to the page now: event handlers (i.e. ``\u003cimg\nsrc=\"nonexistent\" onerror=\"alert(document.cookie)\"\u003e``, links with javascript\ntargets, etc.\n\nMitigation\n~~~~~~~~~~\n\nEscape all untrusted content, when you output it. In this example, to mitigate\nthis kind of attack you can set ``autoescape=True`` when setting up templating\nengine (Jinja2) in ``sqli/app.py``.\nYou can also sanitize text, when users input it and prohibit different kinds of\ncode injection.\n\nBad choice for storing passwords\n--------------------------------\n\nDescription\n~~~~~~~~~~~\n\nAs per `check_paswword function\n\u003chttps://github.com/anxolerd/dvpwa/blob/master/sqli/dao/user.py#L40-L41\u003e`_ and\n`database initialization script\n\u003chttps://github.com/anxolerd/dvpwa/blob/master/sqli/dao/user.py#L40-L41\u003e`_,\npasswords are not stored in the database themselves, but their md5 hashes.\n\nHere are the problems with such approach:\n\n- As hash function produces same output for same input, same passwords will\n  produce the same hash. Passwords are vulnerable to statistical analysis: it\n  is possible to determine how many people use the same password, how popular\n  the password is, etc:\n\n  .. code-block :: sql\n  \n     sqli=# select pwd_hash, array_agg(username), count(*)\n     sqli-# from \"users\"\n     sqli-# group by pwd_hash \n     sqli-# order by count(*) desc;\n                  pwd_hash             |   array_agg    | count\n     ----------------------------------+----------------+-------\n      5f4dcc3b5aa765d61d8327deb882cf99 | {j.doe,s.king} |     2\n      1da0bac388e8e0409a83e121e1af6ef4 | {p.parker}     |     1\n      17c4520f6cfd1ab53d8745e84681eb49 | {superadmin}   |     1\n     (3 rows)\n\n\n- Md5 is considered quite a weak hash, thus collisions can be easily found.\n  Moreover, this hash is easy to bruteforce, as well as a lot of rainbow tables\n  exists for md5. For example, `CrackStation website\n  \u003chttps://crackstation.net/\u003e`_ can be used for such purposes.\n\nMitigation\n~~~~~~~~~~\n\nPassword themselves should never be stored in database. Special hash functions\nfor passwords exist, such as argon2, bcrypt, pbkdf2. These functions should be\nused instead of plain text passwords or weak hashes like md5, or fast hash\nfunctions like sha1, sha2. For examples, see `password hashing\n\u003chttps://pynacl.readthedocs.io/en/stable/password_hashing/\u003e`_ section on PyNaCL\ndocumentation.\n\nCross-site request forgery\n--------------------------\n\nTBA\n\n\n\n.. _`dvwa`: http://dvwa.co.uk\n.. _`bobby-tables xkcd comics`: https://xkcd.com/327/\n.. _`Web vulnerabilities`: https://www.slideshare.net/OlexandrKovalchuk/web-vulnerabilities-78366279\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanxolerd%2Fdvpwa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanxolerd%2Fdvpwa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanxolerd%2Fdvpwa/lists"}